packet.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // Copyright 2012 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package ipv4
  5. import (
  6. "net"
  7. "golang.org/x/net/internal/socket"
  8. )
  9. // BUG(mikio): On Windows, the ReadFrom and WriteTo methods of RawConn
  10. // are not implemented.
  11. // A packetHandler represents the IPv4 datagram handler.
  12. type packetHandler struct {
  13. *net.IPConn
  14. *socket.Conn
  15. rawOpt
  16. }
  17. func (c *packetHandler) ok() bool { return c != nil && c.IPConn != nil && c.Conn != nil }
  18. // ReadFrom reads an IPv4 datagram from the endpoint c, copying the
  19. // datagram into b. It returns the received datagram as the IPv4
  20. // header h, the payload p and the control message cm.
  21. func (c *packetHandler) ReadFrom(b []byte) (h *Header, p []byte, cm *ControlMessage, err error) {
  22. if !c.ok() {
  23. return nil, nil, nil, errInvalidConn
  24. }
  25. c.rawOpt.RLock()
  26. m := socket.Message{
  27. Buffers: [][]byte{b},
  28. OOB: NewControlMessage(c.rawOpt.cflags),
  29. }
  30. c.rawOpt.RUnlock()
  31. if err := c.RecvMsg(&m, 0); err != nil {
  32. return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
  33. }
  34. var hs []byte
  35. if hs, p, err = slicePacket(b[:m.N]); err != nil {
  36. return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
  37. }
  38. if h, err = ParseHeader(hs); err != nil {
  39. return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
  40. }
  41. if m.NN > 0 {
  42. if compatFreeBSD32 {
  43. adjustFreeBSD32(&m)
  44. }
  45. cm = new(ControlMessage)
  46. if err := cm.Parse(m.OOB[:m.NN]); err != nil {
  47. return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
  48. }
  49. }
  50. if src, ok := m.Addr.(*net.IPAddr); ok && cm != nil {
  51. cm.Src = src.IP
  52. }
  53. return
  54. }
  55. func slicePacket(b []byte) (h, p []byte, err error) {
  56. if len(b) < HeaderLen {
  57. return nil, nil, errHeaderTooShort
  58. }
  59. hdrlen := int(b[0]&0x0f) << 2
  60. return b[:hdrlen], b[hdrlen:], nil
  61. }
  62. // WriteTo writes an IPv4 datagram through the endpoint c, copying the
  63. // datagram from the IPv4 header h and the payload p. The control
  64. // message cm allows the datagram path and the outgoing interface to be
  65. // specified. Currently only Darwin and Linux support this. The cm
  66. // may be nil if control of the outgoing datagram is not required.
  67. //
  68. // The IPv4 header h must contain appropriate fields that include:
  69. //
  70. // Version = <must be specified>
  71. // Len = <must be specified>
  72. // TOS = <must be specified>
  73. // TotalLen = <must be specified>
  74. // ID = platform sets an appropriate value if ID is zero
  75. // FragOff = <must be specified>
  76. // TTL = <must be specified>
  77. // Protocol = <must be specified>
  78. // Checksum = platform sets an appropriate value if Checksum is zero
  79. // Src = platform sets an appropriate value if Src is nil
  80. // Dst = <must be specified>
  81. // Options = optional
  82. func (c *packetHandler) WriteTo(h *Header, p []byte, cm *ControlMessage) error {
  83. if !c.ok() {
  84. return errInvalidConn
  85. }
  86. m := socket.Message{
  87. OOB: cm.Marshal(),
  88. }
  89. wh, err := h.Marshal()
  90. if err != nil {
  91. return err
  92. }
  93. m.Buffers = [][]byte{wh, p}
  94. dst := new(net.IPAddr)
  95. if cm != nil {
  96. if ip := cm.Dst.To4(); ip != nil {
  97. dst.IP = ip
  98. }
  99. }
  100. if dst.IP == nil {
  101. dst.IP = h.Dst
  102. }
  103. m.Addr = dst
  104. if err := c.SendMsg(&m, 0); err != nil {
  105. return &net.OpError{Op: "write", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Addr: opAddr(dst), Err: err}
  106. }
  107. return nil
  108. }