| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- package packet
- import (
- "net"
- "syscall"
- "time"
- "golang.org/x/net/bpf"
- )
- const (
- // network is the network reported in net.OpError.
- network = "packet"
- // Operation names which may be returned in net.OpError.
- opClose = "close"
- opGetsockopt = "getsockopt"
- opListen = "listen"
- opRawControl = "raw-control"
- opRawRead = "raw-read"
- opRawWrite = "raw-write"
- opRead = "read"
- opSet = "set"
- opSetsockopt = "setsockopt"
- opSyscallConn = "syscall-conn"
- opWrite = "write"
- )
- // Config contains options for a Conn.
- type Config struct {
- // Filter is an optional assembled BPF filter which can be applied to the
- // Conn before bind(2) is called.
- //
- // The Conn.SetBPF method serves the same purpose once a Conn has already
- // been opened, but setting Filter applies the BPF filter before the Conn is
- // bound. This ensures that unexpected packets will not be captured before
- // the Conn is opened.
- Filter []bpf.RawInstruction
- }
- // Type is a socket type used when creating a Conn with Listen.
- //enumcheck:exhaustive
- type Type int
- // Possible Type values. Note that the zero value is not valid: callers must
- // always specify one of Raw or Datagram when calling Listen.
- const (
- _ Type = iota
- Raw
- Datagram
- )
- // Listen opens a packet sockets connection on the specified interface, using
- // the given socket type and protocol values.
- //
- // The socket type must be one of the Type constants: Raw or Datagram.
- //
- // The Config specifies optional configuration for the Conn. A nil *Config
- // applies the default configuration.
- func Listen(ifi *net.Interface, socketType Type, protocol int, cfg *Config) (*Conn, error) {
- l, err := listen(ifi, socketType, protocol, cfg)
- if err != nil {
- return nil, opError(opListen, err, &Addr{HardwareAddr: ifi.HardwareAddr})
- }
- return l, nil
- }
- // TODO(mdlayher): we want to support FileConn for advanced use cases, but this
- // library would also need a big endian protocol value and an interface index.
- // For now we won't bother, but reconsider in the future.
- var (
- _ net.PacketConn = &Conn{}
- _ syscall.Conn = &Conn{}
- _ bpf.Setter = &Conn{}
- )
- // A Conn is an Linux packet sockets (AF_PACKET) implementation of a
- // net.PacketConn.
- type Conn struct {
- c *conn
- // Metadata about the local connection.
- addr *Addr
- ifIndex int
- protocol uint16
- }
- // Close closes the connection.
- func (c *Conn) Close() error {
- return c.opError(opClose, c.c.Close())
- }
- // LocalAddr returns the local network address. The Addr returned is shared by
- // all invocations of LocalAddr, so do not modify it.
- func (c *Conn) LocalAddr() net.Addr { return c.addr }
- // ReadFrom implements the net.PacketConn ReadFrom method.
- func (c *Conn) ReadFrom(b []byte) (int, net.Addr, error) {
- return c.readFrom(b)
- }
- // WriteTo implements the net.PacketConn WriteTo method.
- func (c *Conn) WriteTo(b []byte, addr net.Addr) (int, error) {
- return c.writeTo(b, addr)
- }
- // SetDeadline implements the net.PacketConn SetDeadline method.
- func (c *Conn) SetDeadline(t time.Time) error {
- return c.opError(opSet, c.c.SetDeadline(t))
- }
- // SetReadDeadline implements the net.PacketConn SetReadDeadline method.
- func (c *Conn) SetReadDeadline(t time.Time) error {
- return c.opError(opSet, c.c.SetReadDeadline(t))
- }
- // SetWriteDeadline implements the net.PacketConn SetWriteDeadline method.
- func (c *Conn) SetWriteDeadline(t time.Time) error {
- return c.opError(opSet, c.c.SetWriteDeadline(t))
- }
- // SetBPF attaches an assembled BPF program to the Conn.
- func (c *Conn) SetBPF(filter []bpf.RawInstruction) error {
- return c.opError(opSetsockopt, c.c.SetBPF(filter))
- }
- // SetPromiscuous enables or disables promiscuous mode on the Conn, allowing it
- // to receive traffic that is not addressed to the Conn's network interface.
- func (c *Conn) SetPromiscuous(enable bool) error {
- return c.setPromiscuous(enable)
- }
- // Stats contains statistics about a Conn reported by the Linux kernel.
- type Stats struct {
- // The total number of packets received.
- Packets uint32
- // The number of packets dropped.
- Drops uint32
- // The total number of times that a receive queue is frozen. May be zero if
- // the Linux kernel is not new enough to support TPACKET_V3 statistics.
- FreezeQueueCount uint32
- }
- // Stats retrieves statistics about the Conn from the Linux kernel.
- //
- // Note that calling Stats will reset the kernel's internal counters for this
- // Conn. If you want to maintain cumulative statistics by polling Stats over
- // time, you must do so in your calling code.
- func (c *Conn) Stats() (*Stats, error) { return c.stats() }
- // SyscallConn returns a raw network connection. This implements the
- // syscall.Conn interface.
- func (c *Conn) SyscallConn() (syscall.RawConn, error) {
- rc, err := c.c.SyscallConn()
- if err != nil {
- return nil, c.opError(opSyscallConn, err)
- }
- return &rawConn{
- rc: rc,
- addr: c.addr,
- }, nil
- }
- // opError is a convenience for the function opError that also passes the local
- // and remote addresses of the Conn.
- func (c *Conn) opError(op string, err error) error {
- return opError(op, err, c.addr)
- }
- // TODO(mdlayher): see if we can port smarter net.OpError logic into
- // socket.Conn's SyscallConn type to avoid the need for this wrapper.
- var _ syscall.RawConn = &rawConn{}
- // A rawConn is a syscall.RawConn that wraps an internal syscall.RawConn in order
- // to produce net.OpError error values.
- type rawConn struct {
- rc syscall.RawConn
- addr *Addr
- }
- // Control implements the syscall.RawConn Control method.
- func (rc *rawConn) Control(fn func(fd uintptr)) error {
- return rc.opError(opRawControl, rc.rc.Control(fn))
- }
- // Control implements the syscall.RawConn Read method.
- func (rc *rawConn) Read(fn func(fd uintptr) (done bool)) error {
- return rc.opError(opRawRead, rc.rc.Read(fn))
- }
- // Control implements the syscall.RawConn Write method.
- func (rc *rawConn) Write(fn func(fd uintptr) (done bool)) error {
- return rc.opError(opRawWrite, rc.rc.Write(fn))
- }
- // opError is a convenience for the function opError that also passes the
- // address of the rawConn.
- func (rc *rawConn) opError(op string, err error) error {
- return opError(op, err, rc.addr)
- }
- var _ net.Addr = &Addr{}
- // TODO(mdlayher): expose sll_hatype and sll_pkttype on receive Addr only.
- // An Addr is a physical-layer address.
- type Addr struct {
- HardwareAddr net.HardwareAddr
- }
- // Network returns the address's network name, "packet".
- func (a *Addr) Network() string { return network }
- // String returns the string representation of an Addr.
- func (a *Addr) String() string {
- return a.HardwareAddr.String()
- }
- // opError unpacks err if possible, producing a net.OpError with the input
- // parameters in order to implement net.PacketConn. As a convenience, opError
- // returns nil if the input error is nil.
- func opError(op string, err error, local net.Addr) error {
- if err == nil {
- return nil
- }
- // TODO(mdlayher): try to comply with net.PacketConn as best as we can; land
- // a nettest.TestPacketConn API upstream.
- return &net.OpError{
- Op: op,
- Net: network,
- Addr: local,
- Err: err,
- }
- }
|