diff options
author | Mikael Magnusson <mikma@users.sourceforge.net> | 2021-01-23 01:14:51 +0100 |
---|---|---|
committer | Mikael Magnusson <mikma@users.sourceforge.net> | 2021-01-23 21:43:01 +0100 |
commit | 2ce080f581556f9512a481e7fcddecaed0ae7be7 (patch) | |
tree | 13e32a386e0fbddd21aa22f07fd1b841a51e2099 /pkg/tcpip/sample | |
parent | 0627e26831c8c58a5fab619d127587dc1ad8a19b (diff) |
WIP GRE tunnel
Diffstat (limited to 'pkg/tcpip/sample')
-rw-r--r-- | pkg/tcpip/sample/tun_tcp_connect/main.go | 145 |
1 files changed, 140 insertions, 5 deletions
diff --git a/pkg/tcpip/sample/tun_tcp_connect/main.go b/pkg/tcpip/sample/tun_tcp_connect/main.go index a7da9dcd9..f44237295 100644 --- a/pkg/tcpip/sample/tun_tcp_connect/main.go +++ b/pkg/tcpip/sample/tun_tcp_connect/main.go @@ -41,6 +41,7 @@ package main import ( + "context" "bufio" "fmt" "log" @@ -54,12 +55,16 @@ import ( "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/buffer" "gvisor.dev/gvisor/pkg/tcpip/header" + "gvisor.dev/gvisor/pkg/tcpip/link/channel" "gvisor.dev/gvisor/pkg/tcpip/link/fdbased" + grelink "gvisor.dev/gvisor/pkg/tcpip/link/gre" "gvisor.dev/gvisor/pkg/tcpip/link/rawfile" "gvisor.dev/gvisor/pkg/tcpip/link/sniffer" "gvisor.dev/gvisor/pkg/tcpip/link/tun" "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" "gvisor.dev/gvisor/pkg/tcpip/stack" + "gvisor.dev/gvisor/pkg/tcpip/transport/gre" + "gvisor.dev/gvisor/pkg/tcpip/transport/raw" "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" "gvisor.dev/gvisor/pkg/waiter" ) @@ -93,9 +98,75 @@ func writer(ch chan struct{}, ep tcpip.Endpoint) { } } +type GrePacketInfo struct { + pi *channel.PacketInfo +} + +func (g GrePacketInfo) FullPayload() ([]byte, *tcpip.Error){ + log.Println("FullPayload") + pkt := g.pi.Pkt + size := pkt.Size() + vv := buffer.NewVectorisedView(size, pkt.Views()) + var buf = make([]byte, size, size) + pos := 0 + for { + copied, err := vv.Read(buf[pos:]) + log.Printf("VectorisedView Read: %d %d %d %v", size, pos, copied, err) + if err != nil { + return nil, tcpip.ErrBadBuffer + } + pos = pos + copied + if pos == size { + break + } + } + + log.Printf("FullPayload return: %d %v", len(buf), buf) + return buf, nil +} + +func (g GrePacketInfo) Payload(size int) ([]byte, *tcpip.Error){ + log.Println("Payload") + return nil, tcpip.ErrNotSupported +} + +type GreHandlerInfo struct { + ChEp *channel.Endpoint + Raw tcpip.Endpoint + Raddr tcpip.FullAddress +} + +func (info *GreHandlerInfo) greHandler(req *gre.ForwarderRequest) { + pkt := req.Pkt + log.Println("greHandler: ", req.Pkt.Size(), req.Pkt.Views()) + views := pkt.Data.Views() + size := pkt.Data.Size() + data := buffer.NewVectorisedView(size, views) + newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ + Data: data, + }) + log.Println("greHandler cloned: ", newPkt.Views()) + + info.ChEp.InjectInbound(header.IPv4ProtocolNumber, newPkt) +} + +func (info *GreHandlerInfo) greRead(ep *channel.Endpoint) { + for { + pi, err := ep.ReadContext(context.Background()); + linkHdr := pi.Pkt.LinkHeader() + greHdr := header.GRE(linkHdr.Push(4)) //header.IPv4MinimumSize + 4) + greHdr.SetProtocolType(header.IPv4ProtocolNumber) + log.Printf("greRead %d %v %v %v", pi.Proto, pi, err, greHdr) + opts := tcpip.WriteOptions{ + //To: &info.Raddr + } + info.Raw.Write(GrePacketInfo{&pi}, opts) + } +} + func main() { - if len(os.Args) != 6 { - log.Fatal("Usage: ", os.Args[0], " <tun-device> <local-ipv4-address> <local-port> <remote-ipv4-address> <remote-port>") + if len(os.Args) != 8 { + log.Fatal("Usage: ", os.Args[0], " <tun-device> <local-ipv4-address> <local-port> <remote-ipv4-address> <remote-port> <local-gre-address> <remote-gre-address>") } tunName := os.Args[1] @@ -103,15 +174,21 @@ func main() { portName := os.Args[3] remoteAddrName := os.Args[4] remotePortName := os.Args[5] + greAddrName := os.Args[6] + greRemoteAddrName := os.Args[7] rand.Seed(time.Now().UnixNano()) addr := tcpip.Address(net.ParseIP(addrName).To4()) + greAddr := tcpip.Address(net.ParseIP(greAddrName).To4()) + greRemoteAddr := tcpip.Address(net.ParseIP(greRemoteAddrName).To4()) remote := tcpip.FullAddress{ - NIC: 1, + NIC: 0, Addr: tcpip.Address(net.ParseIP(remoteAddrName).To4()), } + log.Printf("local:%v remote:%v", addr, remote) + var localPort uint16 if v, err := strconv.Atoi(portName); err != nil { log.Fatalf("Unable to convert port %v: %v", portName, err) @@ -129,7 +206,7 @@ func main() { // NIC and ipv4 address. s := stack.New(stack.Options{ NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol}, - TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol}, + TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, gre.NewProtocol}, }) mtu, err := rawfile.GetMTU(tunName) @@ -150,17 +227,73 @@ func main() { log.Fatal(err) } - if err := s.AddAddress(1, ipv4.ProtocolNumber, addr); err != nil { + if err := s.AddAddress(1, ipv4.ProtocolNumber, greAddr); err != nil { + log.Fatal(err) + } + + // Create TCP endpoint. + var rawWq waiter.Queue + rawEp, tcperr := raw.NewEndpoint(s, ipv4.ProtocolNumber, 47, &rawWq) + if tcperr != nil { + log.Fatal(tcperr) + } + log.Println("EP: %s", rawEp) + + raddr := greRemoteAddr + fraddr := tcpip.FullAddress{NIC: 1, Addr: raddr} + fgreAddr := tcpip.FullAddress{NIC: 1, Addr: greAddr} + tcperr = rawEp.Bind(fgreAddr) + if tcperr != nil { + log.Fatal(tcperr) + } + log.Printf("Remote: %v %v", raddr, fraddr) + + // Create GRE + greEP := grelink.New(mtu - 24) + chEP := greEP.GetChannel() + greEP.NMaxHeaderLength = 4 + 20 + + greInfo := GreHandlerInfo{ +// Ep: loEP, + ChEp: chEP, + Raw: rawEp, + Raddr: fraddr, + } + greFwd := gre.NewForwarder(s, greInfo.greHandler) + s.SetTransportProtocolHandler(47, greFwd.HandlePacket) + + go greInfo.greRead(chEP) + //greEP.Bind(s, greIP) + if err := s.CreateNIC(2, sniffer.New(greEP)); err != nil { + log.Fatal(err) + } + if err := s.AddAddress(2, ipv4.ProtocolNumber, addr); err != nil { log.Fatal(err) } // Add default route. + subnet, err := tcpip.NewSubnet( + tcpip.Address(net.ParseIP("10.0.1.0").To4()), + tcpip.AddressMask(net.ParseIP("255.255.255.0").To4())) + if err != nil { + panic(err) + } s.SetRouteTable([]tcpip.Route{ { + Destination: subnet, + NIC: 2, + }, + { Destination: header.IPv4EmptySubnet, NIC: 1, }, }) + log.Printf("Nics enabled 1:%v 2:%v 3:%v", s.CheckNIC(1), s.CheckNIC(2), s.CheckNIC(3)) + + tcperr = rawEp.Connect(fraddr) + if tcperr != nil { + log.Fatal(tcperr) + } // Create TCP endpoint. var wq waiter.Queue @@ -179,7 +312,9 @@ func main() { // Issue connect request and wait for it to complete. waitEntry, notifyCh := waiter.NewChannelEntry(nil) wq.EventRegister(&waitEntry, waiter.EventOut) + fmt.Println("Connect") terr := ep.Connect(remote) + fmt.Println("Connect called") if terr == tcpip.ErrConnectStarted { fmt.Println("Connect is pending...") <-notifyCh |