mirror of
https://github.com/pnx/pinger.git
synced 2026-06-16 03:24:54 +02:00
Compare commits
22 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 30cee15b19 | |||
| 26de4fa647 | |||
| b9c0d0b416 | |||
| a4343fa706 | |||
| 7870fc361a | |||
| fffed4e4e1 | |||
| 57a969561e | |||
| 2747946264 | |||
| 5571ba3f38 | |||
| 111ff58fcf | |||
| aa05c99bea | |||
| ad48db3b0a | |||
| 4869175152 | |||
| 771e1b994a | |||
| 7dac879682 | |||
| 74a3e98e5b | |||
| c010b082da | |||
| ab292886a8 | |||
| cef5f5daba | |||
| e7c49dac1c | |||
| ede1205501 | |||
| dfc7865bc1 |
10 changed files with 176 additions and 70 deletions
41
.github/workflows/release.yml
vendored
Normal file
41
.github/workflows/release.yml
vendored
Normal 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
27
.github/workflows/test.yml
vendored
Normal 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/)
|
||||||
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
||||||
*.exe
|
pinger
|
||||||
|
*.exe
|
||||||
|
|
|
||||||
|
|
@ -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
21
LICENSE
Normal 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
5
Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
GO=go
|
||||||
|
|
||||||
|
pinger : main.go
|
||||||
|
$(GO) build -o $@ $^
|
||||||
58
README.md
Normal file
58
README.md
Normal 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
8
go.mod
|
|
@ -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
12
go.sum
|
|
@ -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
25
main.go
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue