geoip: read source IP from EDNS0 subnet if provided (#5183)

* geoip: read source IP from EDNS0 subnet if provided

This patch implements EDNS backend processing (similar in powerdns: https://doc.powerdns.com/authoritative/settings.html#setting-edns-subnet-processing). This feature comes very handy to test whether your geo config is working properly.

Signed-off-by: Balazs Nagy <julsevern@gmail.com>
This commit is contained in:
Balazs Nagy
2022-05-02 19:25:02 +02:00
committed by GitHub
parent 66f2ac7568
commit 4ae29a449c
5 changed files with 122 additions and 50 deletions

View File

@@ -1,9 +1,11 @@
# geoip
## Name
*geoip* - Lookup maxmind geoip2 databases using the client IP, then add associated geoip data to the context request.
## Description
The *geoip* plugin add geo location data associated with the client IP, it allows you to configure a [geoIP2 maxmind database](https://dev.maxmind.com/geoip/docs/databases) to add the geo location data associated with the IP address.
The data is added leveraging the *metadata* plugin, values can then be retrieved using it as well, for example:
@@ -16,8 +18,8 @@ import (
// ...
if getLongitude := metadata.ValueFunc(ctx, "geoip/longitude"); getLongitude != nil {
if longitude, err := strconv.ParseFloat(getLongitude(), 64); err == nil {
// Do something useful with longitude.
}
// Do something useful with longitude.
}
} else {
// The metadata label geoip/longitude for some reason, was not set.
}
@@ -25,26 +27,47 @@ if getLongitude := metadata.ValueFunc(ctx, "geoip/longitude"); getLongitude != n
```
## Databases
The supported databases use city schema such as `City` and `Enterprise`. Other databases types with different schemas are not supported yet.
You can download a [free and public City database](https://dev.maxmind.com/geoip/geolite2-free-geolocation-data).
## Syntax
```txt
```text
geoip [DBFILE]
```
* **DBFILE** the mmdb database file path.
or
```text
geoip [DBFILE] {
[edns-subnet]
}
```
* **DBFILE** the mmdb database file path. We recommend updating your mmdb database periodically for more accurate results.
* `edns-subnet`: Optional. Use [EDNS0 subnet](https://en.wikipedia.org/wiki/EDNS_Client_Subnet) (if present) for Geo IP instead of the source IP of the DNS request. This helps identifying the closest source IP address through intermediary DNS resolvers, and it also makes GeoIP testing easy: `dig +subnet=1.2.3.4 @dns-server.example.com www.geo-aware.com`.
**NOTE:** due to security reasons, recursive DNS resolvers may mask a few bits off of the clients' IP address, which can cause inaccuracies in GeoIP resolution.
There is no defined mask size in the standards, but there are examples: [RFC 7871's example](https://datatracker.ietf.org/doc/html/rfc7871#section-13) conceals the last 72 bits of an IPv6 source address, and NS1 Help Center [mentions](https://help.ns1.com/hc/en-us/articles/360020256573-About-the-EDNS-Client-Subnet-ECS-DNS-extension) that ECS-enabled DNS resolvers send only the first three octets (eg. /24) of the source IPv4 address.
## Examples
The following configuration configures the `City` database.
The following configuration configures the `City` database, and looks up geolocation based on EDNS0 subnet if present.
```txt
. {
geoip /opt/geoip2/db/GeoLite2-City.mmdb
geoip /opt/geoip2/db/GeoLite2-City.mmdb {
edns-subnet
}
metadata # Note that metadata plugin must be enabled as well.
}
```
## Metadata Labels
A limited set of fields will be exported as labels, all values are stored using strings **regardless of their underlying value type**, and therefore you may have to convert it back to its original type, note that numeric values are always represented in base 10.
| Label | Type | Example | Description