gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/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 //go:build linux 16 // +build linux 17 18 // This sample creates a stack with TCP and IPv4 protocols on top of a TUN 19 // device, and listens on a port. Data received by the server in the accepted 20 // connections is echoed back to the clients. 21 package main 22 23 import ( 24 "bytes" 25 "flag" 26 "io" 27 "log" 28 "math/rand" 29 "net" 30 "os" 31 "strconv" 32 "strings" 33 "time" 34 35 "gvisor.dev/gvisor/pkg/tcpip" 36 "gvisor.dev/gvisor/pkg/tcpip/link/fdbased" 37 "gvisor.dev/gvisor/pkg/tcpip/link/rawfile" 38 "gvisor.dev/gvisor/pkg/tcpip/link/tun" 39 "gvisor.dev/gvisor/pkg/tcpip/network/arp" 40 "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" 41 "gvisor.dev/gvisor/pkg/tcpip/network/ipv6" 42 "gvisor.dev/gvisor/pkg/tcpip/stack" 43 "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" 44 "gvisor.dev/gvisor/pkg/waiter" 45 ) 46 47 var tap = flag.Bool("tap", false, "use tap instead of tun") 48 var mac = flag.String("mac", "aa:00:01:01:01:01", "mac address to use in tap device") 49 50 type endpointWriter struct { 51 ep tcpip.Endpoint 52 } 53 54 type tcpipError struct { 55 inner tcpip.Error 56 } 57 58 func (e *tcpipError) Error() string { 59 return e.inner.String() 60 } 61 62 func (e *endpointWriter) Write(p []byte) (int, error) { 63 var r bytes.Reader 64 r.Reset(p) 65 n, err := e.ep.Write(&r, tcpip.WriteOptions{}) 66 if err != nil { 67 return int(n), &tcpipError{ 68 inner: err, 69 } 70 } 71 if n != int64(len(p)) { 72 return int(n), io.ErrShortWrite 73 } 74 return int(n), nil 75 } 76 77 func echo(wq *waiter.Queue, ep tcpip.Endpoint) { 78 defer ep.Close() 79 80 // Create wait queue entry that notifies a channel. 81 waitEntry, notifyCh := waiter.NewChannelEntry(waiter.ReadableEvents) 82 wq.EventRegister(&waitEntry) 83 defer wq.EventUnregister(&waitEntry) 84 85 w := endpointWriter{ 86 ep: ep, 87 } 88 89 for { 90 var buf bytes.Buffer 91 if _, err := ep.Read(&buf, tcpip.ReadOptions{}); err != nil { 92 if _, ok := err.(*tcpip.ErrWouldBlock); ok { 93 <-notifyCh 94 continue 95 } 96 97 return 98 } 99 100 if _, err := w.Write(buf.Bytes()); err != nil { 101 return 102 } 103 } 104 } 105 106 func main() { 107 flag.Parse() 108 if len(flag.Args()) != 3 { 109 log.Fatal("Usage: ", os.Args[0], " <tun-device> <local-address> <local-port>") 110 } 111 112 tunName := flag.Arg(0) 113 addrName := flag.Arg(1) 114 portName := flag.Arg(2) 115 116 rand.Seed(time.Now().UnixNano()) 117 118 // Parse the mac address. 119 maddr, err := net.ParseMAC(*mac) 120 if err != nil { 121 log.Fatalf("Bad MAC address: %v", *mac) 122 } 123 124 // Parse the IP address. Support both ipv4 and ipv6. 125 parsedAddr := net.ParseIP(addrName) 126 if parsedAddr == nil { 127 log.Fatalf("Bad IP address: %v", addrName) 128 } 129 130 var addrWithPrefix tcpip.AddressWithPrefix 131 var proto tcpip.NetworkProtocolNumber 132 if parsedAddr.To4() != nil { 133 addrWithPrefix = tcpip.AddrFromSlice(parsedAddr.To4()).WithPrefix() 134 proto = ipv4.ProtocolNumber 135 } else if parsedAddr.To16() != nil { 136 addrWithPrefix = tcpip.AddrFromSlice(parsedAddr.To16()).WithPrefix() 137 proto = ipv6.ProtocolNumber 138 } else { 139 log.Fatalf("Unknown IP type: %v", addrName) 140 } 141 142 localPort, err := strconv.Atoi(portName) 143 if err != nil { 144 log.Fatalf("Unable to convert port %v: %v", portName, err) 145 } 146 147 // Create the stack with ip and tcp protocols, then add a tun-based 148 // NIC and address. 149 s := stack.New(stack.Options{ 150 NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol, arp.NewProtocol}, 151 TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol}, 152 }) 153 154 mtu, err := rawfile.GetMTU(tunName) 155 if err != nil { 156 log.Fatal(err) 157 } 158 159 var fd int 160 if *tap { 161 fd, err = tun.OpenTAP(tunName) 162 } else { 163 fd, err = tun.Open(tunName) 164 } 165 if err != nil { 166 log.Fatal(err) 167 } 168 169 linkEP, err := fdbased.New(&fdbased.Options{ 170 FDs: []int{fd}, 171 MTU: mtu, 172 EthernetHeader: *tap, 173 Address: tcpip.LinkAddress(maddr), 174 }) 175 if err != nil { 176 log.Fatal(err) 177 } 178 if err := s.CreateNIC(1, linkEP); err != nil { 179 log.Fatal(err) 180 } 181 182 protocolAddr := tcpip.ProtocolAddress{ 183 Protocol: proto, 184 AddressWithPrefix: addrWithPrefix, 185 } 186 if err := s.AddProtocolAddress(1, protocolAddr, stack.AddressProperties{}); err != nil { 187 log.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", 1, protocolAddr, err) 188 } 189 190 subnet, err := tcpip.NewSubnet(tcpip.AddrFromSlice([]byte(strings.Repeat("\x00", addrWithPrefix.Address.Len()))), tcpip.MaskFrom(strings.Repeat("\x00", addrWithPrefix.Address.Len()))) 191 if err != nil { 192 log.Fatal(err) 193 } 194 195 // Add default route. 196 s.SetRouteTable([]tcpip.Route{ 197 { 198 Destination: subnet, 199 NIC: 1, 200 }, 201 }) 202 203 // Create TCP endpoint, bind it, then start listening. 204 var wq waiter.Queue 205 ep, e := s.NewEndpoint(tcp.ProtocolNumber, proto, &wq) 206 if e != nil { 207 log.Fatal(e) 208 } 209 210 defer ep.Close() 211 212 if err := ep.Bind(tcpip.FullAddress{Port: uint16(localPort)}); err != nil { 213 log.Fatal("Bind failed: ", err) 214 } 215 216 if err := ep.Listen(10); err != nil { 217 log.Fatal("Listen failed: ", err) 218 } 219 220 // Wait for connections to appear. 221 waitEntry, notifyCh := waiter.NewChannelEntry(waiter.ReadableEvents) 222 wq.EventRegister(&waitEntry) 223 defer wq.EventUnregister(&waitEntry) 224 225 for { 226 n, wq, err := ep.Accept(nil) 227 if err != nil { 228 if _, ok := err.(*tcpip.ErrWouldBlock); ok { 229 <-notifyCh 230 continue 231 } 232 233 log.Fatal("Accept() failed:", err) 234 } 235 236 go echo(wq, n) // S/R-SAFE: sample code. 237 } 238 }