listen_posix.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // Copyright 2014 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. // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
  5. package icmp
  6. import (
  7. "net"
  8. "os"
  9. "runtime"
  10. "syscall"
  11. "golang.org/x/net/internal/iana"
  12. "golang.org/x/net/ipv4"
  13. "golang.org/x/net/ipv6"
  14. )
  15. const sysIP_STRIPHDR = 0x17 // for now only darwin supports this option
  16. // ListenPacket listens for incoming ICMP packets addressed to
  17. // address. See net.Dial for the syntax of address.
  18. //
  19. // For non-privileged datagram-oriented ICMP endpoints, network must
  20. // be "udp4" or "udp6". The endpoint allows to read, write a few
  21. // limited ICMP messages such as echo request and echo reply.
  22. // Currently only Darwin and Linux support this.
  23. //
  24. // Examples:
  25. // ListenPacket("udp4", "192.168.0.1")
  26. // ListenPacket("udp4", "0.0.0.0")
  27. // ListenPacket("udp6", "fe80::1%en0")
  28. // ListenPacket("udp6", "::")
  29. //
  30. // For privileged raw ICMP endpoints, network must be "ip4" or "ip6"
  31. // followed by a colon and an ICMP protocol number or name.
  32. //
  33. // Examples:
  34. // ListenPacket("ip4:icmp", "192.168.0.1")
  35. // ListenPacket("ip4:1", "0.0.0.0")
  36. // ListenPacket("ip6:ipv6-icmp", "fe80::1%en0")
  37. // ListenPacket("ip6:58", "::")
  38. func ListenPacket(network, address string) (*PacketConn, error) {
  39. var family, proto int
  40. switch network {
  41. case "udp4":
  42. family, proto = syscall.AF_INET, iana.ProtocolICMP
  43. case "udp6":
  44. family, proto = syscall.AF_INET6, iana.ProtocolIPv6ICMP
  45. default:
  46. i := last(network, ':')
  47. if i < 0 {
  48. i = len(network)
  49. }
  50. switch network[:i] {
  51. case "ip4":
  52. proto = iana.ProtocolICMP
  53. case "ip6":
  54. proto = iana.ProtocolIPv6ICMP
  55. }
  56. }
  57. var cerr error
  58. var c net.PacketConn
  59. switch family {
  60. case syscall.AF_INET, syscall.AF_INET6:
  61. s, err := syscall.Socket(family, syscall.SOCK_DGRAM, proto)
  62. if err != nil {
  63. return nil, os.NewSyscallError("socket", err)
  64. }
  65. if runtime.GOOS == "darwin" && family == syscall.AF_INET {
  66. if err := syscall.SetsockoptInt(s, iana.ProtocolIP, sysIP_STRIPHDR, 1); err != nil {
  67. syscall.Close(s)
  68. return nil, os.NewSyscallError("setsockopt", err)
  69. }
  70. }
  71. sa, err := sockaddr(family, address)
  72. if err != nil {
  73. syscall.Close(s)
  74. return nil, err
  75. }
  76. if err := syscall.Bind(s, sa); err != nil {
  77. syscall.Close(s)
  78. return nil, os.NewSyscallError("bind", err)
  79. }
  80. f := os.NewFile(uintptr(s), "datagram-oriented icmp")
  81. c, cerr = net.FilePacketConn(f)
  82. f.Close()
  83. default:
  84. c, cerr = net.ListenPacket(network, address)
  85. }
  86. if cerr != nil {
  87. return nil, cerr
  88. }
  89. switch proto {
  90. case iana.ProtocolICMP:
  91. return &PacketConn{c: c, p4: ipv4.NewPacketConn(c)}, nil
  92. case iana.ProtocolIPv6ICMP:
  93. return &PacketConn{c: c, p6: ipv6.NewPacketConn(c)}, nil
  94. default:
  95. return &PacketConn{c: c}, nil
  96. }
  97. }