summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/sample
diff options
context:
space:
mode:
authorGoogler <noreply@google.com>2018-04-27 10:37:02 -0700
committerAdin Scannell <ascannell@google.com>2018-04-28 01:44:26 -0400
commitd02b74a5dcfed4bfc8f2f8e545bca4d2afabb296 (patch)
tree54f95eef73aee6bacbfc736fffc631be2605ed53 /pkg/tcpip/sample
parentf70210e742919f40aa2f0934a22f1c9ba6dada62 (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/BUILD20
-rw-r--r--pkg/tcpip/sample/tun_tcp_connect/main.go208
-rw-r--r--pkg/tcpip/sample/tun_tcp_echo/BUILD20
-rw-r--r--pkg/tcpip/sample/tun_tcp_echo/main.go182
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
+ }
+}