Tobias Begalke 8 yıl önce
işleme
e83cff2da9
1 değiştirilmiş dosya ile 242 ekleme ve 0 silme
  1. 242 0
      grs.go

+ 242 - 0
grs.go

@@ -0,0 +1,242 @@
+package grs
+
+import (
+	"errors"
+	"fmt"
+	"gopkg.in/jmcvetta/napping.v3"
+	"net"
+	"net/url"
+	"regexp"
+)
+
+const (
+	GRS_URL = "http://rest.db.ripe.net/search.json"
+)
+
+type GRS struct {
+	// ID bson.ObjectId `bson:"_id"`
+	Source      string `bson:"source" json:"source"`
+	IpFrom      string `bson:"ip_from" json:"ip_from"`
+	IpTo        string `bson:"ip_to" json:"ip_to"`
+	IpFromRaw   []byte `bson:"ip_from_raw" json:"ip_from_raw"`
+	IpToRaw     []byte `bson:"ip_to_raw" json:"ip_to_raw"`
+	Description string `bson:"description" json:"description"`
+	Country     string `bson:"country" json:"country"`
+	Status      string `bson:"status" json:"status"`
+	Cidr        string `bson:"cidr" json:"cidr"`
+	Name        string `bson:"name" json:"name"`
+	Org         string `bson:"org" json:"org"`
+}
+
+type GRSRaw struct {
+	Service       Name          `json:"service"`
+	Parameters    Parameters    `json:"parameters"`
+	Objects       Objects       `json:"objects"`
+	Terms         Terms         `json:"terms-and-conditions"`
+	ErrorMessages ErrorMessages `json:"errormessages"`
+}
+
+type Name struct {
+	Name string `json:"name"`
+}
+
+type Parameters struct {
+	InverseLookup map[string]interface{} `json:"inverse-lookup"`
+	TypeFilters   map[string]interface{} `json:"type-filters"`
+	Flags         map[string]interface{} `json:"flags"`
+	QueryStrings  QueryString            `json:"query-strings"`
+	Sources       Sources                `json:"sources"`
+}
+
+type QueryString struct {
+	QueryString []Value `json:"query-string"`
+}
+
+type Value struct {
+	Value string `json:"value"`
+}
+
+type Sources struct {
+	Ids []Id `json:"source"`
+}
+
+type Id struct {
+	ID string `json:"id"`
+}
+
+type Objects struct {
+	Objects []Object `json:"object"`
+}
+
+type Object struct {
+	Type       string     `json:"type"`
+	Link       Link       `json:"link"`
+	Source     Id         `json:source"`
+	PrimaryKey Attributes `json:"primary-key"`
+	Attributes Attributes `json:"attributes"`
+	Tags       Tags       `json:"tags"`
+}
+
+type Link struct {
+	Type string `json:"type"`
+	Href string `json:"href"`
+}
+
+type Attributes struct {
+	Attributes []Attribute `json:"attribute"`
+}
+
+type Attribute struct {
+	Link           Link   `json:"link"`
+	Name           string `json:"name"`
+	Value          string `json:"value"`
+	ReferencedType string `json:"referenced-type"`
+}
+
+type Tags struct {
+	Tags []Tag `json:"tag"`
+}
+
+type Tag struct {
+	ID   string `json:"id"`
+	Data string `json:"data"`
+}
+
+type Terms struct {
+	Type string `json:"type"`
+	Href string `json:"href"`
+}
+
+type ErrorMessages struct {
+	ErrorMessage []ErrorMessage `json:"errormessage"`
+}
+
+type ErrorMessage struct {
+	Severity string `json:"severity"`
+	Text     string `json:"text"`
+}
+
+func Lookup(ip string) (GRS, error) {
+	// var data map[string]interface{}
+	var data GRSRaw
+
+	args := url.Values{}
+	args.Set("query-string", ip)
+	args.Add("source", "ripe-grs")
+	args.Add("source", "arin-grs")
+	args.Add("source", "apnic-grs")
+	args.Add("source", "lacnic-grs")
+	args.Add("source", "afrinic-grs")
+
+	resp, err := napping.Get(GRS_URL, &args, &data, nil)
+
+	if err != nil {
+		return GRS{}, errors.New(fmt.Sprint("Failed to load data from ", resp.Url, ": ", err))
+	}
+
+	if resp.Status() != 200 {
+		return GRS{}, errors.New(fmt.Sprint("Failed to load data from GRS server: ", resp.Status()))
+	}
+
+	if len(data.ErrorMessages.ErrorMessage) > 0 {
+		return GRS{}, errors.New(fmt.Sprint("No GRS data for ", ip, ": ", data.ErrorMessages.ErrorMessage[0].Text))
+	}
+
+	grs := GRS{}
+	var grs_inetnum *Object
+	var grs_route *Object
+	var inetnum string
+
+	for i, e := range data.Objects.Objects {
+		switch e.Type {
+		case "inetnum":
+			grs_inetnum = &data.Objects.Objects[i]
+		case "inet6num":
+			grs_inetnum = &data.Objects.Objects[i]
+		case "route":
+			grs_route = &data.Objects.Objects[i]
+		}
+	}
+
+	// Inetnum fields
+	//
+	if grs_inetnum != nil {
+		for _, e := range grs_inetnum.Attributes.Attributes {
+			switch e.Name {
+			case "inetnum":
+				inetnum = e.Value
+			case "inet6num":
+				inetnum = e.Value
+			case "netname":
+				grs.Name = e.Value
+			case "descr":
+				grs.Description = e.Value
+			case "country":
+				grs.Country = e.Value
+			case "status":
+				grs.Status = e.Value
+			case "org":
+				grs.Org = e.Value
+			}
+		}
+	}
+
+	// Route fields
+	//
+	if grs_route != nil {
+		for _, e := range grs_route.Attributes.Attributes {
+			switch e.Name {
+			case "route":
+				grs.Cidr = e.Value
+			case "descr":
+				grs.Description = e.Value
+			}
+		}
+	}
+
+	var ip_from net.IP
+	var ip_to net.IP
+
+	if inetnum != "" {
+
+		_, network, err := net.ParseCIDR(inetnum)
+
+		if err == nil {
+			ip_from, ip_to = networkRange(network)
+			grs.IpFrom = ip_from.String()
+			grs.IpTo = ip_to.String()
+			if grs.Cidr == "" {
+				grs.Cidr = network.String()
+			}
+		} else {
+			reg := regexp.MustCompile(`^\s*(\d+\.\d+\.\d+\.\d+)\s*-\s*(\d+\.\d+\.\d+\.\d+)\s*$`)
+			matches := reg.FindAllStringSubmatch(inetnum, -1)
+
+			if matches != nil && matches[0] != nil && matches[0][1] != "" && matches[0][2] != "" {
+				grs.IpFrom = matches[0][1]
+				grs.IpTo = matches[0][2]
+
+				ip_from = net.ParseIP(grs.IpFrom)
+				ip_to = net.ParseIP(grs.IpTo)
+
+			}
+
+		}
+		grs.IpFromRaw = ip_from.To16()
+		grs.IpToRaw = ip_to.To16()
+
+	}
+
+	return grs, nil
+}
+
+// Calculates the first and last IP addresses in an IPNet
+func networkRange(network *net.IPNet) (net.IP, net.IP) {
+	netIP := network.IP.To16()
+	firstIP := netIP.Mask(network.Mask)
+	lastIP := net.ParseIP("::").To16()
+	for i := 0; i < len(lastIP); i++ {
+		lastIP[i] = netIP[i] | ^network.Mask[i]
+	}
+	return firstIP, lastIP
+}