104 lines
1.9 KiB
Go
104 lines
1.9 KiB
Go
package ping
|
|
|
|
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)
|
|
}
|
|
|
|
type icmpConn struct {
|
|
c *icmp.PacketConn
|
|
ttl int
|
|
}
|
|
|
|
func (c *icmpConn) Close() error {
|
|
return c.c.Close()
|
|
}
|
|
|
|
func (c *icmpConn) SetTTL(ttl int) {
|
|
c.ttl = ttl
|
|
}
|
|
|
|
func (c *icmpConn) SetReadDeadline(t time.Time) error {
|
|
return c.c.SetReadDeadline(t)
|
|
}
|
|
|
|
func (c *icmpConn) WriteTo(b []byte, dst net.Addr) (int, error) {
|
|
if c.c.IPv6PacketConn() != nil {
|
|
if err := c.c.IPv6PacketConn().SetHopLimit(c.ttl); err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
if c.c.IPv4PacketConn() != nil {
|
|
if err := c.c.IPv4PacketConn().SetTTL(c.ttl); err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
|
|
return c.c.WriteTo(b, dst)
|
|
}
|
|
|
|
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) ReadFrom(b []byte) (int, int, net.Addr, error) {
|
|
var ttl int
|
|
n, cm, src, err := c.c.IPv4PacketConn().ReadFrom(b)
|
|
if cm != nil {
|
|
ttl = cm.TTL
|
|
}
|
|
return n, ttl, src, err
|
|
}
|
|
|
|
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) ReadFrom(b []byte) (int, int, net.Addr, error) {
|
|
var ttl int
|
|
n, cm, src, err := c.c.IPv6PacketConn().ReadFrom(b)
|
|
if cm != nil {
|
|
ttl = cm.HopLimit
|
|
}
|
|
return n, ttl, src, err
|
|
}
|
|
|
|
func (c icmpV6Conn) ICMPRequestType() icmp.Type {
|
|
return ipv6.ICMPTypeEchoRequest
|
|
}
|