Skip to content

Commit 5fdc489

Browse files
h3mmyTwiN
andauthored
fix(client): update icmp/ping logic to determine pinger privileged mode (#1346)
* fix(pinger): update logic to determine pinger privileged mode * add some unit tests for pinger Signed-off-by: Zee Aslam <[email protected]> * undo accidental removal Signed-off-by: Zee Aslam <[email protected]> * check for cap_net_raw by trying to open a raw socket and checking for permission error Signed-off-by: Zee Aslam <[email protected]> * revert syscall after testing. It is unable to build a binary on windows Signed-off-by: Zee Aslam <[email protected]> * remove extra import * review icmp section of readme. No changes required Signed-off-by: Zee Aslam <[email protected]> * Update client/client.go Co-authored-by: TwiN <[email protected]> * Update client/client.go Match function name Co-authored-by: TwiN <[email protected]> * Update client/client.go Remove extra line Co-authored-by: TwiN <[email protected]> --------- Signed-off-by: Zee Aslam <[email protected]> Co-authored-by: TwiN <[email protected]>
1 parent 2ebb74a commit 5fdc489

File tree

3 files changed

+68
-24
lines changed

3 files changed

+68
-24
lines changed

README.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -373,13 +373,13 @@ Where:
373373
- Using the example configuration above, the key would be `core_ext-ep-test`.
374374
- `{success}` is a boolean (`true` or `false`) value indicating whether the health check was successful or not.
375375
- `{error}` (optional): a string describing the reason for a failed health check. If {success} is false, this should contain the error message; if the check is successful.
376-
- `{duration}` (optional): the time that the request took as a duration string (e.g. 10s).
376+
- `{duration}` (optional): the time that the request took as a duration string (e.g. 10s).
377377

378378
You must also pass the token as a `Bearer` token in the `Authorization` header.
379379

380380

381381
### Suites (ALPHA)
382-
Suites are collections of endpoints that are executed sequentially with a shared context.
382+
Suites are collections of endpoints that are executed sequentially with a shared context.
383383
This allows you to create complex monitoring scenarios where the result from one endpoint can be used in subsequent endpoints, enabling workflow-style monitoring.
384384

385385
Here are a few cases in which suites could be useful:
@@ -421,7 +421,7 @@ suites:
421421
context:
422422
price: "19.99" # Initial static value in context
423423
endpoints:
424-
# Step 1: Create an item and store the item ID
424+
# Step 1: Create an item and store the item ID
425425
- name: create-item
426426
url: https://api.example.com/items
427427
method: POST
@@ -435,7 +435,7 @@ suites:
435435
alerts:
436436
- type: slack
437437
description: "Failed to create item"
438-
438+
439439
# Step 2: Update the item using the stored item ID
440440
- name: update-item
441441
url: https://api.example.com/items/[CONTEXT].itemId
@@ -446,7 +446,7 @@ suites:
446446
alerts:
447447
- type: slack
448448
description: "Failed to update item"
449-
449+
450450
# Step 3: Fetch the item and validate the price
451451
- name: get-item
452452
url: https://api.example.com/items/[CONTEXT].itemId
@@ -457,7 +457,7 @@ suites:
457457
alerts:
458458
- type: slack
459459
description: "Item price did not update correctly"
460-
460+
461461
# Step 4: Delete the item (always-run: true to ensure cleanup even if step 2 or 3 fails)
462462
- name: delete-item
463463
url: https://api.example.com/items/[CONTEXT].itemId
@@ -536,7 +536,7 @@ System-wide announcements allow you to display important messages at the top of
536536

537537
Types:
538538
- **outage**: Indicates service disruptions or critical issues (red theme)
539-
- **warning**: Indicates potential issues or important notices (yellow theme)
539+
- **warning**: Indicates potential issues or important notices (yellow theme)
540540
- **information**: General information or updates (blue theme)
541541
- **operational**: Indicates resolved issues or normal operations (green theme)
542542
- **none**: Neutral announcements with no specific severity (gray theme, default if none are specified)
@@ -548,7 +548,7 @@ announcements:
548548
type: outage
549549
message: "Scheduled maintenance on database servers from 14:00 to 16:00 UTC"
550550
- timestamp: 2025-08-15T16:15:00Z
551-
type: operational
551+
type: operational
552552
message: "Database maintenance completed successfully. All systems operational."
553553
- timestamp: 2025-08-15T12:00:00Z
554554
type: information
@@ -709,7 +709,7 @@ endpoints:
709709
> 📝 Note that if running in a container, you must volume mount the certificate and key into the container.
710710

711711
### Tunneling
712-
Gatus supports SSH tunneling to monitor internal services through jump hosts or bastion servers.
712+
Gatus supports SSH tunneling to monitor internal services through jump hosts or bastion servers.
713713
This is particularly useful for monitoring services that are not directly accessible from where Gatus is deployed.
714714

715715
SSH tunnels are defined globally in the `tunneling` section and then referenced by name in endpoint client configurations.
@@ -746,7 +746,7 @@ endpoints:
746746
- "[STATUS] == 200"
747747
```
748748

749-
> ⚠️ **WARNING**:: Tunneling may introduce additional latency, especially if the connection to the tunnel is retried frequently.
749+
> ⚠️ **WARNING**:: Tunneling may introduce additional latency, especially if the connection to the tunnel is retried frequently.
750750
> This may lead to inaccurate response time measurements.
751751

752752

@@ -2182,7 +2182,7 @@ Here's an example of what the notifications look like:
21822182
| `alerting.telegram` | Configuration for alerts of type `telegram` | `{}` |
21832183
| `alerting.telegram.token` | Telegram Bot Token | Required `""` |
21842184
| `alerting.telegram.id` | Telegram User ID | Required `""` |
2185-
| `alerting.telegram.topic-id` | Telegram Topic ID in a group corresponds to `message_thread_id` in the Telegram API | `""` |
2185+
| `alerting.telegram.topic-id` | Telegram Topic ID in a group corresponds to `message_thread_id` in the Telegram API | `""` |
21862186
| `alerting.telegram.api-url` | Telegram API URL | `https://api.telegram.org` |
21872187
| `alerting.telegram.client` | Client configuration. <br />See [Client configuration](#client-configuration). | `{}` |
21882188
| `alerting.telegram.default-alert` | Default alert configuration. <br />See [Setting a default alert](#setting-a-default-alert) | N/A |
@@ -2844,7 +2844,7 @@ will send a `POST` request to `http://localhost:8080/playground` with the follow
28442844

28452845

28462846
### Recommended interval
2847-
To ensure that Gatus provides reliable and accurate results (i.e. response time), Gatus limits the number of
2847+
To ensure that Gatus provides reliable and accurate results (i.e. response time), Gatus limits the number of
28482848
endpoints/suites that can be evaluated at the same time.
28492849
In other words, even if you have multiple endpoints with the same interval, they are not guaranteed to run at the same time.
28502850

@@ -2952,8 +2952,8 @@ endpoints:
29522952
```
29532953

29542954
The `[BODY]` placeholder contains the output of the query, and `[CONNECTED]`
2955-
shows whether the connection was successfully established. You can use Go template
2956-
syntax.
2955+
shows whether the connection was successfully established. You can use Go template
2956+
syntax.
29572957

29582958

29592959
### Monitoring an endpoint using ICMP
@@ -2970,7 +2970,7 @@ endpoints:
29702970
Only the placeholders `[CONNECTED]`, `[IP]` and `[RESPONSE_TIME]` are supported for endpoints of type ICMP.
29712971
You can specify a domain prefixed by `icmp://`, or an IP address prefixed by `icmp://`.
29722972

2973-
If you run Gatus on Linux, please read the Linux section on https://github.com/prometheus-community/pro-bing#linux
2973+
If you run Gatus on Linux, please read the Linux section on [https://github.com/prometheus-community/pro-bing#linux]
29742974
if you encounter any problems.
29752975

29762976

@@ -3088,7 +3088,7 @@ endpoints:
30883088
- "[CERTIFICATE_EXPIRATION] > 240h"
30893089
```
30903090

3091-
> ⚠ The usage of the `[DOMAIN_EXPIRATION]` placeholder requires Gatus to use RDAP, or as a fallback, send a request to the official IANA WHOIS service
3091+
> ⚠ The usage of the `[DOMAIN_EXPIRATION]` placeholder requires Gatus to use RDAP, or as a fallback, send a request to the official IANA WHOIS service
30923092
> [through a library](https://github.com/TwiN/whois) and in some cases, a secondary request to a TLD-specific WHOIS server (e.g. `whois.nic.sh`).
30933093
> To prevent the WHOIS service from throttling your IP address if you send too many requests, Gatus will prevent you from
30943094
> using the `[DOMAIN_EXPIRATION]` placeholder on an endpoint with an interval of less than `5m`.
@@ -3117,7 +3117,7 @@ concurrency: 0
31173117

31183118
**Use cases for higher concurrency:**
31193119
- You have a large number of endpoints to monitor
3120-
- You want to monitor endpoints at very short intervals (< 5s)
3120+
- You want to monitor endpoints at very short intervals (< 5s)
31213121
- You're using Gatus for load testing scenarios
31223122

31233123
**Legacy configuration:**
@@ -3201,7 +3201,7 @@ ui:
32013201
default-sort-by: group
32023202
```
32033203
Note that if a user has already sorted the dashboard by a different field, the default sort will not be applied unless the user
3204-
clears their browser's localstorage.
3204+
clears their browser's localstorage.
32053205

32063206

32073207
### Exposing Gatus on a custom path

client/client.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"net"
1414
"net/http"
1515
"net/smtp"
16+
"os"
1617
"runtime"
1718
"strings"
1819
"time"
@@ -343,12 +344,7 @@ func Ping(address string, config *Config) (bool, time.Duration) {
343344
pinger := ping.New(address)
344345
pinger.Count = 1
345346
pinger.Timeout = config.Timeout
346-
// Set the pinger's privileged mode to true for every GOOS except darwin
347-
// See https://github.com/TwiN/gatus/issues/132
348-
//
349-
// Note that for this to work on Linux, Gatus must run with sudo privileges.
350-
// See https://github.com/prometheus-community/pro-bing#linux
351-
pinger.SetPrivileged(runtime.GOOS != "darwin")
347+
pinger.SetPrivileged(ShouldRunPingerAsPrivileged())
352348
pinger.SetNetwork(config.Network)
353349
err := pinger.Run()
354350
if err != nil {
@@ -364,6 +360,25 @@ func Ping(address string, config *Config) (bool, time.Duration) {
364360
return true, 0
365361
}
366362

363+
// ShouldRunPingerAsPrivileged will determine whether or not to run pinger in privileged mode.
364+
// It should be set to privileged when running as root, and always on windows. See https://pkg.go.dev/github.com/macrat/go-parallel-pinger#Pinger.SetPrivileged
365+
func ShouldRunPingerAsPrivileged() bool {
366+
// Set the pinger's privileged mode to false for darwin
367+
// See https://github.com/TwiN/gatus/issues/132
368+
// linux should also be set to false, but there are potential complications
369+
// See https://github.com/TwiN/gatus/pull/748 and https://github.com/TwiN/gatus/issues/697#issuecomment-2081700989
370+
//
371+
// Note that for this to work on Linux, Gatus must run with sudo privileges. (in certain cases)
372+
// See https://github.com/prometheus-community/pro-bing#linux
373+
if runtime.GOOS == "windows" {
374+
return true
375+
}
376+
// To actually check for cap_net_raw capabilities, we would need to add "kernel.org/pub/linux/libs/security/libcap/cap" to gatus.
377+
// Or use a syscall and check for permission errors, but this requires platform specific compilation
378+
// As a backstop we can simply check the effective user id and run as privileged when running as root
379+
return os.Geteuid() == 0
380+
}
381+
367382
// QueryWebSocket opens a websocket connection, write `body` and return a message from the server
368383
func QueryWebSocket(address, body string, headers map[string]string, config *Config) (bool, []byte, error) {
369384
const (

client/client_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"io"
77
"net/http"
88
"net/netip"
9+
"os"
10+
"runtime"
911
"testing"
1012
"time"
1113

@@ -129,6 +131,33 @@ func TestPing(t *testing.T) {
129131
}
130132
}
131133

134+
func TestShouldRunPingerAsPrivileged(t *testing.T) {
135+
// Don't run in parallel since we're testing system-dependent behavior
136+
if runtime.GOOS == "windows" {
137+
result := ShouldRunPingerAsPrivileged()
138+
if !result {
139+
t.Error("On Windows, ShouldRunPingerAsPrivileged() should return true")
140+
}
141+
return
142+
}
143+
144+
// Non-Windows tests
145+
result := ShouldRunPingerAsPrivileged()
146+
isRoot := os.Geteuid() == 0
147+
148+
// Test cases based on current environment
149+
if isRoot {
150+
if !result {
151+
t.Error("When running as root, ShouldRunPingerAsPrivileged() should return true")
152+
}
153+
} else {
154+
// When not root, the result depends on raw socket creation
155+
// We can at least verify the function runs without panic
156+
t.Logf("Non-root privileged result: %v", result)
157+
}
158+
}
159+
160+
132161
func TestCanPerformStartTLS(t *testing.T) {
133162
type args struct {
134163
address string

0 commit comments

Comments
 (0)