rawconn_unix_test.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright 2017 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 || linux || netbsd || openbsd || solaris
  5. package net
  6. import (
  7. "errors"
  8. "syscall"
  9. )
  10. func readRawConn(c syscall.RawConn, b []byte) (int, error) {
  11. var operr error
  12. var n int
  13. err := c.Read(func(s uintptr) bool {
  14. n, operr = syscall.Read(int(s), b)
  15. if operr == syscall.EAGAIN {
  16. return false
  17. }
  18. return true
  19. })
  20. if err != nil {
  21. return n, err
  22. }
  23. return n, operr
  24. }
  25. func writeRawConn(c syscall.RawConn, b []byte) error {
  26. var operr error
  27. err := c.Write(func(s uintptr) bool {
  28. _, operr = syscall.Write(int(s), b)
  29. if operr == syscall.EAGAIN {
  30. return false
  31. }
  32. return true
  33. })
  34. if err != nil {
  35. return err
  36. }
  37. return operr
  38. }
  39. func controlRawConn(c syscall.RawConn, addr Addr) error {
  40. var operr error
  41. fn := func(s uintptr) {
  42. _, operr = syscall.GetsockoptInt(int(s), syscall.SOL_SOCKET, syscall.SO_REUSEADDR)
  43. if operr != nil {
  44. return
  45. }
  46. switch addr := addr.(type) {
  47. case *TCPAddr:
  48. // There's no guarantee that IP-level socket
  49. // options work well with dual stack sockets.
  50. // A simple solution would be to take a look
  51. // at the bound address to the raw connection
  52. // and to classify the address family of the
  53. // underlying socket by the bound address:
  54. //
  55. // - When IP.To16() != nil and IP.To4() == nil,
  56. // we can assume that the raw connection
  57. // consists of an IPv6 socket using only
  58. // IPv6 addresses.
  59. //
  60. // - When IP.To16() == nil and IP.To4() != nil,
  61. // the raw connection consists of an IPv4
  62. // socket using only IPv4 addresses.
  63. //
  64. // - Otherwise, the raw connection is a dual
  65. // stack socket, an IPv6 socket using IPv6
  66. // addresses including IPv4-mapped or
  67. // IPv4-embedded IPv6 addresses.
  68. if addr.IP.To16() != nil && addr.IP.To4() == nil {
  69. operr = syscall.SetsockoptInt(int(s), syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, 1)
  70. } else if addr.IP.To16() == nil && addr.IP.To4() != nil {
  71. operr = syscall.SetsockoptInt(int(s), syscall.IPPROTO_IP, syscall.IP_TTL, 1)
  72. }
  73. }
  74. }
  75. if err := c.Control(fn); err != nil {
  76. return err
  77. }
  78. return operr
  79. }
  80. func controlOnConnSetup(network string, address string, c syscall.RawConn) error {
  81. var operr error
  82. var fn func(uintptr)
  83. switch network {
  84. case "tcp", "udp", "ip":
  85. return errors.New("ambiguous network: " + network)
  86. case "unix", "unixpacket", "unixgram":
  87. fn = func(s uintptr) {
  88. _, operr = syscall.GetsockoptInt(int(s), syscall.SOL_SOCKET, syscall.SO_ERROR)
  89. }
  90. default:
  91. switch network[len(network)-1] {
  92. case '4':
  93. fn = func(s uintptr) {
  94. operr = syscall.SetsockoptInt(int(s), syscall.IPPROTO_IP, syscall.IP_TTL, 1)
  95. }
  96. case '6':
  97. fn = func(s uintptr) {
  98. operr = syscall.SetsockoptInt(int(s), syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, 1)
  99. }
  100. default:
  101. return errors.New("unknown network: " + network)
  102. }
  103. }
  104. if err := c.Control(fn); err != nil {
  105. return err
  106. }
  107. return operr
  108. }