OSDN Git Service

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