packet_linux.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. //go:build linux
  2. // +build linux
  3. package packet
  4. import (
  5. "context"
  6. "encoding/binary"
  7. "errors"
  8. "math"
  9. "net"
  10. "os"
  11. "github.com/josharian/native"
  12. "github.com/mdlayher/socket"
  13. "golang.org/x/sys/unix"
  14. )
  15. // A conn is the net.PacketConn implementation for packet sockets. We can use
  16. // socket.Conn directly on Linux to implement most of the necessary methods.
  17. type conn = socket.Conn
  18. // readFrom implements the net.PacketConn ReadFrom method using recvfrom(2).
  19. func (c *Conn) readFrom(b []byte) (int, net.Addr, error) {
  20. // From net.PacketConn documentation:
  21. //
  22. // "[ReadFrom] returns the number of bytes read (0 <= n <= len(p)) and any
  23. // error encountered. Callers should always process the n > 0 bytes returned
  24. // before considering the error err."
  25. //
  26. // c.opError will return nil if no error, but either way we return all the
  27. // information that we have.
  28. n, sa, err := c.c.Recvfrom(context.Background(), b, 0)
  29. return n, fromSockaddr(sa), c.opError(opRead, err)
  30. }
  31. // writeTo implements the net.PacketConn WriteTo method.
  32. func (c *Conn) writeTo(b []byte, addr net.Addr) (int, error) {
  33. sa, err := c.toSockaddr("sendto", addr)
  34. if err != nil {
  35. return 0, c.opError(opWrite, err)
  36. }
  37. // TODO(mdlayher): it's curious that unix.Sendto does not return the number
  38. // of bytes actually sent. Fake it for now, but investigate upstream.
  39. if err := c.c.Sendto(context.Background(), b, 0, sa); err != nil {
  40. return 0, c.opError(opWrite, err)
  41. }
  42. return len(b), nil
  43. }
  44. // setPromiscuous wraps setsockopt(2) for the unix.PACKET_MR_PROMISC option.
  45. func (c *Conn) setPromiscuous(enable bool) error {
  46. mreq := unix.PacketMreq{
  47. Ifindex: int32(c.ifIndex),
  48. Type: unix.PACKET_MR_PROMISC,
  49. }
  50. membership := unix.PACKET_DROP_MEMBERSHIP
  51. if enable {
  52. membership = unix.PACKET_ADD_MEMBERSHIP
  53. }
  54. return c.opError(
  55. opSetsockopt,
  56. c.c.SetsockoptPacketMreq(unix.SOL_PACKET, membership, &mreq),
  57. )
  58. }
  59. // stats wraps getsockopt(2) for tpacket_stats* types.
  60. func (c *Conn) stats() (*Stats, error) {
  61. const (
  62. level = unix.SOL_PACKET
  63. name = unix.PACKET_STATISTICS
  64. )
  65. // Try to fetch V3 statistics first, they contain more detailed information.
  66. if stats, err := c.c.GetsockoptTpacketStatsV3(level, name); err == nil {
  67. return &Stats{
  68. Packets: stats.Packets,
  69. Drops: stats.Drops,
  70. FreezeQueueCount: stats.Freeze_q_cnt,
  71. }, nil
  72. }
  73. // There was an error fetching v3 stats, try to fall back.
  74. stats, err := c.c.GetsockoptTpacketStats(level, name)
  75. if err != nil {
  76. return nil, c.opError(opGetsockopt, err)
  77. }
  78. return &Stats{
  79. Packets: stats.Packets,
  80. Drops: stats.Drops,
  81. // FreezeQueueCount is not present.
  82. }, nil
  83. }
  84. // listen is the entry point for Listen on Linux.
  85. func listen(ifi *net.Interface, socketType Type, protocol int, cfg *Config) (*Conn, error) {
  86. if cfg == nil {
  87. // Default configuration.
  88. cfg = &Config{}
  89. }
  90. // Convert Type to the matching SOCK_* constant.
  91. var typ int
  92. switch socketType {
  93. case Raw:
  94. typ = unix.SOCK_RAW
  95. case Datagram:
  96. typ = unix.SOCK_DGRAM
  97. default:
  98. return nil, errors.New("packet: invalid Type value")
  99. }
  100. // Protocol is intentionally zero in call to socket(2); we can set it on
  101. // bind(2) instead. Package raw notes: "Do not specify a protocol to avoid
  102. // capturing packets which to not match cfg.Filter."
  103. c, err := socket.Socket(unix.AF_PACKET, typ, 0, network, nil)
  104. if err != nil {
  105. return nil, err
  106. }
  107. conn, err := bind(c, ifi.Index, protocol, cfg)
  108. if err != nil {
  109. _ = c.Close()
  110. return nil, err
  111. }
  112. return conn, nil
  113. }
  114. // bind binds the *socket.Conn to finalize *Conn setup.
  115. func bind(c *socket.Conn, ifIndex, protocol int, cfg *Config) (*Conn, error) {
  116. if len(cfg.Filter) > 0 {
  117. // The caller wants to apply a BPF filter before bind(2).
  118. if err := c.SetBPF(cfg.Filter); err != nil {
  119. return nil, err
  120. }
  121. }
  122. // packet(7) says we sll_protocol must be in network byte order.
  123. pnet, err := htons(protocol)
  124. if err != nil {
  125. return nil, err
  126. }
  127. // TODO(mdlayher): investigate the possibility of sll_ifindex = 0 because we
  128. // could bind to any interface.
  129. err = c.Bind(&unix.SockaddrLinklayer{
  130. Protocol: pnet,
  131. Ifindex: ifIndex,
  132. })
  133. if err != nil {
  134. return nil, err
  135. }
  136. lsa, err := c.Getsockname()
  137. if err != nil {
  138. return nil, err
  139. }
  140. // Parse the physical layer address; sll_halen tells us how many bytes of
  141. // sll_addr we should treat as valid.
  142. lsall := lsa.(*unix.SockaddrLinklayer)
  143. addr := make(net.HardwareAddr, lsall.Halen)
  144. copy(addr, lsall.Addr[:])
  145. return &Conn{
  146. c: c,
  147. addr: &Addr{HardwareAddr: addr},
  148. ifIndex: ifIndex,
  149. protocol: pnet,
  150. }, nil
  151. }
  152. // fromSockaddr converts an opaque unix.Sockaddr to *Addr. If sa is nil, it
  153. // returns nil. It panics if sa is not of type *unix.SockaddrLinklayer.
  154. func fromSockaddr(sa unix.Sockaddr) *Addr {
  155. if sa == nil {
  156. return nil
  157. }
  158. sall := sa.(*unix.SockaddrLinklayer)
  159. return &Addr{
  160. // The syscall already allocated sa; just slice into it with the
  161. // appropriate length and type conversion rather than making a copy.
  162. HardwareAddr: net.HardwareAddr(sall.Addr[:sall.Halen]),
  163. }
  164. }
  165. // toSockaddr converts a net.Addr to an opaque unix.Sockaddr. It returns an
  166. // error if the fields cannot be packed into a *unix.SockaddrLinklayer.
  167. func (c *Conn) toSockaddr(
  168. op string,
  169. addr net.Addr,
  170. ) (unix.Sockaddr, error) {
  171. // The typical error convention for net.Conn types is
  172. // net.OpError(os.SyscallError(syscall.Errno)), so all calls here should
  173. // return os.SyscallError(syscall.Errno) so the caller can apply the final
  174. // net.OpError wrapper.
  175. // Ensure the correct Addr type.
  176. a, ok := addr.(*Addr)
  177. if !ok || a.HardwareAddr == nil {
  178. return nil, os.NewSyscallError(op, unix.EINVAL)
  179. }
  180. // Pack Addr and Conn metadata into the appropriate sockaddr fields. From
  181. // packet(7):
  182. //
  183. // "When you send packets it is enough to specify sll_family, sll_addr,
  184. // sll_halen, sll_ifindex, and sll_protocol. The other fields should be 0."
  185. //
  186. // sll_family is set on the conversion to unix.RawSockaddrLinklayer.
  187. sa := unix.SockaddrLinklayer{
  188. Ifindex: c.ifIndex,
  189. Protocol: c.protocol,
  190. }
  191. // Ensure the input address does not exceed the amount of space available;
  192. // for example an IPoIB address is 20 bytes.
  193. if len(a.HardwareAddr) > len(sa.Addr) {
  194. return nil, os.NewSyscallError(op, unix.EINVAL)
  195. }
  196. sa.Halen = uint8(len(a.HardwareAddr))
  197. copy(sa.Addr[:], a.HardwareAddr)
  198. return &sa, nil
  199. }
  200. // htons converts a short (uint16) from host-to-network byte order.
  201. func htons(i int) (uint16, error) {
  202. if i < 0 || i > math.MaxUint16 {
  203. return 0, errors.New("packet: protocol value out of range")
  204. }
  205. // Store as big endian, retrieve as native endian.
  206. var b [2]byte
  207. binary.BigEndian.PutUint16(b[:], uint16(i))
  208. return native.Endian.Uint16(b[:]), nil
  209. }