https://github.com/pulsejet/geoipns
High performance DNS server to locate IP addresses
https://github.com/pulsejet/geoipns
asn dns dns-server geoip2 geolocation golang subnet
Last synced: 4 months ago
JSON representation
High performance DNS server to locate IP addresses
- Host: GitHub
- URL: https://github.com/pulsejet/geoipns
- Owner: pulsejet
- License: mit
- Created: 2019-10-20T12:15:37.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2020-11-29T06:31:18.000Z (over 5 years ago)
- Last Synced: 2025-08-01T19:36:53.219Z (11 months ago)
- Topics: asn, dns, dns-server, geoip2, geolocation, golang, subnet
- Language: Go
- Homepage:
- Size: 50.8 KB
- Stars: 5
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# GeoIPNS
Make DNS queries to get the geolocation and ASN name of an IP address. You can read the original blog post about why this project exists [here](https://medium.com/@varunpp2/locating-ip-addresses-with-dns-queries-af54228ea29c).
[](https://travis-ci.org/pulsejet/geoipns)
[](https://codecov.io/gh/pulsejet/geoipns)
[](https://goreportcard.com/report/github.com/pulsejet/geoipns)
[](https://github.com/pulsejet/geoipns/blob/master/LICENSE)
## Usage
Make a `TXT` query for `IP.geoipns` to the server to get the location and ASN name of `IP` in an [RFC 1464](https://tools.ietf.org/html/rfc1464) compliant format. The model can be easily extended to store arbitrary data about IP subnets using the configuration file.
To build and run,
```shell
go get github.com/pulsejet/geoipns && cd $GOPATH/src/github.com/pulsejet/geoipns
dep ensure # you may skip this step if deps are obtained automatically
go build
./getdata.sh # write your custom script to get GeoIP data
./geoipns
```
To query,
```shell
$ dig +short @localhost -p5312 -tTXT 3.105.177.255.geoipns
"location=Sydney, NSW, AU"
"asn=Amazon.com, Inc."
```
## Data Structure
Each subnet is stored as an IP range with start and end 128-bit IP addresses. All data points are stored together as an array sorted by the IP address, with a high/low boolean. The data structure is looked up using binary search to find the location of the queried IP address. If a low IP precedes the discovered location, the IP is contained in the corresponding range; if a high IP precedes then the IP is contained in the parent range (if existent). Each data point stores information about the complementary point and the parent range.
## Example Data Structure
The following CSV (with proper configuration)
| cidr | start_ip | end_ip | location |
|-----------------|----------------|----------------|--------------|
| 10.105.0.0/16 | | | OuterIPRange |
| 10.105.177.0/24 | | | Subnet1 |
| | 10.105.177.120 | 10.105.177.200 | Subnet11 |
| | 10.105.177.120 | 10.105.177.128 | Subnet12 |
| | 10.105.200.0 | 10.105.201.255 | Subnet2 |
would produce the following data structure (note that all IP addresses are internally represented as 128-bit bytes slices)
| Address | IP | IsHigh | Data | Complement | Parent |
|---------|----------------|--------|--------------|------------|--------|
| 0x001 | 10.105.0.0 | false | OuterIPRange | 0x010 | 0x000 |
| 0x002 | 10.105.177.0 | false | Subnet1 | 0x007 | 0x001 |
| 0x003 | 10.105.177.120 | false | Subnet11 | 0x006 | 0x002 |
| 0x004 | 10.105.177.120 | false | Subnet12 | 0x005 | 0x003 |
| 0x005 | 10.105.177.128 | true | Subnet12 | 0x004 | 0x003 |
| 0x006 | 10.105.177.200 | true | Subnet11 | 0x003 | 0x002 |
| 0x007 | 10.105.177.255 | true | Subnet1 | 0x002 | 0x001 |
| 0x008 | 10.105.200.0 | false | Subnet2 | 0x009 | 0x001 |
| 0x009 | 10.105.201.255 | true | Subnet2 | 0x008 | 0x001 |
| 0x010 | 10.105.255.255 | true | OuterIPRange | 0x001 | 0x000 |
## Testing
Use `go test -v ./...` to run automated tests.
## Benchmark
Testing GeoIPNS running on an LXC container limited to 4 vCPUs and 4GB RAM on a `24 x Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz` machine with PHP7.3 on the same machine for 10000 randomized IPv4 requests gave the following results:
```text
Average 433μs per GeoIPNS request (native DNS client + PHP, different container)
Average 229μs per GeoIPNS request (phpdns, different container)
Average 150μs per GeoIPNS request (singe-threaded C++, same container)
Average 94μs per GeoIPNS request (goroutines, same container)
```
## Docker
> Since the GeoLite database cannot be downloaded directly any more, you will have to write your own script replacing getdata.sh to download the GeoIP database as a CSV. The `getdata.sh` and `Dockerfile` files are kept in the repository for historical purposes only.
Two environment variables can be set:
* `SUFFIX`: the DNS suffix to listen on
* `INTRANET_CSV_URL`: a URL pointing to a CSV file with location entries other than GeoIP2 lite