github.com/FlowerWrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/sample/tun_tcp_echo/main.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build linux 16 17 // This sample creates a stack with TCP and IPv4 protocols on top of a TUN 18 // device, and listens on a port. Data received by the server in the accepted 19 // connections is echoed back to the clients. 20 package main 21 22 import ( 23 "flag" 24 "log" 25 "math/rand" 26 "net" 27 "os" 28 "strconv" 29 "strings" 30 "time" 31 32 "github.com/FlowerWrong/netstack/tcpip" 33 "github.com/FlowerWrong/netstack/tcpip/link/fdbased" 34 "github.com/FlowerWrong/netstack/tcpip/link/rawfile" 35 "github.com/FlowerWrong/netstack/tcpip/link/tun" 36 "github.com/FlowerWrong/netstack/tcpip/network/arp" 37 "github.com/FlowerWrong/netstack/tcpip/network/ipv4" 38 "github.com/FlowerWrong/netstack/tcpip/network/ipv6" 39 "github.com/FlowerWrong/netstack/tcpip/stack" 40 "github.com/FlowerWrong/netstack/tcpip/transport/tcp" 41 "github.com/FlowerWrong/netstack/waiter" 42 ) 43 44 var tap = flag.Bool("tap", false, "use tap istead of tun") 45 var mac = flag.String("mac", "aa:00:01:01:01:01", "mac address to use in tap device") 46 47 func echo(wq *waiter.Queue, ep tcpip.Endpoint) { 48 defer ep.Close() 49 50 // Create wait queue entry that notifies a channel. 51 waitEntry, notifyCh := waiter.NewChannelEntry(nil) 52 53 wq.EventRegister(&waitEntry, waiter.EventIn) 54 defer wq.EventUnregister(&waitEntry) 55 56 for { 57 v, _, err := ep.Read(nil) 58 if err != nil { 59 if err == tcpip.ErrWouldBlock { 60 <-notifyCh 61 continue 62 } 63 64 return 65 } 66 67 ep.Write(tcpip.SlicePayload(v), tcpip.WriteOptions{}) 68 } 69 } 70 71 func main() { 72 flag.Parse() 73 if len(flag.Args()) != 3 { 74 log.Fatal("Usage: ", os.Args[0], " <tun-device> <local-address> <local-port>") 75 } 76 77 tunName := flag.Arg(0) 78 addrName := flag.Arg(1) 79 portName := flag.Arg(2) 80 81 rand.Seed(time.Now().UnixNano()) 82 83 // Parse the mac address. 84 maddr, err := net.ParseMAC(*mac) 85 if err != nil { 86 log.Fatalf("Bad MAC address: %v", *mac) 87 } 88 89 // Parse the IP address. Support both ipv4 and ipv6. 90 parsedAddr := net.ParseIP(addrName) 91 if parsedAddr == nil { 92 log.Fatalf("Bad IP address: %v", addrName) 93 } 94 95 var addr tcpip.Address 96 var proto tcpip.NetworkProtocolNumber 97 if parsedAddr.To4() != nil { 98 addr = tcpip.Address(parsedAddr.To4()) 99 proto = ipv4.ProtocolNumber 100 } else if parsedAddr.To16() != nil { 101 addr = tcpip.Address(parsedAddr.To16()) 102 proto = ipv6.ProtocolNumber 103 } else { 104 log.Fatalf("Unknown IP type: %v", addrName) 105 } 106 107 localPort, err := strconv.Atoi(portName) 108 if err != nil { 109 log.Fatalf("Unable to convert port %v: %v", portName, err) 110 } 111 112 // Create the stack with ip and tcp protocols, then add a tun-based 113 // NIC and address. 114 s := stack.New(stack.Options{ 115 NetworkProtocols: []stack.NetworkProtocol{ipv4.NewProtocol(), ipv6.NewProtocol(), arp.NewProtocol()}, 116 TransportProtocols: []stack.TransportProtocol{tcp.NewProtocol()}, 117 }) 118 119 mtu, err := rawfile.GetMTU(tunName) 120 if err != nil { 121 log.Fatal(err) 122 } 123 124 var fd int 125 if *tap { 126 fd, err = tun.OpenTAP(tunName) 127 } else { 128 fd, err = tun.Open(tunName) 129 } 130 if err != nil { 131 log.Fatal(err) 132 } 133 134 linkEP, err := fdbased.New(&fdbased.Options{ 135 FDs: []int{fd}, 136 MTU: mtu, 137 EthernetHeader: *tap, 138 Address: tcpip.LinkAddress(maddr), 139 }) 140 if err != nil { 141 log.Fatal(err) 142 } 143 if err := s.CreateNIC(1, linkEP); err != nil { 144 log.Fatal(err) 145 } 146 147 if err := s.AddAddress(1, proto, addr); err != nil { 148 log.Fatal(err) 149 } 150 151 if err := s.AddAddress(1, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { 152 log.Fatal(err) 153 } 154 155 subnet, err := tcpip.NewSubnet(tcpip.Address(strings.Repeat("\x00", len(addr))), tcpip.AddressMask(strings.Repeat("\x00", len(addr)))) 156 if err != nil { 157 log.Fatal(err) 158 } 159 160 // Add default route. 161 s.SetRouteTable([]tcpip.Route{ 162 { 163 Destination: subnet, 164 NIC: 1, 165 }, 166 }) 167 168 // Create TCP endpoint, bind it, then start listening. 169 var wq waiter.Queue 170 ep, e := s.NewEndpoint(tcp.ProtocolNumber, proto, &wq) 171 if err != nil { 172 log.Fatal(e) 173 } 174 175 defer ep.Close() 176 177 if err := ep.Bind(tcpip.FullAddress{0, "", uint16(localPort)}); err != nil { 178 log.Fatal("Bind failed: ", err) 179 } 180 181 if err := ep.Listen(10); err != nil { 182 log.Fatal("Listen failed: ", err) 183 } 184 185 // Wait for connections to appear. 186 waitEntry, notifyCh := waiter.NewChannelEntry(nil) 187 wq.EventRegister(&waitEntry, waiter.EventIn) 188 defer wq.EventUnregister(&waitEntry) 189 190 for { 191 n, wq, err := ep.Accept() 192 if err != nil { 193 if err == tcpip.ErrWouldBlock { 194 <-notifyCh 195 continue 196 } 197 198 log.Fatal("Accept() failed:", err) 199 } 200 201 go echo(wq, n) 202 } 203 }