Skip to content

Commit 1478ef5

Browse files
authored
Merge pull request #171 from malbeclabs/snor/pin-source
feat: support setting ICMP source address for outgoing packets
2 parents e12fd94 + 3244b36 commit 1478ef5

File tree

3 files changed

+46
-0
lines changed

3 files changed

+46
-0
lines changed

packetconn.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type packetConn interface {
2222
SetDoNotFragment() error
2323
SetBroadcastFlag() error
2424
SetIfIndex(ifIndex int)
25+
SetSource(source net.IP)
2526
SetTrafficClass(uint8) error
2627
InstallICMPIDFilter(id int) error
2728
}
@@ -30,6 +31,7 @@ type icmpConn struct {
3031
c *icmp.PacketConn
3132
ttl int
3233
ifIndex int
34+
source net.IP
3335
}
3436

3537
func (c *icmpConn) Close() error {
@@ -44,6 +46,10 @@ func (c *icmpConn) SetIfIndex(ifIndex int) {
4446
c.ifIndex = ifIndex
4547
}
4648

49+
func (c *icmpConn) SetSource(source net.IP) {
50+
c.source = source
51+
}
52+
4753
func (c *icmpConn) SetReadDeadline(t time.Time) error {
4854
return c.c.SetReadDeadline(t)
4955
}
@@ -86,6 +92,13 @@ func (c *icmpv4Conn) WriteTo(b []byte, dst net.Addr) (int, error) {
8692
cm = &ipv4.ControlMessage{IfIndex: c.ifIndex}
8793
}
8894

95+
if c.source != nil {
96+
if cm == nil {
97+
cm = &ipv4.ControlMessage{}
98+
}
99+
cm.Src = c.source
100+
}
101+
89102
return c.c.IPv4PacketConn().WriteTo(b, cm, dst)
90103
}
91104

@@ -131,6 +144,13 @@ func (c *icmpV6Conn) WriteTo(b []byte, dst net.Addr) (int, error) {
131144
cm = &ipv6.ControlMessage{IfIndex: c.ifIndex}
132145
}
133146

147+
if c.source != nil {
148+
if cm == nil {
149+
cm = &ipv6.ControlMessage{}
150+
}
151+
cm.Src = c.source
152+
}
153+
134154
return c.c.IPv6PacketConn().WriteTo(b, cm, dst)
135155
}
136156

ping.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,15 @@ func (p *Pinger) RunWithContext(ctx context.Context) error {
565565
}
566566
conn.SetIfIndex(iface.Index)
567567
}
568+
569+
if p.Source != "" {
570+
ip := net.ParseIP(p.Source)
571+
if ip == nil {
572+
return fmt.Errorf("invalid source address: %s", p.Source)
573+
}
574+
conn.SetSource(ip)
575+
}
576+
568577
return p.run(ctx, conn)
569578
}
570579

ping_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,22 @@ func TestSetInterfaceName(t *testing.T) {
498498
AssertError(t, err, "device not found")
499499
}
500500

501+
func TestSetSource(t *testing.T) {
502+
pinger := New("localhost")
503+
pinger.Count = 1
504+
pinger.Timeout = time.Second
505+
506+
// Set source address
507+
pinger.Source = "127.0.0.1"
508+
err := pinger.Run()
509+
AssertNoError(t, err)
510+
511+
// Set source to invalid IP
512+
pinger.Source = "invalid-ip"
513+
err = pinger.Run()
514+
AssertError(t, err, "invalid source address: invalid-ip")
515+
}
516+
501517
// Test helpers
502518
func makeTestPinger() *Pinger {
503519
pinger := New("127.0.0.1")
@@ -679,6 +695,7 @@ func (c testPacketConn) SetDoNotFragment() error { return nil }
679695
func (c testPacketConn) SetBroadcastFlag() error { return nil }
680696
func (c testPacketConn) InstallICMPIDFilter(id int) error { return nil }
681697
func (c testPacketConn) SetIfIndex(ifIndex int) {}
698+
func (c testPacketConn) SetSource(source net.IP) {}
682699
func (c testPacketConn) SetTrafficClass(uint8) error { return nil }
683700

684701
func (c testPacketConn) ReadFrom(b []byte) (n int, ttl int, src net.Addr, err error) {

0 commit comments

Comments
 (0)