1
0
Fork 0
mirror of https://github.com/pnx/pinger.git synced 2026-06-16 03:24:54 +02:00

Compare commits

...

22 commits
v0.0.2 ... main

Author SHA1 Message Date
30cee15b19 LICENSE: update copyright year to 2026 2026-05-11 18:07:14 +02:00
26de4fa647 v0.0.4 2026-05-11 17:35:28 +02:00
b9c0d0b416 main.go: no need to return as it's the last statement 2026-05-11 17:33:52 +02:00
a4343fa706 README.md: minor fix 2025-05-31 17:34:38 +02:00
7870fc361a main.go: cleanup signal output by printing a newline at the end. 2025-05-31 17:33:12 +02:00
fffed4e4e1 main.go: set printStatus as OnFinish callback to pinger. 2025-05-31 17:24:50 +02:00
57a969561e main.go: make printStats() take a probing.Statistics object. 2025-05-31 17:24:25 +02:00
2747946264 add README and LICENSE 2025-05-31 17:16:33 +02:00
5571ba3f38 go.mod: set minimum version to 1.20 2025-05-31 17:16:22 +02:00
111ff58fcf .github/workflows/release.yml: exclude darwin 386 2025-05-30 16:49:41 +02:00
aa05c99bea .github/workflows/release.yml: set correct version 2025-05-30 16:39:08 +02:00
ad48db3b0a Version 0.0.3 2025-05-29 22:24:29 +02:00
4869175152 adding .github/workflows/release.yml 2025-05-26 19:53:33 +02:00
771e1b994a remove .gitlab-ci.yml 2025-05-26 19:45:06 +02:00
7dac879682 adding .github/workflows/test.yml 2025-05-26 19:44:19 +02:00
74a3e98e5b gitignore: ignore pinger binary 2025-05-25 22:29:24 +02:00
c010b082da Adding makefile 2025-05-25 22:28:47 +02:00
ab292886a8 main.go: add option to changes stats interval. 2025-05-25 22:26:12 +02:00
cef5f5daba main.go: proper improt alias 2025-05-25 22:25:14 +02:00
e7c49dac1c Print signal when received 2024-05-18 17:33:55 +02:00
ede1205501 main.go: defer cleanup functions in eventLoop() 2023-03-15 23:30:49 +01:00
dfc7865bc1 go.mod: Upgrade packages. 2023-03-15 23:28:01 +01:00
10 changed files with 176 additions and 70 deletions

41
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,41 @@
name: Release
permissions:
contents: write
on:
release:
types: [ created ]
jobs:
compile:
strategy:
fail-fast: false
matrix:
os: [ linux, darwin, windows ]
arch: [ amd64, 386 ]
exclude:
- os: darwin
arch: 386
name: Release - ${{matrix.os}}-${{matrix.arch}}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.20"
- name: compile
run: |
GOOS=${{matrix.os}} GOARCH=${{matrix.arch}} make
- name: Upload release assets
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_name: pinger-${{github.event.release.tag_name}}-${{matrix.os}}-${{matrix.arch}}
asset_path: pinger
asset_content_type: application/octal-stream

27
.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: Test
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
- name: Fmt
run: go fmt $(go list ./... | grep -v /vendor/)
- name: Vet
run: go vet $(go list ./... | grep -v /vendor/)
- name: Test
run: go test -race $(go list ./... | grep -v /vendor/)

1
.gitignore vendored
View file

@ -1 +1,2 @@
pinger
*.exe *.exe

View file

@ -1,46 +0,0 @@
# This file is a template, and might need editing before it works on your project.
# You can copy and paste this template into a new `.gitlab-ci.yml` file.
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
#
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Go.gitlab-ci.yml
stages:
- test
- build
- release
format:
image: golang:latest
stage: test
script:
- go fmt $(go list ./... | grep -v /vendor/)
- go vet $(go list ./... | grep -v /vendor/)
- go test -race $(go list ./... | grep -v /vendor/)
compile:
image: golang:latest
stage: build
script:
- mkdir -p bin
- GOOS=windows GOARCH=386 go build -o bin/pinger-32.exe ./...
- GOOS=windows GOARCH=amd64 go build -o bin/pinger-x64.exe ./...
- GOOS=linux GOARCH=386 go build -o bin/pinger-linux-x86 ./...
- GOOS=linux GOARCH=amd64 go build -o bin/pinger-linux-x64 ./...
artifacts:
paths:
- bin
expire_in: 1 week
upload:
stage: release
image: curlimages/curl:latest
rules:
- if: $CI_COMMIT_TAG
script:
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file bin/pinger-32.exe "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/release/${CI_COMMIT_TAG}/pinger-32.exe"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file bin/pinger-x64.exe "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/release/${CI_COMMIT_TAG}/pinger-x64.exe"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file bin/pinger-linux-x86 "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/release/${CI_COMMIT_TAG}/pinger-linux-x86"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file bin/pinger-linux-x64 "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/release/${CI_COMMIT_TAG}/pinger-linux-x64"'

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023-2026 Henrik Hautakoski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

5
Makefile Normal file
View file

@ -0,0 +1,5 @@
GO=go
pinger : main.go
$(GO) build -o $@ $^

58
README.md Normal file
View file

@ -0,0 +1,58 @@
# Pinger
**Pinger** is a lightweight, high-performance network utility written in Go.
It enables users to send ICMP echo requests (pings) to specified hosts, facilitating network diagnostics and monitoring.
## Features
* Send ICMP echo requests to specified hosts.
* Measure round-trip time (RTT) for each ping.
* Support for both IPv4 and IPv6 addresses.
* Configurable number of ping attempts and intervals.
* Lightweight and efficient, suitable for scripting and automation.
## Installation
### Prerequisites
* Go (version 1.20 or later) installed on your system.
* make
### Steps
1. Clone the repository:
```bash
git clone https://github.com/pnx/pinger.git
cd pinger
```
2. Build the application:
```bash
make
```
## Usage
See `./pinger -h`
### Example
```bash
./pinger --udp -t 30s example.com
```
This command sends UDP echo requests to example.com, stopping after 30 seconds
```bash
./pinger -c 8 -i 1s example.com
```
This command sends 8 ICMP echo requests to example.com, with a 1-second interval between pings.
NOTE: this requires root privileges
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

8
go.mod
View file

@ -1,6 +1,6 @@
module pinger module pinger
go 1.19 go 1.20
require ( require (
github.com/pborman/getopt/v2 v2.1.0 github.com/pborman/getopt/v2 v2.1.0
@ -9,7 +9,7 @@ require (
require ( require (
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
golang.org/x/net v0.5.0 // indirect golang.org/x/net v0.8.0 // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.4.0 // indirect golang.org/x/sys v0.6.0 // indirect
) )

12
go.sum
View file

@ -4,9 +4,9 @@ github.com/pborman/getopt/v2 v2.1.0 h1:eNfR+r+dWLdWmV8g5OlpyrTYHkhVNxHBdN2cCrJmO
github.com/pborman/getopt/v2 v2.1.0/go.mod h1:4NtW75ny4eBw9fO1bhtNdYTlZKYX5/tBLtsOpwKIKd0= github.com/pborman/getopt/v2 v2.1.0/go.mod h1:4NtW75ny4eBw9fO1bhtNdYTlZKYX5/tBLtsOpwKIKd0=
github.com/prometheus-community/pro-bing v0.1.0 h1:zjzLGhfNPP0bP1OlzGB+SJcguOViw7df12LPg2vUJh8= github.com/prometheus-community/pro-bing v0.1.0 h1:zjzLGhfNPP0bP1OlzGB+SJcguOViw7df12LPg2vUJh8=
github.com/prometheus-community/pro-bing v0.1.0/go.mod h1:BpWlHurD9flHtzq8wrh8QGWYz9ka9z9ZJAyOel8ej58= github.com/prometheus-community/pro-bing v0.1.0/go.mod h1:BpWlHurD9flHtzq8wrh8QGWYz9ka9z9ZJAyOel8ej58=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

25
main.go
View file

@ -8,13 +8,11 @@ import (
"time" "time"
"github.com/pborman/getopt/v2" "github.com/pborman/getopt/v2"
"github.com/prometheus-community/pro-bing" probing "github.com/prometheus-community/pro-bing"
) )
// printStats prints statistics from a ping. // printStats prints statistics from a ping.
func printStats(pinger *probing.Pinger) { func printStats(stats *probing.Statistics) {
stats := pinger.Statistics()
fmt.Printf("%d packets transmitted, %d packets received, %.2f%% packet loss\n", fmt.Printf("%d packets transmitted, %d packets received, %.2f%% packet loss\n",
stats.PacketsSent, stats.PacketsRecv, stats.PacketLoss) stats.PacketsSent, stats.PacketsRecv, stats.PacketLoss)
@ -22,8 +20,9 @@ func printStats(pinger *probing.Pinger) {
stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt) stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt)
} }
func eventLoop(pinger *probing.Pinger) { func eventLoop(pinger *probing.Pinger, ticker *time.Ticker) {
ticker := time.NewTicker(time.Second * 4) defer ticker.Stop()
defer pinger.Stop()
// Setup signals on term and interrupt. // Setup signals on term and interrupt.
sig := make(chan os.Signal, 1) sig := make(chan os.Signal, 1)
@ -32,13 +31,12 @@ func eventLoop(pinger *probing.Pinger) {
for { for {
select { select {
// Got signal. stop pinger and exit goroutine // Got signal. stop pinger and exit goroutine
case <-sig: case s := <-sig:
ticker.Stop() fmt.Printf("Recived signal: %s, exiting.\n", s)
pinger.Stop()
return return
// Ticker ticks. print stats. // Ticker ticks. print stats.
case <-ticker.C: case <-ticker.C:
printStats(pinger) printStats(pinger.Statistics())
} }
} }
} }
@ -51,6 +49,7 @@ func main() {
count := getopt.IntLong("count", 'c', 0, "Stop after this many packages has been sent (and received). If this option is not specified, pinger will operate until interrupted.") count := getopt.IntLong("count", 'c', 0, "Stop after this many packages has been sent (and received). If this option is not specified, pinger will operate until interrupted.")
timeout := getopt.DurationLong("timeout", 't', 0, "Exit the program after this time is reached, regardless of how many packets have been received.") timeout := getopt.DurationLong("timeout", 't', 0, "Exit the program after this time is reached, regardless of how many packets have been received.")
interval := getopt.DurationLong("interval", 'i', time.Second*2, "Wait time between each packet send") interval := getopt.DurationLong("interval", 'i', time.Second*2, "Wait time between each packet send")
statsInterval := getopt.DurationLong("stats-interval", 0, time.Second*4, "How often stats should be printed to the console.")
proto_udp := getopt.BoolLong("udp", 0, "Send UDP ping instead of a raw IMCP ping, IMCP required super-user privileges") proto_udp := getopt.BoolLong("udp", 0, "Send UDP ping instead of a raw IMCP ping, IMCP required super-user privileges")
record_rtt := getopt.BoolLong("rtt", 0, "Keep a record of rtts of all received packets.") record_rtt := getopt.BoolLong("rtt", 0, "Keep a record of rtts of all received packets.")
@ -58,7 +57,7 @@ func main() {
getopt.Parse() getopt.Parse()
if *version { if *version {
fmt.Println("Version 0.0.2") fmt.Println("Version 0.0.4")
os.Exit(0) os.Exit(0)
} }
@ -79,17 +78,17 @@ func main() {
pinger.Source = *source pinger.Source = *source
pinger.Count = *count pinger.Count = *count
pinger.RecordRtts = *record_rtt pinger.RecordRtts = *record_rtt
pinger.OnFinish = printStats
if timeout != nil && *timeout > 0 { if timeout != nil && *timeout > 0 {
pinger.Timeout = *timeout pinger.Timeout = *timeout
} }
// Enter event loop in another goroutine. // Enter event loop in another goroutine.
go eventLoop(pinger) go eventLoop(pinger, time.NewTicker(*statsInterval))
// Run pinger in main thread. // Run pinger in main thread.
fmt.Println("PING", pinger.Addr()) fmt.Println("PING", pinger.Addr())
if err = pinger.Run(); err != nil { if err = pinger.Run(); err != nil {
fmt.Println("Error:", err) fmt.Println("Error:", err)
return
} }
} }