first release
This commit is contained in:
parent
4f7dfab7d9
commit
604f9fb876
59
.github/workflows/main.yml
vendored
Normal file
59
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
name: build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish_release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
# checkout code
|
||||||
|
- uses: actions/checkout@master
|
||||||
|
# create release
|
||||||
|
- uses: actions/create-release@v1
|
||||||
|
id: create_release
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ github.ref }}
|
||||||
|
release_name: Release ${{ github.ref }}
|
||||||
|
body: |
|
||||||
|
Changes in this Release
|
||||||
|
- First Change
|
||||||
|
- Second Change
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
# build binaries
|
||||||
|
- uses: actions/setup-go@v1
|
||||||
|
with:
|
||||||
|
go-version: '1.13.5'
|
||||||
|
- name: build
|
||||||
|
run: |
|
||||||
|
mkdir pingme-linux-amd64
|
||||||
|
mkdir pingme-darwin-amd64
|
||||||
|
env VERSION=$(echo ${GITHUB_REF:10}) GIN_MODE=release GOOS=linux GOARCH=amd64 bash -c 'go build -ldflags "-X main.VersionString=$VERSION" -o pingme-linux-amd64/pingme *.go'
|
||||||
|
env VERSION=$(echo ${GITHUB_REF:10}) GIN_MODE=release GOOS=darwin GOARCH=amd64 bash -c 'go build -ldflags "-X main.VersionString=$VERSION" -o pingme-darwin-amd64/pingme *.go'
|
||||||
|
tar -C $PWD -cvzf pingme-linux-amd64.tar.gz pingme-linux-amd64
|
||||||
|
tar -C $PWD -cvzf pingme-darwin-amd64.tar.gz pingme-darwin-amd64
|
||||||
|
# upload binaries linux
|
||||||
|
- uses: actions/upload-release-asset@v1.0.1
|
||||||
|
id: upload-release-asset-linux
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: ./pingme-linux-amd64.tar.gz
|
||||||
|
asset_name: pingme-linux-amd64.tar.gz
|
||||||
|
asset_content_type: application/gzip
|
||||||
|
# upload binaries darwin
|
||||||
|
- uses: actions/upload-release-asset@v1.0.1
|
||||||
|
id: upload-release-asset-darwin
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: ./pingme-darwin-amd64.tar.gz
|
||||||
|
asset_name: pingme-darwin-amd64.tar.gz
|
||||||
|
asset_content_type: application/gzip
|
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Binary Output
|
||||||
|
pingme
|
||||||
|
pingme-cli
|
||||||
|
|
||||||
|
# Script
|
||||||
|
*.sh
|
||||||
|
|
||||||
|
# Log
|
||||||
|
*.log
|
||||||
|
*.dat
|
||||||
|
*.txt
|
||||||
|
|
||||||
|
# Database
|
||||||
|
*.db
|
||||||
|
|
||||||
|
# Config
|
||||||
|
config.json
|
20
LICENSE.md
Normal file
20
LICENSE.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Copyright (c) 2019-2020 Noobly
|
||||||
|
|
||||||
|
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.
|
109
README.md
109
README.md
@ -1 +1,108 @@
|
|||||||
# pingme
|
# Introduction
|
||||||
|
|
||||||
|
Pingme is ping probe command line tool, supporting ICMP, TCP and HTTP protocols.
|
||||||
|
|
||||||
|
You can also use it to query IP information from third-party api provider (currently we use [https://ip-api.com](https://ip-api.com)).
|
||||||
|
|
||||||
|
# Features
|
||||||
|
|
||||||
|
- Support ICMP/TCP/HTTP protocols
|
||||||
|
- Query basic IP information
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
|
||||||
|
1. Download latest [release](https://github.com/noobly314/pingme/releases/latest) (recommend)
|
||||||
|
|
||||||
|
2. Use go get
|
||||||
|
|
||||||
|
```
|
||||||
|
go get -u github.com/noobly314/pingme
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Build on your own
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/noobly314/pingme.git
|
||||||
|
cd pingme
|
||||||
|
go build
|
||||||
|
```
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
-h string
|
||||||
|
HTTP Ping
|
||||||
|
-i string
|
||||||
|
ICMP Ping
|
||||||
|
-m string
|
||||||
|
MTR Trace
|
||||||
|
-q string
|
||||||
|
Query ip information
|
||||||
|
-t string
|
||||||
|
TCP Ping
|
||||||
|
-v Version
|
||||||
|
```
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pingme -h https://www.google.com
|
||||||
|
Proxy : false
|
||||||
|
Scheme : https
|
||||||
|
Host : www.google.com
|
||||||
|
DNS Lookup: 2.05 ms
|
||||||
|
TCP : 2.41 ms
|
||||||
|
TLS : 68.92 ms
|
||||||
|
Process : 29.28 ms
|
||||||
|
Transfer : 0.19 ms
|
||||||
|
Total : 103.06 ms
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pingme -i www.google.com
|
||||||
|
ICMP OPEN 74.125.200.147 2.2 ms
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pingme -t www.google.com:443
|
||||||
|
TCP OPEN www.google.com:443
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pingme -q www.google.com
|
||||||
|
IP : 172.217.194.103
|
||||||
|
City : Queenstown Estate
|
||||||
|
Country: Singapore
|
||||||
|
ISP : Google LLC
|
||||||
|
AS : AS15169 Google LLC
|
||||||
|
```
|
||||||
|
|
||||||
|
# Note
|
||||||
|
|
||||||
|
Root permission is required when running ICMP ping, since it needs to open raw socket.
|
||||||
|
|
||||||
|
You can either use sudo command, or set setuid bit for pingme.
|
||||||
|
|
||||||
|
```
|
||||||
|
// Use sudo for one-time ping
|
||||||
|
$ sudo pingme -i google.com
|
||||||
|
|
||||||
|
// Set setuid bit
|
||||||
|
$ sudo chown root:root pingme
|
||||||
|
$ sudo chmod u+s pingme
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
See the [LICENSE](https://github.com/noobly314/pingme/blob/master/LICENSE.md) file for license rights and limitations (MIT).
|
||||||
|
|
||||||
|
# Acknowledgements
|
||||||
|
|
||||||
|
[https://ip-api.com](https://ip-api.com)
|
||||||
|
|
||||||
|
[lmas/icmp_ping.go](https://gist.github.com/lmas/c13d1c9de3b2224f9c26435eb56e6ef3)
|
||||||
|
|
||||||
|
[sparrc/go-ping](https://github.com/sparrc/go-ping)
|
||||||
|
|
||||||
|
[davecheney/httpstat](https://github.com/davecheney/httpstat)
|
||||||
|
49
flag.go
Normal file
49
flag.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Version bool
|
||||||
|
var PingDst string
|
||||||
|
var TCPingDst string
|
||||||
|
var HTTPingDst string
|
||||||
|
var MtrDst string
|
||||||
|
var Query string
|
||||||
|
|
||||||
|
var CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
||||||
|
|
||||||
|
var Usage = func() {
|
||||||
|
fmt.Fprintf(CommandLine.Output(), "Usage:\n")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
func init_flag() {
|
||||||
|
flag.BoolVar(&Version, "v", false, "Version")
|
||||||
|
flag.StringVar(&PingDst, "i", "", "ICMP Ping")
|
||||||
|
flag.StringVar(&TCPingDst, "t", "", "TCP Ping")
|
||||||
|
flag.StringVar(&HTTPingDst, "h", "", "HTTP Ping")
|
||||||
|
flag.StringVar(&MtrDst, "m", "", "MTR Trace")
|
||||||
|
flag.StringVar(&Query, "q", "", "Query ip information")
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasFlag() bool {
|
||||||
|
found := false
|
||||||
|
flag.Visit(func(f *flag.Flag) {
|
||||||
|
found = true
|
||||||
|
})
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFlagPassed(name string) bool {
|
||||||
|
found := false
|
||||||
|
flag.Visit(func(f *flag.Flag) {
|
||||||
|
if f.Name == name {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return found
|
||||||
|
}
|
17
go.mod
Normal file
17
go.mod
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
module github.com/noobly314/pingme
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/aeden/traceroute v0.0.0-20181124220833-147686d9cb0f
|
||||||
|
github.com/fatih/color v1.7.0
|
||||||
|
github.com/gin-contrib/cors v1.3.0
|
||||||
|
github.com/gin-gonic/gin v1.5.0
|
||||||
|
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.10 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.4.2
|
||||||
|
github.com/sparrc/go-ping v0.0.0-20190613174326-4e5b6552494c
|
||||||
|
github.com/syndtr/goleveldb v1.0.0
|
||||||
|
go.etcd.io/bbolt v1.3.3
|
||||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
|
||||||
|
)
|
||||||
|
|
||||||
|
go 1.13
|
96
go.sum
Normal file
96
go.sum
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
github.com/aeden/traceroute v0.0.0-20181124220833-147686d9cb0f h1:LbPChgmEVYTHVg0zmAydDO3YNRgkt31svsI7LJ0crjs=
|
||||||
|
github.com/aeden/traceroute v0.0.0-20181124220833-147686d9cb0f/go.mod h1:WwE/rUGG8pQ7L4JiBoNPCTZGQGWnciVaM+pXYfQR9ps=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/gin-contrib/cors v1.3.0 h1:PolezCc89peu+NgkIWt9OB01Kbzt6IP0J/JvkG6xxlg=
|
||||||
|
github.com/gin-contrib/cors v1.3.0/go.mod h1:artPvLlhkF7oG06nK8v3U8TNz6IeX+w1uzCSEId5/Vc=
|
||||||
|
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
||||||
|
github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc=
|
||||||
|
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||||
|
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||||
|
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||||
|
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
|
||||||
|
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
||||||
|
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||||
|
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||||
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
|
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||||
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/noobly314/pingme v0.0.0-20191212162823-642d9c7d6afb h1:51sLIkuBVRY1BYlv1lxfG1MfugQ+x+7p68l8EMtiiTU=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/sparrc/go-ping v0.0.0-20190613174326-4e5b6552494c h1:gqEdF4VwBu3lTKGHS9rXE9x1/pEaSwCXRLOZRF6qtlw=
|
||||||
|
github.com/sparrc/go-ping v0.0.0-20190613174326-4e5b6552494c/go.mod h1:eMyUVp6f/5jnzM+3zahzl7q6UXLbgSc3MKg/+ow9QW0=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
|
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
|
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||||
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||||
|
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
105
httping/httping.go
Normal file
105
httping/httping.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package httping
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptrace"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/http/httpproxy"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Stats struct {
|
||||||
|
Proxy bool
|
||||||
|
Scheme string
|
||||||
|
DNS int64
|
||||||
|
TCP int64
|
||||||
|
TLS int64
|
||||||
|
Process int64
|
||||||
|
Transfer int64
|
||||||
|
Total int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(address string) (Stats, error) {
|
||||||
|
var err error
|
||||||
|
var stats Stats
|
||||||
|
var t0, t1, t2, t3, t4, t5, t6, t7 int64
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("GET", address, nil)
|
||||||
|
trace := &httptrace.ClientTrace{
|
||||||
|
DNSStart: func(info httptrace.DNSStartInfo) {
|
||||||
|
t0 = time.Now().UnixNano()
|
||||||
|
},
|
||||||
|
DNSDone: func(info httptrace.DNSDoneInfo) {
|
||||||
|
t1 = time.Now().UnixNano()
|
||||||
|
if info.Err != nil {
|
||||||
|
err = info.Err
|
||||||
|
log.Fatal(info.Err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ConnectStart: func(net, addr string) {
|
||||||
|
},
|
||||||
|
ConnectDone: func(net, addr string, err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("unable to connect to host %v: %v", addr, err)
|
||||||
|
}
|
||||||
|
t2 = time.Now().UnixNano()
|
||||||
|
},
|
||||||
|
GotConn: func(info httptrace.GotConnInfo) {
|
||||||
|
t3 = time.Now().UnixNano()
|
||||||
|
},
|
||||||
|
GotFirstResponseByte: func() {
|
||||||
|
t4 = time.Now().UnixNano()
|
||||||
|
},
|
||||||
|
TLSHandshakeStart: func() {
|
||||||
|
t5 = time.Now().UnixNano()
|
||||||
|
},
|
||||||
|
TLSHandshakeDone: func(_ tls.ConnectionState, _ error) {
|
||||||
|
t6 = time.Now().UnixNano()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
|
||||||
|
c := &http.Client{
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
}
|
||||||
|
_, err = c.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
match, _ := regexp.MatchString("Client.Timeout exceeded", err.Error())
|
||||||
|
if match {
|
||||||
|
log.Fatal("Connection timeout")
|
||||||
|
} else {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t7 = time.Now().UnixNano()
|
||||||
|
|
||||||
|
if strings.HasPrefix(address, "http://") {
|
||||||
|
stats.Scheme = "http"
|
||||||
|
} else if strings.HasPrefix(address, "https://") {
|
||||||
|
stats.Scheme = "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
if t0 == 0 {
|
||||||
|
t0 = t2
|
||||||
|
t1 = t2
|
||||||
|
}
|
||||||
|
|
||||||
|
stats.DNS = t1 - t0
|
||||||
|
stats.TCP = t2 - t1
|
||||||
|
stats.Process = t4 - t3
|
||||||
|
stats.Transfer = t7 - t4
|
||||||
|
stats.TLS = t6 - t5
|
||||||
|
stats.Total = t7 - t0
|
||||||
|
|
||||||
|
// Detect proxies
|
||||||
|
pc := httpproxy.FromEnvironment()
|
||||||
|
if pc.HTTPProxy != "" {
|
||||||
|
stats.Proxy = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats, err
|
||||||
|
}
|
102
log.go
Normal file
102
log.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"github.com/noobly314/pingme/httping"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
var (
|
||||||
|
cyan = color.New(color.FgCyan).SprintfFunc()
|
||||||
|
blue = color.New(color.FgBlue).SprintfFunc()
|
||||||
|
green = color.New(color.FgGreen).SprintfFunc()
|
||||||
|
yellow = color.New(color.FgYellow).SprintfFunc()
|
||||||
|
red = color.New(color.FgRed).SprintfFunc()
|
||||||
|
)
|
||||||
|
|
||||||
|
func init_log() {
|
||||||
|
formatter := &logrus.TextFormatter{
|
||||||
|
DisableTimestamp: true,
|
||||||
|
}
|
||||||
|
log.SetFormatter(formatter)
|
||||||
|
log.Out = os.Stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
func logHttping(stats httping.Stats, err error, address string) {
|
||||||
|
if err == nil {
|
||||||
|
fmt.Printf("%s: %s\n", cyan("%-10s", "Proxy"), strconv.FormatBool(stats.Proxy))
|
||||||
|
fmt.Printf("%s: %s\n", cyan("%-10s", "Scheme"), stats.Scheme)
|
||||||
|
fmt.Printf("%s: %s\n", cyan("%-10s", "Host"), parseInput(address))
|
||||||
|
fmt.Printf("%s: %.2f ms\n", cyan("%-10s", "DNS Lookup"), float64(stats.DNS)/1e6)
|
||||||
|
fmt.Printf("%s: %.2f ms\n", cyan("%-10s", "TCP"), float64(stats.TCP)/1e6)
|
||||||
|
if stats.Scheme == "https" {
|
||||||
|
fmt.Printf("%s: %.2f ms\n", cyan("%-10s", "TLS"), float64(stats.TLS)/1e6)
|
||||||
|
}
|
||||||
|
fmt.Printf("%s: %.2f ms\n", cyan("%-10s", "Process"), float64(stats.Process)/1e6)
|
||||||
|
fmt.Printf("%s: %.2f ms\n", cyan("%-10s", "Transfer"), float64(stats.Transfer)/1e6)
|
||||||
|
fmt.Printf("%s: %.2f ms\n", cyan("%-10s", "Total"), float64(stats.Total)/1e6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func logTcping(code int, address string) {
|
||||||
|
if code == 0 {
|
||||||
|
fmt.Printf("%s%s%s\n", cyan("%-7s", "TCP"), green("%-10s", "OPEN"), address)
|
||||||
|
} else if code == 1 {
|
||||||
|
fmt.Printf("%s%s%s\n", cyan("%-7s", "TCP"), yellow("%-10s", "CLOSED"), address)
|
||||||
|
} else if code == 2 {
|
||||||
|
fmt.Printf("%s%s%s\n", cyan("%-7s", "TCP"), red("%-10s", "ERROR"), address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func logPing(dst *net.IPAddr, dur time.Duration, err error) {
|
||||||
|
if err != nil {
|
||||||
|
match, _ := regexp.MatchString("operation not permitted", err.Error())
|
||||||
|
if match {
|
||||||
|
fmt.Printf("%s%s%s\n", cyan("%-7s", "ICMP"), red("%-10s", "ERROR"), red("No privileges"))
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s%s%s\n", cyan("%-7s", "ICMP"), red("%-10s", "ERROR"), dst.String())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("%s%s%s %s ms\n", cyan("%-7s", "ICMP"), green("%-10s", "OPEN"), dst.String(), fmt.Sprintf("%.1f", float64(dur.Microseconds())/1000))
|
||||||
|
}
|
||||||
|
|
||||||
|
func logMtr(hops []string, address string) {
|
||||||
|
for _, h := range hops {
|
||||||
|
fmt.Printf("%s%s\n", cyan("%-7s", "MTR"), h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func logQuery(info IPInfo) {
|
||||||
|
v := reflect.ValueOf(info)
|
||||||
|
names := make([]string, v.NumField())
|
||||||
|
values := make([]string, v.NumField())
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
names[i] = v.Type().Field(i).Name
|
||||||
|
values[i] = v.Field(i).Interface().(string)
|
||||||
|
}
|
||||||
|
l := getMaxNameLength(names)
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
fmt.Printf("%s: %s\n", cyan("%-*s", l, names[i]), values[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMaxNameLength(names []string) int {
|
||||||
|
var length int
|
||||||
|
for _, val := range names {
|
||||||
|
if len(val) > length {
|
||||||
|
length = len(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return length
|
||||||
|
}
|
82
main.go
Normal file
82
main.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/noobly314/pingme/httping"
|
||||||
|
"github.com/noobly314/pingme/mtr"
|
||||||
|
"github.com/noobly314/pingme/ping"
|
||||||
|
"github.com/noobly314/pingme/tcping"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
VersionString string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
init_log()
|
||||||
|
init_flag()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if !hasFlag() {
|
||||||
|
switch len(flag.Args()) {
|
||||||
|
case 0:
|
||||||
|
flag.PrintDefaults()
|
||||||
|
case 1:
|
||||||
|
addr := flag.Args()[0]
|
||||||
|
|
||||||
|
// Query
|
||||||
|
address := parseInput(addr)
|
||||||
|
info := queryInfo(address)
|
||||||
|
logQuery(info)
|
||||||
|
|
||||||
|
// HTTP Ping
|
||||||
|
if strings.HasPrefix(addr, "http://") || strings.HasPrefix(addr, "https://") {
|
||||||
|
fmt.Println()
|
||||||
|
stats, err := httping.New(addr)
|
||||||
|
logHttping(stats, err, addr)
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
addr := flag.Args()[0]
|
||||||
|
port := flag.Args()[1]
|
||||||
|
ip := lookupIP(addr)
|
||||||
|
address := net.JoinHostPort(ip, port)
|
||||||
|
c := tcping.New(address)
|
||||||
|
logTcping(c, address)
|
||||||
|
default:
|
||||||
|
log.Warn("Too many arguments.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if isFlagPassed("v") {
|
||||||
|
// Version
|
||||||
|
fmt.Println(VersionString)
|
||||||
|
} else if isFlagPassed("i") {
|
||||||
|
// ICMP Ping
|
||||||
|
dst, dur, err := ping.New(PingDst)
|
||||||
|
logPing(dst, dur, err)
|
||||||
|
} else if isFlagPassed("t") {
|
||||||
|
// TCP Ping
|
||||||
|
c := tcping.New(TCPingDst)
|
||||||
|
logTcping(c, TCPingDst)
|
||||||
|
} else if isFlagPassed("h") {
|
||||||
|
// HTTP Ping
|
||||||
|
stats, err := httping.New(HTTPingDst)
|
||||||
|
logHttping(stats, err, HTTPingDst)
|
||||||
|
} else if isFlagPassed("m") {
|
||||||
|
// MTR
|
||||||
|
hops, err := mtr.New(MtrDst)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
logMtr(hops, MtrDst)
|
||||||
|
} else if isFlagPassed("q") {
|
||||||
|
address := parseInput(Query)
|
||||||
|
info := queryInfo(address)
|
||||||
|
logQuery(info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
mtr/mtr.go
Normal file
48
mtr/mtr.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package mtr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MtrLine struct {
|
||||||
|
Name string
|
||||||
|
Pos int
|
||||||
|
IP string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(s string) ([]string, error) {
|
||||||
|
_, err := exec.Command("mtr", "-v", s).Output()
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
fmt.Println("Waiting for MTR results...")
|
||||||
|
out, err := exec.Command("mtr", "--raw", s).Output()
|
||||||
|
hops := parseOutput(out)
|
||||||
|
return hops, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseOutput(b []byte) []string {
|
||||||
|
var hops []string
|
||||||
|
var matrix []MtrLine
|
||||||
|
|
||||||
|
raw := strings.Split(string(b), "\n")
|
||||||
|
for _, rec := range raw {
|
||||||
|
if len(rec) > 0 && rec[0] == 104 {
|
||||||
|
tuple := strings.Split(rec, " ")
|
||||||
|
pos, _ := strconv.Atoi(tuple[1])
|
||||||
|
matrix = append(matrix, MtrLine{Name: tuple[0], Pos: pos, IP: tuple[2]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(matrix, func(i, j int) bool { return matrix[i].Pos < matrix[j].Pos })
|
||||||
|
|
||||||
|
for _, tuple := range matrix {
|
||||||
|
hops = append(hops, tuple.IP)
|
||||||
|
}
|
||||||
|
|
||||||
|
return hops
|
||||||
|
}
|
120
ping/ping.go
Normal file
120
ping/ping.go
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
package ping
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/icmp"
|
||||||
|
"golang.org/x/net/ipv4"
|
||||||
|
"golang.org/x/net/ipv6"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IPType struct {
|
||||||
|
Type string
|
||||||
|
ListenAddr string
|
||||||
|
Network string
|
||||||
|
ICMPNetwork string
|
||||||
|
ProtocolNumber int
|
||||||
|
RequestMessageType icmp.Type
|
||||||
|
ReplyMessageType icmp.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
IPType4 = IPType{
|
||||||
|
Type: "4",
|
||||||
|
ListenAddr: "0.0.0.0",
|
||||||
|
Network: "ip4",
|
||||||
|
ICMPNetwork: "ip4:icmp",
|
||||||
|
ProtocolNumber: 1,
|
||||||
|
RequestMessageType: ipv4.ICMPTypeEcho,
|
||||||
|
ReplyMessageType: ipv4.ICMPTypeEchoReply,
|
||||||
|
}
|
||||||
|
IPType6 = IPType{
|
||||||
|
Type: "6",
|
||||||
|
ListenAddr: "::",
|
||||||
|
Network: "ip6",
|
||||||
|
ICMPNetwork: "ip6:ipv6-icmp",
|
||||||
|
ProtocolNumber: 58,
|
||||||
|
RequestMessageType: ipv6.ICMPTypeEchoRequest,
|
||||||
|
ReplyMessageType: ipv6.ICMPTypeEchoReply,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(address string) (*net.IPAddr, time.Duration, error) {
|
||||||
|
// Check ip type
|
||||||
|
// Resolve address
|
||||||
|
var err error
|
||||||
|
var dst *net.IPAddr
|
||||||
|
var ipType IPType
|
||||||
|
dst, err = net.ResolveIPAddr("ip4", address)
|
||||||
|
if err != nil {
|
||||||
|
dst, err = net.ResolveIPAddr("ip6", address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
} else {
|
||||||
|
ipType = IPType6
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ipType = IPType4
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start listening for icmp replies
|
||||||
|
c, err := icmp.ListenPacket(ipType.ICMPNetwork, ipType.ListenAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
// Make a new ICMP message
|
||||||
|
m := icmp.Message{
|
||||||
|
Type: ipType.RequestMessageType,
|
||||||
|
Code: 0,
|
||||||
|
Body: &icmp.Echo{
|
||||||
|
ID: os.Getpid() & 0xffff, Seq: 1,
|
||||||
|
Data: []byte(""),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
b, err := m.Marshal(nil)
|
||||||
|
if err != nil {
|
||||||
|
return dst, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send it
|
||||||
|
start := time.Now()
|
||||||
|
n, err := c.WriteTo(b, dst)
|
||||||
|
if err != nil {
|
||||||
|
return dst, 0, err
|
||||||
|
} else if n != len(b) {
|
||||||
|
return dst, 0, fmt.Errorf("got %v; want %v", n, len(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for a reply
|
||||||
|
reply := make([]byte, 1500)
|
||||||
|
err = c.SetReadDeadline(time.Now().Add(3 * time.Second))
|
||||||
|
if err != nil {
|
||||||
|
return dst, 0, err
|
||||||
|
}
|
||||||
|
n, peer, err := c.ReadFrom(reply)
|
||||||
|
if err != nil {
|
||||||
|
return dst, 0, err
|
||||||
|
}
|
||||||
|
duration := time.Since(start)
|
||||||
|
|
||||||
|
// Pack it up boys, we're done here
|
||||||
|
rm, err := icmp.ParseMessage(ipType.ProtocolNumber, reply[:n])
|
||||||
|
if err != nil {
|
||||||
|
return dst, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//return dst, duration, nil
|
||||||
|
switch rm.Type {
|
||||||
|
case ipType.ReplyMessageType:
|
||||||
|
return dst, duration, nil
|
||||||
|
default:
|
||||||
|
return dst, 0, fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst, 0, err
|
||||||
|
}
|
47
query.go
Normal file
47
query.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
API string = "http://ip-api.com/json/"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IPInfo struct {
|
||||||
|
IP string `json:"query"`
|
||||||
|
City string `json:"city"`
|
||||||
|
Country string `json:"country"`
|
||||||
|
ISP string `json:"isp"`
|
||||||
|
AS string `json:"as"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryInfo(address string) IPInfo {
|
||||||
|
var info IPInfo
|
||||||
|
|
||||||
|
res, err := http.Get(API + address)
|
||||||
|
if err != nil {
|
||||||
|
match, _ := regexp.MatchString("connection reset by peer", err.Error())
|
||||||
|
if match {
|
||||||
|
log.Fatal("Oops, your connection was reset by magic power. You may need to set env http_proxy.")
|
||||||
|
} else {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &info)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
//printInfo(info)
|
||||||
|
return info
|
||||||
|
}
|
29
tcping/tcping.go
Normal file
29
tcping/tcping.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package tcping
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(address string) int {
|
||||||
|
d := net.Dialer{Timeout: 3 * time.Second}
|
||||||
|
_, err := d.Dial("tcp", address)
|
||||||
|
if err != nil {
|
||||||
|
match, _ := regexp.MatchString("refused", err.Error())
|
||||||
|
if match {
|
||||||
|
// Closed
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
match, _ = regexp.MatchString("timeout", err.Error())
|
||||||
|
if match {
|
||||||
|
// Timeout
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Open
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Default
|
||||||
|
return 2
|
||||||
|
}
|
50
util.go
Normal file
50
util.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func lookupIP(s string) string {
|
||||||
|
// is ip
|
||||||
|
if isValidIP(s) {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
// is hostname
|
||||||
|
hostname := parseInput(s)
|
||||||
|
ips, err := net.LookupIP(hostname)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(hostname)
|
||||||
|
fmt.Println(err)
|
||||||
|
log.Fatal("IP address not found.")
|
||||||
|
}
|
||||||
|
return ips[0].String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInput(s string) string {
|
||||||
|
re := regexp.MustCompile(`^https?\:\/\/([^\/:?#]+)(?:[\/:?#]|$)`)
|
||||||
|
results := re.FindStringSubmatch(s)
|
||||||
|
if len(results) == 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
if len(results) == 2 {
|
||||||
|
return results[1]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidIP(s string) bool {
|
||||||
|
re := regexp.MustCompile(`((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))`)
|
||||||
|
return re.Match([]byte(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPrivateIPv4(s string) bool {
|
||||||
|
re := regexp.MustCompile(`(^192\.168\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)|(^172\.([1][6-9]|[2][0-9]|[3][0-1])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)|(^10\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])\.([0-9]|[0-9][0-9]|[0-2][0-5][0-5])$)`)
|
||||||
|
return re.Match([]byte(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPrivateIPv6(s string) bool {
|
||||||
|
re := regexp.MustCompile(`(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`)
|
||||||
|
return re.Match([]byte(s))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user