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