Skip to content

Commit

Permalink
Merge pull request #136 from nvksie/icmp_id_bpf_filter
Browse files Browse the repository at this point in the history
filter icmp id with sock_filter, to optimize rawsocket preformance
  • Loading branch information
SuperQ authored Jan 2, 2025
2 parents b6d1240 + e6f961d commit e89c957
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 0 deletions.
1 change: 1 addition & 0 deletions packetconn.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type packetConn interface {
SetBroadcastFlag() error
SetIfIndex(ifIndex int)
SetTrafficClass(uint8) error
InstallICMPIDFilter(id int) error
}

type icmpConn struct {
Expand Down
7 changes: 7 additions & 0 deletions ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,13 @@ func (p *Pinger) listen() (packetConn, error) {
p.Stop()
return nil, err
}

if p.Privileged() {
if err := conn.InstallICMPIDFilter(p.id); err != nil {
p.logger.Warnf("error installing icmp filter, %v", err)
}
}

return conn, nil
}

Expand Down
1 change: 1 addition & 0 deletions ping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ func (c testPacketConn) SetTTL(t int) {}
func (c testPacketConn) SetMark(m uint) error { return nil }
func (c testPacketConn) SetDoNotFragment() error { return nil }
func (c testPacketConn) SetBroadcastFlag() error { return nil }
func (c testPacketConn) InstallICMPIDFilter(id int) error { return nil }
func (c testPacketConn) SetIfIndex(ifIndex int) {}
func (c testPacketConn) SetTrafficClass(uint8) error { return nil }

Expand Down
38 changes: 38 additions & 0 deletions utils_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import (
"reflect"
"syscall"

"golang.org/x/net/bpf"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)

// Returns the length of an ICMP message.
Expand Down Expand Up @@ -137,6 +140,41 @@ func (c *icmpV6Conn) SetBroadcastFlag() error {
)
}

// InstallICMPIDFilter attaches a BPF program to the connection to filter ICMP packets id.
func (c *icmpv4Conn) InstallICMPIDFilter(id int) error {
filter, err := bpf.Assemble([]bpf.Instruction{
bpf.LoadMemShift{Off: 0}, // Skip IP header
bpf.LoadIndirect{Off: 4, Size: 2}, // Load ICMP echo ident
bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(id), SkipTrue: 0, SkipFalse: 1}, // Jump on ICMP Echo Request (ID check)
bpf.RetConstant{Val: ^uint32(0)}, // If our ID, accept the packet
bpf.LoadIndirect{Off: 0, Size: 1}, // Load ICMP type
bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(ipv4.ICMPTypeEchoReply), SkipTrue: 1, SkipFalse: 0}, // Check if ICMP Echo Reply
bpf.RetConstant{Val: 0xFFFFFFF}, // Accept packet if it's not Echo Reply
bpf.RetConstant{Val: 0}, // Reject Echo packet with wrong identifier
})
if err != nil {
return err
}
return c.c.IPv4PacketConn().SetBPF(filter)
}

// InstallICMPIDFilter attaches a BPF program to the connection to filter ICMPv6 packets id.
func (c *icmpV6Conn) InstallICMPIDFilter(id int) error {
filter, err := bpf.Assemble([]bpf.Instruction{
bpf.LoadAbsolute{Off: 4, Size: 2}, // Load ICMP echo identifier
bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(id), SkipTrue: 0, SkipFalse: 1}, // Check if it matches our identifier
bpf.RetConstant{Val: ^uint32(0)}, // Accept if true
bpf.LoadAbsolute{Off: 0, Size: 1}, // Load ICMP type
bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(ipv6.ICMPTypeEchoReply), SkipTrue: 1, SkipFalse: 0}, // Check if it is an ICMP6 echo reply
bpf.RetConstant{Val: ^uint32(0)}, // Accept if false
bpf.RetConstant{Val: 0}, // Reject if echo with wrong identifier
})
if err != nil {
return err
}
return c.c.IPv6PacketConn().SetBPF(filter)
}

// 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()
Expand Down
8 changes: 8 additions & 0 deletions utils_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,11 @@ func (c *icmpv4Conn) SetBroadcastFlag() error {
func (c *icmpV6Conn) SetBroadcastFlag() error {
return nil
}

func (c *icmpv4Conn) InstallICMPIDFilter(id int) error {
return nil
}

func (c *icmpV6Conn) InstallICMPIDFilter(id int) error {
return nil
}
8 changes: 8 additions & 0 deletions utils_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,11 @@ func (c *icmpv4Conn) SetBroadcastFlag() error {
func (c *icmpV6Conn) SetBroadcastFlag() error {
return nil
}

func (c *icmpv4Conn) InstallICMPIDFilter(id int) error {
return nil
}

func (c *icmpV6Conn) InstallICMPIDFilter(id int) error {
return nil
}

0 comments on commit e89c957

Please sign in to comment.