github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/packetimpact/testbench/rawsockets.go (about) 1 // Copyright 2020 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 package testbench 16 17 import ( 18 "encoding/binary" 19 "fmt" 20 "net" 21 "testing" 22 "time" 23 24 "golang.org/x/sys/unix" 25 "github.com/SagerNet/gvisor/pkg/hostarch" 26 ) 27 28 // Sniffer can sniff raw packets on the wire. 29 type Sniffer struct { 30 fd int 31 } 32 33 func htons(x uint16) uint16 { 34 buf := [2]byte{} 35 binary.BigEndian.PutUint16(buf[:], x) 36 return hostarch.ByteOrder.Uint16(buf[:]) 37 } 38 39 // NewSniffer creates a Sniffer connected to *device. 40 func (n *DUTTestNet) NewSniffer(t *testing.T) (Sniffer, error) { 41 t.Helper() 42 43 ifInfo, err := net.InterfaceByName(n.LocalDevName) 44 if err != nil { 45 return Sniffer{}, err 46 } 47 48 var haddr [8]byte 49 copy(haddr[:], ifInfo.HardwareAddr) 50 sa := unix.SockaddrLinklayer{ 51 Protocol: htons(unix.ETH_P_ALL), 52 Ifindex: ifInfo.Index, 53 } 54 snifferFd, err := unix.Socket(unix.AF_PACKET, unix.SOCK_RAW, int(htons(unix.ETH_P_ALL))) 55 if err != nil { 56 return Sniffer{}, err 57 } 58 if err := unix.Bind(snifferFd, &sa); err != nil { 59 return Sniffer{}, err 60 } 61 if err := unix.SetsockoptInt(snifferFd, unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, 1); err != nil { 62 t.Fatalf("can't set sockopt SO_RCVBUFFORCE to 1: %s", err) 63 } 64 if err := unix.SetsockoptInt(snifferFd, unix.SOL_SOCKET, unix.SO_RCVBUF, 1e7); err != nil { 65 t.Fatalf("can't setsockopt SO_RCVBUF to 10M: %s", err) 66 } 67 return Sniffer{ 68 fd: snifferFd, 69 }, nil 70 } 71 72 // maxReadSize should be large enough for the maximum frame size in bytes. If a 73 // packet too large for the buffer arrives, the test will get a fatal error. 74 const maxReadSize int = 65536 75 76 // Recv tries to read one frame until the timeout is up. If the timeout given 77 // is 0, then no read attempt will be made. 78 func (s *Sniffer) Recv(t *testing.T, timeout time.Duration) []byte { 79 t.Helper() 80 81 deadline := time.Now().Add(timeout) 82 for { 83 timeout = time.Until(deadline) 84 if timeout <= 0 { 85 return nil 86 } 87 usec := timeout.Microseconds() 88 if usec == 0 { 89 // Timeout is less than a microsecond; set usec to 1 to avoid 90 // blocking indefinitely. 91 usec = 1 92 } 93 const microsInOne = 1e6 94 tv := unix.Timeval{ 95 Sec: usec / microsInOne, 96 Usec: usec % microsInOne, 97 } 98 if err := unix.SetsockoptTimeval(s.fd, unix.SOL_SOCKET, unix.SO_RCVTIMEO, &tv); err != nil { 99 t.Fatalf("can't setsockopt SO_RCVTIMEO: %s", err) 100 } 101 102 buf := make([]byte, maxReadSize) 103 nread, _, err := unix.Recvfrom(s.fd, buf, unix.MSG_TRUNC) 104 if err == unix.EINTR || err == unix.EAGAIN { 105 // There was a timeout. 106 continue 107 } 108 if err != nil { 109 t.Fatalf("can't read: %s", err) 110 } 111 if nread > maxReadSize { 112 t.Fatalf("received a truncated frame of %d bytes, want at most %d bytes", nread, maxReadSize) 113 } 114 return buf[:nread] 115 } 116 } 117 118 // Drain drains the Sniffer's socket receive buffer by receiving until there's 119 // nothing else to receive. 120 func (s *Sniffer) Drain(t *testing.T) { 121 t.Helper() 122 123 flags, err := unix.FcntlInt(uintptr(s.fd), unix.F_GETFL, 0) 124 if err != nil { 125 t.Fatalf("failed to get sniffer socket fd flags: %s", err) 126 } 127 nonBlockingFlags := flags | unix.O_NONBLOCK 128 if _, err := unix.FcntlInt(uintptr(s.fd), unix.F_SETFL, nonBlockingFlags); err != nil { 129 t.Fatalf("failed to make sniffer socket non-blocking with flags %b: %s", nonBlockingFlags, err) 130 } 131 for { 132 buf := make([]byte, maxReadSize) 133 _, _, err := unix.Recvfrom(s.fd, buf, unix.MSG_TRUNC) 134 if err == unix.EINTR || err == unix.EAGAIN || err == unix.EWOULDBLOCK { 135 break 136 } 137 } 138 if _, err := unix.FcntlInt(uintptr(s.fd), unix.F_SETFL, flags); err != nil { 139 t.Fatalf("failed to restore sniffer socket fd flags to %b: %s", flags, err) 140 } 141 } 142 143 // close the socket that Sniffer is using. 144 func (s *Sniffer) close() error { 145 if err := unix.Close(s.fd); err != nil { 146 return fmt.Errorf("can't close sniffer socket: %w", err) 147 } 148 s.fd = -1 149 return nil 150 } 151 152 // Injector can inject raw frames. 153 type Injector struct { 154 fd int 155 } 156 157 // NewInjector creates a new injector on *device. 158 func (n *DUTTestNet) NewInjector(t *testing.T) (Injector, error) { 159 t.Helper() 160 161 ifInfo, err := net.InterfaceByName(n.LocalDevName) 162 if err != nil { 163 return Injector{}, err 164 } 165 166 var haddr [8]byte 167 copy(haddr[:], ifInfo.HardwareAddr) 168 sa := unix.SockaddrLinklayer{ 169 Protocol: htons(unix.ETH_P_IP), 170 Ifindex: ifInfo.Index, 171 Halen: uint8(len(ifInfo.HardwareAddr)), 172 Addr: haddr, 173 } 174 175 injectFd, err := unix.Socket(unix.AF_PACKET, unix.SOCK_RAW, int(htons(unix.ETH_P_ALL))) 176 if err != nil { 177 return Injector{}, err 178 } 179 if err := unix.Bind(injectFd, &sa); err != nil { 180 return Injector{}, err 181 } 182 return Injector{ 183 fd: injectFd, 184 }, nil 185 } 186 187 // Send a raw frame. 188 func (i *Injector) Send(t *testing.T, b []byte) { 189 t.Helper() 190 191 n, err := unix.Write(i.fd, b) 192 if err != nil { 193 t.Fatalf("can't write bytes of len %d: %s", len(b), err) 194 } 195 if n != len(b) { 196 t.Fatalf("got %d bytes written, want %d", n, len(b)) 197 } 198 } 199 200 // close the underlying socket. 201 func (i *Injector) close() error { 202 if err := unix.Close(i.fd); err != nil { 203 return fmt.Errorf("can't close sniffer socket: %w", err) 204 } 205 i.fd = -1 206 return nil 207 }