1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
package probing
import (
"net"
"runtime"
"time"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)
type packetConn interface {
Close() error
ICMPRequestType() icmp.Type
ReadFrom(b []byte) (n int, ttl int, src net.Addr, err error)
SetFlagTTL() error
SetReadDeadline(t time.Time) error
WriteTo(b []byte, dst net.Addr) (int, error)
SetTTL(ttl int)
SetMark(m uint) error
SetDoNotFragment() error
SetBroadcastFlag() error
SetIfIndex(ifIndex int)
SetTrafficClass(uint8) error
InstallICMPIDFilter(id int) error
}
type icmpConn struct {
c *icmp.PacketConn
ttl int
ifIndex int
}
func (c *icmpConn) Close() error {
return c.c.Close()
}
func (c *icmpConn) SetTTL(ttl int) {
c.ttl = ttl
}
func (c *icmpConn) SetIfIndex(ifIndex int) {
c.ifIndex = ifIndex
}
func (c *icmpConn) SetReadDeadline(t time.Time) error {
return c.c.SetReadDeadline(t)
}
type icmpv4Conn struct {
icmpConn
}
func (c *icmpv4Conn) SetFlagTTL() error {
err := c.c.IPv4PacketConn().SetControlMessage(ipv4.FlagTTL, true)
if runtime.GOOS == "windows" {
return nil
}
return err
}
func (c *icmpv4Conn) SetTrafficClass(tclass uint8) error {
return c.c.IPv4PacketConn().SetTOS(int(tclass))
}
func (c *icmpv4Conn) ReadFrom(b []byte) (int, int, net.Addr, error) {
ttl := -1
n, cm, src, err := c.c.IPv4PacketConn().ReadFrom(b)
if cm != nil {
ttl = cm.TTL
}
return n, ttl, src, err
}
func (c *icmpv4Conn) WriteTo(b []byte, dst net.Addr) (int, error) {
if err := c.c.IPv4PacketConn().SetTTL(c.ttl); err != nil {
return 0, err
}
var cm *ipv4.ControlMessage
if 1 <= c.ifIndex {
// c.ifIndex == 0 if not set interface
if err := c.c.IPv4PacketConn().SetControlMessage(ipv4.FlagInterface, true); err != nil {
return 0, err
}
cm = &ipv4.ControlMessage{IfIndex: c.ifIndex}
}
return c.c.IPv4PacketConn().WriteTo(b, cm, dst)
}
func (c icmpv4Conn) ICMPRequestType() icmp.Type {
return ipv4.ICMPTypeEcho
}
type icmpV6Conn struct {
icmpConn
}
func (c *icmpV6Conn) SetFlagTTL() error {
err := c.c.IPv6PacketConn().SetControlMessage(ipv6.FlagHopLimit, true)
if runtime.GOOS == "windows" {
return nil
}
return err
}
func (c *icmpV6Conn) SetTrafficClass(tclass uint8) error {
return c.c.IPv6PacketConn().SetTrafficClass(int(tclass))
}
func (c *icmpV6Conn) ReadFrom(b []byte) (int, int, net.Addr, error) {
ttl := -1
n, cm, src, err := c.c.IPv6PacketConn().ReadFrom(b)
if cm != nil {
ttl = cm.HopLimit
}
return n, ttl, src, err
}
func (c *icmpV6Conn) WriteTo(b []byte, dst net.Addr) (int, error) {
if err := c.c.IPv6PacketConn().SetHopLimit(c.ttl); err != nil {
return 0, err
}
var cm *ipv6.ControlMessage
if 1 <= c.ifIndex {
// c.ifIndex == 0 if not set interface
if err := c.c.IPv6PacketConn().SetControlMessage(ipv6.FlagInterface, true); err != nil {
return 0, err
}
cm = &ipv6.ControlMessage{IfIndex: c.ifIndex}
}
return c.c.IPv6PacketConn().WriteTo(b, cm, dst)
}
func (c icmpV6Conn) ICMPRequestType() icmp.Type {
return ipv6.ICMPTypeEchoRequest
}
|