mirror of
https://github.com/balkian/pingish
synced 2024-11-21 19:12:29 +00:00
Version 1.0.1 with server
This commit is contained in:
parent
011f9e57ce
commit
de74385715
60
Dockerfile
Normal file
60
Dockerfile
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# Accept the Go version for the image to be set as a build argument.
|
||||||
|
# Default to Go 1.11
|
||||||
|
ARG GO_VERSION=1.11
|
||||||
|
|
||||||
|
# First stage: build the executable.
|
||||||
|
FROM golang:${GO_VERSION}-alpine AS builder
|
||||||
|
|
||||||
|
# Create the user and group files that will be used in the running container to
|
||||||
|
# run the process as an unprivileged user.
|
||||||
|
# RUN mkdir /user && \
|
||||||
|
# echo 'nobody:x:65534:65534:nobody:/:' > /user/passwd && \
|
||||||
|
# echo 'nobody:x:65534:' > /user/group
|
||||||
|
|
||||||
|
# Install the Certificate-Authority certificates for the app to be able to make
|
||||||
|
# calls to HTTPS endpoints.
|
||||||
|
# Git is required for fetching the dependencies.
|
||||||
|
# libcap might be needed in the future for setcap
|
||||||
|
RUN apk add --no-cache ca-certificates git
|
||||||
|
|
||||||
|
# Set the working directory outside $GOPATH to enable the support for modules.
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
# Fetch dependencies first; they are less susceptible to change on every build
|
||||||
|
# and will therefore be cached for speeding up the next build
|
||||||
|
COPY ./go.mod ./go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Import the code from the context.
|
||||||
|
COPY ./ ./
|
||||||
|
|
||||||
|
# Build the executable to `/app`. Mark the build as statically linked.
|
||||||
|
RUN CGO_ENABLED=0 go build \
|
||||||
|
-installsuffix 'static' \
|
||||||
|
-o /app .
|
||||||
|
|
||||||
|
# Add ping privileges
|
||||||
|
# RUN setcap cap_net_raw+ep /app
|
||||||
|
|
||||||
|
# Final stage: the running container.
|
||||||
|
FROM scratch AS final
|
||||||
|
|
||||||
|
# Import the user and group files from the first stage.
|
||||||
|
# COPY --from=builder /user/group /user/passwd /etc/
|
||||||
|
|
||||||
|
# Import the Certificate-Authority certificates for enabling HTTPS.
|
||||||
|
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||||
|
|
||||||
|
# Import the compiled executable from the first stage.
|
||||||
|
COPY --from=builder /app /app
|
||||||
|
|
||||||
|
# Declare the port on which the webserver will be exposed.
|
||||||
|
# As we're going to run the executable as an unprivileged user, we can't bind
|
||||||
|
# to ports below 1024.
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Perform any further action as an unprivileged user.
|
||||||
|
# USER nobody:nobody
|
||||||
|
|
||||||
|
# Run the compiled binary.
|
||||||
|
ENTRYPOINT ["/app"]
|
3
Makefile
3
Makefile
@ -1,5 +1,8 @@
|
|||||||
build:
|
build:
|
||||||
CGO_ENABLED=0 go build -ldflags="-s -w" -o pingish
|
CGO_ENABLED=0 go build -ldflags="-s -w" -o pingish
|
||||||
|
|
||||||
|
docker-build:
|
||||||
|
docker build -t balkian/pingish .
|
||||||
|
|
||||||
run: build
|
run: build
|
||||||
./pingish -c 10 -host www.google.es
|
./pingish -c 10 -host www.google.es
|
||||||
|
14
README.md
14
README.md
@ -5,6 +5,20 @@ Just copy the binary to the container, and problem solved.
|
|||||||
|
|
||||||
The binary has to be built with `CGO_ENABLED=0` to avoid problems with alpine-based images.
|
The binary has to be built with `CGO_ENABLED=0` to avoid problems with alpine-based images.
|
||||||
|
|
||||||
|
Example of use:
|
||||||
|
|
||||||
|
```
|
||||||
|
pingish www.google.es
|
||||||
|
```
|
||||||
|
|
||||||
|
# Server
|
||||||
|
|
||||||
|
You can start a server that will accept requests on `/ping?host=<target>`, using the `--server` flag. e.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
pingish --server
|
||||||
|
```
|
||||||
|
|
||||||
# TROUBLESHOOTING
|
# TROUBLESHOOTING
|
||||||
|
|
||||||
To run it as a normal user in ubuntu, you might need to configure your host first: `sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"`
|
To run it as a normal user in ubuntu, you might need to configure your host first: `sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"`
|
||||||
|
115
main.go
115
main.go
@ -1,23 +1,81 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tatsushid/go-fastping"
|
"github.com/tatsushid/go-fastping"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
type Response struct {
|
||||||
name := flag.String("host", "www.google.es", "Hostname to ping")
|
Host string
|
||||||
count := flag.Int("c", 3, "Number of times to wait for the ")
|
Up bool
|
||||||
flag.Parse()
|
RTT []time.Duration `json:"RTT,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
adds, err := net.LookupHost(*name)
|
var PING_COUNT = 1
|
||||||
|
|
||||||
|
func homeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprint(w, "<h1>Ping a hostname</h1>"+
|
||||||
|
"<form action=\"/ping/\" method=\"GET\">"+
|
||||||
|
"<input type=\"text\" name=\"host\"><br>"+
|
||||||
|
"<input type=\"submit\" value=\"Ping\">"+
|
||||||
|
"</form>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func pingHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
name := r.URL.Query().Get("host")
|
||||||
|
if name == "" {
|
||||||
|
tokens := strings.Split(r.URL.Path, "/")
|
||||||
|
if len(tokens) < 3 || tokens[2] == "" {
|
||||||
|
http.Error(w, "You have to specify a hostname to ping", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
name = tokens[2]
|
||||||
|
}
|
||||||
|
times := PING_COUNT
|
||||||
|
count := r.URL.Query().Get("count")
|
||||||
|
fmt.Printf("Requested %s %s times\n", name, count)
|
||||||
|
|
||||||
|
if count != "" {
|
||||||
|
if counts, err := strconv.Atoi(count); err == nil {
|
||||||
|
times = counts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
up, rtt, err := CheckHost(name, times)
|
||||||
|
|
||||||
|
response := Response{Host: name, Up: up, RTT: rtt}
|
||||||
|
js, err := json.Marshal(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
if !up {
|
||||||
|
http.Error(w, string(js), http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Write(js)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckHost(name string, times int) (bool, []time.Duration, error) {
|
||||||
|
fmt.Printf("Checking %s\n", name)
|
||||||
|
adds, err := net.LookupHost(name)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
}
|
}
|
||||||
fmt.Println("List of addresses:")
|
fmt.Println("List of addresses:")
|
||||||
for _, add := range adds {
|
for _, add := range adds {
|
||||||
@ -25,21 +83,56 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p := fastping.NewPinger()
|
p := fastping.NewPinger()
|
||||||
ra, err := net.ResolveIPAddr("ip4:icmp", *name)
|
ra, err := net.ResolveIPAddr("ip4:icmp", name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
return false, nil, err
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
rtttimes := make([]time.Duration, 0)
|
||||||
|
recv := make(chan time.Duration)
|
||||||
p.AddIPAddr(ra)
|
p.AddIPAddr(ra)
|
||||||
p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) {
|
p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) {
|
||||||
fmt.Printf("IP Addr: %s receive, RTT: %v\n", addr.String(), rtt)
|
fmt.Printf("IP Addr: %s receive, RTT: %v\n", addr.String(), rtt)
|
||||||
|
recv <- rtt
|
||||||
}
|
}
|
||||||
for i := 0; i < *count; i++ {
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
// Do work
|
||||||
|
for t := range recv {
|
||||||
|
rtttimes = append(rtttimes, t)
|
||||||
|
fmt.Printf("Ping %s: %s\n", name, t)
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for i := 0; i < times; i++ {
|
||||||
err = p.Run()
|
err = p.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
close(recv)
|
||||||
|
wg.Wait()
|
||||||
fmt.Println("finished")
|
fmt.Println("finished")
|
||||||
|
return len(rtttimes) > 0, rtttimes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
name := flag.String("host", "www.google.es", "Hostname to ping")
|
||||||
|
count := flag.Int("c", 3, "Number of ping attempts")
|
||||||
|
serve := flag.Bool("server", false, "Start the http server")
|
||||||
|
address := flag.String("address", ":8080", "Host and port to start the http server on")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if !*serve {
|
||||||
|
_, _, err := CheckHost(*name, *count)
|
||||||
|
if err == nil {
|
||||||
|
fmt.Printf("could not find host %s: %s\n", *name, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
http.HandleFunc("/", homeHandler)
|
||||||
|
http.HandleFunc("/ping/", pingHandler)
|
||||||
|
log.Fatal(http.ListenAndServe(*address, nil))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user