gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 "gvisor.dev/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_RCVBUF, 1e7); err != nil { 62 t.Fatalf("can't setsockopt SO_RCVBUF to 10M: %s", err) 63 } 64 return Sniffer{ 65 fd: snifferFd, 66 }, nil 67 } 68 69 // maxReadSize should be large enough for the maximum frame size in bytes. If a 70 // packet too large for the buffer arrives, the test will get a fatal error. 71 const maxReadSize int = 65536 72 73 // Recv tries to read one frame until the timeout is up. If the timeout given 74 // is 0, then no read attempt will be made. 75 func (s *Sniffer) Recv(t *testing.T, timeout time.Duration) []byte { 76 t.Helper() 77 78 deadline := time.Now().Add(timeout) 79 for { 80 timeout = time.Until(deadline) 81 if timeout <= 0 { 82 return nil 83 } 84 usec := timeout.Microseconds() 85 if usec == 0 { 86 // Timeout is less than a microsecond; set usec to 1 to avoid 87 // blocking indefinitely. 88 usec = 1 89 } 90 const microsInOne = 1e6 91 tv := unix.Timeval{ 92 Sec: usec / microsInOne, 93 Usec: usec % microsInOne, 94 } 95 if err := unix.SetsockoptTimeval(s.fd, unix.SOL_SOCKET, unix.SO_RCVTIMEO, &tv); err != nil { 96 t.Fatalf("can't setsockopt SO_RCVTIMEO: %s", err) 97 } 98 99 buf := make([]byte, maxReadSize) 100 nread, _, err := unix.Recvfrom(s.fd, buf, unix.MSG_TRUNC) 101 if err == unix.EINTR || err == unix.EAGAIN { 102 // There was a timeout. 103 continue 104 } 105 if err != nil { 106 t.Fatalf("can't read: %s", err) 107 } 108 if nread > maxReadSize { 109 t.Fatalf("received a truncated frame of %d bytes, want at most %d bytes", nread, maxReadSize) 110 } 111 return buf[:nread] 112 } 113 } 114 115 // Drain drains the Sniffer's socket receive buffer by receiving until there's 116 // nothing else to receive. 117 func (s *Sniffer) Drain(t *testing.T) { 118 t.Helper() 119 120 flags, err := unix.FcntlInt(uintptr(s.fd), unix.F_GETFL, 0) 121 if err != nil { 122 t.Fatalf("failed to get sniffer socket fd flags: %s", err) 123 } 124 nonBlockingFlags := flags | unix.O_NONBLOCK 125 if _, err := unix.FcntlInt(uintptr(s.fd), unix.F_SETFL, nonBlockingFlags); err != nil { 126 t.Fatalf("failed to make sniffer socket non-blocking with flags %b: %s", nonBlockingFlags, err) 127 } 128 for { 129 buf := make([]byte, maxReadSize) 130 _, _, err := unix.Recvfrom(s.fd, buf, unix.MSG_TRUNC) 131 if err == unix.EINTR || err == unix.EAGAIN || err == unix.EWOULDBLOCK { 132 break 133 } 134 } 135 if _, err := unix.FcntlInt(uintptr(s.fd), unix.F_SETFL, flags); err != nil { 136 t.Fatalf("failed to restore sniffer socket fd flags to %b: %s", flags, err) 137 } 138 } 139 140 // close the socket that Sniffer is using. 141 func (s *Sniffer) close() error { 142 if err := unix.Close(s.fd); err != nil { 143 return fmt.Errorf("can't close sniffer socket: %w", err) 144 } 145 s.fd = -1 146 return nil 147 } 148 149 // Injector can inject raw frames. 150 type Injector struct { 151 fd int 152 } 153 154 // NewInjector creates a new injector on *device. 155 func (n *DUTTestNet) NewInjector(t *testing.T) (Injector, error) { 156 t.Helper() 157 158 ifInfo, err := net.InterfaceByName(n.LocalDevName) 159 if err != nil { 160 return Injector{}, err 161 } 162 163 var haddr [8]byte 164 copy(haddr[:], ifInfo.HardwareAddr) 165 sa := unix.SockaddrLinklayer{ 166 Protocol: htons(unix.ETH_P_IP), 167 Ifindex: ifInfo.Index, 168 Halen: uint8(len(ifInfo.HardwareAddr)), 169 Addr: haddr, 170 } 171 172 injectFd, err := unix.Socket(unix.AF_PACKET, unix.SOCK_RAW, int(htons(unix.ETH_P_ALL))) 173 if err != nil { 174 return Injector{}, err 175 } 176 if err := unix.Bind(injectFd, &sa); err != nil { 177 return Injector{}, err 178 } 179 return Injector{ 180 fd: injectFd, 181 }, nil 182 } 183 184 // Send a raw frame. 185 func (i *Injector) Send(t *testing.T, b []byte) { 186 t.Helper() 187 188 n, err := unix.Write(i.fd, b) 189 if err != nil { 190 t.Fatalf("can't write bytes of len %d: %s", len(b), err) 191 } 192 if n != len(b) { 193 t.Fatalf("got %d bytes written, want %d", n, len(b)) 194 } 195 } 196 197 // close the underlying socket. 198 func (i *Injector) close() error { 199 if err := unix.Close(i.fd); err != nil { 200 return fmt.Errorf("can't close sniffer socket: %w", err) 201 } 202 i.fd = -1 203 return nil 204 }