...
1
2
3
4
5
6
7 package icmp
8
9 import (
10 "net"
11 "os"
12 "runtime"
13 "syscall"
14
15 "golang.org/x/net/internal/iana"
16 "golang.org/x/net/ipv4"
17 "golang.org/x/net/ipv6"
18 )
19
20 const sysIP_STRIPHDR = 0x17
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 func ListenPacket(network, address string) (*PacketConn, error) {
47 var family, proto int
48 switch network {
49 case "udp4":
50 family, proto = syscall.AF_INET, iana.ProtocolICMP
51 case "udp6":
52 family, proto = syscall.AF_INET6, iana.ProtocolIPv6ICMP
53 default:
54 i := last(network, ':')
55 if i < 0 {
56 i = len(network)
57 }
58 switch network[:i] {
59 case "ip4":
60 proto = iana.ProtocolICMP
61 case "ip6":
62 proto = iana.ProtocolIPv6ICMP
63 }
64 }
65 var cerr error
66 var c net.PacketConn
67 switch family {
68 case syscall.AF_INET, syscall.AF_INET6:
69 s, err := syscall.Socket(family, syscall.SOCK_DGRAM, proto)
70 if err != nil {
71 return nil, os.NewSyscallError("socket", err)
72 }
73 if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && family == syscall.AF_INET {
74 if err := syscall.SetsockoptInt(s, iana.ProtocolIP, sysIP_STRIPHDR, 1); err != nil {
75 syscall.Close(s)
76 return nil, os.NewSyscallError("setsockopt", err)
77 }
78 }
79 sa, err := sockaddr(family, address)
80 if err != nil {
81 syscall.Close(s)
82 return nil, err
83 }
84 if err := syscall.Bind(s, sa); err != nil {
85 syscall.Close(s)
86 return nil, os.NewSyscallError("bind", err)
87 }
88 f := os.NewFile(uintptr(s), "datagram-oriented icmp")
89 c, cerr = net.FilePacketConn(f)
90 f.Close()
91 default:
92 c, cerr = net.ListenPacket(network, address)
93 }
94 if cerr != nil {
95 return nil, cerr
96 }
97 switch proto {
98 case iana.ProtocolICMP:
99 return &PacketConn{c: c, p4: ipv4.NewPacketConn(c)}, nil
100 case iana.ProtocolIPv6ICMP:
101 return &PacketConn{c: c, p6: ipv6.NewPacketConn(c)}, nil
102 default:
103 return &PacketConn{c: c}, nil
104 }
105 }
106
View as plain text