1 package packet 2 3 import ( 4 "net" 5 "syscall" 6 "time" 7 8 "golang.org/x/net/bpf" 9 ) 10 11 const ( 12 // network is the network reported in net.OpError. 13 network = "packet" 14 15 // Operation names which may be returned in net.OpError. 16 opClose = "close" 17 opGetsockopt = "getsockopt" 18 opListen = "listen" 19 opRawControl = "raw-control" 20 opRawRead = "raw-read" 21 opRawWrite = "raw-write" 22 opRead = "read" 23 opSet = "set" 24 opSetsockopt = "setsockopt" 25 opSyscallConn = "syscall-conn" 26 opWrite = "write" 27 ) 28 29 // Config contains options for a Conn. 30 type Config struct { 31 // Filter is an optional assembled BPF filter which can be applied to the 32 // Conn before bind(2) is called. 33 // 34 // The Conn.SetBPF method serves the same purpose once a Conn has already 35 // been opened, but setting Filter applies the BPF filter before the Conn is 36 // bound. This ensures that unexpected packets will not be captured before 37 // the Conn is opened. 38 Filter []bpf.RawInstruction 39 } 40 41 // Type is a socket type used when creating a Conn with Listen. 42 //enumcheck:exhaustive 43 type Type int 44 45 // Possible Type values. Note that the zero value is not valid: callers must 46 // always specify one of Raw or Datagram when calling Listen. 47 const ( 48 _ Type = iota 49 Raw 50 Datagram 51 ) 52 53 // Listen opens a packet sockets connection on the specified interface, using 54 // the given socket type and protocol values. 55 // 56 // The socket type must be one of the Type constants: Raw or Datagram. 57 // 58 // The Config specifies optional configuration for the Conn. A nil *Config 59 // applies the default configuration. 60 func Listen(ifi *net.Interface, socketType Type, protocol int, cfg *Config) (*Conn, error) { 61 l, err := listen(ifi, socketType, protocol, cfg) 62 if err != nil { 63 return nil, opError(opListen, err, &Addr{HardwareAddr: ifi.HardwareAddr}) 64 } 65 66 return l, nil 67 } 68 69 // TODO(mdlayher): we want to support FileConn for advanced use cases, but this 70 // library would also need a big endian protocol value and an interface index. 71 // For now we won't bother, but reconsider in the future. 72 73 var ( 74 _ net.PacketConn = &Conn{} 75 _ syscall.Conn = &Conn{} 76 _ bpf.Setter = &Conn{} 77 ) 78 79 // A Conn is an Linux packet sockets (AF_PACKET) implementation of a 80 // net.PacketConn. 81 type Conn struct { 82 c *conn 83 84 // Metadata about the local connection. 85 addr *Addr 86 ifIndex int 87 protocol uint16 88 } 89 90 // Close closes the connection. 91 func (c *Conn) Close() error { 92 return c.opError(opClose, c.c.Close()) 93 } 94 95 // LocalAddr returns the local network address. The Addr returned is shared by 96 // all invocations of LocalAddr, so do not modify it. 97 func (c *Conn) LocalAddr() net.Addr { return c.addr } 98 99 // ReadFrom implements the net.PacketConn ReadFrom method. 100 func (c *Conn) ReadFrom(b []byte) (int, net.Addr, error) { 101 return c.readFrom(b) 102 } 103 104 // WriteTo implements the net.PacketConn WriteTo method. 105 func (c *Conn) WriteTo(b []byte, addr net.Addr) (int, error) { 106 return c.writeTo(b, addr) 107 } 108 109 // SetDeadline implements the net.PacketConn SetDeadline method. 110 func (c *Conn) SetDeadline(t time.Time) error { 111 return c.opError(opSet, c.c.SetDeadline(t)) 112 } 113 114 // SetReadDeadline implements the net.PacketConn SetReadDeadline method. 115 func (c *Conn) SetReadDeadline(t time.Time) error { 116 return c.opError(opSet, c.c.SetReadDeadline(t)) 117 } 118 119 // SetWriteDeadline implements the net.PacketConn SetWriteDeadline method. 120 func (c *Conn) SetWriteDeadline(t time.Time) error { 121 return c.opError(opSet, c.c.SetWriteDeadline(t)) 122 } 123 124 // SetBPF attaches an assembled BPF program to the Conn. 125 func (c *Conn) SetBPF(filter []bpf.RawInstruction) error { 126 return c.opError(opSetsockopt, c.c.SetBPF(filter)) 127 } 128 129 // SetPromiscuous enables or disables promiscuous mode on the Conn, allowing it 130 // to receive traffic that is not addressed to the Conn's network interface. 131 func (c *Conn) SetPromiscuous(enable bool) error { 132 return c.setPromiscuous(enable) 133 } 134 135 // Stats contains statistics about a Conn reported by the Linux kernel. 136 type Stats struct { 137 // The total number of packets received. 138 Packets uint32 139 140 // The number of packets dropped. 141 Drops uint32 142 143 // The total number of times that a receive queue is frozen. May be zero if 144 // the Linux kernel is not new enough to support TPACKET_V3 statistics. 145 FreezeQueueCount uint32 146 } 147 148 // Stats retrieves statistics about the Conn from the Linux kernel. 149 // 150 // Note that calling Stats will reset the kernel's internal counters for this 151 // Conn. If you want to maintain cumulative statistics by polling Stats over 152 // time, you must do so in your calling code. 153 func (c *Conn) Stats() (*Stats, error) { return c.stats() } 154 155 // SyscallConn returns a raw network connection. This implements the 156 // syscall.Conn interface. 157 func (c *Conn) SyscallConn() (syscall.RawConn, error) { 158 rc, err := c.c.SyscallConn() 159 if err != nil { 160 return nil, c.opError(opSyscallConn, err) 161 } 162 163 return &rawConn{ 164 rc: rc, 165 addr: c.addr, 166 }, nil 167 } 168 169 // opError is a convenience for the function opError that also passes the local 170 // and remote addresses of the Conn. 171 func (c *Conn) opError(op string, err error) error { 172 return opError(op, err, c.addr) 173 } 174 175 // TODO(mdlayher): see if we can port smarter net.OpError logic into 176 // socket.Conn's SyscallConn type to avoid the need for this wrapper. 177 178 var _ syscall.RawConn = &rawConn{} 179 180 // A rawConn is a syscall.RawConn that wraps an internal syscall.RawConn in order 181 // to produce net.OpError error values. 182 type rawConn struct { 183 rc syscall.RawConn 184 addr *Addr 185 } 186 187 // Control implements the syscall.RawConn Control method. 188 func (rc *rawConn) Control(fn func(fd uintptr)) error { 189 return rc.opError(opRawControl, rc.rc.Control(fn)) 190 } 191 192 // Control implements the syscall.RawConn Read method. 193 func (rc *rawConn) Read(fn func(fd uintptr) (done bool)) error { 194 return rc.opError(opRawRead, rc.rc.Read(fn)) 195 } 196 197 // Control implements the syscall.RawConn Write method. 198 func (rc *rawConn) Write(fn func(fd uintptr) (done bool)) error { 199 return rc.opError(opRawWrite, rc.rc.Write(fn)) 200 } 201 202 // opError is a convenience for the function opError that also passes the 203 // address of the rawConn. 204 func (rc *rawConn) opError(op string, err error) error { 205 return opError(op, err, rc.addr) 206 } 207 208 var _ net.Addr = &Addr{} 209 210 // TODO(mdlayher): expose sll_hatype and sll_pkttype on receive Addr only. 211 212 // An Addr is a physical-layer address. 213 type Addr struct { 214 HardwareAddr net.HardwareAddr 215 } 216 217 // Network returns the address's network name, "packet". 218 func (a *Addr) Network() string { return network } 219 220 // String returns the string representation of an Addr. 221 func (a *Addr) String() string { 222 return a.HardwareAddr.String() 223 } 224 225 // opError unpacks err if possible, producing a net.OpError with the input 226 // parameters in order to implement net.PacketConn. As a convenience, opError 227 // returns nil if the input error is nil. 228 func opError(op string, err error, local net.Addr) error { 229 if err == nil { 230 return nil 231 } 232 233 // TODO(mdlayher): try to comply with net.PacketConn as best as we can; land 234 // a nettest.TestPacketConn API upstream. 235 return &net.OpError{ 236 Op: op, 237 Net: network, 238 Addr: local, 239 Err: err, 240 } 241 } 242