diff options
author | Googler <noreply@google.com> | 2018-04-27 10:37:02 -0700 |
---|---|---|
committer | Adin Scannell <ascannell@google.com> | 2018-04-28 01:44:26 -0400 |
commit | d02b74a5dcfed4bfc8f2f8e545bca4d2afabb296 (patch) | |
tree | 54f95eef73aee6bacbfc736fffc631be2605ed53 /pkg/tcpip/sample | |
parent | f70210e742919f40aa2f0934a22f1c9ba6dada62 (diff) |
Check in gVisor.
PiperOrigin-RevId: 194583126
Change-Id: Ica1d8821a90f74e7e745962d71801c598c652463
Diffstat (limited to 'pkg/tcpip/sample')
-rw-r--r-- | pkg/tcpip/sample/tun_tcp_connect/BUILD | 20 | ||||
-rw-r--r-- | pkg/tcpip/sample/tun_tcp_connect/main.go | 208 | ||||
-rw-r--r-- | pkg/tcpip/sample/tun_tcp_echo/BUILD | 20 | ||||
-rw-r--r-- | pkg/tcpip/sample/tun_tcp_echo/main.go | 182 |
4 files changed, 430 insertions, 0 deletions
diff --git a/pkg/tcpip/sample/tun_tcp_connect/BUILD b/pkg/tcpip/sample/tun_tcp_connect/BUILD new file mode 100644 index 000000000..870ee0433 --- /dev/null +++ b/pkg/tcpip/sample/tun_tcp_connect/BUILD @@ -0,0 +1,20 @@ +package(licenses = ["notice"]) # BSD + +load("@io_bazel_rules_go//go:def.bzl", "go_binary") + +go_binary( + name = "tun_tcp_connect", + srcs = ["main.go"], + deps = [ + "//pkg/tcpip", + "//pkg/tcpip/buffer", + "//pkg/tcpip/link/fdbased", + "//pkg/tcpip/link/rawfile", + "//pkg/tcpip/link/sniffer", + "//pkg/tcpip/link/tun", + "//pkg/tcpip/network/ipv4", + "//pkg/tcpip/stack", + "//pkg/tcpip/transport/tcp", + "//pkg/waiter", + ], +) diff --git a/pkg/tcpip/sample/tun_tcp_connect/main.go b/pkg/tcpip/sample/tun_tcp_connect/main.go new file mode 100644 index 000000000..332929c85 --- /dev/null +++ b/pkg/tcpip/sample/tun_tcp_connect/main.go @@ -0,0 +1,208 @@ +// 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 connects to a peer. Similar to "nc <address> <port>". While the +// sample is running, attempts to connect to its IPv4 address will result in +// a RST segment. +// +// As an example of how to run it, a TUN device can be created and enabled on +// a linux host as follows (this only needs to be done once per boot): +// +// [sudo] ip tuntap add user <username> mode tun <device-name> +// [sudo] ip link set <device-name> up +// [sudo] ip addr add <ipv4-address>/<mask-length> dev <device-name> +// +// A concrete example: +// +// $ sudo ip tuntap add user wedsonaf mode tun tun0 +// $ sudo ip link set tun0 up +// $ sudo ip addr add 192.168.1.1/24 dev tun0 +// +// Then one can run tun_tcp_connect as such: +// +// $ ./tun/tun_tcp_connect tun0 192.168.1.2 0 192.168.1.1 1234 +// +// This will attempt to connect to the linux host's stack. One can run nc in +// listen mode to accept a connect from tun_tcp_connect and exchange data. +package main + +import ( + "bufio" + "fmt" + "log" + "math/rand" + "net" + "os" + "strconv" + "time" + + "gvisor.googlesource.com/gvisor/pkg/tcpip" + "gvisor.googlesource.com/gvisor/pkg/tcpip/buffer" + "gvisor.googlesource.com/gvisor/pkg/tcpip/link/fdbased" + "gvisor.googlesource.com/gvisor/pkg/tcpip/link/rawfile" + "gvisor.googlesource.com/gvisor/pkg/tcpip/link/sniffer" + "gvisor.googlesource.com/gvisor/pkg/tcpip/link/tun" + "gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv4" + "gvisor.googlesource.com/gvisor/pkg/tcpip/stack" + "gvisor.googlesource.com/gvisor/pkg/tcpip/transport/tcp" + "gvisor.googlesource.com/gvisor/pkg/waiter" +) + +// writer reads from standard input and writes to the endpoint until standard +// input is closed. It signals that it's done by closing the provided channel. +func writer(ch chan struct{}, ep tcpip.Endpoint) { + defer func() { + ep.Shutdown(tcpip.ShutdownWrite) + close(ch) + }() + + r := bufio.NewReader(os.Stdin) + for { + v := buffer.NewView(1024) + n, err := r.Read(v) + if err != nil { + return + } + + v.CapLength(n) + for len(v) > 0 { + n, err := ep.Write(tcpip.SlicePayload(v), tcpip.WriteOptions{}) + if err != nil { + fmt.Println("Write failed:", err) + return + } + + v.TrimFront(int(n)) + } + } +} + +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>") + } + + tunName := os.Args[1] + addrName := os.Args[2] + portName := os.Args[3] + remoteAddrName := os.Args[4] + remotePortName := os.Args[5] + + rand.Seed(time.Now().UnixNano()) + + addr := tcpip.Address(net.ParseIP(addrName).To4()) + remote := tcpip.FullAddress{ + NIC: 1, + Addr: tcpip.Address(net.ParseIP(remoteAddrName).To4()), + } + + var localPort uint16 + if v, err := strconv.Atoi(portName); err != nil { + log.Fatalf("Unable to convert port %v: %v", portName, err) + } else { + localPort = uint16(v) + } + + if v, err := strconv.Atoi(remotePortName); err != nil { + log.Fatalf("Unable to convert port %v: %v", remotePortName, err) + } else { + remote.Port = uint16(v) + } + + // Create the stack with ipv4 and tcp protocols, then add a tun-based + // NIC and ipv4 address. + s := stack.New([]string{ipv4.ProtocolName}, []string{tcp.ProtocolName}) + + mtu, err := rawfile.GetMTU(tunName) + if err != nil { + log.Fatal(err) + } + + fd, err := tun.Open(tunName) + if err != nil { + log.Fatal(err) + } + + linkID := fdbased.New(&fdbased.Options{FD: fd, MTU: mtu}) + if err := s.CreateNIC(1, sniffer.New(linkID)); err != nil { + log.Fatal(err) + } + + if err := s.AddAddress(1, ipv4.ProtocolNumber, addr); err != nil { + log.Fatal(err) + } + + // Add default route. + s.SetRouteTable([]tcpip.Route{ + { + Destination: "\x00\x00\x00\x00", + Mask: "\x00\x00\x00\x00", + Gateway: "", + NIC: 1, + }, + }) + + // Create TCP endpoint. + var wq waiter.Queue + ep, e := s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &wq) + if err != nil { + log.Fatal(e) + } + + // Bind if a port is specified. + if localPort != 0 { + if err := ep.Bind(tcpip.FullAddress{0, "", localPort}, nil); err != nil { + log.Fatal("Bind failed: ", err) + } + } + + // Issue connect request and wait for it to complete. + waitEntry, notifyCh := waiter.NewChannelEntry(nil) + wq.EventRegister(&waitEntry, waiter.EventOut) + terr := ep.Connect(remote) + if terr == tcpip.ErrConnectStarted { + fmt.Println("Connect is pending...") + <-notifyCh + terr = ep.GetSockOpt(tcpip.ErrorOption{}) + } + wq.EventUnregister(&waitEntry) + + if terr != nil { + log.Fatal("Unable to connect: ", terr) + } + + fmt.Println("Connected") + + // Start the writer in its own goroutine. + writerCompletedCh := make(chan struct{}) + go writer(writerCompletedCh, ep) // S/R-FIXME + + // Read data and write to standard output until the peer closes the + // connection from its side. + wq.EventRegister(&waitEntry, waiter.EventIn) + for { + v, err := ep.Read(nil) + if err != nil { + if err == tcpip.ErrClosedForReceive { + break + } + + if err == tcpip.ErrWouldBlock { + <-notifyCh + continue + } + + log.Fatal("Read() failed:", err) + } + + os.Stdout.Write(v) + } + wq.EventUnregister(&waitEntry) + + // The reader has completed. Now wait for the writer as well. + <-writerCompletedCh + + ep.Close() +} diff --git a/pkg/tcpip/sample/tun_tcp_echo/BUILD b/pkg/tcpip/sample/tun_tcp_echo/BUILD new file mode 100644 index 000000000..c51528a12 --- /dev/null +++ b/pkg/tcpip/sample/tun_tcp_echo/BUILD @@ -0,0 +1,20 @@ +package(licenses = ["notice"]) # BSD + +load("@io_bazel_rules_go//go:def.bzl", "go_binary") + +go_binary( + name = "tun_tcp_echo", + srcs = ["main.go"], + deps = [ + "//pkg/tcpip", + "//pkg/tcpip/link/fdbased", + "//pkg/tcpip/link/rawfile", + "//pkg/tcpip/link/tun", + "//pkg/tcpip/network/arp", + "//pkg/tcpip/network/ipv4", + "//pkg/tcpip/network/ipv6", + "//pkg/tcpip/stack", + "//pkg/tcpip/transport/tcp", + "//pkg/waiter", + ], +) 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], " <tun-device> <local-address> <local-port>") + } + + 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 + } +} |