一个nginx geoip2问题

贵司一直使用geoip2的库来判断用户访问国家的来源。之前报问题过来发现都是来自ipv6的问题。

那怎么想的,估计是这个geoip2的库不准导致的,或者压根就没ipv6的数据。

于是就过了那么多年,今天又有人反馈了,于是就仔细去看了下。

首先这个geoip2的库实在太老了,都4年多没更新了,那就给更新一下,发现还是不行。

然后又去看了一下nginx配置,仔细验证了配置内容,发现nginx配置也没有问题。

那就重新来考虑吧,先看看geoip2库是否有问题。发现人maxmind特别贴心,https://github.com/maxmind/GeoIP2-python 这上面代码都给你写好了。

把客户的ipv6地址贴进去,发现返回值是正确的。

接着看了下日志,发现ipv4的来源ip都是记录在remote_addr里的,而ipv6的却是记录在X-Forwarded-For里的,并且remote_addr里是云厂商的slb的ip地址。把云厂商的slb的ip地址贴近geoip2库里解析,直接就报错了。

1
2
3
4
5
6
7
8
9
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/usr/local/lib/python3.8/dist-packages/geoip2/database.py", line 139, in country
Country, self._model_for(geoip2.models.Country, "Country", ip_address)
File "/usr/local/lib/python3.8/dist-packages/geoip2/database.py", line 253, in _model_for
(record, prefix_len) = self._get(types, ip_address)
File "/usr/local/lib/python3.8/dist-packages/geoip2/database.py", line 240, in _get
raise geoip2.errors.AddressNotFoundError(
geoip2.errors.AddressNotFoundError: The address 100.127.1.80 is not in the database.

得了,那估计可能是这个问题了。但是为什么ipv6和ipv4的入口来源会不一致呢,翻看了slb配置,我去,这一个是4层转发,一个是7层转发。4层转发是透传client ip过来的,而7层是放在header里面的。

那是不是解法就是把ipv6的7层转发改成4层就行了? 可这样不好的后果就是本来slb可以帮你卸载tls,现在要你自己来了。这样不符合我们能省则省的精神啊。

于是再翻看一下nginx geoip2库的文档。

https://github.com/leev/ngx_http_geoip2_module

发现原来跟geoip是一样的。只要写上slb的ip,那就直接从X-Forwarded-For来取了,聪明的老铁肯定会问,如果X-Forwarded-For用逗号写了多个ip,那它会怎么取呢?
同时还发现一个mmdblookup的工具,连上面python代码都不用写,直接就命令行用上了。
https://maxmind.github.io/libmaxminddb/mmdblookup.html

1
2
3
4
5
6
    geoip2_proxy           100.64.0.0/10;
# Defines trusted addresses. When a request comes from a trusted address, an address from the "X-Forwarded-For" request header field will be used instead.


geoip2_proxy_recursive on;
# If recursive search is disabled then instead of the original client address that matches one of the trusted addresses, the last address sent in "X-Forwarded-For" will be used. If recursive search is enabled then instead of the original client address that matches one of the trusted addresses, the last non-trusted address sent in "X-Forwarded-For" will be used.

人这里写的很清楚了,就取最新的那个ip,也就是最近的那个。

最后就把那堆4层代理都转成7层代理就算正式收工了。