Skip to content
Snippets Groups Projects
Commit 4de8430f authored by ale's avatar ale
Browse files

Add some initial external sources

DNSBLs and GeoIP databases.

Still no plumbing that connects them with the actual Server.
parent 66d7bf5f
No related branches found
No related tags found
No related merge requests found
package dnsbl
import (
"fmt"
"net"
"regexp"
"strings"
"github.com/d5/tengo/objects"
)
// The DNSBL external source looks up IP addresses in a DNS-based
// blacklist, and expects the result to match a specific pattern.
type DNSBL struct {
domain string
matchRx *regexp.Regexp
}
func New(domain, match string) (*DNSBL, error) {
if match == "" {
match = `^127\.0\.0\.[0-9]*$`
}
rx, err := regexp.Compile(match)
if err != nil {
return nil, err
}
return &DNSBL{
domain: domain,
matchRx: rx,
}, nil
}
func reverseIP(ip net.IP) string {
if ip.To4() != nil {
parts := strings.Split(ip.String(), ".")
rev := make([]string, len(parts))
for i := 0; i < len(parts); i++ {
rev[len(parts)-i-1] = parts[i]
}
return strings.Join(rev, ".")
}
return ""
}
// LookupIP implements the ExternalSource interface. We'd like to
// return a boolean but can't figure out how to build one with Tengo,
// so we return a 0/1 int result instead.
func (d *DNSBL) LookupIP(ip string) (objects.Object, error) {
rev := reverseIP(net.ParseIP(ip))
if rev == "" {
return objects.UndefinedValue, nil
}
query := fmt.Sprintf("%s.%s", rev, d.domain)
ips, err := net.LookupIP(query)
var retval int64 = 0
if err == nil && len(ips) > 0 && d.matchRx.MatchString(ips[0].String()) {
retval = 1
}
return &objects.Int{Value: retval}, nil
}
package ext
import "github.com/d5/tengo/objects"
// An ExternalSource provides per-IP information from third-party
// sources. The lookup can return any Tengo object, we don't want to
// force a specific return type yet (int or string can both be
// useful, we'll see).
type ExternalSource interface {
LookupIP(string) (objects.Object, error)
}
package geoip
import (
"net"
"github.com/d5/tengo/objects"
"github.com/oschwald/maxminddb-golang"
)
var defaultGeoIPPaths = []string{
"/var/lib/GeoIP/GeoLite2-Country.mmdb",
}
type GeoIP struct {
readers []*maxminddb.Reader
}
func NewGeoIP(paths []string) (*GeoIP, error) {
if len(paths) == 0 {
paths = defaultGeoIPPaths
}
g := new(GeoIP)
for _, path := range paths {
r, err := maxminddb.Open(path)
if err != nil {
return nil, err
}
g.readers = append(g.readers, r)
}
return g, nil
}
func (g *GeoIP) LookupIP(ipStr string) (objects.Object, error) {
ip := net.ParseIP(ipStr)
var record struct {
Country struct {
ISOCode string `maxminddb:"iso_code"`
} `maxminddb:"country"`
}
for _, r := range g.readers {
if err := r.Lookup(ip, &record); err == nil {
return &objects.String{Value: record.Country.ISOCode}, nil
}
}
return objects.UndefinedValue, nil
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment