dnsruby 1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/EVENTMACHINE +64 -0
- data/README +63 -0
- data/doc/classes/Dnsruby.html +463 -0
- data/doc/classes/Dnsruby/Algorithms.html +171 -0
- data/doc/classes/Dnsruby/Classes.html +197 -0
- data/doc/classes/Dnsruby/Classes.src/M000209.html +23 -0
- data/doc/classes/Dnsruby/Classes.src/M000210.html +19 -0
- data/doc/classes/Dnsruby/CodeMapper.html +375 -0
- data/doc/classes/Dnsruby/CodeMapper.src/M000186.html +18 -0
- data/doc/classes/Dnsruby/CodeMapper.src/M000187.html +33 -0
- data/doc/classes/Dnsruby/CodeMapper.src/M000188.html +21 -0
- data/doc/classes/Dnsruby/CodeMapper.src/M000189.html +19 -0
- data/doc/classes/Dnsruby/CodeMapper.src/M000190.html +19 -0
- data/doc/classes/Dnsruby/CodeMapper.src/M000191.html +18 -0
- data/doc/classes/Dnsruby/CodeMapper.src/M000192.html +22 -0
- data/doc/classes/Dnsruby/CodeMapper.src/M000193.html +22 -0
- data/doc/classes/Dnsruby/CodeMapper.src/M000194.html +22 -0
- data/doc/classes/Dnsruby/CodeMapper.src/M000195.html +31 -0
- data/doc/classes/Dnsruby/CodeMapper.src/M000196.html +19 -0
- data/doc/classes/Dnsruby/Config.html +413 -0
- data/doc/classes/Dnsruby/Config.src/M000148.html +18 -0
- data/doc/classes/Dnsruby/Config.src/M000149.html +19 -0
- data/doc/classes/Dnsruby/Config.src/M000150.html +19 -0
- data/doc/classes/Dnsruby/Config.src/M000151.html +25 -0
- data/doc/classes/Dnsruby/Config.src/M000152.html +21 -0
- data/doc/classes/Dnsruby/Config.src/M000153.html +38 -0
- data/doc/classes/Dnsruby/Config.src/M000154.html +26 -0
- data/doc/classes/Dnsruby/Config.src/M000155.html +22 -0
- data/doc/classes/Dnsruby/Config.src/M000156.html +27 -0
- data/doc/classes/Dnsruby/Config.src/M000157.html +22 -0
- data/doc/classes/Dnsruby/Config.src/M000158.html +21 -0
- data/doc/classes/Dnsruby/DNS.html +571 -0
- data/doc/classes/Dnsruby/DNS.src/M000258.html +24 -0
- data/doc/classes/Dnsruby/DNS.src/M000259.html +18 -0
- data/doc/classes/Dnsruby/DNS.src/M000260.html +18 -0
- data/doc/classes/Dnsruby/DNS.src/M000261.html +20 -0
- data/doc/classes/Dnsruby/DNS.src/M000262.html +19 -0
- data/doc/classes/Dnsruby/DNS.src/M000263.html +20 -0
- data/doc/classes/Dnsruby/DNS.src/M000264.html +18 -0
- data/doc/classes/Dnsruby/DNS.src/M000265.html +19 -0
- data/doc/classes/Dnsruby/DNS.src/M000266.html +20 -0
- data/doc/classes/Dnsruby/DNS.src/M000267.html +28 -0
- data/doc/classes/Dnsruby/DNS.src/M000268.html +19 -0
- data/doc/classes/Dnsruby/DNS.src/M000269.html +20 -0
- data/doc/classes/Dnsruby/DNS.src/M000270.html +31 -0
- data/doc/classes/Dnsruby/DecodeError.html +120 -0
- data/doc/classes/Dnsruby/Dnssec.html +287 -0
- data/doc/classes/Dnsruby/Dnssec.src/M000249.html +23 -0
- data/doc/classes/Dnsruby/Dnssec.src/M000250.html +19 -0
- data/doc/classes/Dnsruby/Dnssec.src/M000251.html +90 -0
- data/doc/classes/Dnsruby/Dnssec.src/M000252.html +76 -0
- data/doc/classes/Dnsruby/EncodeError.html +120 -0
- data/doc/classes/Dnsruby/FormErr.html +119 -0
- data/doc/classes/Dnsruby/Header.html +501 -0
- data/doc/classes/Dnsruby/Header.src/M000231.html +35 -0
- data/doc/classes/Dnsruby/Header.src/M000232.html +18 -0
- data/doc/classes/Dnsruby/Header.src/M000233.html +18 -0
- data/doc/classes/Dnsruby/Header.src/M000234.html +21 -0
- data/doc/classes/Dnsruby/Header.src/M000235.html +20 -0
- data/doc/classes/Dnsruby/Header.src/M000236.html +32 -0
- data/doc/classes/Dnsruby/Header.src/M000237.html +27 -0
- data/doc/classes/Dnsruby/Header.src/M000238.html +26 -0
- data/doc/classes/Dnsruby/Header.src/M000239.html +47 -0
- data/doc/classes/Dnsruby/Header.src/M000240.html +28 -0
- data/doc/classes/Dnsruby/Header.src/M000241.html +30 -0
- data/doc/classes/Dnsruby/Hosts.html +316 -0
- data/doc/classes/Dnsruby/Hosts.src/M000197.html +20 -0
- data/doc/classes/Dnsruby/Hosts.src/M000198.html +19 -0
- data/doc/classes/Dnsruby/Hosts.src/M000199.html +20 -0
- data/doc/classes/Dnsruby/Hosts.src/M000200.html +21 -0
- data/doc/classes/Dnsruby/Hosts.src/M000201.html +19 -0
- data/doc/classes/Dnsruby/Hosts.src/M000202.html +20 -0
- data/doc/classes/Dnsruby/Hosts.src/M000203.html +21 -0
- data/doc/classes/Dnsruby/IPv4.html +233 -0
- data/doc/classes/Dnsruby/IPv4.src/M000204.html +32 -0
- data/doc/classes/Dnsruby/IPv4.src/M000205.html +19 -0
- data/doc/classes/Dnsruby/IPv4.src/M000206.html +18 -0
- data/doc/classes/Dnsruby/IPv4.src/M000207.html +18 -0
- data/doc/classes/Dnsruby/IPv4.src/M000208.html +18 -0
- data/doc/classes/Dnsruby/IPv6.html +281 -0
- data/doc/classes/Dnsruby/IPv6.src/M000242.html +60 -0
- data/doc/classes/Dnsruby/IPv6.src/M000243.html +22 -0
- data/doc/classes/Dnsruby/IPv6.src/M000244.html +20 -0
- data/doc/classes/Dnsruby/IPv6.src/M000245.html +18 -0
- data/doc/classes/Dnsruby/Message.html +803 -0
- data/doc/classes/Dnsruby/Message.src/M000119.html +38 -0
- data/doc/classes/Dnsruby/Message.src/M000120.html +26 -0
- data/doc/classes/Dnsruby/Message.src/M000121.html +22 -0
- data/doc/classes/Dnsruby/Message.src/M000122.html +22 -0
- data/doc/classes/Dnsruby/Message.src/M000123.html +20 -0
- data/doc/classes/Dnsruby/Message.src/M000124.html +20 -0
- data/doc/classes/Dnsruby/Message.src/M000125.html +20 -0
- data/doc/classes/Dnsruby/Message.src/M000126.html +20 -0
- data/doc/classes/Dnsruby/Message.src/M000127.html +18 -0
- data/doc/classes/Dnsruby/Message.src/M000128.html +20 -0
- data/doc/classes/Dnsruby/Message.src/M000129.html +23 -0
- data/doc/classes/Dnsruby/Message.src/M000130.html +30 -0
- data/doc/classes/Dnsruby/Message.src/M000131.html +20 -0
- data/doc/classes/Dnsruby/Message.src/M000132.html +18 -0
- data/doc/classes/Dnsruby/Message.src/M000133.html +56 -0
- data/doc/classes/Dnsruby/Message.src/M000134.html +35 -0
- data/doc/classes/Dnsruby/Message.src/M000135.html +46 -0
- data/doc/classes/Dnsruby/Message/Section.html +160 -0
- data/doc/classes/Dnsruby/Message/Section.src/M000141.html +29 -0
- data/doc/classes/Dnsruby/Message/Section.src/M000142.html +30 -0
- data/doc/classes/Dnsruby/MetaTypes.html +136 -0
- data/doc/classes/Dnsruby/Modes.html +171 -0
- data/doc/classes/Dnsruby/NXDomain.html +119 -0
- data/doc/classes/Dnsruby/Name.html +330 -0
- data/doc/classes/Dnsruby/Name.src/M000104.html +28 -0
- data/doc/classes/Dnsruby/Name.src/M000105.html +20 -0
- data/doc/classes/Dnsruby/Name.src/M000106.html +18 -0
- data/doc/classes/Dnsruby/Name.src/M000107.html +21 -0
- data/doc/classes/Dnsruby/Name.src/M000108.html +22 -0
- data/doc/classes/Dnsruby/Name.src/M000109.html +18 -0
- data/doc/classes/Dnsruby/Name/Label.html +300 -0
- data/doc/classes/Dnsruby/Name/Label.src/M000110.html +21 -0
- data/doc/classes/Dnsruby/Name/Label.src/M000111.html +18 -0
- data/doc/classes/Dnsruby/Name/Label.src/M000112.html +22 -0
- data/doc/classes/Dnsruby/Name/Label.src/M000113.html +18 -0
- data/doc/classes/Dnsruby/Name/Label.src/M000114.html +18 -0
- data/doc/classes/Dnsruby/Name/Label.src/M000115.html +18 -0
- data/doc/classes/Dnsruby/Name/Label.src/M000116.html +18 -0
- data/doc/classes/Dnsruby/Name/Label.src/M000117.html +18 -0
- data/doc/classes/Dnsruby/Name/Label.src/M000118.html +18 -0
- data/doc/classes/Dnsruby/NotImp.html +119 -0
- data/doc/classes/Dnsruby/OpCode.html +146 -0
- data/doc/classes/Dnsruby/OtherResolvError.html +119 -0
- data/doc/classes/Dnsruby/QTypes.html +146 -0
- data/doc/classes/Dnsruby/Question.html +301 -0
- data/doc/classes/Dnsruby/Question.src/M000226.html +47 -0
- data/doc/classes/Dnsruby/Question.src/M000227.html +18 -0
- data/doc/classes/Dnsruby/Question.src/M000228.html +18 -0
- data/doc/classes/Dnsruby/Question.src/M000229.html +32 -0
- data/doc/classes/Dnsruby/Question.src/M000230.html +18 -0
- data/doc/classes/Dnsruby/RCode.html +211 -0
- data/doc/classes/Dnsruby/RR.html +648 -0
- data/doc/classes/Dnsruby/RR.src/M000001.html +18 -0
- data/doc/classes/Dnsruby/RR.src/M000002.html +22 -0
- data/doc/classes/Dnsruby/RR.src/M000003.html +18 -0
- data/doc/classes/Dnsruby/RR.src/M000004.html +18 -0
- data/doc/classes/Dnsruby/RR.src/M000005.html +26 -0
- data/doc/classes/Dnsruby/RR.src/M000006.html +18 -0
- data/doc/classes/Dnsruby/RR.src/M000007.html +36 -0
- data/doc/classes/Dnsruby/RR.src/M000008.html +100 -0
- data/doc/classes/Dnsruby/RR.src/M000009.html +18 -0
- data/doc/classes/Dnsruby/RR.src/M000010.html +18 -0
- data/doc/classes/Dnsruby/RR.src/M000011.html +22 -0
- data/doc/classes/Dnsruby/RR.src/M000012.html +29 -0
- data/doc/classes/Dnsruby/RR.src/M000013.html +24 -0
- data/doc/classes/Dnsruby/RR/ANY.html +133 -0
- data/doc/classes/Dnsruby/RR/CERT.html +180 -0
- data/doc/classes/Dnsruby/RR/CERT/CertificateTypes.html +169 -0
- data/doc/classes/Dnsruby/RR/CNAME.html +151 -0
- data/doc/classes/Dnsruby/RR/DNAME.html +150 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.html +422 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000044.html +20 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000045.html +21 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000046.html +28 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000047.html +22 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000048.html +18 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000049.html +22 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000050.html +18 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000051.html +26 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000052.html +38 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000053.html +45 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000054.html +21 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000055.html +24 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000056.html +32 -0
- data/doc/classes/Dnsruby/RR/DNSKEY.src/M000057.html +24 -0
- data/doc/classes/Dnsruby/RR/DS.html +286 -0
- data/doc/classes/Dnsruby/RR/DS.src/M000039.html +22 -0
- data/doc/classes/Dnsruby/RR/DS.src/M000040.html +28 -0
- data/doc/classes/Dnsruby/RR/DS.src/M000041.html +24 -0
- data/doc/classes/Dnsruby/RR/DS.src/M000042.html +28 -0
- data/doc/classes/Dnsruby/RR/DS.src/M000043.html +36 -0
- data/doc/classes/Dnsruby/RR/DomainName.html +175 -0
- data/doc/classes/Dnsruby/RR/DomainName.src/M000083.html +18 -0
- data/doc/classes/Dnsruby/RR/Generic.html +133 -0
- data/doc/classes/Dnsruby/RR/HINFO.html +155 -0
- data/doc/classes/Dnsruby/RR/IN.html +155 -0
- data/doc/classes/Dnsruby/RR/IN/A.html +200 -0
- data/doc/classes/Dnsruby/RR/IN/A.src/M000017.html +18 -0
- data/doc/classes/Dnsruby/RR/IN/A.src/M000018.html +18 -0
- data/doc/classes/Dnsruby/RR/IN/A.src/M000019.html +18 -0
- data/doc/classes/Dnsruby/RR/IN/AAAA.html +139 -0
- data/doc/classes/Dnsruby/RR/IN/AFSDB.html +145 -0
- data/doc/classes/Dnsruby/RR/IN/PX.html +143 -0
- data/doc/classes/Dnsruby/RR/IN/SRV.html +238 -0
- data/doc/classes/Dnsruby/RR/IN/SRV.src/M000014.html +29 -0
- data/doc/classes/Dnsruby/RR/IN/SRV.src/M000015.html +26 -0
- data/doc/classes/Dnsruby/RR/IN/SRV.src/M000016.html +22 -0
- data/doc/classes/Dnsruby/RR/IN/WKS.html +166 -0
- data/doc/classes/Dnsruby/RR/IN/WKS.src/M000020.html +20 -0
- data/doc/classes/Dnsruby/RR/ISDN.html +155 -0
- data/doc/classes/Dnsruby/RR/LOC.html +395 -0
- data/doc/classes/Dnsruby/RR/LOC.src/M000025.html +32 -0
- data/doc/classes/Dnsruby/RR/LOC.src/M000026.html +23 -0
- data/doc/classes/Dnsruby/RR/LOC.src/M000027.html +25 -0
- data/doc/classes/Dnsruby/RR/LOC.src/M000028.html +21 -0
- data/doc/classes/Dnsruby/RR/LOC.src/M000029.html +20 -0
- data/doc/classes/Dnsruby/RR/LOC.src/M000030.html +23 -0
- data/doc/classes/Dnsruby/RR/MB.html +150 -0
- data/doc/classes/Dnsruby/RR/MG.html +150 -0
- data/doc/classes/Dnsruby/RR/MINFO.html +156 -0
- data/doc/classes/Dnsruby/RR/MR.html +150 -0
- data/doc/classes/Dnsruby/RR/MX.html +155 -0
- data/doc/classes/Dnsruby/RR/NAPTR.html +190 -0
- data/doc/classes/Dnsruby/RR/NS.html +151 -0
- data/doc/classes/Dnsruby/RR/NSAP.html +293 -0
- data/doc/classes/Dnsruby/RR/NSAP.src/M000093.html +19 -0
- data/doc/classes/Dnsruby/RR/NSAP.src/M000094.html +19 -0
- data/doc/classes/Dnsruby/RR/NSAP.src/M000095.html +22 -0
- data/doc/classes/Dnsruby/RR/NSAP.src/M000096.html +31 -0
- data/doc/classes/Dnsruby/RR/NSEC.html +301 -0
- data/doc/classes/Dnsruby/RR/NSEC.src/M000031.html +19 -0
- data/doc/classes/Dnsruby/RR/NSEC.src/M000032.html +18 -0
- data/doc/classes/Dnsruby/RR/NSEC.src/M000033.html +34 -0
- data/doc/classes/Dnsruby/RR/NSEC.src/M000034.html +18 -0
- data/doc/classes/Dnsruby/RR/NSEC.src/M000035.html +71 -0
- data/doc/classes/Dnsruby/RR/NSEC.src/M000036.html +18 -0
- data/doc/classes/Dnsruby/RR/NSEC.src/M000037.html +80 -0
- data/doc/classes/Dnsruby/RR/NSEC.src/M000038.html +23 -0
- data/doc/classes/Dnsruby/RR/NSEC3.html +366 -0
- data/doc/classes/Dnsruby/RR/NSEC3.src/M000085.html +28 -0
- data/doc/classes/Dnsruby/RR/NSEC3.src/M000086.html +18 -0
- data/doc/classes/Dnsruby/RR/NSEC3.src/M000087.html +18 -0
- data/doc/classes/Dnsruby/RR/NSEC3.src/M000088.html +22 -0
- data/doc/classes/Dnsruby/RR/NSEC3.src/M000089.html +18 -0
- data/doc/classes/Dnsruby/RR/NSEC3.src/M000090.html +21 -0
- data/doc/classes/Dnsruby/RR/NSEC3.src/M000091.html +21 -0
- data/doc/classes/Dnsruby/RR/NSEC3.src/M000092.html +29 -0
- data/doc/classes/Dnsruby/RR/NSEC3PARAM.html +279 -0
- data/doc/classes/Dnsruby/RR/NSEC3PARAM.src/M000077.html +28 -0
- data/doc/classes/Dnsruby/RR/NSEC3PARAM.src/M000078.html +18 -0
- data/doc/classes/Dnsruby/RR/NSEC3PARAM.src/M000079.html +22 -0
- data/doc/classes/Dnsruby/RR/NSEC3PARAM.src/M000080.html +21 -0
- data/doc/classes/Dnsruby/RR/NSEC3PARAM.src/M000081.html +25 -0
- data/doc/classes/Dnsruby/RR/PTR.html +132 -0
- data/doc/classes/Dnsruby/RR/RP.html +183 -0
- data/doc/classes/Dnsruby/RR/RP.src/M000082.html +19 -0
- data/doc/classes/Dnsruby/RR/RRSIG.html +357 -0
- data/doc/classes/Dnsruby/RR/RRSIG.src/M000097.html +26 -0
- data/doc/classes/Dnsruby/RR/RRSIG.src/M000098.html +28 -0
- data/doc/classes/Dnsruby/RR/RRSIG.src/M000099.html +23 -0
- data/doc/classes/Dnsruby/RR/RRSIG.src/M000100.html +23 -0
- data/doc/classes/Dnsruby/RR/RRSIG.src/M000101.html +46 -0
- data/doc/classes/Dnsruby/RR/RRSIG.src/M000102.html +50 -0
- data/doc/classes/Dnsruby/RR/RRSIG.src/M000103.html +27 -0
- data/doc/classes/Dnsruby/RR/RT.html +155 -0
- data/doc/classes/Dnsruby/RR/SOA.html +233 -0
- data/doc/classes/Dnsruby/RR/SOA.src/M000066.html +24 -0
- data/doc/classes/Dnsruby/RR/SOA.src/M000067.html +27 -0
- data/doc/classes/Dnsruby/RR/SPF.html +138 -0
- data/doc/classes/Dnsruby/RR/TKEY.html +313 -0
- data/doc/classes/Dnsruby/RR/TKEY.src/M000021.html +19 -0
- data/doc/classes/Dnsruby/RR/TKEY.src/M000022.html +29 -0
- data/doc/classes/Dnsruby/RR/TKEY.src/M000023.html +21 -0
- data/doc/classes/Dnsruby/RR/TKEY.src/M000024.html +29 -0
- data/doc/classes/Dnsruby/RR/TSIG.html +524 -0
- data/doc/classes/Dnsruby/RR/TSIG.src/M000068.html +24 -0
- data/doc/classes/Dnsruby/RR/TSIG.src/M000069.html +32 -0
- data/doc/classes/Dnsruby/RR/TSIG.src/M000070.html +54 -0
- data/doc/classes/Dnsruby/RR/TSIG.src/M000071.html +121 -0
- data/doc/classes/Dnsruby/RR/TSIG.src/M000072.html +33 -0
- data/doc/classes/Dnsruby/RR/TSIG.src/M000073.html +25 -0
- data/doc/classes/Dnsruby/RR/TSIG.src/M000074.html +36 -0
- data/doc/classes/Dnsruby/RR/TSIG.src/M000075.html +22 -0
- data/doc/classes/Dnsruby/RR/TSIG.src/M000076.html +29 -0
- data/doc/classes/Dnsruby/RR/TXT.html +233 -0
- data/doc/classes/Dnsruby/RR/TXT.src/M000061.html +18 -0
- data/doc/classes/Dnsruby/RR/TXT.src/M000062.html +18 -0
- data/doc/classes/Dnsruby/RR/TXT.src/M000063.html +20 -0
- data/doc/classes/Dnsruby/RR/TXT.src/M000064.html +27 -0
- data/doc/classes/Dnsruby/RR/TXT.src/M000065.html +25 -0
- data/doc/classes/Dnsruby/RR/X25.html +203 -0
- data/doc/classes/Dnsruby/RR/X25.src/M000058.html +18 -0
- data/doc/classes/Dnsruby/RR/X25.src/M000059.html +18 -0
- data/doc/classes/Dnsruby/RR/X25.src/M000060.html +22 -0
- data/doc/classes/Dnsruby/RRSet.html +404 -0
- data/doc/classes/Dnsruby/RRSet.src/M000211.html +23 -0
- data/doc/classes/Dnsruby/RRSet.src/M000212.html +18 -0
- data/doc/classes/Dnsruby/RRSet.src/M000213.html +18 -0
- data/doc/classes/Dnsruby/RRSet.src/M000214.html +47 -0
- data/doc/classes/Dnsruby/RRSet.src/M000215.html +42 -0
- data/doc/classes/Dnsruby/RRSet.src/M000216.html +18 -0
- data/doc/classes/Dnsruby/RRSet.src/M000217.html +20 -0
- data/doc/classes/Dnsruby/RRSet.src/M000218.html +18 -0
- data/doc/classes/Dnsruby/RRSet.src/M000219.html +18 -0
- data/doc/classes/Dnsruby/RRSet.src/M000220.html +18 -0
- data/doc/classes/Dnsruby/RRSet.src/M000221.html +18 -0
- data/doc/classes/Dnsruby/RRSet.src/M000222.html +22 -0
- data/doc/classes/Dnsruby/RRSet.src/M000223.html +18 -0
- data/doc/classes/Dnsruby/RRSet.src/M000224.html +22 -0
- data/doc/classes/Dnsruby/RRSet.src/M000225.html +18 -0
- data/doc/classes/Dnsruby/Refused.html +119 -0
- data/doc/classes/Dnsruby/Resolv.html +401 -0
- data/doc/classes/Dnsruby/Resolv.src/M000159.html +18 -0
- data/doc/classes/Dnsruby/Resolv.src/M000160.html +18 -0
- data/doc/classes/Dnsruby/Resolv.src/M000161.html +18 -0
- data/doc/classes/Dnsruby/Resolv.src/M000162.html +18 -0
- data/doc/classes/Dnsruby/Resolv.src/M000163.html +18 -0
- data/doc/classes/Dnsruby/Resolv.src/M000164.html +18 -0
- data/doc/classes/Dnsruby/Resolv.src/M000165.html +18 -0
- data/doc/classes/Dnsruby/Resolv.src/M000166.html +19 -0
- data/doc/classes/Dnsruby/Resolv.src/M000167.html +20 -0
- data/doc/classes/Dnsruby/Resolv.src/M000168.html +29 -0
- data/doc/classes/Dnsruby/Resolv.src/M000169.html +19 -0
- data/doc/classes/Dnsruby/Resolv.src/M000170.html +20 -0
- data/doc/classes/Dnsruby/Resolv.src/M000171.html +25 -0
- data/doc/classes/Dnsruby/ResolvError.html +117 -0
- data/doc/classes/Dnsruby/ResolvTimeout.html +117 -0
- data/doc/classes/Dnsruby/Resolver.html +1055 -0
- data/doc/classes/Dnsruby/Resolver.src/M000271.html +21 -0
- data/doc/classes/Dnsruby/Resolver.src/M000272.html +27 -0
- data/doc/classes/Dnsruby/Resolver.src/M000273.html +28 -0
- data/doc/classes/Dnsruby/Resolver.src/M000274.html +18 -0
- data/doc/classes/Dnsruby/Resolver.src/M000275.html +51 -0
- data/doc/classes/Dnsruby/Resolver.src/M000276.html +21 -0
- data/doc/classes/Dnsruby/Resolver.src/M000277.html +22 -0
- data/doc/classes/Dnsruby/Resolver.src/M000278.html +18 -0
- data/doc/classes/Dnsruby/Resolver.src/M000279.html +20 -0
- data/doc/classes/Dnsruby/Resolver.src/M000280.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000281.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000282.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000283.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000284.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000285.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000286.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000287.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000288.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000289.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000290.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000291.html +19 -0
- data/doc/classes/Dnsruby/Resolver.src/M000292.html +26 -0
- data/doc/classes/Dnsruby/Resolver.src/M000293.html +18 -0
- data/doc/classes/Dnsruby/Resolver.src/M000294.html +23 -0
- data/doc/classes/Dnsruby/Resolver.src/M000295.html +18 -0
- data/doc/classes/Dnsruby/ServFail.html +119 -0
- data/doc/classes/Dnsruby/SingleResolver.html +674 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000172.html +18 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000173.html +24 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000174.html +36 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000175.html +18 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000176.html +19 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000177.html +50 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000178.html +19 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000179.html +21 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000180.html +25 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000181.html +54 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000182.html +27 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000183.html +27 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000184.html +35 -0
- data/doc/classes/Dnsruby/SingleResolver.src/M000185.html +21 -0
- data/doc/classes/Dnsruby/TheLog.html +196 -0
- data/doc/classes/Dnsruby/TheLog.src/M000246.html +20 -0
- data/doc/classes/Dnsruby/TheLog.src/M000247.html +20 -0
- data/doc/classes/Dnsruby/TheLog.src/M000248.html +20 -0
- data/doc/classes/Dnsruby/Types.html +436 -0
- data/doc/classes/Dnsruby/Update.html +368 -0
- data/doc/classes/Dnsruby/Update.src/M000253.html +32 -0
- data/doc/classes/Dnsruby/Update.src/M000254.html +36 -0
- data/doc/classes/Dnsruby/Update.src/M000255.html +32 -0
- data/doc/classes/Dnsruby/Update.src/M000256.html +41 -0
- data/doc/classes/Dnsruby/Update.src/M000257.html +34 -0
- data/doc/classes/Dnsruby/VerifyError.html +119 -0
- data/doc/classes/Dnsruby/ZoneTransfer.html +300 -0
- data/doc/classes/Dnsruby/ZoneTransfer.src/M000143.html +18 -0
- data/doc/classes/Dnsruby/ZoneTransfer.src/M000144.html +24 -0
- data/doc/classes/Dnsruby/ZoneTransfer.src/M000145.html +35 -0
- data/doc/classes/Dnsruby/ZoneTransfer/Delta.html +200 -0
- data/doc/classes/Dnsruby/ZoneTransfer/Delta.src/M000146.html +19 -0
- data/doc/classes/Dnsruby/ZoneTransfer/Delta.src/M000147.html +19 -0
- data/doc/created.rid +1 -0
- data/doc/files/lib/Dnsruby/Config_rb.html +101 -0
- data/doc/files/lib/Dnsruby/DNS_rb.html +110 -0
- data/doc/files/lib/Dnsruby/Hosts_rb.html +108 -0
- data/doc/files/lib/Dnsruby/Resolver_rb.html +109 -0
- data/doc/files/lib/Dnsruby/SingleResolver_rb.html +108 -0
- data/doc/files/lib/Dnsruby/TheLog_rb.html +110 -0
- data/doc/files/lib/Dnsruby/code_mapper_rb.html +101 -0
- data/doc/files/lib/Dnsruby/dnssec_rb.html +107 -0
- data/doc/files/lib/Dnsruby/event_machine_interface_rb.html +108 -0
- data/doc/files/lib/Dnsruby/ipv4_rb.html +101 -0
- data/doc/files/lib/Dnsruby/ipv6_rb.html +101 -0
- data/doc/files/lib/Dnsruby/message_rb.html +109 -0
- data/doc/files/lib/Dnsruby/name_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/AAAA_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/AFSDB_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/A_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/CERT_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/DNSKEY_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/DS_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/HINFO_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/IN_rb.html +112 -0
- data/doc/files/lib/Dnsruby/resource/ISDN_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/LOC_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/MINFO_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/MX_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/NAPTR_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/NSAP_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/NSEC3PARAM_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/NSEC3_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/NSEC_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/OPT_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/PX_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/RP_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/RRSIG_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/RT_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/SOA_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/SPF_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/SRV_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/TKEY_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/TSIG_rb.html +114 -0
- data/doc/files/lib/Dnsruby/resource/TXT_rb.html +108 -0
- data/doc/files/lib/Dnsruby/resource/X25_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/domain_name_rb.html +101 -0
- data/doc/files/lib/Dnsruby/resource/generic_rb.html +131 -0
- data/doc/files/lib/Dnsruby/resource/resource_rb.html +110 -0
- data/doc/files/lib/Dnsruby/select_thread_rb.html +111 -0
- data/doc/files/lib/Dnsruby/update_rb.html +101 -0
- data/doc/files/lib/Dnsruby/zone_transfer_rb.html +101 -0
- data/doc/files/lib/dnsruby_rb.html +118 -0
- data/doc/fr_class_index.html +108 -0
- data/doc/fr_file_index.html +75 -0
- data/doc/fr_method_index.html +321 -0
- data/doc/index.html +24 -0
- data/lib/Dnsruby/Config.rb +363 -0
- data/lib/Dnsruby/DNS.rb +293 -0
- data/lib/Dnsruby/Hosts.rb +126 -0
- data/lib/Dnsruby/Resolver.rb +999 -0
- data/lib/Dnsruby/SingleResolver.rb +493 -0
- data/lib/Dnsruby/TheLog.rb +60 -0
- data/lib/Dnsruby/code_mapper.rb +165 -0
- data/lib/Dnsruby/dnssec.rb +357 -0
- data/lib/Dnsruby/event_machine_interface.rb +264 -0
- data/lib/Dnsruby/ipv4.rb +74 -0
- data/lib/Dnsruby/ipv6.rb +144 -0
- data/lib/Dnsruby/message.rb +961 -0
- data/lib/Dnsruby/name.rb +332 -0
- data/lib/Dnsruby/resource/A.rb +56 -0
- data/lib/Dnsruby/resource/AAAA.rb +54 -0
- data/lib/Dnsruby/resource/AFSDB.rb +68 -0
- data/lib/Dnsruby/resource/CERT.rb +89 -0
- data/lib/Dnsruby/resource/DNSKEY.rb +242 -0
- data/lib/Dnsruby/resource/DS.rb +162 -0
- data/lib/Dnsruby/resource/HINFO.rb +52 -0
- data/lib/Dnsruby/resource/IN.rb +70 -0
- data/lib/Dnsruby/resource/ISDN.rb +54 -0
- data/lib/Dnsruby/resource/LOC.rb +255 -0
- data/lib/Dnsruby/resource/MINFO.rb +70 -0
- data/lib/Dnsruby/resource/MX.rb +66 -0
- data/lib/Dnsruby/resource/NAPTR.rb +90 -0
- data/lib/Dnsruby/resource/NSAP.rb +172 -0
- data/lib/Dnsruby/resource/NSEC.rb +243 -0
- data/lib/Dnsruby/resource/NSEC3.rb +173 -0
- data/lib/Dnsruby/resource/NSEC3PARAM.rb +120 -0
- data/lib/Dnsruby/resource/OPT.rb +210 -0
- data/lib/Dnsruby/resource/PX.rb +71 -0
- data/lib/Dnsruby/resource/RP.rb +67 -0
- data/lib/Dnsruby/resource/RRSIG.rb +256 -0
- data/lib/Dnsruby/resource/RT.rb +67 -0
- data/lib/Dnsruby/resource/SOA.rb +95 -0
- data/lib/Dnsruby/resource/SPF.rb +29 -0
- data/lib/Dnsruby/resource/SRV.rb +112 -0
- data/lib/Dnsruby/resource/TKEY.rb +163 -0
- data/lib/Dnsruby/resource/TSIG.rb +584 -0
- data/lib/Dnsruby/resource/TXT.rb +76 -0
- data/lib/Dnsruby/resource/X25.rb +53 -0
- data/lib/Dnsruby/resource/domain_name.rb +54 -0
- data/lib/Dnsruby/resource/generic.rb +151 -0
- data/lib/Dnsruby/resource/resource.rb +561 -0
- data/lib/Dnsruby/select_thread.rb +449 -0
- data/lib/Dnsruby/update.rb +262 -0
- data/lib/Dnsruby/zone_transfer.rb +332 -0
- data/lib/dnsruby.rb +512 -0
- data/test/custom.txt +4 -0
- data/test/resolv.conf +4 -0
- data/test/tc_axfr.rb +32 -0
- data/test/tc_dns.rb +230 -0
- data/test/tc_dnskey.rb +52 -0
- data/test/tc_dnsruby.rb +42 -0
- data/test/tc_dnssec.rb +88 -0
- data/test/tc_ds.rb +38 -0
- data/test/tc_escapedchars.rb +484 -0
- data/test/tc_event_machine_deferrable.rb +85 -0
- data/test/tc_event_machine_res.rb +174 -0
- data/test/tc_event_machine_single_res.rb +101 -0
- data/test/tc_event_machine_soak.rb +98 -0
- data/test/tc_header.rb +104 -0
- data/test/tc_misc.rb +139 -0
- data/test/tc_name.rb +53 -0
- data/test/tc_nsec.rb +36 -0
- data/test/tc_nsec3.rb +63 -0
- data/test/tc_nsec3param.rb +30 -0
- data/test/tc_packet.rb +179 -0
- data/test/tc_packet_unique_push.rb +102 -0
- data/test/tc_question.rb +51 -0
- data/test/tc_res_config.rb +92 -0
- data/test/tc_res_env.rb +51 -0
- data/test/tc_res_file.rb +42 -0
- data/test/tc_res_opt.rb +187 -0
- data/test/tc_resolver.rb +184 -0
- data/test/tc_rr-opt.rb +82 -0
- data/test/tc_rr-txt.rb +137 -0
- data/test/tc_rr-unknown.rb +99 -0
- data/test/tc_rr.rb +258 -0
- data/test/tc_rrset.rb +58 -0
- data/test/tc_rrsig.rb +32 -0
- data/test/tc_single_resolver.rb +169 -0
- data/test/tc_soak.rb +200 -0
- data/test/tc_soak_base.rb +136 -0
- data/test/tc_tcp.rb +35 -0
- data/test/tc_tkey.rb +75 -0
- data/test/tc_tsig.rb +237 -0
- data/test/tc_update.rb +215 -0
- data/test/ts_dnsruby.rb +17 -0
- data/test/ts_offline.rb +42 -0
- data/test/ts_online.rb +107 -0
- metadata +627 -0
data/lib/Dnsruby/DNS.rb
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#Copyright 2007 Nominet UK
|
|
3
|
+
#
|
|
4
|
+
#Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
#you may not use this file except in compliance with the License.
|
|
6
|
+
#You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
#Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
#See the License for the specific language governing permissions and
|
|
14
|
+
#limitations under the License.
|
|
15
|
+
#++
|
|
16
|
+
require 'Dnsruby/Hosts'
|
|
17
|
+
require 'Dnsruby/Config'
|
|
18
|
+
require "Dnsruby/Resolver"
|
|
19
|
+
module Dnsruby
|
|
20
|
+
|
|
21
|
+
#== Dnsruby::DNS class
|
|
22
|
+
#Resolv::DNS performs DNS queries.
|
|
23
|
+
#
|
|
24
|
+
#=== class methods
|
|
25
|
+
#* Dnsruby::DNS.new(config_info=nil)
|
|
26
|
+
#
|
|
27
|
+
# ((|config_info|)) should be nil, a string or a hash.
|
|
28
|
+
# If nil is given, /etc/resolv.conf and platform specific information is used.
|
|
29
|
+
# If a string is given, it should be a filename which format is same as /etc/resolv.conf.
|
|
30
|
+
# If a hash is given, it may contains information for nameserver, search and ndots as follows.
|
|
31
|
+
#
|
|
32
|
+
# Dnsruby::DNS.new({:nameserver=>["210.251.121.21"], :search=>["ruby-lang.org"], :ndots=>1})
|
|
33
|
+
#
|
|
34
|
+
#* Dnsruby::DNS.open(config_info=nil)
|
|
35
|
+
#* Dnsruby::Resolv::DNS.open(config_info=nil) {|dns| ...}
|
|
36
|
+
#
|
|
37
|
+
#=== methods
|
|
38
|
+
#* Dnsruby::DNS#close
|
|
39
|
+
#
|
|
40
|
+
#* Dnsruby::DNS#getaddress(name)
|
|
41
|
+
#* Dnsruby::DNS#getaddresses(name)
|
|
42
|
+
#* Dnsruby::DNS#each_address(name) {|address| ...}
|
|
43
|
+
# address lookup methods.
|
|
44
|
+
#
|
|
45
|
+
# ((|name|)) must be an instance of Dnsruby::Name or String. Resultant
|
|
46
|
+
# address is represented as an instance of Dnsruby::IPv4 or Dnsruby::IPv6.
|
|
47
|
+
#
|
|
48
|
+
#* Dnsruby::DNS#getname(address)
|
|
49
|
+
#* Dnsruby::DNS#getnames(address)
|
|
50
|
+
#* Dnsruby::DNS#each_name(address) {|name| ...}
|
|
51
|
+
# These methods lookup hostnames .
|
|
52
|
+
#
|
|
53
|
+
# ((|address|)) must be an instance of Dnsruby::IPv4, Dnsruby::IPv6 or String.
|
|
54
|
+
# Resultant name is represented as an instance of Dnsruby::Name.
|
|
55
|
+
#
|
|
56
|
+
#* Dnsruby::DNS#getresource(name, type, class)
|
|
57
|
+
#* Dnsruby::DNS#getresources(name, type, class)
|
|
58
|
+
#* Dnsruby::DNS#each_resource(name, type, class) {|resource| ...}
|
|
59
|
+
# These methods lookup DNS resources of ((|name|)).
|
|
60
|
+
# ((|name|)) must be a instance of Dnsruby::Name or String.
|
|
61
|
+
#
|
|
62
|
+
# ((|type|)) must be a member of Dnsruby::Types
|
|
63
|
+
# ((|class|)) must be a member of Dnsruby::Classes
|
|
64
|
+
#
|
|
65
|
+
# Resultant resource is represented as an instance of (a subclass of)
|
|
66
|
+
# Dnsruby::RR.
|
|
67
|
+
# (Dnsruby::RR::IN::A, etc.)
|
|
68
|
+
#
|
|
69
|
+
#The searchlist and other Config info is applied to the domain name if appropriate. All the nameservers
|
|
70
|
+
#are tried (if there is no timely answer from the first).
|
|
71
|
+
#
|
|
72
|
+
#This class uses Resolver to perform the queries.
|
|
73
|
+
#
|
|
74
|
+
#Information taken from the following places :
|
|
75
|
+
#* STD0013
|
|
76
|
+
#* RFC 1035, etc.
|
|
77
|
+
#* ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
|
|
78
|
+
#* etc.
|
|
79
|
+
class DNS
|
|
80
|
+
|
|
81
|
+
#Creates a new DNS resolver. See Resolv::DNS.new for argument details.
|
|
82
|
+
#
|
|
83
|
+
#Yields the created DNS resolver to the block, if given, otherwise returns it.
|
|
84
|
+
def self.open(*args)
|
|
85
|
+
dns = new(*args)
|
|
86
|
+
return dns unless block_given?
|
|
87
|
+
begin
|
|
88
|
+
yield dns
|
|
89
|
+
ensure
|
|
90
|
+
dns.close
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
#Closes the resolver
|
|
95
|
+
def close
|
|
96
|
+
@resolver.close
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def to_s
|
|
101
|
+
return "DNS : " + @config.to_s
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
#Creates a new DNS resolver
|
|
105
|
+
#
|
|
106
|
+
#+config_info+ can be:
|
|
107
|
+
#
|
|
108
|
+
#* nil:: Uses platform default (e.g. /etc/resolv.conf)
|
|
109
|
+
#* String:: Path to a file using /etc/resolv.conf's format
|
|
110
|
+
#* Hash:: Must contain :nameserver, :search and :ndots keys
|
|
111
|
+
# example :
|
|
112
|
+
#
|
|
113
|
+
# Dnsruby::DNS.new({:nameserver => ['210.251.121.21'],
|
|
114
|
+
# :search => ['ruby-lang.org'],
|
|
115
|
+
# :ndots => 1})
|
|
116
|
+
def initialize(config_info=nil)
|
|
117
|
+
@config = Config.new()
|
|
118
|
+
@config.set_config_info(config_info)
|
|
119
|
+
@resolver = Resolver.new(@config)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
attr_reader :config
|
|
123
|
+
|
|
124
|
+
#Gets the first IP address of +name+ from the DNS resolver
|
|
125
|
+
#
|
|
126
|
+
#+name+ can be a Dnsruby::Name or a String. Retrieved address will be a
|
|
127
|
+
#Dnsruby::IPv4 or a Dnsruby::IPv6
|
|
128
|
+
def getaddress(name)
|
|
129
|
+
each_address(name) {|address| return address}
|
|
130
|
+
raise ResolvError.new("DNS result has no information for #{name}")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
#Gets all IP addresses of +name+ from the DNS resolver
|
|
134
|
+
#
|
|
135
|
+
#+name+ can be a Dnsruby::Name or a String. Retrieved address will be a
|
|
136
|
+
#Dnsruby::IPv4 or a Dnsruby::IPv6
|
|
137
|
+
def getaddresses(name)
|
|
138
|
+
ret = []
|
|
139
|
+
each_address(name) {|address| ret << address}
|
|
140
|
+
return ret
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
#Iterates over all IP addresses of +name+ retrieved from the DNS resolver
|
|
144
|
+
#
|
|
145
|
+
#+name+ can be a Dnsruby::Name or a String. Retrieved address will be a
|
|
146
|
+
#Dnsruby::IPv4 or a Dnsruby::IPv6
|
|
147
|
+
def each_address(name)
|
|
148
|
+
each_resource(name) {|resource| yield resource.address}
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
#Gets the first hostname for +address+ from the DNS resolver
|
|
152
|
+
#
|
|
153
|
+
#+address+ must be a Dnsruby::IPv4, Dnsruby::IPv6 or a String. Retrieved
|
|
154
|
+
#name will be a Dnsruby::Name.
|
|
155
|
+
def getname(address)
|
|
156
|
+
each_name(address) {|name| return name}
|
|
157
|
+
raise ResolvError.new("DNS result has no information for #{address}")
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
#Gets all hostnames for +address+ from the DNS resolver
|
|
161
|
+
#
|
|
162
|
+
#+address+ must be a Dnsruby::IPv4, Dnsruby::IPv6 or a String. Retrieved
|
|
163
|
+
#name will be a Dnsruby::Name.
|
|
164
|
+
def getnames(address)
|
|
165
|
+
ret = []
|
|
166
|
+
each_name(address) {|name| ret << name}
|
|
167
|
+
return ret
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
#Iterates over all hostnames for +address+ retrieved from the DNS resolver
|
|
171
|
+
#
|
|
172
|
+
#+address+ must be a Dnsruby::IPv4, Dnsruby::IPv6 or a String. Retrieved
|
|
173
|
+
#name will be a Dnsruby::Name.
|
|
174
|
+
def each_name(address)
|
|
175
|
+
case address
|
|
176
|
+
when Name
|
|
177
|
+
ptr = address
|
|
178
|
+
when IPv4::Regex
|
|
179
|
+
ptr = IPv4.create(address).to_name
|
|
180
|
+
when IPv6::Regex
|
|
181
|
+
ptr = IPv6.create(address).to_name
|
|
182
|
+
else
|
|
183
|
+
raise ResolvError.new("cannot interpret as address: #{address}")
|
|
184
|
+
end
|
|
185
|
+
each_resource(ptr, Types.PTR, Classes.IN) {|resource| yield resource.domainname}
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
#Look up the first +type+, +klass+ resource for +name+
|
|
189
|
+
#
|
|
190
|
+
#+type+ defaults to Dnsruby::Types.A
|
|
191
|
+
#+klass+ defaults to Dnsruby::Classes.IN
|
|
192
|
+
#
|
|
193
|
+
#Returned resource is represented as a Dnsruby::RR instance, e.g.
|
|
194
|
+
#Dnsruby::RR::IN::A
|
|
195
|
+
def getresource(name, type=Types.A, klass=Classes.IN)
|
|
196
|
+
each_resource(name, type, klass) {|resource| return resource}
|
|
197
|
+
raise ResolvError.new("DNS result has no information for #{name}")
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
#Look up all +type+, +klass+ resources for +name+
|
|
201
|
+
#
|
|
202
|
+
#+type+ defaults to Dnsruby::Types.A
|
|
203
|
+
#+klass+ defaults to Dnsruby::Classes.IN
|
|
204
|
+
#
|
|
205
|
+
#Returned resource is represented as a Dnsruby::RR instance, e.g.
|
|
206
|
+
#Dnsruby::RR::IN::A
|
|
207
|
+
def getresources(name, type=Types.A, klass=Classes.IN)
|
|
208
|
+
ret = []
|
|
209
|
+
each_resource(name, type, klass) {|resource| ret << resource}
|
|
210
|
+
return ret
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
#Iterates over all +type+, +klass+ resources for +name+
|
|
214
|
+
#
|
|
215
|
+
#+type+ defaults to Dnsruby::Types.A
|
|
216
|
+
#+klass+ defaults to Dnsruby::Classes.IN
|
|
217
|
+
#
|
|
218
|
+
#Yielded resource is represented as a Dnsruby::RR instance, e.g.
|
|
219
|
+
#Dnsruby::RR::IN::A
|
|
220
|
+
def each_resource(name, type=Types.A, klass=Classes.IN, &proc)
|
|
221
|
+
type = Types.new(type)
|
|
222
|
+
klass = Classes.new(klass)
|
|
223
|
+
reply, reply_name = send_query(name, type, klass)
|
|
224
|
+
case reply.header.rcode.code
|
|
225
|
+
when RCode::NOERROR
|
|
226
|
+
extract_resources(reply, reply_name, type, klass, &proc)
|
|
227
|
+
return
|
|
228
|
+
# when RCode::NXDomain
|
|
229
|
+
# TheLog.debug("RCode::NXDomain returned - raising error")
|
|
230
|
+
# raise Config::NXDomain.new(reply_name.to_s)
|
|
231
|
+
else
|
|
232
|
+
TheLog.error("Unexpected rcode : #{reply.header.rcode.string}")
|
|
233
|
+
raise Config::OtherResolvError.new(reply_name.to_s)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def extract_resources(msg, name, type, klass) # :nodoc:
|
|
238
|
+
if type == Types.ANY
|
|
239
|
+
n0 = Name.create(name)
|
|
240
|
+
msg.each_answer {|rec|
|
|
241
|
+
yield rec if n0 == rec.name
|
|
242
|
+
}
|
|
243
|
+
end
|
|
244
|
+
yielded = false
|
|
245
|
+
n0 = Name.create(name)
|
|
246
|
+
msg.each_answer {|rec|
|
|
247
|
+
if n0 == rec.name
|
|
248
|
+
case rec.type
|
|
249
|
+
when type
|
|
250
|
+
if (rec.klass == klass)
|
|
251
|
+
yield rec
|
|
252
|
+
yielded = true
|
|
253
|
+
end
|
|
254
|
+
when Types.CNAME
|
|
255
|
+
n0 = rec.domainname
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
}
|
|
259
|
+
return if yielded
|
|
260
|
+
msg.each_answer {|rec|
|
|
261
|
+
if n0 == rec.name
|
|
262
|
+
case rec.type
|
|
263
|
+
when type
|
|
264
|
+
if (rec.klass == klass)
|
|
265
|
+
yield rec
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
}
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def send_query(name, type=Types.A, klass=Classes.IN) # :nodoc:
|
|
273
|
+
candidates = @config.generate_candidates(name)
|
|
274
|
+
exception = nil
|
|
275
|
+
candidates.each do |candidate|
|
|
276
|
+
q = Queue.new
|
|
277
|
+
msg = Message.new
|
|
278
|
+
msg.header.rd = 1
|
|
279
|
+
msg.add_question(candidate, type, klass)
|
|
280
|
+
@resolver.send_async(msg, q)
|
|
281
|
+
id, ret, exception = q.pop
|
|
282
|
+
if (exception == nil && ret.header.rcode == RCode.NOERROR)
|
|
283
|
+
return ret, ret.question[0].qname
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
raise exception
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
#--
|
|
292
|
+
#@TODO@ Asynchronous interface. Some sort of Deferrable?
|
|
293
|
+
#++
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#Copyright 2007 Nominet UK
|
|
3
|
+
#
|
|
4
|
+
#Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
#you may not use this file except in compliance with the License.
|
|
6
|
+
#You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
#Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
#See the License for the specific language governing permissions and
|
|
14
|
+
#limitations under the License.
|
|
15
|
+
#++
|
|
16
|
+
module Dnsruby
|
|
17
|
+
#== Dnsruby::Hosts class
|
|
18
|
+
#Dnsruby::Hosts is a hostname resolver that uses the system hosts file
|
|
19
|
+
#
|
|
20
|
+
#=== class methods
|
|
21
|
+
#* Dnsruby::Hosts.new(hosts='/etc/hosts')
|
|
22
|
+
#
|
|
23
|
+
#=== methods
|
|
24
|
+
#* Dnsruby::Hosts#getaddress(name)
|
|
25
|
+
#* Dnsruby::Hosts#getaddresses(name)
|
|
26
|
+
#* Dnsruby::Hosts#each_address(name) {|address| ...}
|
|
27
|
+
# address lookup methods.
|
|
28
|
+
#
|
|
29
|
+
#* Dnsruby::Hosts#getname(address)
|
|
30
|
+
#* Dnsruby::Hosts#getnames(address)
|
|
31
|
+
#* Dnsruby::Hosts#each_name(address) {|name| ...}
|
|
32
|
+
# hostnames lookup methods.
|
|
33
|
+
#
|
|
34
|
+
class Hosts
|
|
35
|
+
if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
|
|
36
|
+
require 'win32/resolv'
|
|
37
|
+
DefaultFileName = Win32::Resolv.get_hosts_path
|
|
38
|
+
else
|
|
39
|
+
DefaultFileName = '/etc/hosts'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
#Creates a new Dnsruby::Hosts using +filename+ for its data source
|
|
43
|
+
def initialize(filename = DefaultFileName)
|
|
44
|
+
@filename = filename
|
|
45
|
+
@mutex = Mutex.new
|
|
46
|
+
@initialized = nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def lazy_initialize# :nodoc:
|
|
50
|
+
@mutex.synchronize {
|
|
51
|
+
unless @initialized
|
|
52
|
+
@name2addr = {}
|
|
53
|
+
@addr2name = {}
|
|
54
|
+
begin
|
|
55
|
+
open(@filename) {|f|
|
|
56
|
+
f.each {|line|
|
|
57
|
+
line.sub!(/#.*/, '')
|
|
58
|
+
addr, hostname, *aliases = line.split(/\s+/)
|
|
59
|
+
next unless addr
|
|
60
|
+
addr.untaint
|
|
61
|
+
hostname.untaint
|
|
62
|
+
@addr2name[addr] = [] unless @addr2name.include? addr
|
|
63
|
+
@addr2name[addr] << hostname
|
|
64
|
+
@addr2name[addr] += aliases
|
|
65
|
+
@name2addr[hostname] = [] unless @name2addr.include? hostname
|
|
66
|
+
@name2addr[hostname] << addr
|
|
67
|
+
aliases.each {|n|
|
|
68
|
+
n.untaint
|
|
69
|
+
@name2addr[n] = [] unless @name2addr.include? n
|
|
70
|
+
@name2addr[n] << addr
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
rescue Exception
|
|
75
|
+
# Java won't find this file if running on Windows
|
|
76
|
+
end
|
|
77
|
+
@name2addr.each {|name, arr| arr.reverse!}
|
|
78
|
+
@initialized = true
|
|
79
|
+
end
|
|
80
|
+
}
|
|
81
|
+
self
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
#Gets the first IP address for +name+ from the hosts file
|
|
85
|
+
def getaddress(name)
|
|
86
|
+
each_address(name) {|address| return address}
|
|
87
|
+
raise ResolvError.new("#{@filename} has no name: #{name}")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
#Gets all IP addresses for +name+ from the hosts file
|
|
91
|
+
def getaddresses(name)
|
|
92
|
+
ret = []
|
|
93
|
+
each_address(name) {|address| ret << address}
|
|
94
|
+
return ret
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
#Iterates over all IP addresses for +name+ retrieved from the hosts file
|
|
98
|
+
def each_address(name, &proc)
|
|
99
|
+
lazy_initialize
|
|
100
|
+
if @name2addr.include?(name)
|
|
101
|
+
@name2addr[name].each(&proc)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
#Gets the first hostname of +address+ from the hosts file
|
|
106
|
+
def getname(address)
|
|
107
|
+
each_name(address) {|name| return name}
|
|
108
|
+
raise ResolvError.new("#{@filename} has no address: #{address}")
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
#Gets all hostnames for +address+ from the hosts file
|
|
112
|
+
def getnames(address)
|
|
113
|
+
ret = []
|
|
114
|
+
each_name(address) {|name| ret << name}
|
|
115
|
+
return ret
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
#Iterates over all hostnames for +address+ retrieved from the hosts file
|
|
119
|
+
def each_name(address, &proc)
|
|
120
|
+
lazy_initialize
|
|
121
|
+
if @addr2name.include?(address)
|
|
122
|
+
@addr2name[address].each(&proc)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,999 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#Copyright 2007 Nominet UK
|
|
3
|
+
#
|
|
4
|
+
#Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
#you may not use this file except in compliance with the License.
|
|
6
|
+
#You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
#Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
#distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
#See the License for the specific language governing permissions and
|
|
14
|
+
#limitations under the License.
|
|
15
|
+
#++
|
|
16
|
+
require "Dnsruby/SingleResolver"
|
|
17
|
+
module Dnsruby
|
|
18
|
+
#== Description
|
|
19
|
+
#Dnsruby::Resolver is a DNS stub resolver.
|
|
20
|
+
#This class uses a set of SingleResolvers to perform queries with retries across multiple nameservers.
|
|
21
|
+
#
|
|
22
|
+
#The retry policy is a combination of the Net::DNS and dnsjava approach, and has the option of :
|
|
23
|
+
#* A total timeout for the query (defaults to 0, meaning "no total timeout")
|
|
24
|
+
#* A retransmission system that targets the namervers concurrently once the first query round is
|
|
25
|
+
# complete, but in which the total time per query round is split between the number of nameservers
|
|
26
|
+
# targetted for the first round. and total time for query round is doubled for each query round
|
|
27
|
+
#
|
|
28
|
+
# Note that, if a total timeout is specified, then that will apply regardless of the retry policy
|
|
29
|
+
#(i.e. it may cut retries short).
|
|
30
|
+
#
|
|
31
|
+
# Note also that these timeouts are distinct from the SingleResolver's packet_timeout
|
|
32
|
+
#
|
|
33
|
+
#== Methods
|
|
34
|
+
#
|
|
35
|
+
#=== Synchronous
|
|
36
|
+
#These methods raise an exception or return a response message with rcode==NOERROR
|
|
37
|
+
#
|
|
38
|
+
#* Dnsruby::Resolver#send_message(msg)
|
|
39
|
+
#* Dnsruby::Resolver#query(name [, type [, klass]])
|
|
40
|
+
#
|
|
41
|
+
#=== Asynchronous
|
|
42
|
+
#These methods use a response queue to return the response and the error
|
|
43
|
+
#
|
|
44
|
+
#* Dnsruby::Resolver#send_async(msg, response_queue, query_id)
|
|
45
|
+
#
|
|
46
|
+
#== Event Loop
|
|
47
|
+
#Dnsruby runs a pure Ruby event loop to handle I/O in a single thread.
|
|
48
|
+
#It is also possible to configure Dnsruby to use EventMachine instead.
|
|
49
|
+
#See the Dnsruby::Resolver::use_eventmachine method for details.
|
|
50
|
+
#
|
|
51
|
+
#Note that, if using Dnsruby from an EventMachine loop, you will need to tell
|
|
52
|
+
#Dnsruby not to start the event loop itself :
|
|
53
|
+
#
|
|
54
|
+
# Dnsruby::Resolver::use_eventmachine(true)
|
|
55
|
+
# Dnsruby::Resolver::start_eventmachine_loop(false)
|
|
56
|
+
class Resolver
|
|
57
|
+
@@event_machine_available=false
|
|
58
|
+
begin
|
|
59
|
+
require 'Dnsruby/event_machine_interface'
|
|
60
|
+
@@event_machine_available=true
|
|
61
|
+
TheLog.debug("EventMachine loaded")
|
|
62
|
+
rescue LoadError
|
|
63
|
+
TheLog.error("EventMachine not found")
|
|
64
|
+
end
|
|
65
|
+
DefaultQueryTimeout = 0
|
|
66
|
+
DefaultPacketTimeout = 10
|
|
67
|
+
DefaultRetryTimes = 4
|
|
68
|
+
DefaultRetryDelay = 5
|
|
69
|
+
DefaultPort = 53
|
|
70
|
+
DefaultUDPSize = 512
|
|
71
|
+
# The port to send queries to on the resolver
|
|
72
|
+
attr_reader :port
|
|
73
|
+
|
|
74
|
+
# Should TCP be used as a transport rather than UDP?
|
|
75
|
+
attr_reader :use_tcp
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
attr_reader :tsig
|
|
79
|
+
|
|
80
|
+
# Should truncation be ignored?
|
|
81
|
+
# i.e. the TC bit is ignored and thus the resolver will not requery over TCP if TC is set
|
|
82
|
+
attr_reader :ignore_truncation
|
|
83
|
+
|
|
84
|
+
# The source address to send queries from
|
|
85
|
+
attr_reader :src_address
|
|
86
|
+
# The source port to send queries from
|
|
87
|
+
attr_reader :src_port
|
|
88
|
+
|
|
89
|
+
# Should TCP queries be sent on a persistent socket?
|
|
90
|
+
attr_reader :persistent_tcp
|
|
91
|
+
# Should UDP queries be sent on a persistent socket?
|
|
92
|
+
attr_reader :persistent_udp
|
|
93
|
+
|
|
94
|
+
# Should the Recursion Desired bit be set?
|
|
95
|
+
attr_reader :recurse
|
|
96
|
+
|
|
97
|
+
# The maximum UDP size to be used
|
|
98
|
+
attr_reader :udp_size
|
|
99
|
+
|
|
100
|
+
# The current Config
|
|
101
|
+
attr_reader :config
|
|
102
|
+
|
|
103
|
+
# The array of SingleResolvers used for sending query messages
|
|
104
|
+
attr_reader :single_resolvers
|
|
105
|
+
|
|
106
|
+
#The timeout for any individual packet. This is the timeout used by SingleResolver
|
|
107
|
+
attr_reader :packet_timeout
|
|
108
|
+
|
|
109
|
+
# Note that this timeout represents the total time a query may run for - multiple packets
|
|
110
|
+
# can be sent to multiple nameservers in this time.
|
|
111
|
+
# This is distinct from the SingleResolver per-packet timeout
|
|
112
|
+
# The query_timeout is not required - it will default to 0, which means "do not use query_timeout".
|
|
113
|
+
# If this is the case then the timeout will be dictated by the retry_times and retry_delay attributes
|
|
114
|
+
attr_accessor :query_timeout
|
|
115
|
+
|
|
116
|
+
# The query will be tried across nameservers retry_times times, with a delay of retry_delay seconds
|
|
117
|
+
# between each retry. The first time round, retry_delay will be divided by the number of nameservers
|
|
118
|
+
# being targetted, and a new nameserver will be queried with the resultant delay.
|
|
119
|
+
attr_accessor :retry_times, :retry_delay
|
|
120
|
+
|
|
121
|
+
# Use DNSSEC for this Resolver
|
|
122
|
+
attr_reader :dnssec
|
|
123
|
+
|
|
124
|
+
@@use_eventmachine=false
|
|
125
|
+
@@start_eventmachine_loop=true
|
|
126
|
+
|
|
127
|
+
#--
|
|
128
|
+
#@TODO@ add load_balance? i.e. Target nameservers in a random, rather than pre-determined, order?
|
|
129
|
+
#++
|
|
130
|
+
|
|
131
|
+
# Query for a n. If a valid Message is received, then it is returned
|
|
132
|
+
# to the caller. Otherwise an exception (a Dnsruby::ResolvError or Dnsruby::ResolvTimeout) is raised.
|
|
133
|
+
#
|
|
134
|
+
# require 'Dnsruby'
|
|
135
|
+
# res = Dnsruby::Resolver.new
|
|
136
|
+
# response = res.query("example.com") # defaults to Types.A, Classes.IN
|
|
137
|
+
# response = res.query("example.com", Types.MX)
|
|
138
|
+
# response = res.query("208.77.188.166") # IPv4 address so PTR query will be made
|
|
139
|
+
# response = res.query("208.77.188.166", Types.PTR)
|
|
140
|
+
def query(name, type=Types.A, klass=Classes.IN)
|
|
141
|
+
msg = Message.new
|
|
142
|
+
msg.header.rd = 1
|
|
143
|
+
msg.add_question(name, type, klass)
|
|
144
|
+
return send_message(msg)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Send a message, and wait for the response. If a valid Message is received, then it is returned
|
|
148
|
+
# to the caller. Otherwise an exception (a Dnsruby::ResolvError or Dnsruby::ResolvTimeout) is raised.
|
|
149
|
+
#
|
|
150
|
+
# send_async is called internally.
|
|
151
|
+
#
|
|
152
|
+
# example :
|
|
153
|
+
#
|
|
154
|
+
# require 'Dnsruby'
|
|
155
|
+
# res = Dnsruby::Resolver.new
|
|
156
|
+
# begin
|
|
157
|
+
# response = res.send_message(Message.new("example.com", Types.MX))
|
|
158
|
+
# rescue ResolvError
|
|
159
|
+
# # ...
|
|
160
|
+
# rescue ResolvTimeout
|
|
161
|
+
# # ...
|
|
162
|
+
# end
|
|
163
|
+
def send_message(message)
|
|
164
|
+
TheLog.debug("Resolver : sending message")
|
|
165
|
+
q = Queue.new
|
|
166
|
+
send_async(message, q)
|
|
167
|
+
id, result, error = q.pop
|
|
168
|
+
TheLog.debug("Resolver : result received")
|
|
169
|
+
if (error != nil)
|
|
170
|
+
raise error
|
|
171
|
+
else
|
|
172
|
+
return result
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
#Asynchronously send a Message to the server. The send can be done using just
|
|
178
|
+
#Dnsruby, or using EventMachine.
|
|
179
|
+
#
|
|
180
|
+
#== Dnsruby pure Ruby event loop :
|
|
181
|
+
#
|
|
182
|
+
#A client_queue is supplied by the client,
|
|
183
|
+
#along with an optional client_query_id to identify the response. The client_query_id
|
|
184
|
+
#is generated, if not supplied, and returned to the client.
|
|
185
|
+
#When the response is known,
|
|
186
|
+
#a tuple of (query_id, response_message, exception) will be added to the client_queue.
|
|
187
|
+
#
|
|
188
|
+
#The query is sent synchronously in the caller's thread. The select thread is then used to
|
|
189
|
+
#listen for and process the response (up to pushing it to the client_queue). The client thread
|
|
190
|
+
#is then used to retrieve the response and deal with it.
|
|
191
|
+
#
|
|
192
|
+
#Takes :
|
|
193
|
+
#
|
|
194
|
+
#* msg - the message to send
|
|
195
|
+
#* client_queue - a Queue to push the response to, when it arrives
|
|
196
|
+
#* client_query_id - an optional ID to identify the query to the client
|
|
197
|
+
#* use_tcp - whether to use TCP (defaults to SingleResolver.use_tcp)
|
|
198
|
+
#
|
|
199
|
+
#Returns :
|
|
200
|
+
#
|
|
201
|
+
#* client_query_id - to identify the query response to the client. This ID is
|
|
202
|
+
#generated if it is not passed in by the client
|
|
203
|
+
#
|
|
204
|
+
#=== Example invocations :
|
|
205
|
+
#
|
|
206
|
+
# id = res.send_async(msg, queue)
|
|
207
|
+
# NOT SUPPORTED : id = res.send_async(msg, queue, use_tcp)
|
|
208
|
+
# id = res.send_async(msg, queue, id)
|
|
209
|
+
# id = res.send_async(msg, queue, id, use_tcp)
|
|
210
|
+
#
|
|
211
|
+
#=== Example code :
|
|
212
|
+
#
|
|
213
|
+
# require 'Dnsruby'
|
|
214
|
+
# res = Dnsruby::Resolver.new
|
|
215
|
+
# query_id = 10 # can be any object you like
|
|
216
|
+
# query_queue = Queue.new
|
|
217
|
+
# res.send_async(Message.new("example.com", Types.MX), query_queue, query_id)
|
|
218
|
+
# query_id_2 = res.send_async(Message.new("example.com", Types.A), query_queue)
|
|
219
|
+
# # ...do a load of other stuff here...
|
|
220
|
+
# 2.times do
|
|
221
|
+
# response_id, response, exception = query_queue.pop
|
|
222
|
+
# # You can check the ID to see which query has been answered
|
|
223
|
+
# if (exception == nil)
|
|
224
|
+
# # deal with good response
|
|
225
|
+
# else
|
|
226
|
+
# # deal with problem
|
|
227
|
+
# end
|
|
228
|
+
# end
|
|
229
|
+
#
|
|
230
|
+
#== If EventMachine is being used :
|
|
231
|
+
#
|
|
232
|
+
#If EventMachine is being used (see Dnsruby::Resolver::use_eventmachine, then this method returns
|
|
233
|
+
#an EM::Deferrable object. When the response is known, then the Deferrable will complete.
|
|
234
|
+
#If a queue (and ID) is passed in, then the response will also be
|
|
235
|
+
#pushed to the Queue. Note that an ID is not automatically generated by this version.
|
|
236
|
+
#
|
|
237
|
+
#=== Example invocations :
|
|
238
|
+
#
|
|
239
|
+
# deferrable = res.send_async(msg)
|
|
240
|
+
# deferrable = res.send_async(msg, use_tcp)
|
|
241
|
+
# deferrable = res.send_async(msg, q, id, use_tcp)
|
|
242
|
+
#
|
|
243
|
+
#=== Example code
|
|
244
|
+
#* Here is an example of using the code in an EventMachine style :
|
|
245
|
+
#
|
|
246
|
+
# require 'Dnsruby'
|
|
247
|
+
# require 'eventmachine'
|
|
248
|
+
# res = Dnsruby::Resolver.new
|
|
249
|
+
# Dnsruby::Resolver.use_eventmachine
|
|
250
|
+
# Dnsruby::Resolver.start_eventmachine_loop(false)
|
|
251
|
+
# EventMachine::run {
|
|
252
|
+
# df = res.send_async(Dnsruby::Message.new("example.com"))
|
|
253
|
+
# df.callback {|msg|
|
|
254
|
+
# puts "Response : #{msg}"
|
|
255
|
+
# EM.stop}
|
|
256
|
+
# df.errback {|msg, err|
|
|
257
|
+
# puts "Response : #{msg}"
|
|
258
|
+
# puts "Error: #{err}"
|
|
259
|
+
# EM.stop}
|
|
260
|
+
# }
|
|
261
|
+
#
|
|
262
|
+
#* And an example in a normal Dnsruby style :
|
|
263
|
+
#
|
|
264
|
+
# require 'Dnsruby'
|
|
265
|
+
# res = Dnsruby::Resolver.new
|
|
266
|
+
# Dnsruby::Resolver.use_eventmachine
|
|
267
|
+
# Dnsruby::Resolver.start_eventmachine_loop(true) # default
|
|
268
|
+
# q = Queue.new
|
|
269
|
+
# id = res.send_async(Dnsruby::Message.new("example.com"),q)
|
|
270
|
+
# id, response, error = q.pop
|
|
271
|
+
#
|
|
272
|
+
def send_async(*args) # msg, client_queue, client_query_id)
|
|
273
|
+
if (Resolver.eventmachine?)
|
|
274
|
+
if (!@resolver_em)
|
|
275
|
+
@resolver_em = ResolverEM.new(self)
|
|
276
|
+
end
|
|
277
|
+
return @resolver_em.send_async(*args)
|
|
278
|
+
else
|
|
279
|
+
if (!@resolver_ruby) # @TODO@ Synchronize this?
|
|
280
|
+
@resolver_ruby = ResolverRuby.new(self)
|
|
281
|
+
end
|
|
282
|
+
return @resolver_ruby.send_async(*args)
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Close the Resolver. Unfinished queries are terminated with OtherResolvError.
|
|
287
|
+
def close
|
|
288
|
+
[@resolver_em, @resolver_ruby].each do |r| r.close if r end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Create a new Resolver object. If no parameters are passed in, then the default
|
|
292
|
+
# system configuration will be used. Otherwise, a Hash may be passed in with the
|
|
293
|
+
# following optional elements :
|
|
294
|
+
#
|
|
295
|
+
#
|
|
296
|
+
# * :port
|
|
297
|
+
# * :use_tcp
|
|
298
|
+
# * :tsig
|
|
299
|
+
# * :ignore_truncation
|
|
300
|
+
# * :src_address
|
|
301
|
+
# * :src_port
|
|
302
|
+
# * :persistent_tcp
|
|
303
|
+
# * :persistent_udp
|
|
304
|
+
# * :recurse
|
|
305
|
+
# * :udp_size
|
|
306
|
+
# * :config_info - see Config
|
|
307
|
+
# * :nameserver - can be either a String or an array of Strings
|
|
308
|
+
# * :packet_timeout
|
|
309
|
+
# * :query_timeout
|
|
310
|
+
# * :retry_times
|
|
311
|
+
# * :retry_delay
|
|
312
|
+
def initialize(*args)
|
|
313
|
+
@resolver_em = nil
|
|
314
|
+
@resolver_ruby = nil
|
|
315
|
+
@src_address = nil
|
|
316
|
+
reset_attributes
|
|
317
|
+
|
|
318
|
+
# Process args
|
|
319
|
+
if (args.length==1)
|
|
320
|
+
if (args[0].class == Hash)
|
|
321
|
+
args[0].keys.each do |key|
|
|
322
|
+
begin
|
|
323
|
+
if (key == :config_info)
|
|
324
|
+
@config.set_config_info(args[0][:config_info])
|
|
325
|
+
elsif (key==:nameserver)
|
|
326
|
+
set_config_nameserver(args[0][:nameserver])
|
|
327
|
+
else
|
|
328
|
+
send(key.to_s+"=", args[0][key])
|
|
329
|
+
end
|
|
330
|
+
rescue Exception
|
|
331
|
+
TheLog.error("Argument #{key} not valid\n")
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
elsif (args[0].class == String)
|
|
335
|
+
set_config_nameserver(args[0])
|
|
336
|
+
elsif (args[0].class == Config)
|
|
337
|
+
# also accepts a Config object from Dnsruby::Resolv
|
|
338
|
+
@config = args[0]
|
|
339
|
+
end
|
|
340
|
+
else
|
|
341
|
+
# Anything to do?
|
|
342
|
+
end
|
|
343
|
+
if (@single_resolvers==[])
|
|
344
|
+
add_config_nameservers
|
|
345
|
+
end
|
|
346
|
+
update
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def add_config_nameservers
|
|
350
|
+
# Add the Config nameservers
|
|
351
|
+
@config.nameserver.each do |ns|
|
|
352
|
+
@single_resolvers.push(SingleResolver.new({:server=>ns}))
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def set_config_nameserver(n)
|
|
357
|
+
if (n).kind_of?String
|
|
358
|
+
@config.nameserver=[n]
|
|
359
|
+
else
|
|
360
|
+
@config.nameserver=n
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def reset_attributes #:nodoc: all
|
|
365
|
+
if (@resolver_em)
|
|
366
|
+
@resolver_em.reset_attributes
|
|
367
|
+
end
|
|
368
|
+
if (@resolver_ruby)
|
|
369
|
+
@resolver_ruby.reset_attributes
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
# Attributes
|
|
373
|
+
@query_timeout = DefaultQueryTimeout
|
|
374
|
+
@retry_delay = DefaultRetryDelay
|
|
375
|
+
@retry_times = DefaultRetryTimes
|
|
376
|
+
@packet_timeout = DefaultPacketTimeout
|
|
377
|
+
@port = DefaultPort
|
|
378
|
+
@udp_size = DefaultUDPSize
|
|
379
|
+
@use_tcp = false
|
|
380
|
+
@tsig = nil
|
|
381
|
+
@ignore_truncation = false
|
|
382
|
+
@config = Config.new()
|
|
383
|
+
@src_addr = '0.0.0.0'
|
|
384
|
+
@src_port = 0
|
|
385
|
+
@recurse = true
|
|
386
|
+
@persistent_udp = false
|
|
387
|
+
@persistent_tcp = false
|
|
388
|
+
@single_resolvers=[]
|
|
389
|
+
@dnssec = true
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def update #:nodoc: all
|
|
393
|
+
#Update any resolvers we have with the latest config
|
|
394
|
+
@single_resolvers.each do |res|
|
|
395
|
+
[:port, :use_tcp, :tsig, :ignore_truncation, :packet_timeout,
|
|
396
|
+
:src_address, :src_port, :persistent_tcp, :persistent_udp, :recurse,
|
|
397
|
+
:udp_size, :dnssec].each do |param|
|
|
398
|
+
|
|
399
|
+
res.send(param.to_s+"=", instance_variable_get("@"+param.to_s))
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# Add a new SingleResolver to the list of resolvers this Resolver object will
|
|
405
|
+
# query.
|
|
406
|
+
def add_resolver(single)
|
|
407
|
+
@single_resolvers.push(single)
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
def nameserver=(n)
|
|
411
|
+
@single_resolvers=[]
|
|
412
|
+
set_config_nameserver(n)
|
|
413
|
+
add_config_nameservers
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
#--
|
|
417
|
+
#@TODO@ Should really auto-generate these methods.
|
|
418
|
+
#Also, any way to tie them up with SingleResolver RDoc?
|
|
419
|
+
#++
|
|
420
|
+
|
|
421
|
+
def packet_timeout=(t)
|
|
422
|
+
@packet_timeout = t
|
|
423
|
+
update
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
def port=(p)
|
|
427
|
+
@port = p
|
|
428
|
+
update
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def use_tcp=(on)
|
|
432
|
+
@use_tcp = on
|
|
433
|
+
update
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
#Sets the TSIG to sign outgoing messages with.
|
|
437
|
+
#Pass in either a Dnsruby::RR::TSIG, or a key_name and key (or just a key)
|
|
438
|
+
#Pass in nil to stop tsig signing.
|
|
439
|
+
#* res.tsig=(tsig_rr)
|
|
440
|
+
#* res.tsig=(key_name, key)
|
|
441
|
+
#* res.tsig=nil # Stop the resolver from signing
|
|
442
|
+
def tsig=(t)
|
|
443
|
+
@tsig=t
|
|
444
|
+
update
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
def ignore_truncation=(on)
|
|
448
|
+
@ignore_truncation = on
|
|
449
|
+
update
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def src_address=(a)
|
|
453
|
+
@src_address = a
|
|
454
|
+
update
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def src_port=(a)
|
|
458
|
+
@src_port = a
|
|
459
|
+
update
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def persistent_tcp=(on)
|
|
463
|
+
@persistent_tcp = on
|
|
464
|
+
update
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
def persistent_udp=(on)
|
|
468
|
+
@persistent_udp = on
|
|
469
|
+
update
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
def recurse=(a)
|
|
473
|
+
@recurse = a
|
|
474
|
+
update
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def dnssec=(d)
|
|
478
|
+
@dnssec = d
|
|
479
|
+
update
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
def udp_size=(s)
|
|
483
|
+
@udp_size = s
|
|
484
|
+
update
|
|
485
|
+
end
|
|
486
|
+
#Tell Dnsruby to use EventMachine for I/O.
|
|
487
|
+
#
|
|
488
|
+
#If EventMachine is not used, then the pure Ruby event loop in Dnsruby will
|
|
489
|
+
#be used instead.
|
|
490
|
+
#
|
|
491
|
+
#If EventMachine is not available on the platform, then a RuntimeError will be raised.
|
|
492
|
+
#
|
|
493
|
+
#Takes a bool to say whether or not to use EventMachine.
|
|
494
|
+
def Resolver.use_eventmachine(on=true)
|
|
495
|
+
if (on && !@@event_machine_available)
|
|
496
|
+
raise RuntimeError.new("EventMachine is not available in this environment!")
|
|
497
|
+
end
|
|
498
|
+
@@use_eventmachine = on
|
|
499
|
+
if (on)
|
|
500
|
+
TheLog.info("EventMachine will be used for IO")
|
|
501
|
+
else
|
|
502
|
+
TheLog.info("EventMachine will not be used for IO")
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
#Check whether EventMachine will be used by Dnsruby
|
|
506
|
+
def Resolver.eventmachine?
|
|
507
|
+
return @@use_eventmachine
|
|
508
|
+
end
|
|
509
|
+
#If EventMachine is being used, then this method tells Dnsruby whether or not
|
|
510
|
+
#to start the EventMachine loop. If you want to use Dnsruby client code as
|
|
511
|
+
#is, but using EventMachine for I/O, then Dnsruby must start the EventMachine
|
|
512
|
+
#loop for you. This is the default behaviour.
|
|
513
|
+
#If you want to use EventMachine-style code, where everything is wrapped
|
|
514
|
+
#up in an EventMachine::run{} call, then this method should be called with
|
|
515
|
+
#false as the parameter.
|
|
516
|
+
#
|
|
517
|
+
#Takes a bool argument to say whether or not to start the event loop when required.
|
|
518
|
+
def Resolver.start_eventmachine_loop(on=true)
|
|
519
|
+
@@start_eventmachine_loop=on
|
|
520
|
+
if (on)
|
|
521
|
+
TheLog.info("EventMachine loop will be started by Dnsruby")
|
|
522
|
+
else
|
|
523
|
+
TheLog.info("EventMachine loop will not be started by Dnsruby")
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
#Checks whether Dnsruby will start the EventMachine loop when required.
|
|
527
|
+
def Resolver.start_eventmachine_loop?
|
|
528
|
+
return @@start_eventmachine_loop
|
|
529
|
+
end
|
|
530
|
+
def generate_timeouts(base=0) #:nodoc: all
|
|
531
|
+
#These should be be pegged to the single_resolver they are targetting :
|
|
532
|
+
# e.g. timeouts[timeout1]=nameserver
|
|
533
|
+
timeouts = {}
|
|
534
|
+
retry_delay = @retry_delay
|
|
535
|
+
@retry_times.times do |retry_count|
|
|
536
|
+
if (retry_count>0)
|
|
537
|
+
retry_delay *= 2
|
|
538
|
+
end
|
|
539
|
+
servers=[]
|
|
540
|
+
@single_resolvers.each do |r| servers.push(r.server) end
|
|
541
|
+
@single_resolvers.each_index do |i|
|
|
542
|
+
res= @single_resolvers[i]
|
|
543
|
+
offset = (i*@retry_delay.to_f/@single_resolvers.length)
|
|
544
|
+
if (retry_count==0)
|
|
545
|
+
timeouts[base+offset]=[res, retry_count]
|
|
546
|
+
else
|
|
547
|
+
if (timeouts.has_key?(base+retry_delay+offset))
|
|
548
|
+
TheLog.error("Duplicate timeout key!")
|
|
549
|
+
raise RuntimeError.new("Duplicate timeout key!")
|
|
550
|
+
end
|
|
551
|
+
timeouts[base+retry_delay+offset]=[res, retry_count]
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
end
|
|
555
|
+
return timeouts
|
|
556
|
+
end
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
# This class implements the I/O using EventMachine.
|
|
560
|
+
# This is the preferred implementation.
|
|
561
|
+
# NOTE - EM does not work properly on Windows with version 0.8.1 - do not use!
|
|
562
|
+
class ResolverEM #:nodoc: all
|
|
563
|
+
TIMER_PERIOD = 0.1
|
|
564
|
+
def initialize(parent)
|
|
565
|
+
@parent=parent
|
|
566
|
+
end
|
|
567
|
+
def reset_attributes #:nodoc: all
|
|
568
|
+
end
|
|
569
|
+
class PersistentData
|
|
570
|
+
attr_accessor :outstanding, :deferrable, :to_send, :timeouts, :timer_procs, :timer_keys_sorted, :finish
|
|
571
|
+
end
|
|
572
|
+
def send_async(*args) #msg, client_queue=nil, client_query_id=nil)
|
|
573
|
+
msg=args[0]
|
|
574
|
+
client_queue=nil
|
|
575
|
+
client_query_id=nil
|
|
576
|
+
if (args.length>1)
|
|
577
|
+
client_queue=args[1]
|
|
578
|
+
if (args.length > 2)
|
|
579
|
+
client_query_id = args[2]
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
# We want to send the query to the first resolver.
|
|
583
|
+
# We then want to set up all the timers for all of the events which might happen
|
|
584
|
+
# (first round timers, retry timers, etc.)
|
|
585
|
+
# The callbacks for these should be able to cancel any of the rest (including any for broken resolvers)
|
|
586
|
+
# We can then forget about the query, as all the callbacks will be lodged with EventMachine.
|
|
587
|
+
|
|
588
|
+
EventMachineInterface::start_em_for_resolver(self)
|
|
589
|
+
persistent_data = PersistentData.new
|
|
590
|
+
persistent_data.deferrable = EM::DefaultDeferrable.new
|
|
591
|
+
persistent_data.outstanding = []
|
|
592
|
+
persistent_data.to_send = 0
|
|
593
|
+
persistent_data.timeouts=@parent.generate_timeouts(Time.now)
|
|
594
|
+
persistent_data.timer_procs = {}
|
|
595
|
+
persistent_data.finish = false
|
|
596
|
+
persistent_data.timeouts.keys.sort.each do |timeout|
|
|
597
|
+
value = persistent_data.timeouts[timeout]
|
|
598
|
+
# timeout = timeout.round
|
|
599
|
+
single_resolver, retry_count = value
|
|
600
|
+
persistent_data.to_send+=1
|
|
601
|
+
df = nil
|
|
602
|
+
if (timeout == 0)
|
|
603
|
+
# Send immediately
|
|
604
|
+
TheLog.debug("Sending first EM query")
|
|
605
|
+
df = send_new_em_query(single_resolver, msg, client_queue, client_query_id, persistent_data)
|
|
606
|
+
persistent_data.outstanding.push(df)
|
|
607
|
+
else
|
|
608
|
+
# Send later
|
|
609
|
+
persistent_data.timer_procs[timeout]=Proc.new{
|
|
610
|
+
TheLog.debug("Sending #{timeout} delayed EM query")
|
|
611
|
+
df = send_new_em_query(single_resolver, msg, client_queue, client_query_id, persistent_data)
|
|
612
|
+
persistent_data.outstanding.push(df)
|
|
613
|
+
}
|
|
614
|
+
end
|
|
615
|
+
end
|
|
616
|
+
query_timeout = @parent.query_timeout
|
|
617
|
+
if (query_timeout > 0)
|
|
618
|
+
persistent_data.timer_procs[Time.now+query_timeout]=Proc.new{
|
|
619
|
+
cancel_queries(persistent_data)
|
|
620
|
+
return_to_client(persistent_data.deferrable, client_queue, client_query_id, nil, ResolvTimeout.new("Query timed out after query_timeout=#{query_timeout.round} seconds"))
|
|
621
|
+
}
|
|
622
|
+
end
|
|
623
|
+
persistent_data.timer_keys_sorted = persistent_data.timer_procs.keys.sort
|
|
624
|
+
EventMachine::add_timer(0) {process_eventmachine_timers(persistent_data)}
|
|
625
|
+
return persistent_data.deferrable
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
# Close the Resolver. Unfinished queries are terminated with OtherResolvError.
|
|
629
|
+
def close
|
|
630
|
+
# @TODO@ We need a list of open deferrables so that we can complete them
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
def process_eventmachine_timers(persistent_data)
|
|
634
|
+
if (persistent_data.finish)
|
|
635
|
+
return
|
|
636
|
+
end
|
|
637
|
+
now = Time.now
|
|
638
|
+
persistent_data.timer_keys_sorted.each do |timeout|
|
|
639
|
+
if (timeout > now)
|
|
640
|
+
break
|
|
641
|
+
end
|
|
642
|
+
persistent_data.timer_procs[timeout].call
|
|
643
|
+
persistent_data.timer_procs.delete(timeout)
|
|
644
|
+
persistent_data.timer_keys_sorted.delete(timeout)
|
|
645
|
+
end
|
|
646
|
+
EventMachine::add_timer(TIMER_PERIOD) {process_eventmachine_timers(persistent_data)}
|
|
647
|
+
end
|
|
648
|
+
|
|
649
|
+
def send_new_em_query(single_resolver, msg, client_queue, client_query_id, persistent_data)
|
|
650
|
+
df = single_resolver.send_async(msg) # client_queue, client_query_id)
|
|
651
|
+
persistent_data.to_send-=1
|
|
652
|
+
df.callback { |answer|
|
|
653
|
+
TheLog.debug("Response returned")
|
|
654
|
+
persistent_data.outstanding.delete(df)
|
|
655
|
+
cancel_queries(persistent_data)
|
|
656
|
+
return_to_client(persistent_data.deferrable, client_queue, client_query_id, answer, nil)
|
|
657
|
+
}
|
|
658
|
+
df.errback { |response, error|
|
|
659
|
+
TheLog.debug("Error #{error} returned")
|
|
660
|
+
persistent_data.outstanding.delete(df)
|
|
661
|
+
if (response!="cancelling")
|
|
662
|
+
|
|
663
|
+
if (error.kind_of?(ResolvTimeout))
|
|
664
|
+
# - if it was a timeout, then check which number it was, and how many retries are expected on that server
|
|
665
|
+
# - if it was the last retry, on the last server, then return a timeout to the client (and clean up)
|
|
666
|
+
# - otherwise, continue
|
|
667
|
+
# Do we have any more packets to send to this resolver?
|
|
668
|
+
if (persistent_data.outstanding.empty? && persistent_data.to_send==0)
|
|
669
|
+
TheLog.debug("Sending timeout to client")
|
|
670
|
+
return_to_client(persistent_data.deferrable, client_queue, client_query_id, response, error)
|
|
671
|
+
end
|
|
672
|
+
elsif (error.kind_of?NXDomain)
|
|
673
|
+
# - if it was an NXDomain, then return that to the client, and stop all new queries (and clean up)
|
|
674
|
+
TheLog.debug("NXDomain - returning to client")
|
|
675
|
+
cancel_queries(persistent_data)
|
|
676
|
+
return_to_client(persistent_data.deferrable, client_queue, client_query_id, response, error)
|
|
677
|
+
elsif (error.kind_of?FormErr)
|
|
678
|
+
# - if it was a FormErr, then return that to the client, and stop all new queries (and clean up)
|
|
679
|
+
TheLog.debug("FormErr - returning to client")
|
|
680
|
+
cancel_queries(persistent_data)
|
|
681
|
+
return_to_client(persistent_data.deferrable, client_queue, client_query_id, response, error)
|
|
682
|
+
else
|
|
683
|
+
# - if it was any other error, then remove that server from the list for that query
|
|
684
|
+
# If a Too Many Open Files error, then don't remove, but let retry work.
|
|
685
|
+
if (!(error.to_s=~/Errno::EMFILE/))
|
|
686
|
+
remove_server(single_resolver, persistent_data)
|
|
687
|
+
TheLog.debug("Removing #{single_resolver.server} from resolver list for this query")
|
|
688
|
+
else
|
|
689
|
+
TheLog.debug("NOT Removing #{single_resolver.server} due to Errno::EMFILE")
|
|
690
|
+
end
|
|
691
|
+
# - if it was the last server, then return an error to the client (and clean up)
|
|
692
|
+
if (persistent_data.outstanding.empty? && persistent_data.to_send==0)
|
|
693
|
+
# if (outstanding.empty?)
|
|
694
|
+
TheLog.debug("Sending error to client")
|
|
695
|
+
return_to_client(persistent_data.deferrable, client_queue, client_query_id, response, error)
|
|
696
|
+
end
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
}
|
|
700
|
+
return df
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
def remove_server(server, persistent_data)
|
|
704
|
+
# Go through persistent_data.timeouts and check all the values for that resolver
|
|
705
|
+
persistent_data.timeouts.each do |key, value|
|
|
706
|
+
if (value[0] == server)
|
|
707
|
+
# Remove the server from the list
|
|
708
|
+
persistent_data.timer_procs.delete(key)
|
|
709
|
+
persistent_data.timer_keys_sorted.delete(key)
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
def cancel_queries(persistent_data)
|
|
715
|
+
TheLog.debug("Cancelling EM queries")
|
|
716
|
+
persistent_data.outstanding.each do |df|
|
|
717
|
+
df.set_deferred_status :failed, "cancelling", "cancelling"
|
|
718
|
+
end
|
|
719
|
+
# Cancel the next tick
|
|
720
|
+
persistent_data.finish = true
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
def return_to_client(deferrable, client_queue, client_query_id, answer, error)
|
|
724
|
+
if (client_queue)
|
|
725
|
+
client_queue.push([client_query_id, answer, error])
|
|
726
|
+
end
|
|
727
|
+
# We call set_defered_status when done
|
|
728
|
+
if (error != nil)
|
|
729
|
+
deferrable.set_deferred_status :failed, answer, error
|
|
730
|
+
else
|
|
731
|
+
deferrable.set_deferred_status :succeeded, answer
|
|
732
|
+
end
|
|
733
|
+
EventMachineInterface::stop_em_for_resolver(self)
|
|
734
|
+
end
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
# This class implements the I/O using pure Ruby, with no dependencies.
|
|
738
|
+
class ResolverRuby #:nodoc: all
|
|
739
|
+
def initialize(parent)
|
|
740
|
+
reset_attributes
|
|
741
|
+
@parent=parent
|
|
742
|
+
end
|
|
743
|
+
def reset_attributes #:nodoc: all
|
|
744
|
+
# data structures
|
|
745
|
+
@mutex=Mutex.new
|
|
746
|
+
@query_list = {}
|
|
747
|
+
@timeouts = {}
|
|
748
|
+
end
|
|
749
|
+
def send_async(*args) # msg, client_queue, client_query_id=nil)
|
|
750
|
+
msg=args[0]
|
|
751
|
+
client_queue=nil
|
|
752
|
+
client_query_id=nil
|
|
753
|
+
client_queue=args[1]
|
|
754
|
+
if (args.length > 2)
|
|
755
|
+
client_query_id = args[2]
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
# This is the whole point of the Resolver class.
|
|
760
|
+
# We want to use multiple SingleResolvers to run a query.
|
|
761
|
+
# So we kick off a system with select_thread where we send
|
|
762
|
+
# a query with a queue, but log ourselves as observers for that
|
|
763
|
+
# queue. When a new response is pushed on to the queue, then the
|
|
764
|
+
# select thread will call this class' handler method IN THAT THREAD.
|
|
765
|
+
# When the final response is known, this class then sticks it in
|
|
766
|
+
# to the client queue.
|
|
767
|
+
|
|
768
|
+
q = Queue.new
|
|
769
|
+
if (client_query_id==nil)
|
|
770
|
+
client_query_id = Time.now + rand(10000)
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
if (!client_queue.kind_of?Queue)
|
|
774
|
+
TheLog.error("Wrong type for client_queue in Resolver#send_async")
|
|
775
|
+
client_queue.push([client_query_id, ArgumentError.new("Wrong type of client_queue passed to Dnsruby::Resolver#send_async - should have been Queue, was #{client_queue.class}")])
|
|
776
|
+
return
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
if (!msg.kind_of?Message)
|
|
780
|
+
TheLog.error("Wrong type for msg in Resolver#send_async")
|
|
781
|
+
client_queue.push([client_query_id, ArgumentError.new("Wrong type of msg passed to Dnsruby::Resolver#send_async - should have been Message, was #{msg.class}")])
|
|
782
|
+
return
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
tick_needed=false
|
|
786
|
+
# add to our data structures
|
|
787
|
+
@mutex.synchronize{
|
|
788
|
+
tick_needed = true if @query_list.empty?
|
|
789
|
+
if (@query_list.has_key?client_query_id)
|
|
790
|
+
TheLog.error("Duplicate query id requested (#{client_query_id}")
|
|
791
|
+
client_queue.push([client_query_id, ArgumentError.new("Client query ID already in use")])
|
|
792
|
+
return
|
|
793
|
+
end
|
|
794
|
+
outstanding = []
|
|
795
|
+
@query_list[client_query_id]=[msg, client_queue, q, outstanding]
|
|
796
|
+
|
|
797
|
+
query_timeout = Time.now+@parent.query_timeout
|
|
798
|
+
if (@parent.query_timeout == 0)
|
|
799
|
+
query_timeout = Time.now+31536000 # a year from now
|
|
800
|
+
end
|
|
801
|
+
@timeouts[client_query_id]=[query_timeout, generate_timeouts()]
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
# Now do querying stuff using SingleResolver
|
|
805
|
+
# All this will be handled by the tick method (if we have 0 as the first timeout)
|
|
806
|
+
st = SelectThread.instance
|
|
807
|
+
st.add_observer(q, self)
|
|
808
|
+
tick if tick_needed
|
|
809
|
+
return client_query_id
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
def generate_timeouts() #:nodoc: all
|
|
813
|
+
# Create the timeouts for the query from the retry_times and retry_delay attributes.
|
|
814
|
+
# These are created at the same time in case the parameters change during the life of the query.
|
|
815
|
+
#
|
|
816
|
+
# These should be absolute, rather than relative
|
|
817
|
+
# The first value should be Time.now[
|
|
818
|
+
time_now = Time.now
|
|
819
|
+
timeouts=@parent.generate_timeouts(time_now)
|
|
820
|
+
return timeouts
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
# Close the Resolver. Unfinished queries are terminated with OtherResolvError.
|
|
824
|
+
def close
|
|
825
|
+
@mutex.synchronize {
|
|
826
|
+
@query_list.each do |client_query_id, values|
|
|
827
|
+
msg, client_queue, q, outstanding = values
|
|
828
|
+
send_result_and_close(client_queue, client_query_id, q, nil, OtherResolvError.new("Resolver closing!"))
|
|
829
|
+
end
|
|
830
|
+
}
|
|
831
|
+
end
|
|
832
|
+
|
|
833
|
+
# MUST BE CALLED IN A SYNCHRONIZED BLOCK!
|
|
834
|
+
#
|
|
835
|
+
# Send the result back to the client, and close the socket for that query by removing
|
|
836
|
+
# the query from the select thread.
|
|
837
|
+
def send_result_and_close(client_queue, client_query_id, select_queue, msg, error) #:nodoc: all
|
|
838
|
+
# We might still get some callbacks, which we should ignore
|
|
839
|
+
st = SelectThread.instance
|
|
840
|
+
st.remove_observer(select_queue, self)
|
|
841
|
+
# @mutex.synchronize{
|
|
842
|
+
# Remove the query from all of the data structures
|
|
843
|
+
@timeouts.delete(client_query_id)
|
|
844
|
+
@query_list.delete(client_query_id)
|
|
845
|
+
# }
|
|
846
|
+
# Return the response to the client
|
|
847
|
+
client_queue.push([client_query_id, msg, error])
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
# This method is called ten times a second from the select loop, in the select thread.
|
|
851
|
+
# It should arguably be called from another worker thread...
|
|
852
|
+
# Each tick, we check if any timeouts have occurred. If so, we take the appropriate action :
|
|
853
|
+
# Return a timeout to the client, or send a new query
|
|
854
|
+
def tick #:nodoc: all
|
|
855
|
+
# Handle the tick
|
|
856
|
+
# Do we have any retries due to be sent yet?
|
|
857
|
+
@mutex.synchronize{
|
|
858
|
+
time_now = Time.now
|
|
859
|
+
@timeouts.keys.each do |client_query_id|
|
|
860
|
+
msg, client_queue, select_queue, outstanding = @query_list[client_query_id]
|
|
861
|
+
query_timeout, timeouts = @timeouts[client_query_id]
|
|
862
|
+
if (query_timeout < Time.now)
|
|
863
|
+
#Time the query out
|
|
864
|
+
send_result_and_close(client_queue, client_query_id, select_queue, nil, ResolvTimeout.new("Query timed out"))
|
|
865
|
+
next
|
|
866
|
+
end
|
|
867
|
+
timeouts_done = []
|
|
868
|
+
timeouts.keys.sort.each do |timeout|
|
|
869
|
+
if (timeout < time_now)
|
|
870
|
+
# Send the next query
|
|
871
|
+
res, retry_count = timeouts[timeout]
|
|
872
|
+
id = [res, msg, client_query_id, retry_count]
|
|
873
|
+
TheLog.debug("Sending msg to #{res.server}")
|
|
874
|
+
# We should keep a list of the queries which are outstanding
|
|
875
|
+
outstanding.push(id)
|
|
876
|
+
timeouts_done.push(timeout)
|
|
877
|
+
timeouts.delete(timeout)
|
|
878
|
+
res.send_async(msg, select_queue, id)
|
|
879
|
+
else
|
|
880
|
+
break
|
|
881
|
+
end
|
|
882
|
+
end
|
|
883
|
+
timeouts_done.each do |t|
|
|
884
|
+
timeouts.delete(t)
|
|
885
|
+
end
|
|
886
|
+
end
|
|
887
|
+
}
|
|
888
|
+
end
|
|
889
|
+
|
|
890
|
+
# This method is called by the SelectThread (in the select thread) when the queue has a new item on it.
|
|
891
|
+
# The queue interface is used to separate producer/consumer threads, but we're using it here in one thread.
|
|
892
|
+
# It's probably a good idea to create a new "worker thread" to take items from the select thread queue and
|
|
893
|
+
# call this method in the worker thread.
|
|
894
|
+
#
|
|
895
|
+
# Time to process a new queue event.
|
|
896
|
+
def handle_queue_event(queue, id) #:nodoc: all
|
|
897
|
+
# If we get a callback for an ID we don't know about, don't worry -
|
|
898
|
+
# just ignore it. It may be for a query we've already completed.
|
|
899
|
+
#
|
|
900
|
+
# So, get the next response from the queue (presuming there is one!)
|
|
901
|
+
#
|
|
902
|
+
# @TODO@ Tick could poll the queue and then call this method if needed - no need for observer interface.
|
|
903
|
+
# @TODO@ Currently, tick and handle_queue_event called from select_thread - could have thread chuck events in to tick_queue. But then, clients would have to call in on other thread!
|
|
904
|
+
#
|
|
905
|
+
if (queue.empty?)
|
|
906
|
+
TheLog.fatal("Queue empty in handle_queue_event!")
|
|
907
|
+
raise RuntimeError.new("Severe internal error - Queue empty in handle_queue_event")
|
|
908
|
+
end
|
|
909
|
+
event_id, response, error = queue.pop
|
|
910
|
+
# We should remove this packet from the list of outstanding packets for this query
|
|
911
|
+
resolver, msg, client_query_id, retry_count = id
|
|
912
|
+
if (id != event_id)
|
|
913
|
+
TheLog.error("Serious internal error!! #{id} expected, #{event_id} received")
|
|
914
|
+
raise RuntimeError.new("Serious internal error!! #{id} expected, #{event_id} received")
|
|
915
|
+
end
|
|
916
|
+
@mutex.synchronize{
|
|
917
|
+
if (@query_list[client_query_id]==nil)
|
|
918
|
+
TheLog.debug("Ignoring response for dead query")
|
|
919
|
+
return
|
|
920
|
+
end
|
|
921
|
+
msg, client_queue, select_queue, outstanding = @query_list[client_query_id]
|
|
922
|
+
if (!outstanding.include?id)
|
|
923
|
+
TheLog.error("Query id not on outstanding list! #{outstanding.length} items. #{id} not on #{outstanding}")
|
|
924
|
+
raise RuntimeError.new("Query id not on outstanding!")
|
|
925
|
+
end
|
|
926
|
+
outstanding.delete(id)
|
|
927
|
+
}
|
|
928
|
+
# if (event.kind_of?(Exception))
|
|
929
|
+
if (error != nil)
|
|
930
|
+
handle_error_response(queue, event_id, error, response)
|
|
931
|
+
else # if (event.kind_of?(Message))
|
|
932
|
+
handle_response(queue, event_id, response)
|
|
933
|
+
# else
|
|
934
|
+
# TheLog.error("Random object #{event.class} returned through queue to Resolver")
|
|
935
|
+
end
|
|
936
|
+
end
|
|
937
|
+
|
|
938
|
+
def handle_error_response(select_queue, query_id, error, response) #:nodoc: all
|
|
939
|
+
#Handle an error
|
|
940
|
+
@mutex.synchronize{
|
|
941
|
+
TheLog.debug("handling error #{error.class}, #{error}")
|
|
942
|
+
# Check what sort of error it was :
|
|
943
|
+
resolver, msg, client_query_id, retry_count = query_id
|
|
944
|
+
msg, client_queue, select_queue, outstanding = @query_list[client_query_id]
|
|
945
|
+
if (error.kind_of?(ResolvTimeout))
|
|
946
|
+
# - if it was a timeout, then check which number it was, and how many retries are expected on that server
|
|
947
|
+
# - if it was the last retry, on the last server, then return a timeout to the client (and clean up)
|
|
948
|
+
# - otherwise, continue
|
|
949
|
+
# Do we have any more packets to send to this resolver?
|
|
950
|
+
timeouts = @timeouts[client_query_id]
|
|
951
|
+
if (outstanding.empty? && timeouts[1].values.empty?)
|
|
952
|
+
TheLog.debug("Sending timeout to client")
|
|
953
|
+
send_result_and_close(client_queue, client_query_id, select_queue, response, error)
|
|
954
|
+
end
|
|
955
|
+
elsif (error.kind_of?NXDomain)
|
|
956
|
+
# - if it was an NXDomain, then return that to the client, and stop all new queries (and clean up)
|
|
957
|
+
send_result_and_close(client_queue, client_query_id, select_queue, response, error)
|
|
958
|
+
else
|
|
959
|
+
# - if it was any other error, then remove that server from the list for that query
|
|
960
|
+
# If a Too Many Open Files error, then don't remove, but let retry work.
|
|
961
|
+
timeouts = @timeouts[client_query_id]
|
|
962
|
+
if (!(error.to_s=~/Errno::EMFILE/))
|
|
963
|
+
TheLog.debug("Removing #{resolver.server} from resolver list for this query")
|
|
964
|
+
timeouts[1].each do |key, value|
|
|
965
|
+
res = value[0]
|
|
966
|
+
if (res == resolver)
|
|
967
|
+
timeouts[1].delete(key)
|
|
968
|
+
end
|
|
969
|
+
end
|
|
970
|
+
else
|
|
971
|
+
TheLog.debug("NOT Removing #{resolver.server} due to Errno::EMFILE")
|
|
972
|
+
end
|
|
973
|
+
# - if it was the last server, then return an error to the client (and clean up)
|
|
974
|
+
if (outstanding.empty? && timeouts[1].values.empty?)
|
|
975
|
+
# if (outstanding.empty?)
|
|
976
|
+
TheLog.debug("Sending error to client")
|
|
977
|
+
send_result_and_close(client_queue, client_query_id, select_queue, response, error)
|
|
978
|
+
end
|
|
979
|
+
end
|
|
980
|
+
#@TODO@ If we're still sending packets for this query, but none are outstanding, then
|
|
981
|
+
#jumpstart the next query?
|
|
982
|
+
}
|
|
983
|
+
end
|
|
984
|
+
|
|
985
|
+
def handle_response(select_queue, query_id, response) #:nodoc: all
|
|
986
|
+
# Handle a good response
|
|
987
|
+
TheLog.debug("Handling good response")
|
|
988
|
+
resolver, msg, client_query_id, retry_count = query_id
|
|
989
|
+
@mutex.synchronize{
|
|
990
|
+
query, client_queue, s_queue, outstanding = @query_list[client_query_id]
|
|
991
|
+
if (s_queue != select_queue)
|
|
992
|
+
TheLog.error("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
|
|
993
|
+
raise RuntimeError.new("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
|
|
994
|
+
end
|
|
995
|
+
send_result_and_close(client_queue, client_query_id, select_queue, response, nil)
|
|
996
|
+
}
|
|
997
|
+
end
|
|
998
|
+
end
|
|
999
|
+
end
|