From d02b74a5dcfed4bfc8f2f8e545bca4d2afabb296 Mon Sep 17 00:00:00 2001 From: Googler Date: Fri, 27 Apr 2018 10:37:02 -0700 Subject: Check in gVisor. PiperOrigin-RevId: 194583126 Change-Id: Ica1d8821a90f74e7e745962d71801c598c652463 --- pkg/tcpip/sample/tun_tcp_echo/main.go | 182 ++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 pkg/tcpip/sample/tun_tcp_echo/main.go (limited to 'pkg/tcpip/sample/tun_tcp_echo/main.go') diff --git a/pkg/tcpip/sample/tun_tcp_echo/main.go b/pkg/tcpip/sample/tun_tcp_echo/main.go new file mode 100644 index 000000000..10cd701af --- /dev/null +++ b/pkg/tcpip/sample/tun_tcp_echo/main.go @@ -0,0 +1,182 @@ +// Copyright 2016 The Netstack Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This sample creates a stack with TCP and IPv4 protocols on top of a TUN +// device, and listens on a port. Data received by the server in the accepted +// connections is echoed back to the clients. +package main + +import ( + "flag" + "log" + "math/rand" + "net" + "os" + "strconv" + "strings" + "time" + + "gvisor.googlesource.com/gvisor/pkg/tcpip" + "gvisor.googlesource.com/gvisor/pkg/tcpip/link/fdbased" + "gvisor.googlesource.com/gvisor/pkg/tcpip/link/rawfile" + "gvisor.googlesource.com/gvisor/pkg/tcpip/link/tun" + "gvisor.googlesource.com/gvisor/pkg/tcpip/network/arp" + "gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv4" + "gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv6" + "gvisor.googlesource.com/gvisor/pkg/tcpip/stack" + "gvisor.googlesource.com/gvisor/pkg/tcpip/transport/tcp" + "gvisor.googlesource.com/gvisor/pkg/waiter" +) + +var tap = flag.Bool("tap", false, "use tap istead of tun") +var mac = flag.String("mac", "aa:00:01:01:01:01", "mac address to use in tap device") + +func echo(wq *waiter.Queue, ep tcpip.Endpoint) { + defer ep.Close() + + // Create wait queue entry that notifies a channel. + waitEntry, notifyCh := waiter.NewChannelEntry(nil) + + wq.EventRegister(&waitEntry, waiter.EventIn) + defer wq.EventUnregister(&waitEntry) + + for { + v, err := ep.Read(nil) + if err != nil { + if err == tcpip.ErrWouldBlock { + <-notifyCh + continue + } + + return + } + + ep.Write(tcpip.SlicePayload(v), tcpip.WriteOptions{}) + } +} + +func main() { + flag.Parse() + if len(flag.Args()) != 3 { + log.Fatal("Usage: ", os.Args[0], " ") + } + + tunName := flag.Arg(0) + addrName := flag.Arg(1) + portName := flag.Arg(2) + + rand.Seed(time.Now().UnixNano()) + + // Parse the mac address. + maddr, err := net.ParseMAC(*mac) + if err != nil { + log.Fatalf("Bad MAC address: %v", *mac) + } + + // Parse the IP address. Support both ipv4 and ipv6. + parsedAddr := net.ParseIP(addrName) + if parsedAddr == nil { + log.Fatalf("Bad IP address: %v", addrName) + } + + var addr tcpip.Address + var proto tcpip.NetworkProtocolNumber + if parsedAddr.To4() != nil { + addr = tcpip.Address(parsedAddr.To4()) + proto = ipv4.ProtocolNumber + } else if parsedAddr.To16() != nil { + addr = tcpip.Address(parsedAddr.To16()) + proto = ipv6.ProtocolNumber + } else { + log.Fatalf("Unknown IP type: %v", addrName) + } + + localPort, err := strconv.Atoi(portName) + if err != nil { + log.Fatalf("Unable to convert port %v: %v", portName, err) + } + + // Create the stack with ip and tcp protocols, then add a tun-based + // NIC and address. + s := stack.New([]string{ipv4.ProtocolName, ipv6.ProtocolName, arp.ProtocolName}, []string{tcp.ProtocolName}) + + mtu, err := rawfile.GetMTU(tunName) + if err != nil { + log.Fatal(err) + } + + var fd int + if *tap { + fd, err = tun.OpenTAP(tunName) + } else { + fd, err = tun.Open(tunName) + } + if err != nil { + log.Fatal(err) + } + + linkID := fdbased.New(&fdbased.Options{ + FD: fd, + MTU: mtu, + EthernetHeader: *tap, + Address: tcpip.LinkAddress(maddr), + }) + if err := s.CreateNIC(1, linkID); err != nil { + log.Fatal(err) + } + + if err := s.AddAddress(1, proto, addr); err != nil { + log.Fatal(err) + } + + if err := s.AddAddress(1, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { + log.Fatal(err) + } + + // Add default route. + s.SetRouteTable([]tcpip.Route{ + { + Destination: tcpip.Address(strings.Repeat("\x00", len(addr))), + Mask: tcpip.Address(strings.Repeat("\x00", len(addr))), + Gateway: "", + NIC: 1, + }, + }) + + // Create TCP endpoint, bind it, then start listening. + var wq waiter.Queue + ep, e := s.NewEndpoint(tcp.ProtocolNumber, proto, &wq) + if err != nil { + log.Fatal(e) + } + + defer ep.Close() + + if err := ep.Bind(tcpip.FullAddress{0, "", uint16(localPort)}, nil); err != nil { + log.Fatal("Bind failed: ", err) + } + + if err := ep.Listen(10); err != nil { + log.Fatal("Listen failed: ", err) + } + + // Wait for connections to appear. + waitEntry, notifyCh := waiter.NewChannelEntry(nil) + wq.EventRegister(&waitEntry, waiter.EventIn) + defer wq.EventUnregister(&waitEntry) + + for { + n, wq, err := ep.Accept() + if err != nil { + if err == tcpip.ErrWouldBlock { + <-notifyCh + continue + } + + log.Fatal("Accept() failed:", err) + } + + go echo(wq, n) // S/R-FIXME + } +} -- cgit v1.2.3