fangpsh's blog

基于OpenResty 的whoami.akaimai.net 实现

上次收集整理[[170822 获取Local DNS 地址信息]]) 的时候看到akamai 的whoami.akamai.net,想起之前看到agentzh 基于OpenResty实现了一个权威DNS 服务器,感觉可以用openresty 简单快速的实现。

找到agentzh 当时的 gist,第一次学习OpenResty ,决定照猫画虎。看起来要在OpenResty 里面接受dns 数据包,并且返回,需要用到stream-lua-nginx-module这个模块,这里要注意的时候,截至目前(2017-08-30) master 分支还不支持 ngx.req.udp_socket ,agentzh 当时hack 的代码都在 bloody-dns-server 分支下面。

编译OpenResty

说来惭愧,编译OpenResty费了好大一番工夫。先是没有看清stream-lua-nginx-modele 的分支,直接用master 分支的编译,测试代码的时候直接返回 ngx.req.udp_socket 是空。

然后用bloody-dns-server 分支编译,又遇到 mmdb 库的问题。Mac OS 下需要在编译的时候指定maxminddb 的库:

./configure \
--with-cc-opt="-I/usr/local/opt/openssl/include/ -I/usr/local/opt/pcre/include/" \
--with-ld-opt="-L/usr/local/opt/openssl/lib/ -L/usr/local/opt/pcre/lib/ -L/opt/mmdb/lib -lmaxminddb" \ 
--with-stream \
--with-stream_ssl_module \
--add-module=./bundle/stream-lua-nginx-module

不然会出现一堆:

undefined reference to `MMDB_open'
undefined reference to `MMDB_strerror'
undefined reference to `MMDB_lookup_sockaddr'
ndefined reference to `MMDB_strerror'
...

我看了一下 stream-lua-nginx-module 的build.sh 是显式指定了-L/opt/mmdb/lib -lmaxminddb,但是nginx 编译的时候没指定,就会报错。

相关问题:ld: symbols not found for architecture x86_64, clang: linker command failed

遇到错误:

nginx: [alert] cannot open file /opt/mmdb/database/GeoLite2-Country.mmdb for reading: Error opening the specified MaxMind DB file in

去Maxmind 官网下一个,丢到对应的目录即可。

另外编译的时候要注意选择版本,我选择的是OpenResty-1.11.2.5,其中的Nginx 的版本是1.11.2,太新的Nginx 可能没测试过。

实现whoami.akamai.net

编译成功之后,就是开始动手了。

首先是DNS 报文格式,参考这2篇文章:

以及自己用wireshark 抓包分析。

对着文档一个一个bit 校对,对任何DNS 查询报文,都拿出它的IP,然后返回一条A记录就好了,效果如下:

whoami

上线

我在个人的VPS 上部署了一个,再添加一条NS 记录,注意需要是域名,不能添加IP:

whoami_ns

dig whoami.example.com 或者 ping whoami.example.com 即可。

whoami_dig

代码

实现代码: whoami.lua