Make registry generic and split query and registry functions

This commit is contained in:
Zach 2018-09-01 22:11:57 -04:00
parent 9b95591361
commit 40b9c4eb99
3 changed files with 120 additions and 103 deletions

View File

@ -13,7 +13,7 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/Mic92/whois42d/whois" "github.com/zgiles/whois42d/whois"
) )
type Server struct { type Server struct {
@ -25,7 +25,7 @@ type Server struct {
} }
func New(dataPath string) *Server { func New(dataPath string) *Server {
registry := whois.Registry{dataPath} registry := whois.New(dataPath, "This is the dn42 whois query service.", "dn42", "DN42")
return &Server{registry, time.Now(), false, 0, sync.WaitGroup{}} return &Server{registry, time.Now(), false, 0, sync.WaitGroup{}}
} }

View File

@ -2,63 +2,17 @@ package whois
import ( import (
"bufio" "bufio"
"bytes"
"flag" "flag"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os" "os"
"path" "path"
"regexp"
"sort"
"strings" "strings"
) )
type Registry struct {
DataPath string
}
type Type struct {
Name string
Pattern *regexp.Regexp
Kind int
}
type Object map[int]interface{}
const (
UPPER = iota
LOWER
ROUTE
ROUTE6
)
type Query struct {
Objects []Object
Flags *Flags
}
var whoisTypes = []Type{
{"aut-num", regexp.MustCompile(`^AS([0123456789]+)$`), UPPER},
{"dns", regexp.MustCompile(`.dn42$`), LOWER},
{"person", regexp.MustCompile(`-DN42$`), UPPER},
{"mntner", regexp.MustCompile(`-MNT$`), UPPER},
{"schema", regexp.MustCompile(`-SCHEMA$`), UPPER},
{"organisation", regexp.MustCompile(`ORG-`), UPPER},
{"tinc-keyset", regexp.MustCompile(`^SET-.+-TINC$`), UPPER},
{"tinc-key", regexp.MustCompile(`-TINC$`), UPPER},
{"as-set", regexp.MustCompile(`^AS`), UPPER},
{"route-set", regexp.MustCompile(`^RS-`), UPPER},
{"inetnum", nil, ROUTE},
{"inet6num", nil, ROUTE6},
{"route", nil, ROUTE},
{"route6", nil, ROUTE6},
{"as-block", regexp.MustCompile(`\d+_\d+`), UPPER},
}
func (r *Registry) handleObject(conn *net.TCPConn, object Object, flags *Flags) bool { func (r *Registry) handleObject(conn *net.TCPConn, object Object, flags *Flags) bool {
found := false found := false
for _, t := range whoisTypes { for _, t := range r.whoisTypes {
if len(flags.Types) > 0 && !flags.Types[t.Name] { if len(flags.Types) > 0 && !flags.Types[t.Name] {
continue continue
} }
@ -79,7 +33,7 @@ func (r *Registry) handleObject(conn *net.TCPConn, object Object, flags *Flags)
} }
func (r *Registry) HandleQuery(conn *net.TCPConn) { func (r *Registry) HandleQuery(conn *net.TCPConn) {
fmt.Fprint(conn, "% This is the dn42 whois query service.\n\n") fmt.Fprint(conn, "% " + r.Header + "\n\n")
query := parseQuery(conn) query := parseQuery(conn)
if query == nil { if query == nil {
@ -88,7 +42,7 @@ func (r *Registry) HandleQuery(conn *net.TCPConn) {
flags := query.Flags flags := query.Flags
if flags.ServerInfo != "" { if flags.ServerInfo != "" {
printServerInfo(conn, strings.TrimSpace(flags.ServerInfo)) r.printServerInfo(conn, strings.TrimSpace(flags.ServerInfo))
return return
} }
found := false found := false
@ -104,55 +58,6 @@ func (r *Registry) HandleQuery(conn *net.TCPConn) {
fmt.Fprint(conn, "\n") fmt.Fprint(conn, "\n")
} }
func readCidrs(path string) ([]net.IPNet, error) {
files, err := ioutil.ReadDir(path)
if err != nil {
return nil, err
}
cidrs := []net.IPNet{}
for _, f := range files {
name := strings.Replace(f.Name(), "_", "/", -1)
_, cidr, err := net.ParseCIDR(name)
if err != nil {
fmt.Fprintf(os.Stderr, "skip invalid net '%s'", f.Name())
continue
}
i := sort.Search(len(cidrs), func(i int) bool {
c := cidrs[i]
return bytes.Compare(c.Mask, cidr.Mask) >= 0
})
if i < len(cidrs) {
cidrs = append(cidrs[:i], append([]net.IPNet{*cidr}, cidrs[i:]...)...)
} else {
cidrs = append(cidrs, *cidr)
}
}
return cidrs, nil
}
func parseObject(arg string) Object {
obj := path.Base(arg)
object := Object{
UPPER: strings.ToUpper(obj),
LOWER: strings.ToLower(obj),
}
ip := net.ParseIP(obj)
if ip == nil {
ip, _, _ = net.ParseCIDR(arg)
}
if ip != nil {
if ip.To4() == nil {
object[ROUTE6] = ip
} else {
object[ROUTE] = ip.To4()
}
}
return object
}
func parseQuery(conn *net.TCPConn) *Query { func parseQuery(conn *net.TCPConn) *Query {
r := bufio.NewReader(conn) r := bufio.NewReader(conn)
req, e := r.ReadString('\n') req, e := r.ReadString('\n')
@ -180,14 +85,14 @@ func parseQuery(conn *net.TCPConn) *Query {
return &query return &query
} }
func printServerInfo(conn *net.TCPConn, what string) { func (r *Registry) printServerInfo(conn *net.TCPConn, what string) {
switch what { switch what {
case "version": case "version":
fmt.Fprintf(conn, "%% whois42d v%d\n", VERSION) fmt.Fprintf(conn, "%% whois42d v%d\n", VERSION)
case "sources": case "sources":
fmt.Fprintf(conn, "DN42:3:N:0-0\n") fmt.Fprintf(conn, r.RegistryTopLevel+":3:N:0-0\n")
case "types": case "types":
for _, t := range whoisTypes { for _, t := range r.whoisTypes {
fmt.Fprintf(conn, "%s\n", t.Name) fmt.Fprintf(conn, "%s\n", t.Name)
} }
default: default:

112
whois/registry.go Normal file
View File

@ -0,0 +1,112 @@
package whois
import (
"bytes"
"fmt"
"io/ioutil"
"net"
"os"
"path"
"regexp"
"sort"
"strings"
)
type Registry struct {
DataPath string
Header string
DNSTopLevel string
RegistryTopLevel string
whoisTypes []Type
}
type Type struct {
Name string
Pattern *regexp.Regexp
Kind int
}
type Object map[int]interface{}
const (
UPPER = iota
LOWER
ROUTE
ROUTE6
)
type Query struct {
Objects []Object
Flags *Flags
}
func New(DataPath string, Header string, DNSTopLevel string, RegistryTopLevel string) Registry {
r := Registry{DataPath: DataPath, Header: Header, DNSTopLevel: DNSTopLevel, RegistryTopLevel: RegistryTopLevel}
r.whoisTypes = []Type{
{"aut-num", regexp.MustCompile(`^AS([0123456789]+)$`), UPPER},
{"dns", regexp.MustCompile(`.` + r.DNSTopLevel + `$`), LOWER},
{"person", regexp.MustCompile(`-` + r.RegistryTopLevel + `$`), UPPER},
{"mntner", regexp.MustCompile(`-MNT$`), UPPER},
{"schema", regexp.MustCompile(`-SCHEMA$`), UPPER},
{"organisation", regexp.MustCompile(`ORG-`), UPPER},
{"tinc-keyset", regexp.MustCompile(`^SET-.+-TINC$`), UPPER},
{"tinc-key", regexp.MustCompile(`-TINC$`), UPPER},
{"as-set", regexp.MustCompile(`^AS`), UPPER},
{"route-set", regexp.MustCompile(`^RS-`), UPPER},
{"inetnum", nil, ROUTE},
{"inet6num", nil, ROUTE6},
{"route", nil, ROUTE},
{"route6", nil, ROUTE6},
{"as-block", regexp.MustCompile(`\d+_\d+`), UPPER},
}
return r
}
func readCidrs(path string) ([]net.IPNet, error) {
files, err := ioutil.ReadDir(path)
if err != nil {
return nil, err
}
cidrs := []net.IPNet{}
for _, f := range files {
name := strings.Replace(f.Name(), "_", "/", -1)
_, cidr, err := net.ParseCIDR(name)
if err != nil {
fmt.Fprintf(os.Stderr, "skip invalid net '%s'", f.Name())
continue
}
i := sort.Search(len(cidrs), func(i int) bool {
c := cidrs[i]
return bytes.Compare(c.Mask, cidr.Mask) >= 0
})
if i < len(cidrs) {
cidrs = append(cidrs[:i], append([]net.IPNet{*cidr}, cidrs[i:]...)...)
} else {
cidrs = append(cidrs, *cidr)
}
}
return cidrs, nil
}
func parseObject(arg string) Object {
obj := path.Base(arg)
object := Object{
UPPER: strings.ToUpper(obj),
LOWER: strings.ToLower(obj),
}
ip := net.ParseIP(obj)
if ip == nil {
ip, _, _ = net.ParseCIDR(arg)
}
if ip != nil {
if ip.To4() == nil {
object[ROUTE6] = ip
} else {
object[ROUTE] = ip.To4()
}
}
return object
}