Skip to content

Commit c30d050

Browse files
authored
Merge pull request #51 from situation-sh/50-socket-permission-denied-on-ping
Socket permission denied on ping
2 parents ac88953 + e4a7689 commit c30d050

File tree

11 files changed

+136
-109
lines changed

11 files changed

+136
-109
lines changed

.github/workflows/docs.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
name: docs
33

44
on:
5+
workflow_dispatch:
56
push:
67
branches:
78
- main
89
paths:
910
- "docs/**"
1011
- ".github/workflows/docs.yaml"
1112
- "mkdocs.yml"
13+
- "Makefile"
1214

1315
jobs:
1416
deploy:

.github/workflows/test.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ jobs:
6969
test-windows:
7070
strategy:
7171
matrix:
72-
os: [windows-2022, windows-2019, windows-10, windows-11]
72+
os: [windows-2022, windows-2019]
7373
needs: build
7474
runs-on: ${{ matrix.os }}
7575
steps:

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#
2525

2626
MODULE := github.com/situation-sh/situation
27-
VERSION := 0.17.1
27+
VERSION := 0.17.3
2828
COMMIT := $(shell git rev-parse HEAD)
2929

3030
# system stuff

go.mod

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/invopop/jsonschema v0.12.0
1414
github.com/jaypipes/ghw v0.12.0
1515
github.com/libp2p/go-netroute v0.2.1
16+
github.com/lorenzosaino/go-sysctl v0.3.1
1617
github.com/prometheus-community/pro-bing v0.4.1
1718
github.com/shiena/ansicolor v0.0.0-20230509054315-a9deabde6e02
1819
github.com/shirou/gopsutil/v4 v4.24.7
@@ -76,13 +77,17 @@ require (
7677
go.opentelemetry.io/otel/metric v1.29.0 // indirect
7778
go.opentelemetry.io/otel/sdk v1.29.0 // indirect
7879
go.opentelemetry.io/otel/trace v1.29.0 // indirect
80+
golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d // indirect
81+
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
82+
golang.org/x/mod v0.20.0 // indirect
7983
golang.org/x/net v0.28.0 // indirect
8084
golang.org/x/sync v0.8.0 // indirect
8185
golang.org/x/time v0.6.0 // indirect
8286
golang.org/x/tools v0.24.0 // indirect
8387
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
8488
gopkg.in/yaml.v2 v2.4.0 // indirect
8589
gotest.tools/v3 v3.5.1 // indirect
90+
honnef.co/go/tools v0.3.2 // indirect
8691
howett.net/plist v1.0.1 // indirect
8792
modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a // indirect
8893
modernc.org/libc v1.59.9 // indirect

go.sum

+8
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
8282
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
8383
github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=
8484
github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ=
85+
github.com/lorenzosaino/go-sysctl v0.3.1 h1:3phX80tdITw2fJjZlwbXQnDWs4S30beNcMbw0cn0HtY=
86+
github.com/lorenzosaino/go-sysctl v0.3.1/go.mod h1:5grcsBRpspKknNS1qzt1eIeRDLrhpKZAtz8Fcuvs1Rc=
8587
github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 h1:5RK988zAqB3/AN3opGfRpoQgAVqr6/A5+qRTi67VUZY=
8688
github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
8789
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
@@ -171,7 +173,11 @@ go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR
171173
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
172174
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
173175
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
176+
golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d h1:+W8Qf4iJtMGKkyAygcKohjxTk4JPsL9DpzApJ22m5Ic=
177+
golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
174178
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
179+
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
180+
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
175181
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
176182
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
177183
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -237,6 +243,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
237243
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
238244
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
239245
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
246+
honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34=
247+
honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=
240248
howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
241249
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
242250
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=

models/machine.go

-57
Original file line numberDiff line numberDiff line change
@@ -207,60 +207,3 @@ func (m *Machine) InsertPackage(pkg *Package) (*Package, bool) {
207207
// m.Packages = append(m.Packages, pkg)
208208
return nil, false
209209
}
210-
211-
func (m *Machine) GetOrCreateHostLoopback(ip net.IP) (*NetworkInterface, bool) {
212-
// check if the iface already exist
213-
// it returns the first iface found
214-
for _, nic := range m.NICS {
215-
if nic.Flags.Loopback {
216-
return nic, false
217-
}
218-
}
219-
220-
ifaces, err := net.Interfaces()
221-
if err != nil {
222-
return nil, false
223-
}
224-
for _, iface := range ifaces {
225-
if (iface.Flags & net.FlagLoopback) > 0 {
226-
addrs, err := iface.Addrs()
227-
if err != nil {
228-
continue
229-
}
230-
if len(addrs) > 0 {
231-
nic := NetworkInterface{
232-
Name: iface.Name,
233-
MAC: iface.HardwareAddr,
234-
}
235-
// set the iface flags
236-
nic.SetFlags(iface.Flags)
237-
238-
for _, addr := range addrs {
239-
ipAddress, network, err := net.ParseCIDR(addr.String())
240-
if ipAddress == nil || network == nil || err != nil {
241-
continue
242-
}
243-
size, _ := network.Mask.Size()
244-
245-
if ipAddress.To4() == nil && nic.IP6 == nil {
246-
// IPv6
247-
nic.IP6 = ipAddress.To16()
248-
nic.Mask6Size = size
249-
} else if nic.IP == nil {
250-
// IPv4
251-
nic.IP = ipAddress.To4()
252-
nic.MaskSize = size
253-
}
254-
255-
}
256-
257-
m.NICS = append(m.NICS, &nic)
258-
return &nic, true
259-
260-
}
261-
262-
}
263-
264-
}
265-
return nil, false
266-
}

modules/host_network.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ func filterInterfaces(interfaces []net.Interface) []net.Interface {
169169
filtered := make([]net.Interface, 0)
170170
for _, iface := range interfaces {
171171
// ignore loopback
172-
if (iface.Flags & net.FlagLoopback) != 0 {
173-
continue
174-
}
172+
// if (iface.Flags & net.FlagLoopback) != 0 {
173+
// continue
174+
// }
175175
// ignore non up
176176
if (iface.Flags & net.FlagUp) == 0 {
177177
continue

modules/netstat.go

+24-24
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func (m *NetstatModule) Name() string {
3737
}
3838

3939
func (m *NetstatModule) Dependencies() []string {
40-
return []string{"host-basic"}
40+
return []string{"host-basic", "host-network"}
4141
}
4242

4343
func flowFilter(state netstat.SkState) bool {
@@ -58,12 +58,15 @@ func flowFilter(state netstat.SkState) bool {
5858

5959
// portFilter returns true when the connection is listening, established or close-wait
6060
func portFilter(e *netstat.SockTabEntry) bool {
61-
if e.LocalAddr.IP.IsLoopback() && !e.RemoteAddr.IP.IsLoopback() {
62-
return false
63-
}
61+
// accept everything
6462
if e.State == netstat.Listen || flowFilter(e.State) {
6563
return true
6664
}
65+
// fmt.Println(e.LocalAddr.IP, ":", e.LocalAddr.Port, " -> ", e.RemoteAddr.IP, ":", e.RemoteAddr.Port)
66+
// if e.LocalAddr.IP.IsLoopback() && !e.RemoteAddr.IP.IsLoopback() {
67+
// return false
68+
// }
69+
6770
return false
6871
}
6972

@@ -99,11 +102,6 @@ func (m *NetstatModule) Run() error {
99102
continue
100103
}
101104

102-
// (NEW!) create localhost if needed (localhost communication)
103-
if entry.LocalAddr.IP.IsLoopback() && entry.RemoteAddr.IP.IsLoopback() {
104-
machine.GetOrCreateHostLoopback(entry.LocalAddr.IP)
105-
}
106-
107105
name := entry.Process.Name
108106
args, err := utils.GetCmd(entry.Process.Pid)
109107
if err == nil && len(args) > 0 {
@@ -146,21 +144,23 @@ func (m *NetstatModule) Run() error {
146144
soft.Args = args
147145
}
148146

149-
endpoint, created := soft.AddEndpoint(
150-
entry.LocalAddr.IP,
151-
entry.LocalAddr.Port,
152-
protocols[k])
153-
// fmt.Printf("%+v\n", soft)
154-
// fmt.Printf("len: %v, cap: %v, %v\n",
155-
// len(soft.Endpoints), cap(soft.Endpoints), soft.Endpoints)
156-
if created {
157-
// fmt.Println(len(soft.Endpoints))
158-
// logging
159-
l := logger.WithField("app", soft.Name)
160-
l = l.WithField("ip", endpoint.Addr)
161-
l = l.WithField("port", endpoint.Port)
162-
l = l.WithField("proto", endpoint.Protocol)
163-
l.Info("Endpoint found")
147+
if entry.State == netstat.Listen {
148+
endpoint, created := soft.AddEndpoint(
149+
entry.LocalAddr.IP,
150+
entry.LocalAddr.Port,
151+
protocols[k])
152+
// fmt.Printf("%+v\n", soft)
153+
// fmt.Printf("len: %v, cap: %v, %v\n",
154+
// len(soft.Endpoints), cap(soft.Endpoints), soft.Endpoints)
155+
if created {
156+
// fmt.Println(len(soft.Endpoints))
157+
// logging
158+
l := logger.WithField("app", soft.Name)
159+
l = l.WithField("ip", endpoint.Addr)
160+
l = l.WithField("port", endpoint.Port)
161+
l = l.WithField("proto", endpoint.Protocol)
162+
l.Info("Endpoint found")
163+
}
164164
}
165165
}
166166
}

modules/ping.go

+8-23
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,18 @@ package modules
77
import (
88
"fmt"
99
"net"
10-
"os/user"
11-
"runtime"
1210
"strings"
1311
"sync"
1412
"time"
1513

1614
ping "github.com/prometheus-community/pro-bing"
1715
"github.com/sirupsen/logrus"
1816
"github.com/situation-sh/situation/models"
17+
"github.com/situation-sh/situation/modules/pingconfig"
1918
"github.com/situation-sh/situation/store"
2019
"github.com/situation-sh/situation/utils"
2120
)
2221

23-
var useICMP bool = func() bool {
24-
// According to the authors of go-ping
25-
// the pinger must be privileged on windows
26-
// even if we do not run the agent as admin/root
27-
if runtime.GOOS == "windows" {
28-
return true
29-
}
30-
u, err := user.Current()
31-
if err != nil {
32-
return false
33-
}
34-
// On alpine VM with root account, we notice that
35-
// the ping privilege must be set to true
36-
if runtime.GOOS == "linux" && u.Uid == "0" {
37-
return false
38-
}
39-
return false
40-
}()
41-
4222
const errorPrefix = "[ERROR_PREFIX]"
4323

4424
func init() {
@@ -72,10 +52,10 @@ func singlePing(ip net.IP, maskSize int, wg *sync.WaitGroup, cerr chan error) {
7252
return
7353
}
7454
pinger.Count = 1
75-
pinger.SetPrivileged(useICMP)
55+
pinger.SetPrivileged(pingconfig.UseICMP())
7656
pinger.Timeout = 300 * time.Millisecond
7757
// see https://github.com/go-ping/ping/issues/168
78-
pinger.Size = 548
58+
pinger.Size = 2048
7959

8060
// callback when a target responds
8161
pinger.OnRecv = func(p *ping.Packet) {
@@ -108,6 +88,11 @@ func singlePing(ip net.IP, maskSize int, wg *sync.WaitGroup, cerr chan error) {
10888
logger.Info("New machine added")
10989
store.InsertMachine(m)
11090
}
91+
92+
pinger.OnSendError = func(p *ping.Packet, err error) {
93+
94+
}
95+
// run
11196
if err := pinger.Run(); err != nil {
11297
logrus.Debugf("Error: %v", err)
11398
cerr <- fmt.Errorf("error while pinging %v: %v", ip, err)

modules/pingconfig/ping_linux.go

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//go:build linux
2+
// +build linux
3+
4+
package pingconfig
5+
6+
import (
7+
"os/user"
8+
"regexp"
9+
"strconv"
10+
"strings"
11+
12+
sysctl "github.com/lorenzosaino/go-sysctl"
13+
)
14+
15+
// Retrieve net.ipv4.ping_group_range
16+
func getPingGroupRange() (int, int, error) {
17+
start := -1
18+
end := -1
19+
value, err := sysctl.Get("net.ipv4.ping_group_range")
20+
if err != nil {
21+
return start, end, err
22+
}
23+
24+
value = strings.TrimSpace(value)
25+
re := regexp.MustCompile(`^([0-9]+)[ ]+([0-9]+)$`)
26+
subm := re.FindStringSubmatch(value)
27+
if len(subm) < 3 {
28+
return start, end, err
29+
}
30+
start, err = strconv.Atoi(subm[1])
31+
if err != nil {
32+
return start, end, err
33+
}
34+
end, err = strconv.Atoi(subm[2])
35+
return start, end, err
36+
}
37+
38+
func isUserAllowedToPing(usr *user.User) (bool, error) {
39+
groups, err := usr.GroupIds()
40+
if err != nil {
41+
return false, err
42+
}
43+
start, end, err := getPingGroupRange()
44+
if err != nil {
45+
return false, err
46+
}
47+
48+
if start > end {
49+
return false, nil
50+
}
51+
52+
for gid := range groups {
53+
if (start <= gid) && (gid <= end) {
54+
return true, nil
55+
}
56+
}
57+
return false, nil
58+
}
59+
60+
func UseICMP() bool {
61+
usr, err := user.Current()
62+
if err != nil {
63+
return false
64+
}
65+
66+
// check sysctl
67+
allowed, err := isUserAllowedToPing(usr)
68+
if err != nil {
69+
return false
70+
}
71+
72+
return !allowed
73+
}

modules/pingconfig/ping_windows.go

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//go:build windows
2+
// +build windows
3+
4+
package pingconfig
5+
6+
// According to the authors of go-ping
7+
// the pinger must be privileged on windows
8+
// even if we do not run the agent as admin/root
9+
func UseICMP() bool {
10+
return true
11+
}

0 commit comments

Comments
 (0)