# vim:set ft= ts=4 sw=4 et: use Test::Nginx::Socket::Lua; use Cwd qw(cwd); repeat_each(2); plan tests => repeat_each() * (3 * blocks()); my $pwd = cwd(); $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; our $HttpConfig = qq( lua_package_path "$pwd/t/lib/?.lua;$pwd/lib/?.lua;;"; lua_package_cpath "/usr/local/openresty-debug/lualib/?.so;/usr/local/openresty/lualib/?.so;;"; resolver '$ENV{TEST_NGINX_RESOLVER}'; ); no_long_string(); run_tests(); __DATA__ === TEST 1: A records --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("www.google.com", { qtype = r.TYPE_A }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[.*?"address":"(?:\d{1,3}\.){3}\d+".*?\]$ --- no_error_log [error] --- no_check_leak === TEST 2: CNAME records --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("www.yahoo.com", { qtype = r.TYPE_CNAME }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[.*?"cname":"[-_a-z0-9.]+".*?\]$ --- no_error_log [error] --- no_check_leak === TEST 3: AAAA records --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("www.google.com", { qtype = r.TYPE_AAAA }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[.*?"address":"[a-fA-F0-9]*(?::[a-fA-F0-9]*)+".*?\]$ --- no_error_log [error] --- no_check_leak === TEST 4: compress ipv6 addr --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local c = resolver.compress_ipv6_addr ngx.say(c("1080:0:0:0:8:800:200C:417A")) ngx.say(c("FF01:0:0:0:0:0:0:101")) ngx.say(c("0:0:0:0:0:0:0:1")) ngx.say(c("1:5:0:0:0:0:0:0")) ngx.say(c("7:25:0:0:0:3:0:0")) ngx.say(c("0:0:0:0:0:0:0:0")) '; } --- request GET /t --- response_body 1080::8:800:200C:417A FF01::101 ::1 1:5:: 7:25::3:0:0 :: --- no_error_log [error] === TEST 5: A records (TCP) --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:tcp_query("www.google.com", { qtype = r.TYPE_A }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[.*?"address":"(?:\d{1,3}\.){3}\d+".*?\]$ --- no_error_log [error] --- no_check_leak === TEST 6: MX records --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("gmail.com", { qtype = r.TYPE_MX }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[\{.*?"preference":\d+,.*?"exchange":"[^"]+".*?\}\]$ --- no_error_log [error] --- no_check_leak === TEST 7: NS records --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("google.com", { qtype = r.TYPE_NS }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[\{.*?"nsdname":"[^"]+".*?\}\]$ --- no_error_log [error] --- no_check_leak === TEST 8: TXT query (no ans) --- SKIP --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("agentzh.org", { qtype = r.TYPE_TXT }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body records: {} --- no_error_log [error] --- timeout: 10 === TEST 9: TXT query (with ans) --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("gmail.com", { qtype = r.TYPE_TXT }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[\{.*?"txt":"v=spf\d+\s[^"]+".*?\}\]$ --- no_error_log [error] --- no_check_leak === TEST 10: PTR query --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("4.4.8.8.in-addr.arpa", { qtype = r.TYPE_PTR }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[\{.*?"ptrdname":"dns\.google".*?\}\]$ --- no_error_log [error] --- no_check_leak === TEST 11: domains with a trailing dot --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("www.google.com.", { qtype = r.TYPE_A }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[.*?"address":"(?:\d{1,3}\.){3}\d+".*?\]$ --- no_error_log [error] --- no_check_leak === TEST 12: domains with a leading dot --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query(".www.google.com", { qtype = r.TYPE_A }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body failed to query: bad name --- no_error_log [error] === TEST 13: SRV records or XMPP --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("_xmpp-client._tcp.jabber.org", { qtype = r.TYPE_SRV }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[(?:{"class":1,"name":"_xmpp-client._tcp.jabber.org","port":\d+,"priority":\d+,"section":1,"target":"[\w-]+.jabber.org","ttl":\d+,"type":33,"weight":\d+},?)+\]$ --- no_error_log [error] --- no_check_leak === TEST 14: SPF query (with ans) SPF records are deprecated by RFC 7208 in favor of TXT records, and linkedin.com has migrated to such TXT records. --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("linkedin.com", { qtype = r.TYPE_SPF }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body records: [] --- no_error_log [error] --- no_check_leak === TEST 15: SPF query (no ans) --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("agentzh.org", { qtype = r.TYPE_SPF }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body records: [] --- no_error_log [error] --- timeout: 10 === TEST 16: SPF query (as TXT with ans) --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("linkedin.com", { qtype = r.TYPE_TXT }) if not ans then ngx.say("failed to query: ", err) return end for i = 1, #ans do if string.find(ans[i].txt, "v=spf", nil, true) then local ljson = require "ljson" ngx.say("ans: ", ljson.encode(ans[i])) end end '; } --- request GET /t --- response_body_like chop ^ans: \{.*?"txt":"v=spf\d+\s[^"]+".*?\}$ --- no_error_log [error] --- no_check_leak === TEST 17: generate arpa_str --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local c = resolver.arpa_str ngx.say(c("1234:5678:abcd:ef99:1234:5678:abcd:ef99")) ngx.say(c("1080::8:800:200c:417a")) ngx.say(c("ff01::101")) ngx.say(c("::1")) ngx.say(c("::")) ngx.say(c("1::")) ngx.say(c("127.0.0.1")) ngx.say(c("251.252.253.254")) '; } --- request GET /t --- response_body 9.9.f.e.d.c.b.a.8.7.6.5.4.3.2.1.9.9.f.e.d.c.b.a.8.7.6.5.4.3.2.1.ip6.arpa a.7.1.4.c.0.0.2.0.0.8.0.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.0.1.ip6.arpa 1.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.f.f.ip6.arpa 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa 1.0.0.127.in-addr.arpa 254.253.252.251.in-addr.arpa --- no_error_log [error] === TEST 18: SOA records --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("www.google.com", { qtype = r.TYPE_SOA }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[(?:{"class":1,"expire":\d+,"minimum":\d+,"mname":"ns\d+\.google\.com","name":"google\.com","refresh":\d+,"retry":\d+,"rname":"dns-admin\.google\.com","section":2,"serial":\d+,"ttl":\d+,"type":6},?)+\]$ --- no_error_log [error] --- no_check_leak === TEST 19: RRTYPE larger than 255 This test case skipped due to changes of the DNS response. --- SKIP --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("comodo.com", { qtype = 257 }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[(?:{"class":1,"name":"comodo\.com","rdata":"[^"]+","section":1,"ttl":\d+,"type":257},?)+\]$ --- no_error_log [error] --- no_check_leak === TEST 20: SOA records --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end local ans, err = r:query("google.com", { qtype = r.TYPE_SOA }) if not ans then ngx.say("failed to query: ", err) return end local ljson = require "ljson" ngx.say("records: ", ljson.encode(ans)) '; } --- request GET /t --- response_body_like chop ^records: \[.*?"name":"google.com".*?\]$ --- no_error_log [error] --- no_check_leak === TEST 21: destroy --- http_config eval: $::HttpConfig --- config location /t { content_by_lua_block { local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = { "$TEST_NGINX_RESOLVER" } } if not r then ngx.say("failed to instantiate resolver: ", err) return end r:destroy() local udp = r.socks or "nil" local tcp = r.tcp_sock or "nil" ngx.say("udp socket: " .. udp .. ", tcp socket: " .. tcp) } } --- request GET /t --- response_body_like chop udp socket: nil, tcp socket: nil --- no_error_log [error] --- no_check_leak