Skip to content

Commit b6be97f

Browse files
authored
Merge pull request #38 from zmap/phillip/implement-rdns
Implement Reverse DNS Annotation
2 parents 7b80105 + 0721741 commit b6be97f

File tree

5 files changed

+289
-18
lines changed

5 files changed

+289
-18
lines changed

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,38 @@ echo "1.1.1.1" | zannotate --geoasn --geoasn-database=/path-to-downloaded-file/G
5555
```shell
5656
{"ip":"1.1.1.1","geoasn":{"asn":13335,"org":"CLOUDFLARENET"}}
5757
```
58+
59+
# Input/Output
60+
61+
## Output
62+
By default, ZAnnotate reads new-line delimited IP addresses from standard input and outputs a JSON object per line to standard output like:
63+
64+
```shell
65+
echo "1.1.1.1" | zannotate --rdns --geoasn --geoasn-database=/path-to-geo-asn.mmdb
66+
```
67+
68+
```json
69+
{"ip":"1.1.1.1","geoasn":{"asn":13335,"org":"CLOUDFLARENET"},"rdns":{"domain_names":["one.one.one.one"]}}
70+
```
71+
72+
If an IP address cannot be annotated, either because of an error or lack of data, there will be an empty field for that annotation.
73+
For example, if an IP address is private and therefore has no RDNS or ASN data, the output will look like:
74+
```shell
75+
echo "127.0.0.1" | zannotate --rdns --geoasn --geoasn-database=/path-to-geo-asn.mmdb
76+
```
77+
78+
```json
79+
{"geoasn":{},"rdns":{},"ip":"127.0.0.1"}
80+
```
81+
82+
## Input
83+
You may wish to annotate data that is already in JSON format. You'll then need to use the `--input-file-type=json` flag.
84+
This will insert a `zannotate` field into the existing JSON object. For example:
85+
86+
```shell
87+
echo '{"ip": "1.1.1.1"}' | ./zannotate --rdns --geoasn --geoasn-database=/path-to-geo-asn.mmdb --input-file-type=json
88+
```
89+
90+
```json
91+
{"ip":"1.1.1.1","zannotate":{"geoasn":{"asn":13335,"org":"CLOUDFLARENET"},"rdns":{"domain_names":["one.one.one.one"]}}}
92+
```

go.mod

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,38 @@ require (
88
github.com/osrg/gobgp/v3 v3.37.0
99
github.com/sirupsen/logrus v1.9.3
1010
github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837
11+
github.com/zmap/zdns/v2 v2.0.5
1112
gotest.tools/v3 v3.5.2
1213
)
1314

1415
require (
1516
github.com/asergeyev/nradix v0.0.0-20220715161825-e451993e425c // indirect
16-
github.com/google/go-cmp v0.6.0 // indirect
17+
github.com/beorn7/perks v1.0.1 // indirect
18+
github.com/censys/cidranger v1.1.3 // indirect
19+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
20+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
21+
github.com/google/go-cmp v0.7.0 // indirect
1722
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
1823
github.com/modern-go/reflect2 v1.0.2 // indirect
24+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
1925
github.com/oschwald/maxminddb-golang v1.13.1 // indirect
26+
github.com/pkg/errors v0.9.1 // indirect
27+
github.com/prometheus/client_golang v1.22.0 // indirect
28+
github.com/prometheus/client_model v0.6.2 // indirect
29+
github.com/prometheus/common v0.63.0 // indirect
30+
github.com/prometheus/procfs v0.16.0 // indirect
31+
github.com/weppos/publicsuffix-go v0.40.3-0.20250311103038-7794c8c0723b // indirect
32+
github.com/zmap/dns v1.1.67 // indirect
33+
github.com/zmap/go-dns-root-anchors v0.0.0-20250415191259-6d65fb878756 // indirect
34+
github.com/zmap/zcrypto v0.0.0-20250416162916-8ff8dfaa718d // indirect
35+
github.com/zmap/zflags v1.4.0-beta.1.0.20200204220219-9d95409821b6 // indirect
36+
github.com/zmap/zgrab2 v0.2.0 // indirect
37+
golang.org/x/crypto v0.39.0 // indirect
38+
golang.org/x/mod v0.25.0 // indirect
39+
golang.org/x/net v0.41.0 // indirect
40+
golang.org/x/sync v0.15.0 // indirect
2041
golang.org/x/sys v0.36.0 // indirect
42+
golang.org/x/text v0.26.0 // indirect
43+
golang.org/x/tools v0.33.0 // indirect
44+
google.golang.org/protobuf v1.36.6 // indirect
2145
)

go.sum

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,104 @@
11
github.com/asergeyev/nradix v0.0.0-20170505151046-3872ab85bb56/go.mod h1:8BhOLuqtSuT5NZtZMwfvEibi09RO3u79uqfHZzfDTR4=
22
github.com/asergeyev/nradix v0.0.0-20220715161825-e451993e425c h1:cN6WRmhJkh/u5bvf/XXjoqcHxljVKIz3Nt7q2dVJySo=
33
github.com/asergeyev/nradix v0.0.0-20220715161825-e451993e425c/go.mod h1:8BhOLuqtSuT5NZtZMwfvEibi09RO3u79uqfHZzfDTR4=
4+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
5+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
6+
github.com/censys/cidranger v1.1.3 h1:YZxgTxj1N9e283yhWybErvuV28TluEUa/3WlIwDrp9k=
7+
github.com/censys/cidranger v1.1.3/go.mod h1:QQ2LmUiOSV/1o7qUG8Bcx+uAWwC9bfSKUHV51EnGcZg=
8+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
9+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
410
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5-
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
611
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
13+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
714
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
815
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
9-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
10-
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
16+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
17+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
1118
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
1219
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
1320
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
21+
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
22+
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
23+
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
24+
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
25+
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
26+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
27+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
28+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
1429
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
1530
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
1631
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
1732
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
1833
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
34+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
35+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
1936
github.com/oschwald/geoip2-golang v1.13.0 h1:Q44/Ldc703pasJeP5V9+aFSZFmBN7DKHbNsSFzQATJI=
2037
github.com/oschwald/geoip2-golang v1.13.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
2138
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
2239
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
2340
github.com/osrg/gobgp/v3 v3.37.0 h1:+ObuOdvj7G7nxrT0fKFta+EAupdWf/q1WzbXydr8IOY=
2441
github.com/osrg/gobgp/v3 v3.37.0/go.mod h1:kVHVFy1/fyZHJ8P32+ctvPeJogn9qKwa1YCeMRXXrP0=
25-
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
42+
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
43+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
2644
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
45+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
46+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
47+
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
48+
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
49+
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
50+
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
51+
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
52+
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
53+
github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
54+
github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
55+
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
56+
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
2757
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
2858
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
2959
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
3060
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
61+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
3162
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
32-
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
33-
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
63+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
64+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
65+
github.com/weppos/publicsuffix-go v0.40.3-0.20250311103038-7794c8c0723b h1:PFOWooJRLwIuZk9i3ihzKzZffPrAVyOCzPInvLbn140=
66+
github.com/weppos/publicsuffix-go v0.40.3-0.20250311103038-7794c8c0723b/go.mod h1:EACzvcFHnxqmDapI/oqMjtpXz+mtjNzJe7r1zhRczZ0=
67+
github.com/zmap/dns v1.1.67 h1:6WXzSZdzGMOAFmockRtjNc7F3t4YIuDm/gkmitp56Ec=
68+
github.com/zmap/dns v1.1.67/go.mod h1:/Zt3MfW9PFlp3pN3VdTF2Mi6q6b+o0iy46MesRiM434=
69+
github.com/zmap/go-dns-root-anchors v0.0.0-20250415191259-6d65fb878756 h1:yeprVDswfVwnP3uCPm1h1vUZYUOMk7Ue56//8ttmUwA=
70+
github.com/zmap/go-dns-root-anchors v0.0.0-20250415191259-6d65fb878756/go.mod h1:W5CEzaf+B3Pg1hzUQotwQ2EBg7jB49DkmKuiNuWPO80=
3471
github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837 h1:DjHnADS2r2zynZ3WkCFAQ+PNYngMSNceRROi0pO6c3M=
3572
github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837/go.mod h1:9vp0bxqozzQwcjBwenEXfKVq8+mYbwHkQ1NF9Ap0DMw=
73+
github.com/zmap/zcrypto v0.0.0-20250416162916-8ff8dfaa718d h1:QcrqQ8a285ozWrRrsPUtYl4y+9YJAM4gSTF3EQDTQk8=
74+
github.com/zmap/zcrypto v0.0.0-20250416162916-8ff8dfaa718d/go.mod h1:Zz4/7kyRgJXC+PTpLV4tIgaCMTHWnNbgOLZoXuVrkws=
75+
github.com/zmap/zdns/v2 v2.0.5 h1:RNrKZWki/LzKIXiHcO3oJwVM0mXkwu5mNs5s3Phniy0=
76+
github.com/zmap/zdns/v2 v2.0.5/go.mod h1:Q0RdCE5MdkTUHm3CUscxke3hyba6fjV8kIuCS/yeiDo=
77+
github.com/zmap/zflags v1.4.0-beta.1.0.20200204220219-9d95409821b6 h1:XYA+NN2AS4mRmIDVu2nCtrjU17zKlRihO3MnlcmueUw=
78+
github.com/zmap/zflags v1.4.0-beta.1.0.20200204220219-9d95409821b6/go.mod h1:HXDUD+uue8yeLHr0eXx1lvY6CvMiHbTKw5nGmA9OUoo=
79+
github.com/zmap/zgrab2 v0.2.0 h1:j48+zkSw4rbvQOq9em5MnPxwP5QyUmzTXSCtQzZ2MnI=
80+
github.com/zmap/zgrab2 v0.2.0/go.mod h1:vM5eYaxZTjIGZe9oijtxjU4EfucELIr9mbG7Chxmn2I=
81+
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
82+
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
83+
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
84+
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
85+
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
86+
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
87+
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
88+
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
3689
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3790
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
3891
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
92+
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
93+
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
94+
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
95+
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
96+
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
97+
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
3998
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
99+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
100+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
101+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
40102
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
41103
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
42104
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

rdns.go

Lines changed: 93 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* ZAnnotate Copyright 2018 Regents of the University of Michigan
2+
* ZAnnotate Copyright 2025 Regents of the University of Michigan
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
55
* use this file except in compliance with the License. You may obtain a copy
@@ -15,18 +15,33 @@
1515
package zannotate
1616

1717
import (
18+
"context"
1819
"flag"
20+
"fmt"
1921
"net"
22+
"strings"
23+
"time"
24+
25+
log "github.com/sirupsen/logrus"
26+
"github.com/zmap/dns"
27+
"github.com/zmap/zdns/v2/src/zdns"
2028
)
2129

30+
type RDNSOutput struct {
31+
DomainNames []string `json:"domain_names,omitempty"`
32+
}
33+
2234
type RDNSAnnotatorFactory struct {
2335
BasePluginConf
2436
RawResolvers string
37+
zdnsConfig *zdns.ResolverConfig
38+
timeoutSecs int
2539
}
2640

2741
type RDNSAnnotator struct {
28-
Factory *RDNSAnnotatorFactory
29-
Id int
42+
Factory *RDNSAnnotatorFactory
43+
Id int
44+
zdnsResolver *zdns.Resolver
3045
}
3146

3247
// RDNS Annotator Factory (Global)
@@ -38,7 +53,35 @@ func (a *RDNSAnnotatorFactory) MakeAnnotator(i int) Annotator {
3853
return &v
3954
}
4055

41-
func (a *RDNSAnnotatorFactory) Initialize(conf *GlobalConf) error {
56+
func (a *RDNSAnnotatorFactory) Initialize(_ *GlobalConf) error {
57+
a.zdnsConfig = zdns.NewResolverConfig()
58+
a.zdnsConfig.NetworkTimeout = time.Second * 5
59+
if len(strings.TrimSpace(a.RawResolvers)) > 0 {
60+
// Parse and Validate the User-Specified Resolvers
61+
// 1. split on comma
62+
resolvers := strings.Split(a.RawResolvers, ",")
63+
// 2. trim whitespace
64+
for _, resolver := range resolvers {
65+
trimmedString := strings.TrimSpace(resolver)
66+
// 3. validate IP
67+
ip := net.ParseIP(trimmedString)
68+
if ip == nil {
69+
return fmt.Errorf("failed to parse dns server IP address: %s", trimmedString)
70+
}
71+
// 4. Differentiate between IPv4 and IPv6
72+
ns := zdns.NameServer{
73+
IP: ip,
74+
Port: 53,
75+
DomainName: "",
76+
}
77+
if ip.To4() != nil {
78+
a.zdnsConfig.ExternalNameServersV4 = append(a.zdnsConfig.ExternalNameServersV4, ns)
79+
} else {
80+
a.zdnsConfig.ExternalNameServersV6 = append(a.zdnsConfig.ExternalNameServersV6, ns)
81+
}
82+
}
83+
}
84+
4285
return nil
4386
}
4487

@@ -57,29 +100,68 @@ func (a *RDNSAnnotatorFactory) IsEnabled() bool {
57100
func (a *RDNSAnnotatorFactory) AddFlags(flags *flag.FlagSet) {
58101
// Reverse DNS Lookup
59102
flags.BoolVar(&a.Enabled, "rdns", false, "reverse dns lookup")
60-
flags.StringVar(&a.RawResolvers, "rdns-dns-servers", "", "list of DNS servers to use for DNS lookups")
103+
flags.StringVar(&a.RawResolvers, "rdns-dns-servers", "", "list of DNS servers to use for DNS lookups, comma-separated IP list. If empty, will use system defaults")
61104
flags.IntVar(&a.Threads, "rdns-threads", 100, "how many reverse dns threads")
105+
flags.IntVar(&a.timeoutSecs, "rdns-timeout", 2, "timeout for each rdns query, in seconds")
62106
}
63107

64108
// RDNS Annotator (Per-Worker)
65109

66-
func (a *RDNSAnnotator) Initialize() error {
110+
func (a *RDNSAnnotator) Initialize() (err error) {
111+
a.zdnsResolver, err = zdns.InitResolver(a.Factory.zdnsConfig)
112+
if err != nil {
113+
return fmt.Errorf("failed to initialize zdns resolver: %w", err)
114+
}
67115
return nil
68116
}
69117

70118
func (a *RDNSAnnotator) GetFieldName() string {
71119
return "rdns"
72120
}
73121

122+
// Annotate performs a reverse DNS lookup for the given IP address and returns the results.
123+
// If an error occurs or a lookup fails, it returns nil
74124
func (a *RDNSAnnotator) Annotate(ip net.IP) interface{} {
75-
return nil
125+
q := zdns.Question{
126+
Type: dns.TypePTR,
127+
Class: dns.ClassINET,
128+
Name: ip.String(),
129+
}
130+
output := &RDNSOutput{}
131+
res, _, status, err := a.zdnsResolver.ExternalLookup(context.Background(), &q, nil)
132+
if err != nil {
133+
log.Debug("encountered error when resolving rdns for ", ip.String(), ": ", err)
134+
return output
135+
}
136+
if status != zdns.StatusNoError {
137+
log.Debug("could not resolve rdns for ", ip.String(), " with status: ", status)
138+
return output
139+
}
140+
if res == nil {
141+
// this should never happen, but this will be more helpful than a panic
142+
log.Fatalf("zdns returned a nil result without erroring, zannotate cannot continue")
143+
}
144+
output.DomainNames = make([]string, 0, len(res.Answers))
145+
for _, answer := range res.Answers {
146+
if castAns, ok := answer.(zdns.Answer); ok {
147+
// Sometimes, CNAME records are returned in addition to PTR records. We'll ignore all non-PTR records.
148+
// This replicates the behavior of Go's net.LookupAddr
149+
if castAns.Type != "PTR" {
150+
continue
151+
}
152+
// remove trailing period from domain name, ex: example.com. -> example.com
153+
output.DomainNames = append(output.DomainNames, strings.TrimSuffix(castAns.Answer, "."))
154+
}
155+
}
156+
return output
76157
}
77158

78159
func (a *RDNSAnnotator) Close() error {
160+
a.zdnsResolver.Close()
79161
return nil
80162
}
81163

82-
//func init() {
83-
// s := new(RDNSAnnotatorFactory)
84-
// RegisterAnnotator(s)
85-
//}
164+
func init() {
165+
s := new(RDNSAnnotatorFactory)
166+
RegisterAnnotator(s)
167+
}

0 commit comments

Comments
 (0)