iprawsock_posix.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Copyright 2010 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. //go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
  5. package net
  6. import (
  7. "context"
  8. "syscall"
  9. )
  10. func sockaddrToIP(sa syscall.Sockaddr) Addr {
  11. switch sa := sa.(type) {
  12. case *syscall.SockaddrInet4:
  13. return &IPAddr{IP: sa.Addr[0:]}
  14. case *syscall.SockaddrInet6:
  15. return &IPAddr{IP: sa.Addr[0:], Zone: zoneCache.name(int(sa.ZoneId))}
  16. }
  17. return nil
  18. }
  19. func (a *IPAddr) family() int {
  20. if a == nil || len(a.IP) <= IPv4len {
  21. return syscall.AF_INET
  22. }
  23. if a.IP.To4() != nil {
  24. return syscall.AF_INET
  25. }
  26. return syscall.AF_INET6
  27. }
  28. func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
  29. if a == nil {
  30. return nil, nil
  31. }
  32. return ipToSockaddr(family, a.IP, 0, a.Zone)
  33. }
  34. func (a *IPAddr) toLocal(net string) sockaddr {
  35. return &IPAddr{loopbackIP(net), a.Zone}
  36. }
  37. func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) {
  38. // TODO(cw,rsc): consider using readv if we know the family
  39. // type to avoid the header trim/copy
  40. var addr *IPAddr
  41. n, sa, err := c.fd.readFrom(b)
  42. switch sa := sa.(type) {
  43. case *syscall.SockaddrInet4:
  44. addr = &IPAddr{IP: sa.Addr[0:]}
  45. n = stripIPv4Header(n, b)
  46. case *syscall.SockaddrInet6:
  47. addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneCache.name(int(sa.ZoneId))}
  48. }
  49. return n, addr, err
  50. }
  51. func stripIPv4Header(n int, b []byte) int {
  52. if len(b) < 20 {
  53. return n
  54. }
  55. l := int(b[0]&0x0f) << 2
  56. if 20 > l || l > len(b) {
  57. return n
  58. }
  59. if b[0]>>4 != 4 {
  60. return n
  61. }
  62. copy(b, b[l:])
  63. return n - l
  64. }
  65. func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
  66. var sa syscall.Sockaddr
  67. n, oobn, flags, sa, err = c.fd.readMsg(b, oob, 0)
  68. switch sa := sa.(type) {
  69. case *syscall.SockaddrInet4:
  70. addr = &IPAddr{IP: sa.Addr[0:]}
  71. case *syscall.SockaddrInet6:
  72. addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneCache.name(int(sa.ZoneId))}
  73. }
  74. return
  75. }
  76. func (c *IPConn) writeTo(b []byte, addr *IPAddr) (int, error) {
  77. if c.fd.isConnected {
  78. return 0, ErrWriteToConnected
  79. }
  80. if addr == nil {
  81. return 0, errMissingAddress
  82. }
  83. sa, err := addr.sockaddr(c.fd.family)
  84. if err != nil {
  85. return 0, err
  86. }
  87. return c.fd.writeTo(b, sa)
  88. }
  89. func (c *IPConn) writeMsg(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
  90. if c.fd.isConnected {
  91. return 0, 0, ErrWriteToConnected
  92. }
  93. if addr == nil {
  94. return 0, 0, errMissingAddress
  95. }
  96. sa, err := addr.sockaddr(c.fd.family)
  97. if err != nil {
  98. return 0, 0, err
  99. }
  100. return c.fd.writeMsg(b, oob, sa)
  101. }
  102. func (sd *sysDialer) dialIP(ctx context.Context, laddr, raddr *IPAddr) (*IPConn, error) {
  103. network, proto, err := parseNetwork(ctx, sd.network, true)
  104. if err != nil {
  105. return nil, err
  106. }
  107. switch network {
  108. case "ip", "ip4", "ip6":
  109. default:
  110. return nil, UnknownNetworkError(sd.network)
  111. }
  112. fd, err := internetSocket(ctx, network, laddr, raddr, syscall.SOCK_RAW, proto, "dial", sd.Dialer.Control)
  113. if err != nil {
  114. return nil, err
  115. }
  116. return newIPConn(fd), nil
  117. }
  118. func (sl *sysListener) listenIP(ctx context.Context, laddr *IPAddr) (*IPConn, error) {
  119. network, proto, err := parseNetwork(ctx, sl.network, true)
  120. if err != nil {
  121. return nil, err
  122. }
  123. switch network {
  124. case "ip", "ip4", "ip6":
  125. default:
  126. return nil, UnknownNetworkError(sl.network)
  127. }
  128. fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_RAW, proto, "listen", sl.ListenConfig.Control)
  129. if err != nil {
  130. return nil, err
  131. }
  132. return newIPConn(fd), nil
  133. }