159 lines
3.8 KiB
Go
159 lines
3.8 KiB
Go
//go:build linux
|
|
// +build linux
|
|
|
|
package probing
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"reflect"
|
|
"syscall"
|
|
|
|
"golang.org/x/net/icmp"
|
|
)
|
|
|
|
// Returns the length of an ICMP message.
|
|
func (p *Pinger) getMessageLength() int {
|
|
return p.Size + 8
|
|
}
|
|
|
|
// Attempts to match the ID of an ICMP packet.
|
|
func (p *Pinger) matchID(ID int) bool {
|
|
// On Linux we can only match ID if we are privileged.
|
|
if p.protocol == "icmp" {
|
|
return ID == p.id
|
|
}
|
|
return true
|
|
}
|
|
|
|
// SetMark sets the SO_MARK socket option on outgoing ICMP packets.
|
|
// Setting this option requires CAP_NET_ADMIN.
|
|
func (c *icmpConn) SetMark(mark uint) error {
|
|
fd, err := getFD(c.c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.NewSyscallError(
|
|
"setsockopt",
|
|
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(mark)),
|
|
)
|
|
}
|
|
|
|
// SetMark sets the SO_MARK socket option on outgoing ICMP packets.
|
|
// Setting this option requires CAP_NET_ADMIN.
|
|
func (c *icmpv4Conn) SetMark(mark uint) error {
|
|
fd, err := getFD(c.icmpConn.c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.NewSyscallError(
|
|
"setsockopt",
|
|
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(mark)),
|
|
)
|
|
}
|
|
|
|
// SetMark sets the SO_MARK socket option on outgoing ICMP packets.
|
|
// Setting this option requires CAP_NET_ADMIN.
|
|
func (c *icmpV6Conn) SetMark(mark uint) error {
|
|
fd, err := getFD(c.icmpConn.c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.NewSyscallError(
|
|
"setsockopt",
|
|
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(mark)),
|
|
)
|
|
}
|
|
|
|
// SetDoNotFragment sets the do-not-fragment bit in the IP header of outgoing ICMP packets.
|
|
func (c *icmpConn) SetDoNotFragment() error {
|
|
fd, err := getFD(c.c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.NewSyscallError(
|
|
"setsockopt",
|
|
syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_DO),
|
|
)
|
|
}
|
|
|
|
// SetDoNotFragment sets the do-not-fragment bit in the IP header of outgoing ICMP packets.
|
|
func (c *icmpv4Conn) SetDoNotFragment() error {
|
|
fd, err := getFD(c.icmpConn.c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.NewSyscallError(
|
|
"setsockopt",
|
|
syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_DO),
|
|
)
|
|
}
|
|
|
|
// SetDoNotFragment sets the do-not-fragment bit in the IPv6 header of outgoing ICMPv6 packets.
|
|
func (c *icmpV6Conn) SetDoNotFragment() error {
|
|
fd, err := getFD(c.icmpConn.c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.NewSyscallError(
|
|
"setsockopt",
|
|
syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_MTU_DISCOVER, syscall.IP_PMTUDISC_DO),
|
|
)
|
|
}
|
|
|
|
func (c *icmpConn) SetBroadcastFlag() error {
|
|
fd, err := getFD(c.c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.NewSyscallError(
|
|
"setsockopt",
|
|
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1),
|
|
)
|
|
}
|
|
|
|
func (c *icmpv4Conn) SetBroadcastFlag() error {
|
|
fd, err := getFD(c.icmpConn.c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.NewSyscallError(
|
|
"setsockopt",
|
|
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1),
|
|
)
|
|
}
|
|
|
|
func (c *icmpV6Conn) SetBroadcastFlag() error {
|
|
fd, err := getFD(c.icmpConn.c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.NewSyscallError(
|
|
"setsockopt",
|
|
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1),
|
|
)
|
|
}
|
|
|
|
// getFD gets the system file descriptor for an icmp.PacketConn
|
|
func getFD(c *icmp.PacketConn) (uintptr, error) {
|
|
v := reflect.ValueOf(c).Elem().FieldByName("c").Elem()
|
|
if v.Elem().Kind() != reflect.Struct {
|
|
return 0, errors.New("invalid type")
|
|
}
|
|
|
|
fd := v.Elem().FieldByName("conn").FieldByName("fd")
|
|
if fd.Elem().Kind() != reflect.Struct {
|
|
return 0, errors.New("invalid type")
|
|
}
|
|
|
|
pfd := fd.Elem().FieldByName("pfd")
|
|
if pfd.Kind() != reflect.Struct {
|
|
return 0, errors.New("invalid type")
|
|
}
|
|
|
|
return uintptr(pfd.FieldByName("Sysfd").Int()), nil
|
|
}
|