first commit
This commit is contained in:
commit
7181502a64
11 changed files with 770 additions and 0 deletions
138
server.go
Normal file
138
server.go
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
Name string
|
||||
Subdomains map[string]bool
|
||||
Directories map[string]bool
|
||||
FilterV4 bool
|
||||
FilterV6 bool
|
||||
}
|
||||
|
||||
func BuildServices(cfg *Config) map[string]*Service {
|
||||
services := make(map[string]*Service)
|
||||
|
||||
for name, sc := range cfg.Services {
|
||||
if !sc.Enabled {
|
||||
continue
|
||||
}
|
||||
svc := &Service{
|
||||
Name: name,
|
||||
Subdomains: make(map[string]bool),
|
||||
Directories: make(map[string]bool),
|
||||
}
|
||||
for _, s := range sc.Subdomains {
|
||||
svc.Subdomains[strings.ToLower(s)] = true
|
||||
}
|
||||
for _, d := range sc.Directories {
|
||||
svc.Directories[d] = true
|
||||
}
|
||||
switch name {
|
||||
case "ip4":
|
||||
svc.FilterV4 = true
|
||||
case "ip6":
|
||||
svc.FilterV6 = true
|
||||
}
|
||||
services[name] = svc
|
||||
}
|
||||
return services
|
||||
}
|
||||
|
||||
func extractIP(r *http.Request) net.IP {
|
||||
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
||||
parts := strings.Split(xff, ",")
|
||||
if ip := net.ParseIP(strings.TrimSpace(parts[0])); ip != nil {
|
||||
return ip
|
||||
}
|
||||
}
|
||||
if xri := r.Header.Get("X-Real-IP"); xri != "" {
|
||||
if ip := net.ParseIP(strings.TrimSpace(xri)); ip != nil {
|
||||
return ip
|
||||
}
|
||||
}
|
||||
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
return net.ParseIP(r.RemoteAddr)
|
||||
}
|
||||
return net.ParseIP(host)
|
||||
}
|
||||
|
||||
func matchService(host, path string, services map[string]*Service) *Service {
|
||||
hostname := host
|
||||
if i := strings.IndexByte(host, ':'); i != -1 {
|
||||
hostname = host[:i]
|
||||
}
|
||||
|
||||
for _, svc := range services {
|
||||
if svc.Subdomains[hostname] {
|
||||
return svc
|
||||
}
|
||||
}
|
||||
|
||||
parts := strings.Split(hostname, ".")
|
||||
if len(parts) >= 2 {
|
||||
label := parts[len(parts)-2]
|
||||
for _, svc := range services {
|
||||
if svc.Subdomains[label] {
|
||||
return svc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, svc := range services {
|
||||
if svc.Directories[path] {
|
||||
return svc
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Handle(services map[string]*Service, geo *Geo) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
svc := matchService(r.Host, r.URL.Path, services)
|
||||
if svc == nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
ip := extractIP(r)
|
||||
if ip == nil {
|
||||
http.Error(w, "cannot determine client IP", 500)
|
||||
return
|
||||
}
|
||||
|
||||
isV4 := ip.To4() != nil
|
||||
if (svc.FilterV4 && !isV4) || (svc.FilterV6 && isV4) {
|
||||
http.Error(w, fmt.Sprintf("this endpoint requires %s", map[bool]string{true: "IPv6", false: "IPv4"}[svc.FilterV6]), 400)
|
||||
return
|
||||
}
|
||||
|
||||
info := geo.Lookup(ip)
|
||||
|
||||
fmt.Fprintf(w, "%s\n", ip)
|
||||
fmt.Fprintf(w, "%s\n", info.ReverseDNS)
|
||||
fmt.Fprintf(w, "proxy=NO, type=UNKNOWN, tor=NO\n")
|
||||
continent, country, city := info.Continent, info.Country, info.City
|
||||
if continent == "" {
|
||||
continent = "Unknown"
|
||||
}
|
||||
if country == "" {
|
||||
country = "Unknown"
|
||||
}
|
||||
if city == "" {
|
||||
city = "Unknown"
|
||||
}
|
||||
fmt.Fprintf(w, "%s, %s, %s\n", continent, country, city)
|
||||
if info.Org != "" {
|
||||
fmt.Fprintf(w, "%s / %s\n", info.Org, info.ASN)
|
||||
} else {
|
||||
fmt.Fprintf(w, "Unknown\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue