Skip to content

Commit 6852e0f

Browse files
5aaee9corny
authored andcommitted
feat: allow set fwmark to icmp connection
1 parent 9d7152f commit 6852e0f

3 files changed

Lines changed: 81 additions & 0 deletions

File tree

cmd/pingnet/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ var (
2626
size = uint(56)
2727
force bool
2828
verbose bool
29+
mark uint
2930
pinger *ping.Pinger
3031
)
3132

@@ -84,6 +85,7 @@ func main() {
8485
flag.IntVar(&poolSize, "P", poolSize, "concurrency level")
8586
flag.BoolVar(&force, "f", force, "sanity flag needed if you want to ping more than 4096 hosts (/20)")
8687
flag.BoolVar(&verbose, "v", verbose, "also print out unreachable addresses")
88+
flag.UintVar(&mark, "m", mark, "set socket mark (SO_MARK) to this value")
8789
flag.Parse()
8890

8991
// simple error checking
@@ -127,6 +129,10 @@ func main() {
127129
pinger = p
128130
}
129131

132+
if mark > 0 {
133+
pinger.SetMark(mark)
134+
}
135+
130136
// prepare worker
131137
wg := &sync.WaitGroup{}
132138
wg.Add(poolSize)

pinger_linux.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package ping
2+
3+
import (
4+
"errors"
5+
"os"
6+
"reflect"
7+
"syscall"
8+
9+
"golang.org/x/net/icmp"
10+
)
11+
12+
// getFD gets the system file descriptor for an icmp.PacketConn
13+
func getFD(c *icmp.PacketConn) (uintptr, error) {
14+
v := reflect.ValueOf(c).Elem().FieldByName("c").Elem()
15+
if v.Elem().Kind() != reflect.Struct {
16+
return 0, errors.New("invalid type")
17+
}
18+
19+
fd := v.Elem().FieldByName("conn").FieldByName("fd")
20+
if fd.Elem().Kind() != reflect.Struct {
21+
return 0, errors.New("invalid type")
22+
}
23+
24+
pfd := fd.Elem().FieldByName("pfd")
25+
if pfd.Kind() != reflect.Struct {
26+
return 0, errors.New("invalid type")
27+
}
28+
29+
return uintptr(pfd.FieldByName("Sysfd").Int()), nil
30+
}
31+
32+
func (pinger *Pinger) SetMark(mark uint) error {
33+
conn4, ok := pinger.conn4.(*icmp.PacketConn)
34+
if !ok {
35+
return errors.New("invalid connection type")
36+
}
37+
38+
fd, err := getFD(conn4)
39+
if err != nil {
40+
return err
41+
}
42+
43+
err = os.NewSyscallError(
44+
"setsockopt",
45+
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(mark)),
46+
)
47+
48+
if err != nil {
49+
return err
50+
}
51+
52+
conn6, ok := pinger.conn6.(*icmp.PacketConn)
53+
if !ok {
54+
return errors.New("invalid connection type")
55+
}
56+
57+
fd, err = getFD(conn6)
58+
if err != nil {
59+
return err
60+
}
61+
62+
return os.NewSyscallError(
63+
"setsockopt",
64+
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(mark)),
65+
)
66+
}

pinger_other.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//go:build !linux
2+
3+
package ping
4+
5+
import "errors"
6+
7+
func (pinger *Pinger) SetMark(mark uint) error {
8+
return errors.New("setting SO_MARK socket option is not supported on this platform")
9+
}

0 commit comments

Comments
 (0)