129 lines
3.4 KiB
Go
129 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
_ "net/http/pprof"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.eve.moe/jackyyf/navigator/ipgeo"
|
|
"git.eve.moe/jackyyf/navigator/mapping"
|
|
"github.com/ipipdotnet/ipdb-go"
|
|
)
|
|
|
|
const (
|
|
errIPv4Only = "Navigator works for IPv4 only :)"
|
|
)
|
|
|
|
type errorMessage struct {
|
|
Error string `json:error`
|
|
}
|
|
|
|
func responseWithError(resp http.ResponseWriter, statusCode int, message string) {
|
|
resp.Header().Set("Content-Type", "text/plain")
|
|
resp.WriteHeader(statusCode)
|
|
resp.Write([]byte("error: " + message))
|
|
}
|
|
|
|
func responseWithJsonError(resp http.ResponseWriter, statusCode int, message string) {
|
|
resp.Header().Set("Content-Type", "application/json")
|
|
body, err := json.Marshal(&errorMessage{
|
|
Error: message,
|
|
})
|
|
resp.Header().Set("Content-Length", strconv.Itoa(len(body)))
|
|
if err != nil {
|
|
// This should never happen
|
|
panic("json marshal failed, check code")
|
|
}
|
|
resp.WriteHeader(statusCode)
|
|
resp.Write(body)
|
|
}
|
|
|
|
func buildLocation(info *ipdb.CityInfo) string {
|
|
ret := ""
|
|
if info.CountryName != "" {
|
|
ret += info.CountryName + " "
|
|
}
|
|
if info.RegionName != "" {
|
|
ret += info.RegionName + " "
|
|
}
|
|
if info.CityName != "" {
|
|
ret += info.CityName + " "
|
|
}
|
|
return strings.TrimSpace(ret)
|
|
}
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
http.HandleFunc("/healthz", func(resp http.ResponseWriter, req *http.Request) {
|
|
resp.WriteHeader(200)
|
|
resp.Write([]byte("ok"))
|
|
})
|
|
|
|
http.HandleFunc("/info", func(resp http.ResponseWriter, req *http.Request) {
|
|
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
|
if err != nil {
|
|
responseWithError(resp, http.StatusPreconditionFailed, errIPv4Only)
|
|
return
|
|
}
|
|
if net.ParseIP(host).To4() == nil {
|
|
responseWithError(resp, http.StatusPreconditionFailed, errIPv4Only)
|
|
return
|
|
}
|
|
db := ipgeo.Get()
|
|
|
|
info_cn, err := db.FindInfo(host, "CN")
|
|
if err != nil {
|
|
fmt.Fprintf(resp, "IP %s not found in the database.", host)
|
|
return
|
|
}
|
|
info_en, err := db.FindInfo(host, "EN")
|
|
if err != nil {
|
|
fmt.Fprintf(resp, "IP %s not found in the database.", host)
|
|
return
|
|
}
|
|
resp.Header().Set("Content-Type", "text/plain")
|
|
resp.WriteHeader(http.StatusOK)
|
|
server := mapping.Get(host)
|
|
fmt.Fprintln(resp, "您的IP:", host)
|
|
fmt.Fprintln(resp, "数据库中IP所属位置:", buildLocation(info_cn))
|
|
if info_cn.IspDomain != "" {
|
|
fmt.Fprintln(resp, "数据库中IP所属运营商:", info_cn.IspDomain)
|
|
}
|
|
fmt.Fprintln(resp, "您被分配的CDN节点为:", server)
|
|
fmt.Fprintln(resp)
|
|
fmt.Fprintln(resp, strings.Repeat("=", 72))
|
|
|
|
fmt.Fprintln(resp, "Your IP:", host)
|
|
fmt.Fprintln(resp, "Location for your IP according our database:", buildLocation(info_en))
|
|
if info_en.IspDomain != "" {
|
|
fmt.Fprintln(resp, "ISP for your IP according our database:", info_en.IspDomain)
|
|
}
|
|
fmt.Fprintln(resp, "Allocated CDN node for you:", server)
|
|
fmt.Fprintln(resp)
|
|
})
|
|
|
|
http.HandleFunc("/mapping", func(resp http.ResponseWriter, req *http.Request) {
|
|
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
|
if err != nil {
|
|
responseWithError(resp, http.StatusPreconditionFailed, errIPv4Only)
|
|
return
|
|
}
|
|
if net.ParseIP(host).To4() == nil {
|
|
responseWithError(resp, http.StatusPreconditionFailed, errIPv4Only)
|
|
return
|
|
}
|
|
resp.Header().Set("Content-Type", "text/plain")
|
|
resp.WriteHeader(http.StatusOK)
|
|
server := mapping.Get(host)
|
|
fmt.Fprint(resp, server)
|
|
})
|
|
ipgeo.Init()
|
|
http.ListenAndServe("0.0.0.0:8086", nil)
|
|
}
|