mirror of
https://github.com/balkian/pingish
synced 2024-11-23 20:12:28 +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:
|
||||
CGO_ENABLED=0 go build -ldflags="-s -w" -o pingish
|
||||
|
||||
docker-build:
|
||||
docker build -t balkian/pingish .
|
||||
|
||||
run: build
|
||||
./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.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/tatsushid/go-fastping"
|
||||
)
|
||||
|
||||
func main() {
|
||||
name := flag.String("host", "www.google.es", "Hostname to ping")
|
||||
count := flag.Int("c", 3, "Number of times to wait for the ")
|
||||
flag.Parse()
|
||||
type Response struct {
|
||||
Host string
|
||||
Up bool
|
||||
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 {
|
||||
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:")
|
||||
for _, add := range adds {
|
||||
@ -25,21 +83,56 @@ func main() {
|
||||
}
|
||||
|
||||
p := fastping.NewPinger()
|
||||
ra, err := net.ResolveIPAddr("ip4:icmp", *name)
|
||||
ra, err := net.ResolveIPAddr("ip4:icmp", name)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
return false, nil, err
|
||||
}
|
||||
rtttimes := make([]time.Duration, 0)
|
||||
recv := make(chan time.Duration)
|
||||
p.AddIPAddr(ra)
|
||||
p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) {
|
||||
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()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
close(recv)
|
||||
wg.Wait()
|
||||
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