...

Source file src/github.com/mdlayher/packet/packet.go

Documentation: github.com/mdlayher/packet

     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  

View as plain text