Compare commits

...
Author SHA1 Message Date
Wouter Wijngaards e116e5b5de Created 1.1.0 release tag.
git-svn-id: file:///svn/unbound/tags/release-1.1.0@1351 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-14 06:28:14 +00:00
Wouter Wijngaards 9fa2964d95 review comments.
git-svn-id: file:///svn/unbound/trunk@1350 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-13 13:45:27 +00:00
Wouter Wijngaards d0eb5cad47 silence host is down error, which the resolver operator cannot do anything
about.  Verbosity 2 shows it for debugging of course.



git-svn-id: file:///svn/unbound/trunk@1349 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-13 13:24:36 +00:00
Wouter Wijngaards e9d742c16d doc update for plans and done items
git-svn-id: file:///svn/unbound/trunk@1348 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-13 11:50:56 +00:00
Wouter Wijngaards 2547a0a9bb neater comments
git-svn-id: file:///svn/unbound/trunk@1347 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-13 10:19:14 +00:00
Wouter Wijngaards 3bdd807610 ldns version check added.
git-svn-id: file:///svn/unbound/trunk@1346 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-13 09:26:02 +00:00
Wouter Wijngaards 7fc590cda5 Fedora package files for 1.1.0, by Paul Wouters.
git-svn-id: file:///svn/unbound/trunk@1345 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-13 08:45:20 +00:00
Wouter Wijngaards 9525cdb01b add unbound-control manpage to makedist replace list.
git-svn-id: file:///svn/unbound/trunk@1344 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-12 09:20:35 +00:00
Wouter Wijngaards 21a64ef247 fixup wrap around for very large mem usage on printout.
git-svn-id: file:///svn/unbound/trunk@1343 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-11 13:47:25 +00:00
Wouter Wijngaards 5cfd778608 - unit test for negative cache, stress tests the refcounting.
- fix for refcounting error that could cause fptr_wlist fatal exit
	  in the negative cache rbtree (upcoming 1.1 feature). (Thanks to 
	  Attila Nagy for testing).
	- nicer comments in cachedump about failed RR to string conversion.


git-svn-id: file:///svn/unbound/trunk@1342 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-11 11:54:06 +00:00
Wouter Wijngaards 3973cd8f26 Fixup getaddrinfo compat.
git-svn-id: file:///svn/unbound/trunk@1341 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-10 08:04:22 +00:00
Wouter Wijngaards c12bf8692c used autoconf 2.61
git-svn-id: file:///svn/unbound/trunk@1340 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-08 10:49:16 +00:00
Wouter Wijngaards 327e1f4b10 Fixup eee build.
git-svn-id: file:///svn/unbound/trunk@1339 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-08 10:05:39 +00:00
Wouter Wijngaards 847107403f detect nonblocking broken.
git-svn-id: file:///svn/unbound/trunk@1338 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-07 14:28:06 +00:00
Wouter Wijngaards d469081eda Fixup warning on FreeBSD (hopefully).
git-svn-id: file:///svn/unbound/trunk@1337 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-07 09:35:25 +00:00
Wouter Wijngaards 345e5e82d3 Fix bug #217
git-svn-id: file:///svn/unbound/trunk@1336 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-07 09:24:39 +00:00
Wouter Wijngaards c6541a2def iana portlist updated.
doxygen comments better.



git-svn-id: file:///svn/unbound/trunk@1335 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-06 11:12:25 +00:00
Wouter Wijngaards 3708097870 Fixup decompression for private-name checks.
git-svn-id: file:///svn/unbound/trunk@1334 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-06 10:59:31 +00:00
Wouter Wijngaards 69af0f10e9 Elusive bad-file-descriptor error caught.
git-svn-id: file:///svn/unbound/trunk@1333 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-05 14:56:49 +00:00
Wouter Wijngaards 747dc4e3ab please lint.
git-svn-id: file:///svn/unbound/trunk@1332 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-05 10:50:43 +00:00
Wouter Wijngaards 6c7416128c fixup memleaks.
git-svn-id: file:///svn/unbound/trunk@1331 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-05 10:38:22 +00:00
Wouter Wijngaards 515b892024 write-strings warnings fixed.
git-svn-id: file:///svn/unbound/trunk@1330 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-04 14:53:50 +00:00
Wouter Wijngaards 3af6fd7980 Key algo RSASHA512.
git-svn-id: file:///svn/unbound/trunk@1329 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-04 07:50:38 +00:00
Wouter Wijngaards 0d01be50bc detection of sha256 and sha512 by testing if functionality was compiled
into openssl.


git-svn-id: file:///svn/unbound/trunk@1328 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-03 16:06:12 +00:00
Wouter Wijngaards 8a32f9003b - RSASHA256_NSEC3 and RSASHA512_NSEC3 algos are supported.
- updated ldns tarball (with those algos).



git-svn-id: file:///svn/unbound/trunk@1327 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-03 15:42:07 +00:00
Wouter Wijngaards 7bf176eeba Fixup static linking with libssl.
git-svn-id: file:///svn/unbound/trunk@1326 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-03 15:09:37 +00:00
Wouter Wijngaards c6af78bfd3 portlist updated.
git-svn-id: file:///svn/unbound/trunk@1325 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-03 14:47:50 +00:00
Wouter Wijngaards 8eb31df3d0 Created configure with autoconf 2.61
git-svn-id: file:///svn/unbound/trunk@1324 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-03 14:40:47 +00:00
Wouter Wijngaards 7176710b7f Fixup b32 compat for Mac OSX linker.
git-svn-id: file:///svn/unbound/trunk@1323 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-11-03 14:38:03 +00:00
Wouter Wijngaards 1b1694a959 More verbose on signer name error.
git-svn-id: file:///svn/unbound/trunk@1322 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-23 10:54:03 +00:00
Wouter Wijngaards 6cebdd2baf unwanted reply threshold like in the draft.
git-svn-id: file:///svn/unbound/trunk@1321 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-22 14:36:46 +00:00
Wouter Wijngaards 60d8b26ba1 root-hints check automated.
git-svn-id: file:///svn/unbound/trunk@1320 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-22 13:40:21 +00:00
Wouter Wijngaards 83a017d3d1 stub-prime option.
git-svn-id: file:///svn/unbound/trunk@1319 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-22 12:01:40 +00:00
Wouter Wijngaards 18b09fe9c1 ldns update.
iana update.



git-svn-id: file:///svn/unbound/trunk@1318 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-22 09:05:29 +00:00
Wouter Wijngaards f59b1a96b1 Fixup Cflags detection in configure.
git-svn-id: file:///svn/unbound/trunk@1317 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-22 07:40:37 +00:00
Wouter Wijngaards 8fb41f5c00 ported 1.1 to windows.
git-svn-id: file:///svn/unbound/trunk@1316 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-21 13:00:07 +00:00
Wouter Wijngaards 64959c8097 fixup update anchors to sort keys.
git-svn-id: file:///svn/unbound/trunk@1315 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-21 09:02:34 +00:00
Wouter Wijngaards 2a6846f30c fixup unbound control compilation on windows.
git-svn-id: file:///svn/unbound/trunk@1314 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-20 15:41:12 +00:00
Wouter Wijngaards 00f301d35f Ask more nameservers if choice is limited.
Lowered bogus-ttl to help validation-failure recovery times.



git-svn-id: file:///svn/unbound/trunk@1313 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-20 14:24:35 +00:00
Wouter Wijngaards f4ad52dffd Do not query bogus name servers.
git-svn-id: file:///svn/unbound/trunk@1312 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-20 13:51:47 +00:00
Wouter Wijngaards a50b796a40 iana portlist updated
git-svn-id: file:///svn/unbound/trunk@1311 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-20 09:28:09 +00:00
Wouter Wijngaards e5c52a7032 less log
git-svn-id: file:///svn/unbound/trunk@1310 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-20 09:11:17 +00:00
Wouter Wijngaards a0d9d48d8f root prime validation
git-svn-id: file:///svn/unbound/trunk@1309 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-17 15:07:28 +00:00
Wouter Wijngaards 1275afa125 please ranlib
git-svn-id: file:///svn/unbound/trunk@1308 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-17 09:19:37 +00:00
Wouter Wijngaards 371b9f08ef typefix
git-svn-id: file:///svn/unbound/trunk@1307 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-17 09:10:24 +00:00
Wouter Wijngaards 265c199445 Fixup negative TTLs Attila Nagy has reported.
git-svn-id: file:///svn/unbound/trunk@1306 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-16 13:12:32 +00:00
Wouter Wijngaards bf659c8362 Referral path checking, for spoof mitigation, improved.
git-svn-id: file:///svn/unbound/trunk@1305 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-15 13:32:49 +00:00
Wouter Wijngaards 3dc4715109 doc updates
git-svn-id: file:///svn/unbound/trunk@1304 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-15 11:16:54 +00:00
Wouter Wijngaards b3dd2b5b98 more portable check for make/gmake in iana portlist update checker.
git-svn-id: file:///svn/unbound/trunk@1303 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-14 15:15:55 +00:00
Wouter Wijngaards 5a1e91af35 test fix.
git-svn-id: file:///svn/unbound/trunk@1302 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-14 09:20:10 +00:00
Wouter Wijngaards a21136cf66 fwd_three updated.
git-svn-id: file:///svn/unbound/trunk@1301 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-14 09:13:17 +00:00
Wouter Wijngaards ebb63767cd update ldns src tarball.
git-svn-id: file:///svn/unbound/trunk@1300 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-14 09:06:15 +00:00
Wouter Wijngaards 07efa0f4ea Fixup stub and ldns.
git-svn-id: file:///svn/unbound/trunk@1299 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-14 09:05:17 +00:00
Wouter Wijngaards 1b8d87e202 stub udp update.
git-svn-id: file:///svn/unbound/trunk@1298 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-14 08:33:15 +00:00
Wouter Wijngaards 1e37e00a27 Change test to be more reliable.
git-svn-id: file:///svn/unbound/trunk@1297 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-14 08:30:30 +00:00
Wouter Wijngaards 628c970ecc ldns_update
git-svn-id: file:///svn/unbound/trunk@1296 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-13 14:23:21 +00:00
Wouter Wijngaards f59885053a iana portlist update
git-svn-id: file:///svn/unbound/trunk@1295 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-13 09:25:03 +00:00
Wouter Wijngaards dbaa5194a6 Recursion lame is detected and last resort is used to resolve.
git-svn-id: file:///svn/unbound/trunk@1294 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-13 09:11:42 +00:00
Wouter Wijngaards 5b7a514119 fixup tests
git-svn-id: file:///svn/unbound/trunk@1293 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-10 08:04:38 +00:00
Wouter Wijngaards b6696c1342 nsec3 negative cache works.
git-svn-id: file:///svn/unbound/trunk@1292 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-09 15:06:35 +00:00
Wouter Wijngaards bfb4e20f43 max iterations for neg cache.
git-svn-id: file:///svn/unbound/trunk@1291 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-09 13:06:06 +00:00
Wouter Wijngaards c73c662fce work on nsec3 negative cache for qtype DS .
git-svn-id: file:///svn/unbound/trunk@1290 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-08 14:42:46 +00:00
Wouter Wijngaards 45afaf3e08 nsec negative DS.
git-svn-id: file:///svn/unbound/trunk@1289 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-08 10:04:27 +00:00
Wouter Wijngaards c04451cc58 working on negative DS
git-svn-id: file:///svn/unbound/trunk@1288 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-07 15:22:32 +00:00
Wouter Wijngaards 6d721dd6bd another test package
git-svn-id: file:///svn/unbound/trunk@1287 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-07 07:55:36 +00:00
Wouter Wijngaards 408a0cfd31 requirements update with design decisions.
git-svn-id: file:///svn/unbound/trunk@1286 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-06 15:07:27 +00:00
Wouter Wijngaards 939fabd809 0x20 fallback code.
git-svn-id: file:///svn/unbound/trunk@1285 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-06 14:46:22 +00:00
Wouter Wijngaards 3ddabf26f3 please_lint
git-svn-id: file:///svn/unbound/trunk@1284 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-06 10:38:07 +00:00
Wouter Wijngaards e2277ca9d1 please_lint
git-svn-id: file:///svn/unbound/trunk@1283 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-06 09:42:31 +00:00
Wouter Wijngaards 351ef6e252 Option for DOS protection on slower links.
git-svn-id: file:///svn/unbound/trunk@1282 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-06 09:28:50 +00:00
Wouter Wijngaards 620c85ee32 missing test file
git-svn-id: file:///svn/unbound/trunk@1281 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-02 09:39:02 +00:00
Wouter Wijngaards 7d242d400f Easier update script.
git-svn-id: file:///svn/unbound/trunk@1280 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-02 09:22:02 +00:00
Wouter Wijngaards cb659ab13b fixup SHA256 algorithm set routine
git-svn-id: file:///svn/unbound/trunk@1279 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-02 09:05:20 +00:00
Wouter Wijngaards 74909b66b4 fixup pidfile unlink.
git-svn-id: file:///svn/unbound/trunk@1278 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-10-02 08:47:21 +00:00
Wouter Wijngaards 896e4fea2a local data PTR shorthand.
git-svn-id: file:///svn/unbound/trunk@1277 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-30 15:04:32 +00:00
Wouter Wijngaards 3385bcc255 Stub on same host works
git-svn-id: file:///svn/unbound/trunk@1276 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-30 13:40:44 +00:00
Wouter Wijngaards 5e1193f19d SHA256 support.
git-svn-id: file:///svn/unbound/trunk@1275 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-30 13:06:07 +00:00
Wouter Wijngaards 2e5c620f2c doxygen, detect SHA256 support for test.
git-svn-id: file:///svn/unbound/trunk@1274 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-30 11:35:48 +00:00
Wouter Wijngaards 13a68aac89 Fix for SHA256 DS downgrade. And test of resistance.
git-svn-id: file:///svn/unbound/trunk@1273 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-30 10:42:02 +00:00
Wouter Wijngaards d4fadf55a8 EDNS fallback when timeout and multiple query rtt backoff.
git-svn-id: file:///svn/unbound/trunk@1272 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-29 14:50:35 +00:00
Wouter Wijngaards a2b261f8b2 portlist updated.
git-svn-id: file:///svn/unbound/trunk@1271 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-26 13:48:00 +00:00
Wouter Wijngaards 556d5407e2 remote control tests.
git-svn-id: file:///svn/unbound/trunk@1270 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-26 13:02:34 +00:00
Wouter Wijngaards 66dcc95a78 plan update.
git-svn-id: file:///svn/unbound/trunk@1269 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-23 14:10:49 +00:00
Wouter Wijngaards 16734a0e04 flush data from cache.
git-svn-id: file:///svn/unbound/trunk@1268 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-23 14:07:02 +00:00
Wouter Wijngaards 91138fc32a doxygen fixup.
git-svn-id: file:///svn/unbound/trunk@1267 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-23 11:47:09 +00:00
Wouter Wijngaards cfceb6487d lookup delegation from cache and printout.
git-svn-id: file:///svn/unbound/trunk@1266 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-23 10:55:36 +00:00
Wouter Wijngaards de0f903d37 load from cache works
git-svn-id: file:///svn/unbound/trunk@1265 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-23 09:23:38 +00:00
Wouter Wijngaards 67bec33e20 cache dump and load files
git-svn-id: file:///svn/unbound/trunk@1264 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-22 18:05:22 +00:00
Wouter Wijngaards 46e50e861f dump and load cache.
git-svn-id: file:///svn/unbound/trunk@1263 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-22 15:20:18 +00:00
Wouter Wijngaards b479dfd33d ldns update, test update.
git-svn-id: file:///svn/unbound/trunk@1262 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-19 15:24:30 +00:00
Wouter Wijngaards cf4b56d883 add remove local data and local zone with remote control
(ldns-testpkts sync with ldns trunk).


git-svn-id: file:///svn/unbound/trunk@1261 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-19 14:49:29 +00:00
Wouter Wijngaards c77be35670 qps for histogram.
git-svn-id: file:///svn/unbound/trunk@1260 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 14:55:13 +00:00
Wouter Wijngaards 763431c059 cache hits in histogram.
git-svn-id: file:///svn/unbound/trunk@1259 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 14:45:15 +00:00
Wouter Wijngaards 089261572a histogram support for stats.
git-svn-id: file:///svn/unbound/trunk@1258 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 14:37:20 +00:00
Wouter Wijngaards 055ebe3d0b better docs.
git-svn-id: file:///svn/unbound/trunk@1257 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 12:11:20 +00:00
Wouter Wijngaards 33bc592a83 spelling more.
git-svn-id: file:///svn/unbound/trunk@1256 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 11:54:04 +00:00
Wouter Wijngaards 076fb3bc53 spelling.
git-svn-id: file:///svn/unbound/trunk@1255 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 11:52:43 +00:00
Wouter Wijngaards 10316f091f more locking.
git-svn-id: file:///svn/unbound/trunk@1254 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 11:51:09 +00:00
Wouter Wijngaards a14c4fa6e5 locking for munin
git-svn-id: file:///svn/unbound/trunk@1253 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 11:49:09 +00:00
Wouter Wijngaards 9d6df1964b documentation.
git-svn-id: file:///svn/unbound/trunk@1252 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 09:44:37 +00:00
Wouter Wijngaards 897bb0c0e6 fixup test.
git-svn-id: file:///svn/unbound/trunk@1251 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 08:53:50 +00:00
Wouter Wijngaards 50b728aa08 upgrade lee value to working. nicer desc in munin plugin.
git-svn-id: file:///svn/unbound/trunk@1250 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 08:47:04 +00:00
Wouter Wijngaards 25c1232d22 nice names for high query types.
git-svn-id: file:///svn/unbound/trunk@1249 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 08:38:53 +00:00
Wouter Wijngaards 5814e0f5b6 better munin, iana update
git-svn-id: file:///svn/unbound/trunk@1248 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 08:13:41 +00:00
Wouter Wijngaards 3ca6d2e5a2 Fixup error in time calculation.
git-svn-id: file:///svn/unbound/trunk@1247 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-18 07:55:01 +00:00
Wouter Wijngaards d4151219a2 print uptime always.
git-svn-id: file:///svn/unbound/trunk@1246 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-17 16:45:32 +00:00
Wouter Wijngaards e0d36e6561 munin plugin first version.
git-svn-id: file:///svn/unbound/trunk@1245 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-17 15:34:48 +00:00
Wouter Wijngaards 7a1ba7785d rcode stat printout fixed.
git-svn-id: file:///svn/unbound/trunk@1244 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-17 11:33:40 +00:00
Wouter Wijngaards 370236cb65 testpkts const fixup.
git-svn-id: file:///svn/unbound/trunk@1243 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-17 08:16:17 +00:00
Wouter Wijngaards 91972c229d gen configure on linux. ldns tarball updated.
git-svn-id: file:///svn/unbound/trunk@1242 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-17 08:06:13 +00:00
Wouter Wijngaards 144978d633 b32 compat stuff.
git-svn-id: file:///svn/unbound/trunk@1241 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-17 08:00:14 +00:00
Wouter Wijngaards 62fc91f7f1 threadsafe rrset counter.
git-svn-id: file:///svn/unbound/trunk@1240 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-17 07:13:31 +00:00
Wouter Wijngaards 636f742ef0 extended statistics.
git-svn-id: file:///svn/unbound/trunk@1239 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-16 14:08:38 +00:00
Wouter Wijngaards f0b77ed022 extended stats option.
git-svn-id: file:///svn/unbound/trunk@1238 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-16 09:08:45 +00:00
Wouter Wijngaards 0b3c133dd3 verbosity and stats control.
git-svn-id: file:///svn/unbound/trunk@1237 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-15 14:19:41 +00:00
Wouter Wijngaards 757eff88f5 Test, exit value.
git-svn-id: file:///svn/unbound/trunk@1236 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-15 10:36:13 +00:00
Wouter Wijngaards 3137c88a43 start, stop, reload commands.
git-svn-id: file:///svn/unbound/trunk@1235 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-15 08:35:45 +00:00
Wouter Wijngaards 08e0563483 remote setup.
git-svn-id: file:///svn/unbound/trunk@1234 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-12 13:01:20 +00:00
Wouter Wijngaards 9157324788 proto spec.
git-svn-id: file:///svn/unbound/trunk@1233 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-12 12:09:00 +00:00
Wouter Wijngaards f918da13d2 neater.
git-svn-id: file:///svn/unbound/trunk@1232 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-11 14:56:46 +00:00
Wouter Wijngaards e8e30550df fixup.
git-svn-id: file:///svn/unbound/trunk@1231 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-11 14:55:50 +00:00
Wouter Wijngaards 5dbc854a48 Install of unbound-control-setup.
git-svn-id: file:///svn/unbound/trunk@1230 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-11 14:30:55 +00:00
Wouter Wijngaards af57e5163d control channel security.
git-svn-id: file:///svn/unbound/trunk@1229 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-11 14:14:12 +00:00
Wouter Wijngaards 56b91454ba doxygen fix.
git-svn-id: file:///svn/unbound/trunk@1228 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-10 15:43:09 +00:00
Wouter Wijngaards 121cb15d67 remote control setup, port binding and service.
git-svn-id: file:///svn/unbound/trunk@1227 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-10 15:23:01 +00:00
Wouter Wijngaards 265eedb0d3 certificate creation script.
git-svn-id: file:///svn/unbound/trunk@1226 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-09 14:15:55 +00:00
Wouter Wijngaards 26429c9457 refactored code.
git-svn-id: file:///svn/unbound/trunk@1225 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-04 14:29:05 +00:00
Wouter Wijngaards 72904a3366 private-addresses.
git-svn-id: file:///svn/unbound/trunk@1224 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-04 12:25:15 +00:00
Wouter Wijngaards ff1a7ec42e private address and private domain config option read and store.
git-svn-id: file:///svn/unbound/trunk@1223 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-03 14:40:09 +00:00
Wouter Wijngaards 05cd134de9 Do not mark additional section items bogus.
git-svn-id: file:///svn/unbound/trunk@1222 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-02 14:35:13 +00:00
Wouter Wijngaards 960da40475 DoS protection.
git-svn-id: file:///svn/unbound/trunk@1221 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-02 13:04:47 +00:00
Wouter Wijngaards 01cabbebc1 do not allow cache snooping by default.
git-svn-id: file:///svn/unbound/trunk@1220 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-09-01 13:48:24 +00:00
Wouter Wijngaards a66e16cb31 new NS queries is not an option (off by default).
git-svn-id: file:///svn/unbound/trunk@1219 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-29 14:46:08 +00:00
Wouter Wijngaards 49d295755d plan update svn:NO TEST
git-svn-id: file:///svn/unbound/trunk@1218 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-29 13:41:06 +00:00
Wouter Wijngaards b858018446 planning svn:NO TEST
git-svn-id: file:///svn/unbound/trunk@1217 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-29 12:32:57 +00:00
Wouter Wijngaards 71a535a6f2 iana port update
git-svn-id: file:///svn/unbound/trunk@1216 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-29 08:02:29 +00:00
Wouter Wijngaards 28a388b517 1.1
git-svn-id: file:///svn/unbound/trunk@1215 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-29 07:48:40 +00:00
Wouter Wijngaards 51d548563c logfile creation fixup.
git-svn-id: file:///svn/unbound/trunk@1214 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-28 09:02:48 +00:00
Wouter Wijngaards 21cd9936d8 dlv negative cache size option.
git-svn-id: file:///svn/unbound/trunk@1213 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-27 13:02:22 +00:00
Wouter Wijngaards e474ca2619 bug #199.
git-svn-id: file:///svn/unbound/trunk@1212 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-27 11:29:46 +00:00
Wouter Wijngaards f809bfa145 Remove daemon(3) usage.
git-svn-id: file:///svn/unbound/trunk@1211 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-27 06:17:55 +00:00
Wouter Wijngaards 4993c646e7 use daemon(3) if available.
git-svn-id: file:///svn/unbound/trunk@1210 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-26 12:47:26 +00:00
Wouter Wijngaards 53fed5315c Drop privileges more.
git-svn-id: file:///svn/unbound/trunk@1209 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-26 12:11:42 +00:00
Wouter Wijngaards 21895f6013 iana port update.
git-svn-id: file:///svn/unbound/trunk@1208 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-26 10:39:35 +00:00
Wouter Wijngaards 82ce090a35 Remove overreaching NSEC rrsets.
git-svn-id: file:///svn/unbound/trunk@1207 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-26 10:32:46 +00:00
Wouter Wijngaards fcbc34bd7f DLV tests.
git-svn-id: file:///svn/unbound/trunk@1206 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-26 10:13:31 +00:00
Wouter Wijngaards 0720031ce0 patch to make realclean more clean.
git-svn-id: file:///svn/unbound/trunk@1205 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-25 06:23:21 +00:00
Wouter Wijngaards 23db41c292 iana port update
git-svn-id: file:///svn/unbound/trunk@1204 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-22 10:25:27 +00:00
Wouter Wijngaards d60b281055 more test DLV.
git-svn-id: file:///svn/unbound/trunk@1203 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-22 10:06:14 +00:00
Wouter Wijngaards a7cfe2bf65 Test DLV anchor.
git-svn-id: file:///svn/unbound/trunk@1202 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-21 14:58:39 +00:00
Wouter Wijngaards d9cd60a41c iana portlist update.
git-svn-id: file:///svn/unbound/trunk@1201 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-21 12:05:57 +00:00
Wouter Wijngaards a39a7704af DLV negative cache works.
git-svn-id: file:///svn/unbound/trunk@1200 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-21 10:43:45 +00:00
Wouter Wijngaards a61d10f715 Negative cache code.
git-svn-id: file:///svn/unbound/trunk@1199 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-20 13:31:06 +00:00
Wouter Wijngaards a4e4f424d1 negative cache work for DLV
git-svn-id: file:///svn/unbound/trunk@1198 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-19 15:27:31 +00:00
Wouter Wijngaards bcec1a7593 negative cache design.
git-svn-id: file:///svn/unbound/trunk@1197 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-18 15:00:17 +00:00
Wouter Wijngaards 38396319c7 Patch from Pierre David.
git-svn-id: file:///svn/unbound/trunk@1196 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-18 11:38:37 +00:00
Wouter Wijngaards ee874fab01 please doxygen.
git-svn-id: file:///svn/unbound/trunk@1195 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-18 08:36:28 +00:00
Wouter Wijngaards 8cbb13f251 Better logfile classification for log_bug, log_hex and log_addr.
git-svn-id: file:///svn/unbound/trunk@1194 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-18 08:17:07 +00:00
Wouter Wijngaards 87fe8871b0 doxygen.
git-svn-id: file:///svn/unbound/trunk@1193 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-15 14:00:08 +00:00
Wouter Wijngaards 55f7bbc051 negative cache design.
git-svn-id: file:///svn/unbound/trunk@1192 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-15 13:31:16 +00:00
Wouter Wijngaards 8e39c9c1cb basic DLV works.
iana port update.



git-svn-id: file:///svn/unbound/trunk@1191 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-15 10:55:09 +00:00
Wouter Wijngaards 7549bddfda DLV work
git-svn-id: file:///svn/unbound/trunk@1190 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-14 15:16:50 +00:00
Wouter Wijngaards 44f5800da9 proper handling of empty files and neater code.
git-svn-id: file:///svn/unbound/trunk@1189 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-13 15:18:39 +00:00
Wouter Wijngaards 4cf4659a1d dlv anchor file and chroot.
git-svn-id: file:///svn/unbound/trunk@1188 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-13 14:46:33 +00:00
Wouter Wijngaards 080d9d6540 - ldns snapshot r2699 taken (includes DLV type).
- DLV work, config file element, trust anchor read in.



git-svn-id: file:///svn/unbound/trunk@1187 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-13 14:30:35 +00:00
Wouter Wijngaards 77b79fde5d bug fixes 203, 204, 206.
git-svn-id: file:///svn/unbound/trunk@1186 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-13 07:11:42 +00:00
Wouter Wijngaards 1e4e8cb68a - Fixup rrset security updates overwriting 2181 trust status.
This makes validated to be insecure data just as worthless as
	  nonvalidated data, and 2181 rules prevent cache overwrites to them.
	- Fix assertion fail on bogus key handling.
	- dnssec lameness detection works on first query at trust apex.
	- NS queries get proper cache and dnssec lameness treatment.
	- fixup compilation without pthreads on linux.
	- NS queries are done after every referral.
	  validator is used on those NS records (if anchors enabled).




git-svn-id: file:///svn/unbound/trunk@1185 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-12 10:13:57 +00:00
Wouter Wijngaards 0d8ce6f075 more fixup pthreads compile.
git-svn-id: file:///svn/unbound/trunk@1184 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-11 14:02:37 +00:00
Wouter Wijngaards 23ac4b02e3 Fixup compilation without pthreads.
git-svn-id: file:///svn/unbound/trunk@1183 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-11 13:58:33 +00:00
Wouter Wijngaards 8b93a85a7d Porting of update-anchor script.
git-svn-id: file:///svn/unbound/trunk@1182 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-07 13:52:36 +00:00
Wouter Wijngaards 4fe0d98ff4 Same scrubber patch to trunk.
git-svn-id: file:///svn/unbound/trunk@1181 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-07 07:31:05 +00:00
Wouter Wijngaards a30026a7d8 iana port update.
git-svn-id: file:///svn/unbound/trunk@1178 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-05 11:39:32 +00:00
Wouter Wijngaards 9d068a12f5 fixup DS test for apex validation of NODATA.
git-svn-id: file:///svn/unbound/trunk@1177 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-05 10:54:27 +00:00
Wouter Wijngaards 144d35120c manpage fixup. TODO cleanup.
git-svn-id: file:///svn/unbound/trunk@1176 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-04 13:08:08 +00:00
Wouter Wijngaards 014cc821ba Fix bug #201
git-svn-id: file:///svn/unbound/trunk@1173 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-04 12:15:12 +00:00
Wouter Wijngaards 428524a8c8 Iana port list updated.
git-svn-id: file:///svn/unbound/trunk@1172 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-04 08:46:28 +00:00
Wouter Wijngaards 2d49dd1494 TODO for 1.1
git-svn-id: file:///svn/unbound/trunk@1171 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-08-04 08:30:49 +00:00
Wouter Wijngaards 995b01a9b7 bugfix to DS qtype from client.
git-svn-id: file:///svn/unbound/trunk@1170 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-30 21:38:37 +00:00
Wouter Wijngaards 665a98e47b print openssl version.
git-svn-id: file:///svn/unbound/trunk@1168 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-25 11:33:31 +00:00
Wouter Wijngaards fe106d38b2 remove socketpair compat.
git-svn-id: file:///svn/unbound/trunk@1167 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-25 09:33:14 +00:00
Wouter Wijngaards 75ac5e0fe0 make pipe work with fallback on windows.
git-svn-id: file:///svn/unbound/trunk@1166 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-25 09:26:15 +00:00
Wouter Wijngaards d452ba59b5 Added copyright statement from OpenBSD authors.
git-svn-id: file:///svn/unbound/trunk@1165 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-25 05:32:52 +00:00
Wouter Wijngaards c2c5b5522c windows tube functionality writeup.
git-svn-id: file:///svn/unbound/trunk@1164 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-23 15:19:18 +00:00
Wouter Wijngaards 34d75b1994 - moved pipe actions to util/tube.c. easier porting and shared code.
- check _raw() commpoint callbacks with fptr_wlist.
- iana port update.


git-svn-id: file:///svn/unbound/trunk@1163 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-23 09:23:03 +00:00
Wouter Wijngaards b61f24e8d3 #198 bug fixups.
git-svn-id: file:///svn/unbound/trunk@1162 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-21 07:59:29 +00:00
Wouter Wijngaards 072142cfa2 #198 fix.
git-svn-id: file:///svn/unbound/trunk@1161 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-19 15:34:57 +00:00
Wouter Wijngaards afe9b3e83c please doxygen, fixup fake func prototypes and make typedef more portable.
git-svn-id: file:///svn/unbound/trunk@1160 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-18 15:29:33 +00:00
Wouter Wijngaards e4ef5a6156 tube work for mingw port.
git-svn-id: file:///svn/unbound/trunk@1159 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-18 15:06:59 +00:00
Wouter Wijngaards ad041b9b8e branch for 1.0 support
git-svn-id: file:///svn/unbound/trunk@1158 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-18 13:00:57 +00:00
Wouter Wijngaards 45dd63d7c8 TODO request.
git-svn-id: file:///svn/unbound/trunk@1157 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-18 11:00:49 +00:00
Wouter Wijngaards 8ab18cb0f7 fds max test before start.
git-svn-id: file:///svn/unbound/trunk@1156 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-17 10:07:40 +00:00
Wouter Wijngaards 4e2ca85842 fix bug #195.
git-svn-id: file:///svn/unbound/trunk@1155 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-17 09:00:38 +00:00
Wouter Wijngaards 71d292580b fixup #196.
git-svn-id: file:///svn/unbound/trunk@1154 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-17 08:45:12 +00:00
Wouter Wijngaards d4b612e48b 1.0.1 tag
trunk to 1.0.2
sha256 support in trunk makedist.sh



git-svn-id: file:///svn/unbound/trunk@1153 be551aaa-1e26-0410-a405-d3ace91eadb9
2008-07-16 13:16:36 +00:00
301 changed files with 24767 additions and 3291 deletions
+32 -14
View File
@@ -34,6 +34,7 @@ libtool=@libtool@
ldnsdir=@ldnsdir@
staticexe=@staticexe@
configfile=@ub_conf_file@
UNBOUND_RUN_DIR=@UNBOUND_RUN_DIR@
CHECKLOCK_SRC=@CHECKLOCK_SRC@
YACC=@YACC@
@@ -76,6 +77,8 @@ DAEMON_SRC=$(patsubst $(srcdir)/%,%, $(wildcard $(srcdir)/daemon/*.c)) \
DAEMON_OBJ=$(addprefix $(BUILD),$(DAEMON_SRC:.c=.lo)) $(COMPAT_OBJ)
CHECKCONF_SRC=smallapp/unbound-checkconf.c smallapp/worker_cb.c $(COMMON_SRC)
CHECKCONF_OBJ=$(addprefix $(BUILD),$(CHECKCONF_SRC:.c=.lo)) $(COMPAT_OBJ)
CONTROL_SRC=smallapp/unbound-control.c smallapp/worker_cb.c $(COMMON_SRC)
CONTROL_OBJ=$(addprefix $(BUILD),$(CONTROL_SRC:.c=.lo)) $(COMPAT_OBJ)
HOST_SRC=smallapp/unbound-host.c
HOST_OBJ=$(addprefix $(BUILD),$(HOST_SRC:.c=.lo)) $(COMPAT_OBJ)
TESTBOUND_SRC=testcode/testbound.c testcode/ldns-testpkts.c \
@@ -109,7 +112,7 @@ ALL_SRC=$(sort $(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \
$(TESTBOUND_SRC) $(LOCKVERIFY_SRC) $(PKTVIEW_SRC) $(SIGNIT_SRC) \
$(MEMSTATS_SRC) $(CHECKCONF_SRC) $(LIBUNBOUND_SRC) $(HOST_SRC) \
$(ASYNCLOOK_SRC) $(STREAMTCP_SRC) $(PERF_SRC) $(DELAYER_SRC) \
$(HARVEST_SRC) )
$(HARVEST_SRC) $(CONTROL_SRC))
ALL_OBJ=$(addprefix $(BUILD),$(ALL_SRC:.c=.lo) \
$(addprefix compat/,$(LIBOBJS:.o=.lo))) $(COMPAT_OBJ)
@@ -126,10 +129,11 @@ $(BUILD)%.lo: $(srcdir)/%.c
@-if test ! -d $(dir $@); then $(INSTALL) -d $(patsubst %/,%,$(dir $@)); fi
$Q$(COMPILE) -c $< -o $@
all: $(COMMON_OBJ) unbound unbound-checkconf lib unbound-host
all: $(COMMON_OBJ) unbound unbound-checkconf lib unbound-host unbound-control unbound-control-setup
tests: all unittest testbound lock-verify pktview signit memstats \
asynclook streamtcp perf delayer harvest
TEST_BIN=asynclook delayer harvest lock-verify memstats perf pktview signit \
streamtcp testbound unittest
tests: all $(TEST_BIN)
test: tests
if test -x "`which bash`"; then bash testcode/do-tests.sh; else sh testcode/do-tests.sh; fi
@@ -151,12 +155,16 @@ endif
unbound: $(DAEMON_OBJ) $(ldnslib)
$(INFO) Link $@
$Q$(LINK) -o $@ $(sort $(DAEMON_OBJ)) $(LIBS)
$Q$(LINK) -o $@ $(sort $(DAEMON_OBJ)) -lssl $(LIBS)
unbound-checkconf: $(CHECKCONF_OBJ) $(ldnslib)
$(INFO) Link $@
$Q$(LINK) -o $@ $(sort $(CHECKCONF_OBJ)) $(LIBS)
unbound-control: $(CONTROL_OBJ) $(ldnslib)
$(INFO) Link $@
$Q$(LINK) -o $@ $(sort $(CONTROL_OBJ)) -lssl $(LIBS)
unbound-host: $(HOST_OBJ) libunbound.la $(ldnslib)
$(INFO) Link $@
$Q$(LINK) -o $@ $(sort $(HOST_OBJ)) -L. -L.libs -lunbound $(LIBS)
@@ -167,7 +175,7 @@ unittest: $(UNITTEST_OBJ) $(ldnslib)
testbound: $(TESTBOUND_OBJ) $(ldnslib)
$(INFO) Link $@
$Q$(LINK) -o $@ $(sort $(TESTBOUND_OBJ)) $(LIBS)
$Q$(LINK) -o $@ $(sort $(TESTBOUND_OBJ)) -lssl $(LIBS)
lock-verify: $(LOCKVERIFY_OBJ) $(ldnslib)
$(INFO) Link $@
@@ -205,6 +213,11 @@ harvest: $(HARVEST_OBJ) $(ldnslib) libunbound.la
$(INFO) Link $@
$Q$(LINK) -o $@ $(sort $(HARVEST_OBJ)) $(LIBS) -L. -L.libs -lunbound
unbound-control-setup: $(srcdir)/smallapp/unbound-control-setup.sh
$(INFO) Sed $@
$Qsed -e 's:^DESTDIR=.*$$:DESTDIR=$(UNBOUND_RUN_DIR):' < $< > $@
$Q-chmod +x $@
#testcode/ldns-testpkts.c: $(ldnsdir)/examples/ldns-testpkts.c \
# $(ldnsdir)/examples/ldns-testpkts.h
# cp $(ldnsdir)/examples/ldns-testpkts.c testcode/ldns-testpkts.c
@@ -235,6 +248,7 @@ realclean: clean
rm -f config.status config.log config.h.in config.h
rm -f configure config.sub config.guess ltmain.sh aclocal.m4 libtool
rm -f util/configlexer.c util/configparser.c util/configparser.h
rm -f $(TEST_BIN)
if test -d ldns-src; then rm -rf ldns-src; fi
rm -f Makefile
@@ -256,6 +270,7 @@ doc:
strip:
strip unbound
strip unbound-checkconf
strip unbound-control
strip unbound-host
install:
@@ -269,20 +284,23 @@ install:
$(INSTALL) -m 755 -d $(DESTDIR)$(includedir)
$(LIBTOOL) --mode=install cp unbound $(DESTDIR)$(sbindir)/unbound
$(LIBTOOL) --mode=install cp unbound-checkconf $(DESTDIR)$(sbindir)/unbound-checkconf
$(LIBTOOL) --mode=install cp unbound-control $(DESTDIR)$(sbindir)/unbound-control
$(LIBTOOL) --mode=install cp unbound-host $(DESTDIR)$(sbindir)/unbound-host
$(INSTALL) -c -m 644 $(srcdir)/doc/unbound.8 $(DESTDIR)$(mandir)/man8
$(INSTALL) -c -m 644 $(srcdir)/doc/unbound-checkconf.8 $(DESTDIR)$(mandir)/man8
$(INSTALL) -c -m 644 $(srcdir)/doc/unbound.conf.5 $(DESTDIR)$(mandir)/man5
$(INSTALL) -c -m 644 doc/unbound.8 $(DESTDIR)$(mandir)/man8
$(INSTALL) -c -m 644 doc/unbound-checkconf.8 $(DESTDIR)$(mandir)/man8
$(INSTALL) -c -m 644 doc/unbound-control.8 $(DESTDIR)$(mandir)/man8
$(INSTALL) -c -m 644 doc/unbound.conf.5 $(DESTDIR)$(mandir)/man5
$(INSTALL) -c -m 644 $(srcdir)/doc/unbound-host.1 $(DESTDIR)$(mandir)/man1
$(INSTALL) -c -m 644 $(srcdir)/doc/libunbound.3 $(DESTDIR)$(mandir)/man3
if test ! -e $(DESTDIR)$(configfile); then $(INSTALL) -d `dirname $(DESTDIR)$(configfile)`; $(INSTALL) -c -m 644 $(srcdir)/doc/example.conf $(DESTDIR)$(configfile); fi
$(INSTALL) -c -m 644 doc/libunbound.3 $(DESTDIR)$(mandir)/man3
$(INSTALL) -c -m 755 unbound-control-setup $(DESTDIR)$(sbindir)/unbound-control-setup
if test ! -e $(DESTDIR)$(configfile); then $(INSTALL) -d `dirname $(DESTDIR)$(configfile)`; $(INSTALL) -c -m 644 doc/example.conf $(DESTDIR)$(configfile); fi
$(LIBTOOL) --mode=install cp $(srcdir)/libunbound/unbound.h $(DESTDIR)$(includedir)/unbound.h
$(LIBTOOL) --mode=install cp libunbound.la $(DESTDIR)$(libdir)
$(LIBTOOL) --mode=finish $(DESTDIR)$(libdir)
uninstall:
rm -f -- $(DESTDIR)$(sbindir)/unbound $(DESTDIR)$(sbindir)/unbound-checkconf $(DESTDIR)$(sbindir)/unbound-host
rm -f -- $(DESTDIR)$(mandir)/man8/unbound.8 $(DESTDIR)$(mandir)/man8/unbound-checkconf.8 $(DESTDIR)$(mandir)/man5/unbound.conf.5
rm -f -- $(DESTDIR)$(sbindir)/unbound $(DESTDIR)$(sbindir)/unbound-checkconf $(DESTDIR)$(sbindir)/unbound-host $(DESTDIR)$(sbindir)/unbound-control $(DESTDIR)$(sbindir)/unbound-control-setup
rm -f -- $(DESTDIR)$(mandir)/man8/unbound.8 $(DESTDIR)$(mandir)/man8/unbound-checkconf.8 $(DESTDIR)$(mandir)/man5/unbound.conf.5 $(DESTDIR)$(mandir)/man8/unbound-control.8
rm -f -- $(DESTDIR)$(mandir)/man1/unbound-host.1 $(DESTDIR)$(mandir)/man3/libunbound.3
rm -f -- $(DESTDIR)$(includedir)/unbound.h
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/libunbound.la
@@ -297,7 +315,7 @@ download_ldns:
iana_update:
curl -o port-numbers.tmp http://www.iana.org/assignments/port-numbers
egrep -v "Unassigned|Reserved" port-numbers.tmp | awk '{ match($$0, "[0-9]+/udp"); if (RLENGTH > 0) print substr($$0, RSTART, RLENGTH - 4) ","}' | sort -nu > portslist.tmp
awk '/Unassigned|Reserved/ {next;} { match($$0, "[0-9]+/udp"); if (RLENGTH > 0) print substr($$0, RSTART, RLENGTH - 4) ","}' port-numbers.tmp | sort -nu > portslist.tmp
cat portslist.tmp > util/iana_ports.inc
rm -f port-numbers.tmp portslist.tmp
+4 -4
View File
@@ -149,23 +149,23 @@ struct addrinfo {
#ifdef getaddrinfo
# undef getaddrinfo
#endif
#define getaddrinfo(a,b,c,d) (ssh_getaddrinfo(a,b,c,d))
#define getaddrinfo(a,b,c,d) (getaddrinfo_unbound(a,b,c,d))
int getaddrinfo(const char *, const char *,
const struct addrinfo *, struct addrinfo **);
#endif /* !HAVE_GETADDRINFO */
#if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO)
#define gai_strerror(a) (ssh_gai_strerror(a))
#define gai_strerror(a) (gai_strerror_unbound(a))
char *gai_strerror(int);
#endif /* !HAVE_GAI_STRERROR */
#ifndef HAVE_FREEADDRINFO
#define freeaddrinfo(a) (ssh_freeaddrinfo(a))
#define freeaddrinfo(a) (freeaddrinfo_unbound(a))
void freeaddrinfo(struct addrinfo *);
#endif /* !HAVE_FREEADDRINFO */
#ifndef HAVE_GETNAMEINFO
#define getnameinfo(a,b,c,d,e,f,g) (ssh_getnameinfo(a,b,c,d,e,f,g))
#define getnameinfo(a,b,c,d,e,f,g) (getnameinfo_unbound(a,b,c,d,e,f,g))
int getnameinfo(const struct sockaddr *, size_t, char *, size_t,
char *, size_t, int);
#endif /* !HAVE_GETNAMEINFO */
-34
View File
@@ -1,34 +0,0 @@
/* socketpair.c - windows mingw32 replacement for socketpair.
* creates a pipe that works like a socketpair a bit
* Taken from libevent-1.4.3.stable WIN32-Code/misc.c
* License: BSD.
*/
#include "config.h"
#include <stdio.h>
#include <windows.h>
int
socketpair(int d, int type, int protocol, int *sv)
{
static int count;
char buf[64];
HANDLE fd;
DWORD dwMode;
(void)d; (void)type; (void)protocol;
sprintf(buf, "\\\\.\\pipe\\levent-%d", count++);
/* Create a duplex pipe which will behave like a socket pair */
fd = CreateNamedPipe(buf, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_NOWAIT,
PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, NULL);
if (fd == INVALID_HANDLE_VALUE)
return (-1);
sv[0] = (int)fd;
fd = CreateFile(buf, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fd == INVALID_HANDLE_VALUE)
return (-1);
dwMode = PIPE_NOWAIT;
SetNamedPipeHandleState(fd, &dwMode, NULL, NULL);
sv[1] = (int)fd;
return (0);
}
+32 -11
View File
@@ -6,6 +6,10 @@
/* Pathname to the Unbound configuration file */
#undef CONFIGFILE
/* Define this if on macOSX10.4-darwin8 and setreuid and setregid do not work
*/
#undef DARWIN_BROKEN_SETREUID
/* Define if you want to use debug lock checking (slow). */
#undef ENABLE_LOCK_CHECKS
@@ -39,6 +43,15 @@
/* Define to 1 if you have the <event.h> header file. */
#undef HAVE_EVENT_H
/* Define to 1 if you have the `EVP_sha1' function. */
#undef HAVE_EVP_SHA1
/* Define to 1 if you have the `EVP_sha256' function. */
#undef HAVE_EVP_SHA256
/* Define to 1 if you have the `EVP_sha512' function. */
#undef HAVE_EVP_SHA512
/* Define to 1 if you have the `fcntl' function. */
#undef HAVE_FCNTL
@@ -136,6 +149,18 @@
/* Define to 1 if you have the `sendmsg' function. */
#undef HAVE_SENDMSG
/* Define to 1 if you have the `setregid' function. */
#undef HAVE_SETREGID
/* Define to 1 if you have the `setresgid' function. */
#undef HAVE_SETRESGID
/* Define to 1 if you have the `setresuid' function. */
#undef HAVE_SETRESUID
/* Define to 1 if you have the `setreuid' function. */
#undef HAVE_SETREUID
/* Define to 1 if you have the `setsid' function. */
#undef HAVE_SETSID
@@ -148,9 +173,6 @@
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* Define to 1 if you have the `socketpair' function. */
#undef HAVE_SOCKETPAIR
/* Using Solaris threads */
#undef HAVE_SOLARIS_THREADS
@@ -250,6 +272,10 @@
/* Define if mkdir has one argument. */
#undef MKDIR_HAS_ONE_ARG
/* Define if the network stack does not fully support nonblocking io (causes
lower performance). */
#undef NONBLOCKING_IS_BROKEN
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
@@ -281,6 +307,9 @@
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* default username */
#undef UB_USERNAME
/* use statistics for allocs and frees, for debug use */
#undef UNBOUND_ALLOC_STATS
@@ -529,14 +558,9 @@ size_t strlcpy(char *dst, const char *src, size_t siz);
struct tm *gmtime_r(const time_t *timep, struct tm *result);
#endif
#ifndef HAVE_GETADDRINFO
#define getaddrinfo getaddrinfo_unbound
#define gai_strerror gai_strerror_unbound
#define freeaddrinfo freeaddrinfo_unbound
#define getnameinfo getnameinfo_unbound
struct sockaddr_storage;
#include "compat/fake-rfc2553.h"
#endif
#ifndef HAVE_SLEEP
#define sleep(x) Sleep((x)*1000) /* on win32 */
#endif /* HAVE_SLEEP */
@@ -549,9 +573,6 @@ struct sockaddr_storage;
#ifndef HAVE_SRANDOM
#define srandom(x) srand(x) /* on win32, for tests only (bad random) */
#endif /* HAVE_SRANDOM */
#ifndef HAVE_SOCKETPAIR
int socketpair(int d, int type, int protocol, int *sv);
#endif
/* detect if we need to cast to unsigned int for FD_SET to avoid warnings */
#ifdef HAVE_WINSOCK2_H
Vendored
+658 -144
View File
File diff suppressed because it is too large Load Diff
+182 -19
View File
@@ -2,13 +2,15 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.56)
AC_INIT(unbound,1.0.1, unbound-bugs@nlnetlabs.nl, unbound)
AC_INIT(unbound,1.1.0, unbound-bugs@nlnetlabs.nl, unbound)
LIBUNBOUND_CURRENT=0
LIBUNBOUND_REVISION=13
LIBUNBOUND_REVISION=15
LIBUNBOUND_AGE=0
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
# 1.0.2 had 0:14:0
# 1.1.0 had 0:15:0
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -32,7 +34,7 @@ AC_SUBST(LIBUNBOUND_CURRENT)
AC_SUBST(LIBUNBOUND_REVISION)
AC_SUBST(LIBUNBOUND_AGE)
CFLAGS=
CFLAGS="$CFLAGS"
AC_AIX
dnl
@@ -80,6 +82,14 @@ AC_ARG_WITH(pidfile,
AC_SUBST(UNBOUND_PIDFILE)
AC_DEFINE_UNQUOTED(PIDFILE, ["$UNBOUND_PIDFILE"], [default pidfile location])
AC_ARG_WITH(username,
AC_HELP_STRING([--with-username=user],
[set default user that unbound changes to (default user is unbound)]),
UNBOUND_USERNAME="$withval",
UNBOUND_USERNAME="unbound")
AC_SUBST(UNBOUND_USERNAME)
AC_DEFINE_UNQUOTED(UB_USERNAME, ["$UNBOUND_USERNAME"], [default username])
AC_DEFINE(WINVER, 0x0502, [the version of the windows API enabled])
dnl routine to help check for compiler flags.
@@ -267,6 +277,20 @@ int test() {
}
], [CFLAGS="$CFLAGS -D_GNU_SOURCE"])
# check again for GNU_SOURCE for setresgid. May fail if setresgid
# is not available at all. -D_FRSRESGID is to make this check unique.
# otherwise we would get the previous cached result.
CHECK_COMPILER_FLAG_NEEDED(-D_GNU_SOURCE -D_FRSRESGID,
[
#include <unistd.h>
int test() {
int a = setresgid(0,0,0);
a = setresuid(0,0,0);
return a;
}
], [CFLAGS="$CFLAGS -D_GNU_SOURCE"])
CHECK_COMPILER_FLAG_NEEDED(-D_POSIX_C_SOURCE=200112,
[
#include "confdefs.h"
@@ -512,7 +536,6 @@ AC_ARG_WITH(ssl, AC_HELP_STRING([--with-ssl=pathname],
fi
AC_MSG_CHECKING([for HMAC_CTX_init in -lcrypto])
ORIGLIBS="$LIBS"
LIBS="$LIBS -lcrypto"
AC_TRY_LINK(, [
int HMAC_CTX_init(void);
@@ -545,6 +568,20 @@ AC_ARG_WITH(ssl, AC_HELP_STRING([--with-ssl=pathname],
AC_CHECK_HEADERS([openssl/ssl.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/err.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_FUNCS([EVP_sha1 EVP_sha256 EVP_sha512])
# check if libssl needs libdl
BAKLIBS="$LIBS"
LIBS="-lssl $LIBS"
AC_MSG_CHECKING([if libssl needs libdl])
AC_TRY_LINK_FUNC([SSL_CTX_new], [
AC_MSG_RESULT([no])
LIBS="$BAKLIBS"
] , [
AC_MSG_RESULT([yes])
LIBS="$BAKLIBS"
AC_SEARCH_LIBS([dlopen], [dl])
])
# check for thread library.
AC_ARG_WITH(pthreads, AC_HELP_STRING([--with-pthreads],
@@ -772,7 +809,140 @@ AC_CHECK_GETADDRINFO_WITH_INCLUDES
if test $ac_cv_func_getaddrinfo = no; then
AC_LIBOBJ([fake-rfc2553])
fi
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam getrlimit setsid sbrk chroot kill sleep usleep random srandom recvmsg sendmsg writev])
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam getrlimit setsid sbrk chroot kill sleep usleep random srandom recvmsg sendmsg writev setresuid setreuid setresgid setregid])
# check if setreuid en setregid fail, on MacOSX10.4(darwin8).
if echo $build_os | grep darwin8 > /dev/null; then
AC_DEFINE(DARWIN_BROKEN_SETREUID, 1, [Define this if on macOSX10.4-darwin8 and setreuid and setregid do not work])
fi
# check if select and nonblocking sockets actually work.
AC_MSG_CHECKING([if nonblocking sockets work])
AC_RUN_IFELSE(AC_LANG_PROGRAM([
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
],[[
int port;
int sfd, cfd;
int num = 10;
int i, p;
struct sockaddr_in a;
/* test if select and nonblocking reads work well together */
/* open port.
fork child to send 10 messages.
select to read.
then try to nonblocking read the 10 messages
then, nonblocking read must give EAGAIN
*/
port = 12345 + (time(0)%32);
sfd = socket(PF_INET, SOCK_DGRAM, 0);
if(sfd == -1) {
perror("socket");
return 1;
}
memset(&a, 0, sizeof(a));
a.sin_family = AF_INET;
a.sin_port = htons(port);
a.sin_addr.s_addr = inet_addr("127.0.0.1");
if(bind(sfd, (struct sockaddr*)&a, sizeof(a)) < 0) {
perror("bind");
return 1;
}
if(fcntl(sfd, F_SETFL, O_NONBLOCK) == -1) {
perror("fcntl");
return 1;
}
cfd = socket(PF_INET, SOCK_DGRAM, 0);
if(cfd == -1) {
perror("client socket");
return 1;
}
a.sin_port = 0;
if(bind(cfd, (struct sockaddr*)&a, sizeof(a)) < 0) {
perror("client bind");
return 1;
}
a.sin_port = htons(port);
/* no handler, causes exit in 10 seconds */
alarm(10);
/* send and receive on the socket */
if((p=fork()) == 0) {
for(i=0; i<num; i++) {
if(sendto(cfd, &i, sizeof(i), 0,
(struct sockaddr*)&a, sizeof(a)) < 0) {
perror("sendto");
return 1;
}
}
} else {
/* parent */
fd_set rset;
int x;
if(p == -1) {
perror("fork");
return 1;
}
FD_ZERO(&rset);
FD_SET(sfd, &rset);
if(select(sfd+1, &rset, NULL, NULL, NULL) < 1) {
perror("select");
return 1;
}
i = 0;
while(i < num) {
if(recv(sfd, &x, sizeof(x), 0) != sizeof(x)) {
if(errno == EAGAIN)
continue;
perror("recv");
return 1;
}
i++;
}
/* now we want to get EAGAIN: nonblocking goodness */
errno = 0;
recv(sfd, &x, sizeof(x), 0);
if(errno != EAGAIN) {
perror("trying to recv again");
return 1;
}
/* EAGAIN encountered */
}
close(sfd);
close(cfd);
]]), [
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
AC_DEFINE([NONBLOCKING_IS_BROKEN], 1, [Define if the network stack does not fully support nonblocking io (causes lower performance).])
], [
AC_MSG_RESULT([crosscompile(yes)])
])
# check mkdir
AC_MSG_CHECKING([whether mkdir has one arg])
@@ -814,7 +984,6 @@ AC_REPLACE_FUNCS(snprintf)
AC_REPLACE_FUNCS(strlcpy)
AC_REPLACE_FUNCS(memmove)
AC_REPLACE_FUNCS(gmtime_r)
AC_REPLACE_FUNCS(socketpair) dnl for mingw32
# check this after all other compilation checks, since the linking of the lib
# may break checks after this.
@@ -830,6 +999,8 @@ AC_ARG_WITH(ldns,
AC_CHECK_LIB(ldns, ldns_buffer_copy, [
dnl ldns was found, check compat functions
AC_CHECK_LIB(ldns, [ldns_rr_free])
AC_CHECK_FUNC([ldns_b32_ntop_extended_hex],, [
AC_MSG_ERROR([ldns version too old, need >=1.4.0])])
] , [
dnl use the builtin ldns-src.tar.gz file to build ldns.
if test ! -f $srcdir/ldns-src.tar.gz; then
@@ -841,11 +1012,11 @@ echo "*** ldns library not found (--with-ldns= to specify by hand) ***"
echo "*** Building ldns library from package included in this one. ***"
echo "*** ***"
echo "****************************************************************"
if test -d ldns-src; then rm -rf ldns-src; fi
mkdir ldns-src; cp $srcdir/ldns-src.tar.gz ldns-src/ldns-src.tar.gz; (cd ldns-src; gzip -cd ldns-src.tar.gz | tar xf -); rm -f ldns-src/ldns-src.tar.gz
ldnsdir=`ls -d ldns-src/ldns*`
if test -d $srcdir/ldns-src; then rm -rf $srcdir/ldns-src; fi
mkdir $srcdir/ldns-src; cp $srcdir/ldns-src.tar.gz $srcdir/ldns-src/ldns-src.tar.gz; (cd $srcdir/ldns-src; gzip -cd ldns-src.tar.gz | tar xf -); rm -f $srcdir/ldns-src/ldns-src.tar.gz; mv $srcdir/ldns-src $srcdir/ldns-srcb; mv $srcdir/ldns-srcb/ldns* $srcdir/ldns-src; rmdir $srcdir/ldns-srcb
ldnsdir="ldns-src"
AC_MSG_NOTICE([Configure $ldnsdir scheduled after config.status])
AC_CONFIG_SUBDIRS([ldns-src/ldns*])
AC_CONFIG_SUBDIRS([ldns-src])
CPPFLAGS="-I$ldnsdir/include $CPPFLAGS"
LDFLAGS="$LDFLAGS $ldnsdir/*.lo"
AC_SUBST(ldnsdir)
@@ -995,14 +1166,9 @@ size_t strlcpy(char *dst, const char *src, size_t siz);
struct tm *gmtime_r(const time_t *timep, struct tm *result);
#endif
#ifndef HAVE_GETADDRINFO
#define getaddrinfo getaddrinfo_unbound
#define gai_strerror gai_strerror_unbound
#define freeaddrinfo freeaddrinfo_unbound
#define getnameinfo getnameinfo_unbound
struct sockaddr_storage;
#include "compat/fake-rfc2553.h"
#endif
#ifndef HAVE_SLEEP
#define sleep(x) Sleep((x)*1000) /* on win32 */
#endif /* HAVE_SLEEP */
@@ -1015,9 +1181,6 @@ struct sockaddr_storage;
#ifndef HAVE_SRANDOM
#define srandom(x) srand(x) /* on win32, for tests only (bad random) */
#endif /* HAVE_SRANDOM */
#ifndef HAVE_SOCKETPAIR
int socketpair(int d, int type, int protocol, int *sv);
#endif
/* detect if we need to cast to unsigned int for FD_SET to avoid warnings */
#ifdef HAVE_WINSOCK2_H
@@ -1051,6 +1214,6 @@ void *unbound_stat_realloc_log(void *ptr, size_t size, const char* file,
#define UNBOUND_DNS_PORT 53
])
AC_CONFIG_FILES([Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-checkconf.8 doc/unbound.conf.5])
AC_CONFIG_FILES([Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8])
AC_CONFIG_HEADER([config.h])
AC_OUTPUT
+1
View File
@@ -7,3 +7,4 @@ distribution but may be helpful.
* unbound.spec and unbound.init: RPM specfile and Linux rc.d initfile.
* update-anchor.sh: shell script that uses unbound-host to update a set
of trust anchor files. Run from cron twice a month.
* unbound_munin_ : plugin for munin statistics report
+4 -2
View File
@@ -15,9 +15,11 @@
name="unbound"
rcvar=`set_rcvar`
load_rc_config $name
command="/usr/local/sbin/unbound"
pidfile="/usr/local/etc/unbound/unbound.pid"
pidfile=${unbound_pidfile:-"/usr/local/etc/unbound/unbound.pid"}
command_args=${unbound_flags:-"-c /usr/local/etc/unbound/unbound.conf"}
extra_commands="reload"
load_rc_config $name
run_rc_command "$1"
+119
View File
@@ -0,0 +1,119 @@
#!/bin/sh
#
# unbound This shell script takes care of starting and stopping
# unbound (DNS server).
#
# chkconfig: - 14 86
# description: unbound is a Domain Name Server (DNS) \
# that is used to resolve host names to IP addresses.
### BEGIN INIT INFO
# Provides: unbound
# Required-Start: $network $local_fs
# Required-Stop: $network $local_fs
# Should-Start: $syslog
# Should-Stop: $syslog
# Short-Description: unbound recursive Domain Name Server.
# Description: unbound is a Domain Name Server (DNS)
# that is used to resolve host names to IP addresses.
### END INIT INFO
# Source function library.
. /etc/rc.d/init.d/functions
exec="/usr/sbin/unbound"
config="/var/lib/unbound/unbound.conf"
rootdir="/var/lib/unbound"
pidfile="/var/run/unbound/unbound.pid"
[ -e /etc/sysconfig/unbound ] && . /etc/sysconfig/unbound
lockfile=/var/lock/subsys/unbound
start() {
[ -x $exec ] || exit 5
[ -f $config ] || exit 6
echo -n $"Starting unbound: "
if [ ! -e ${rootdir}/etc/resolv.conf ] || /usr/bin/cmp -s /etc/resolv.conf ${rootdir}/etc/resolv.conf; then
cp -fp /etc/resolv.conf ${rootdir}/etc/resolv.conf
fi;
if [ ! -e ${rootdir}/etc/localtime ] || /usr/bin/cmp -s /etc/localtime ${rootdir}/etc/localtime; then
cp -fp /etc/localtime ${rootdir}/etc/localtime
fi;
mount --bind -n /dev/log ${rootdir}/dev/log >/dev/null 2>&1;
mount --bind -n /dev/random ${rootdir}/dev/random >/dev/null 2>&1;
mount --bind -n /var/run/unbound ${rootdir}/var/run/unbound >/dev/null 2>&1;
# if not running, start it up here
daemon $exec
retval=$?
[ $retval -eq 0 ] && touch $lockfile
echo
}
stop() {
echo -n $"Stopping unbound: "
# stop it here, often "killproc unbound"
killproc -p $pidfile unbound
retval=$?
[ $retval -eq 0 ] && rm -f $lockfile
for mountfile in /dev/log /dev/random /etc/localtime /etc/resolv.conf /var/run/unbound
do
if egrep -q '^/[^[:space:]]+[[:space:]]+'${rootdir}''${mountfile}'' /proc/mounts; then
umount ${rootdir}$mountfile >/dev/null 2>&1
fi;
done
echo
}
restart() {
stop
start
}
reload() {
kill -HUP `cat $pidfile`
}
force_reload() {
restart
}
rh_status() {
# run checks to determine if the service is running or use generic status
status -p $pidfile unbound
}
rh_status_q() {
rh_status -p $pidfile >/dev/null 2>&1
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
reload)
reload
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
restart
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
exit 2
esac
exit $?
+185
View File
@@ -0,0 +1,185 @@
Summary: Validating, recursive, and caching DNS(SEC) resolver
Name: unbound
Version: 1.1.0
Release: 1%{?dist}
License: BSD
Url: http://www.nlnetlabs.nl/unbound/
Source: http://www.unbound.net/downloads/%{name}-%{version}.tar.gz
Source1: unbound.init
Source2: unbound.conf
Group: System Environment/Daemons
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: flex, openssl-devel, ldns-devel >= 1.3.0, libevent-devel
Requires(post): chkconfig
Requires(preun): chkconfig
Requires(preun): initscripts
Requires(postun): initscripts
Requires: ldns >= 1.3.0
Requires(pre): shadow-utils
# Is this obsolete?
#Provides: caching-nameserver
%description
Unbound is a validating, recursive, and caching DNS(SEC) resolver.
The C implementation of Unbound is developed and maintained by NLnet
Labs. It is based on ideas and algorithms taken from a java prototype
developed by Verisign labs, Nominet, Kirei and ep.net.
Unbound is designed as a set of modular components, so that also
DNSSEC (secure DNS) validation and stub-resolvers (that do not run
as a server, but are linked into an application) are easily possible.
%package devel
Summary: Development package that includes the unbound header files
Group: Development/Libraries
Requires: %{name}-libs = %{version}-%{release}, openssl-devel, ldns-devel
Requires: libevent-devel
%description devel
The devel package contains the unbound library and the include files
%package libs
Summary: Libraries used by the unbound server and client applications
Group: Applications/System
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
%description libs
Contains libraries used by the unbound server and client applications
%prep
%setup -q
%build
%configure --with-ldns= --with-libevent --with-pthreads --with-ssl \
--disable-rpath --enable-debug --disable-static \
--with-run-dir=%{_localstatedir}/lib/%{name}\
--with-conf-file=%{_localstatedir}/lib/%{name}/unbound.conf \
--with-pidfile=%{_localstatedir}/run/%{name}/%{name}.pid
%{__make} CFLAGS="$RPM_OPT_FLAGS -D_GNU_SOURCE" QUIET=no %{?_smp_mflags}
%install
rm -rf %{buildroot}
%{__make} DESTDIR=%{buildroot} install
install -d 0755 %{buildroot}%{_localstatedir}/lib/%{name}
install -d 0755 %{buildroot}%{_initrddir}
#install -m 0755 contrib/unbound.init %{buildroot}%{_initrddir}/unbound
install -m 0755 %{SOURCE1} %{buildroot}%{_initrddir}/unbound
#overwrite stock unbound.conf with our own
install -m 0755 %{SOURCE2} %{buildroot}%{_localstatedir}/lib/%{name}
# add symbolic link from /etc/unbound.conf -> /var/unbound/unbound.conf
( cd %{buildroot}%{_sysconfdir}/ ; ln -s ..%{_localstatedir}/lib/unbound/unbound.conf )
# remove static library from install (fedora packaging guidelines)
rm -rf %{buildroot}%{_libdir}/*.la
# The chroot needs /dev/log, /dev/random, /etc/resolv.conf and /etc/localtime
# but the init script uses mount --bind, so just create empty files
mkdir -p %{buildroot}%{_localstatedir}/lib/unbound/etc \
%{buildroot}%{_localstatedir}/lib/unbound/dev
echo "Used for mount --bind in initscript" > %{buildroot}%{_localstatedir}/lib/unbound/etc/resolv.conf
echo "Used for mount --bind in initscript" > %{buildroot}%{_localstatedir}/lib/unbound/etc/localtime
echo "Used for mount --bind in initscript" > %{buildroot}%{_localstatedir}/lib/unbound/dev/log
echo "Used for mount --bind in initscript" > %{buildroot}%{_localstatedir}/lib/unbound/dev/random
mkdir -p %{buildroot}%{_localstatedir}/lib/unbound/var/run/unbound
mkdir -p %{buildroot}%{_localstatedir}/run/unbound
%clean
rm -rf ${RPM_BUILD_ROOT}
%files
%defattr(-,root,root,-)
%doc doc/README doc/CREDITS doc/LICENSE doc/FEATURES
%attr(0755,root,root) %{_initrddir}/%{name}
# the chroot env
%attr(0755,root,root) %dir %{_localstatedir}/lib/%{name}
%attr(0755,unbound,unbound) %dir %{_localstatedir}/run/%{name}
%attr(0755,root,root) %dir %{_localstatedir}/lib/%{name}/dev
%attr(0755,root,root) %dir %{_localstatedir}/lib/%{name}/etc
%attr(0755,root,root) %dir %{_localstatedir}/lib/%{name}/var
%attr(0755,root,root) %dir %{_localstatedir}/lib/%{name}/var/run
%attr(0755,root,root) %dir %{_localstatedir}/lib/%{name}/var/run/unbound
%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/unbound.conf
%attr(0644,root,root) %config(noreplace) %{_localstatedir}/lib/%{name}/unbound.conf
%attr(0644,root,root) %{_localstatedir}/lib/%{name}/dev/*
%attr(0644,root,root) %{_localstatedir}/lib/%{name}/etc/*
%{_sbindir}/*
%{_mandir}/*/*
%files devel
%defattr(-,root,root,-)
%{_libdir}/libunbound.so
%{_includedir}/unbound.h
%doc README
%files libs
%defattr(-,root,root,-)
%{_libdir}/libunbound.so.*
%doc doc/README doc/LICENSE
%pre
getent group unbound >/dev/null || groupadd -r unbound
getent passwd unbound >/dev/null || \
useradd -r -g unbound -d %{_localstatedir}/lib/%{name} -s /sbin/nologin \
-c "Unbound DNS resolver" unbound
exit 0
%post
/sbin/chkconfig --add %{name}
%post libs -p /sbin/ldconfig
%preun
if [ $1 -eq 0 ]; then
/sbin/service %{name} stop >/dev/null 2>&1
/sbin/chkconfig --del %{name}
fi
%postun
if [ "$1" -ge "1" ]; then
/sbin/service %{name} condrestart >/dev/null 2>&1 || :
fi
%postun libs -p /sbin/ldconfig
%changelog
* Wed Oct 22 2008 Paul Wouters <paul@xelerance.com> - 1.0.2-5
- Only call ldconfig in -libs package
- Move configure into build section
- devel subpackage should only depend on libs subpackage
* Tue Oct 21 2008 Paul Wouters <paul@xelerance.com> - 1.0.2-4
- Fix CFLAGS getting lost in build
- Don't enable interface-automatic:yes because that
causes unbound to listen on 0.0.0.0 instead of 127.0.0.1
* Sun Oct 19 2008 Paul Wouters <paul@xelerance.com> - 1.0.2-3
- Split off unbound-libs, make build verbose
* Thu Oct 9 2008 Paul Wouters <paul@xelerance.com> - 1.0.2-2
- FSB compliance, chroot fixes, initscript fixes
* Thu Sep 11 2008 Paul Wouters <paul@xelerance.com> - 1.0.2-1
- Upgraded to 1.0.2
* Wed Jul 16 2008 Paul Wouters <paul@xelerance.com> - 1.0.1-1
- upgraded to new release
* Wed May 21 2008 Paul Wouters <paul@xelerance.com> - 1.0.0-2
- Build against ldns-1.3.0
* Wed May 21 2008 Paul Wouters <paul@xelerance.com> - 1.0.0-1
- Split of -devel package, fixed dependancies, make rpmlint happy
* Thu Apr 25 2008 Wouter Wijngaards <wouter@nlnetlabs.nl> - 0.12
- Using parts from ports collection entry by Jaap Akkerhuis.
- Using Fedoraproject wiki guidelines.
* Wed Apr 23 2008 Wouter Wijngaards <wouter@nlnetlabs.nl> - 0.11
- Initial version.
+527
View File
@@ -0,0 +1,527 @@
#!/bin/sh
#
# plugin for munin to monitor usage of unbound servers.
#
# (C) 2008 W.C.A. Wijngaards. BSD Licensed.
#
# To install; enable statistics and unbound-control in unbound.conf
# server: extended-statistics: yes
# statistics-cumulative: no
# statistics-interval: 0
# remote-control: control-enable: yes
# Run the command unbound-control-setup to generate the key files.
#
# Environment variables for this script
# statefile - where to put temporary statefile.
# unbound_conf - where the unbound.conf file is located.
# unbound_control - where to find unbound-control executable.
# spoof_warn - what level to warn about spoofing
# spoof_crit - what level to crit about spoofing
#
# You can set them in your munin/plugin-conf.d/plugins.conf file
# with:
# [unbound*]
# user root
# env.statefile /usr/local/var/munin/plugin-state/unbound-state
# env.unbound_conf /usr/local/etc/unbound/unbound.conf
# env.unbound_control /usr/local/sbin/unbound-control
# env.spoof_warn 1000
# env.spoof_crit 100000
#
# This plugin can create different graphs depending on what name
# you link it as (with ln -s) into the plugins directory
# You can link it multiple times.
# If you are only a casual user, the _hits and _by_type are most interesting,
# possibly followed by _by_rcode.
#
# unbound_munin_hits - base volume, cache hits, unwanted traffic
# unbound_munin_queue - to monitor the internal requestlist
# unbound_munin_memory - memory usage
# unbound_munin_by_type - incoming queries by type
# unbound_munin_by_class - incoming queries by class
# unbound_munin_by_opcode - incoming queries by opcode
# unbound_munin_by_rcode - answers by rcode, validation status
# unbound_munin_by_flags - incoming queries by flags
# unbound_munin_histogram - histogram of query resolving times
#
# Magic markers - optional - used by installation scripts and
# munin-config:
#
#%# family=contrib
#%# capabilities=autoconf suggest
# POD documentation
: <<=cut
=head1 NAME
unbound_munin_ - Munin plugin to monitor the Unbound DNS resolver.
=head1 APPLICABLE SYSTEMS
System with unbound daemon.
=head1 CONFIGURATION
[unbound*]
user root
env.statefile /usr/local/var/munin/plugin-state/unbound-state
env.unbound_conf /usr/local/etc/unbound/unbound.conf
env.unbound_control /usr/local/sbin/unbound-control
env.spoof_warn 1000
env.spoof_crit 100000
Use the .env settings to override the defaults.
=head1 USAGE
Can be used to present different graphs. Use ln -s for that name in
the plugins directory to enable the graph.
unbound_munin_hits - base volume, cache hits, unwanted traffic
unbound_munin_queue - to monitor the internal requestlist
unbound_munin_memory - memory usage
unbound_munin_by_type - incoming queries by type
unbound_munin_by_class - incoming queries by class
unbound_munin_by_opcode - incoming queries by opcode
unbound_munin_by_rcode - answers by rcode, validation status
unbound_munin_by_flags - incoming queries by flags
unbound_munin_histogram - histogram of query resolving times
=head1 AUTHOR
Copyright 2008 W.C.A. Wijngaards
=head1 LICENSE
BSD
=cut
state=${statefile:-/usr/local/var/munin/plugin-state/unbound-state}
conf=${unbound_conf:-/usr/local/etc/unbound/unbound.conf}
ctrl=${unbound_control:-/usr/local/sbin/unbound-control}
warn=${spoof_warn:-1000}
crit=${spoof_crit:-100000}
lock=$state.lock
# number of seconds between polling attempts.
# makes the statefile hang around for at least this many seconds,
# so that multiple links of this script can share the results.
lee=55
# to keep things within 19 characters
ABBREV="-e s/total/t/ -e s/thread/t/ -e s/num/n/ -e s/query/q/ -e s/answer/a/ -e s/unwanted/u/ -e s/requestlist/ql/ -e s/type/t/ -e s/class/c/ -e s/opcode/o/ -e s/rcode/r/ -e s/edns/e/ -e s/mem/m/ -e s/cache/c/ -e s/mod/m/"
# get value from $1 into return variable $value
get_value ( ) {
value="`grep '^'$1'=' $state | sed -e 's/^.*=//'`"
if test "$value"x = ""x; then
value="0"
fi
}
# download the state from the unbound server.
get_state ( ) {
# obtain lock for fetching the state
# because there is a race condition in fetching and writing to file
i=0
while test ! -f $lock || test "`cat $lock`" != $$; do
while test -f $lock; do
# wait
i=`expr $i + 1`
if test $i -gt 1000; then
sleep 1;
fi
if test $i -gt 1500; then
echo "error locking $lock" "=" `cat $lock`
rm -f $lock
exit 1
fi
done
# try to get it
echo $$ >$lock
done
# do not refetch if the file exists and only LEE seconds old
if test -f $state; then
now=`date +%s`
get_value "time.now"
value="`echo $value | sed -e 's/\..*$//'`"
if test $now -lt `expr $value + $lee`; then
rm -f $lock
return
fi
fi
$ctrl -c $conf stats > $state
if test $? -ne 0; then
echo "error retrieving data from unbound server"
rm -f $lock
exit 1
fi
rm -f $lock
}
if test "$1" = "autoconf" ; then
if test ! -f $conf; then
echo no "($conf does not exist)"
exit 1
fi
if test ! -d `dirname $state`; then
echo no "($state directory does not exist)"
exit 1
fi
echo yes
exit 0
fi
if test "$1" = "suggest" ; then
echo "hits"
echo "queue"
echo "memory"
echo "by_type"
echo "by_class"
echo "by_opcode"
echo "by_rcode"
echo "by_flags"
echo "histogram"
exit 0
fi
# determine my type, by name
id=`echo $0 | sed -e 's/^.*unbound_munin_//'`
if test "$id"x = ""x; then
# some default to keep people sane.
id="hits"
fi
# if $1 exists in statefile, config is echoed with label $2
exist_config ( ) {
mn=`echo $1 | sed $ABBREV | tr . _`
if grep '^'$1'=' $state >/dev/null 2>&1; then
echo "$mn.label $2"
echo "$mn.min 0"
fi
}
# print label and min 0 for a name $1 in unbound format
p_config ( ) {
mn=`echo $1 | sed $ABBREV | tr . _`
echo $mn.label "$2"
echo $mn.min 0
}
if test "$1" = "config" ; then
if test ! -f $state; then
get_state
fi
case $id in
hits)
echo "graph_title Unbound DNS traffic and cache hits"
echo "graph_args --base 1000 -l 0"
echo "graph_vlabel queries / second"
echo "graph_category DNS"
for x in thread0.num.queries thread1.num.queries \
thread2.num.queries thread3.num.queries thread4.num.queries \
thread5.num.queries thread6.num.queries thread7.num.queries; do
exist_config $x "queries handled by `basename $x .num.queries`"
done
p_config "total.num.queries" "total queries from clients"
p_config "total.num.cachehits" "cache hits"
p_config "num.query.tcp" "TCP queries"
p_config "unwanted.queries" "queries that failed acl"
p_config "unwanted.replies" "unwanted or unsolicited replies"
echo "u_replies.warning $warn"
echo "u_replies.critical $crit"
echo "graph_info DNS queries to the recursive resolver. The unwanted replies could be innocent duplicate packets, late replies, or spoof threats."
;;
queue)
echo "graph_title Unbound requestlist size"
echo "graph_args --base 1000 -l 0"
echo "graph_vlabel number of queries"
echo "graph_category DNS"
p_config "total.requestlist.avg" "Average size of queue on insert"
p_config "total.requestlist.max" "Max size of queue (in 5 min)"
p_config "total.requestlist.overwritten" "Number of queries replaced by new ones"
p_config "total.requestlist.exceeded" "Number of queries dropped due to lack of space"
echo "graph_info The queries that did not hit the cache and need recursion service take up space in the requestlist. If there are too many queries, first queries get overwritten, and at last resort dropped."
;;
memory)
echo "graph_title Unbound memory usage"
echo "graph_args --base 1024 -l 0"
echo "graph_vlabel memory used in bytes"
echo "graph_category DNS"
p_config "mem.total.sbrk" "Total memory"
p_config "mem.cache.rrset" "RRset cache memory"
p_config "mem.cache.message" "Message cache memory"
p_config "mem.mod.iterator" "Iterator module memory"
p_config "mem.mod.validator" "Validator module and key cache memory"
echo "graph_info The memory used by unbound."
;;
by_type)
echo "graph_title Unbound DNS queries by type"
echo "graph_args --base 1000 -l 0"
echo "graph_vlabel queries / second"
echo "graph_category DNS"
for x in `grep "^num.query.type" $state`; do
nm=`echo $x | sed -e 's/=.*$//'`
tp=`echo $nm | sed -e s/num.query.type.//`
p_config "$nm" "$tp"
done
echo "graph_info queries by DNS RR type queried for"
;;
by_class)
echo "graph_title Unbound DNS queries by class"
echo "graph_args --base 1000 -l 0"
echo "graph_vlabel queries / second"
echo "graph_category DNS"
for x in `grep "^num.query.class" $state`; do
nm=`echo $x | sed -e 's/=.*$//'`
tp=`echo $nm | sed -e s/num.query.class.//`
p_config "$nm" "$tp"
done
echo "graph_info queries by DNS RR class queried for."
;;
by_opcode)
echo "graph_title Unbound DNS queries by opcode"
echo "graph_args --base 1000 -l 0"
echo "graph_vlabel queries / second"
echo "graph_category DNS"
for x in `grep "^num.query.opcode" $state`; do
nm=`echo $x | sed -e 's/=.*$//'`
tp=`echo $nm | sed -e s/num.query.opcode.//`
p_config "$nm" "$tp"
done
echo "graph_info queries by opcode in the query packet."
;;
by_rcode)
echo "graph_title Unbound DNS answers by return code"
echo "graph_args --base 1000 -l 0"
echo "graph_vlabel answer packets / second"
echo "graph_category DNS"
for x in `grep "^num.answer.rcode" $state`; do
nm=`echo $x | sed -e 's/=.*$//'`
tp=`echo $nm | sed -e s/num.answer.rcode.//`
p_config "$nm" "$tp"
done
p_config "num.answer.secure" "answer secure"
p_config "num.answer.bogus" "answer bogus"
p_config "num.rrset.bogus" "num rrsets marked bogus"
echo "graph_info answers sorted by return value. rrsets bogus is the number of rrsets marked bogus per second by the validator"
;;
by_flags)
echo "graph_title Unbound DNS incoming queries by flags"
echo "graph_args --base 1000 -l 0"
echo "graph_vlabel queries / second"
echo "graph_category DNS"
p_config "num.query.flags.QR" "QR (query reply) flag"
p_config "num.query.flags.AA" "AA (auth answer) flag"
p_config "num.query.flags.TC" "TC (truncated) flag"
p_config "num.query.flags.RD" "RD (recursion desired) flag"
p_config "num.query.flags.RA" "RA (rec avail) flag"
p_config "num.query.flags.Z" "Z (zero) flag"
p_config "num.query.flags.AD" "AD (auth data) flag"
p_config "num.query.flags.CD" "CD (check disabled) flag"
p_config "num.query.edns.present" "EDNS OPT present"
p_config "num.query.edns.DO" "DO (DNSSEC OK) flag"
echo "graph_info This graphs plots the flags inside incoming queries. For example, if QR, AA, TC, RA, Z flags are set, the query can be rejected. RD, AD, CD and DO are legitimately set by some software."
;;
histogram)
echo "graph_title Unbound DNS histogram of reply time"
echo "graph_args --base 1000 -l 0"
echo "graph_vlabel queries / second"
echo "graph_category DNS"
echo hcache.label "cache hits"
echo hcache.min 0
echo hcache.draw AREA
echo hcache.colour 999999
echo h64ms.label "0 msec - 66 msec"
echo h64ms.min 0
echo h64ms.draw STACK
echo h64ms.colour 0000FF
echo h128ms.label "66 msec - 131 msec"
echo h128ms.min 0
echo h128ms.colour 1F00DF
echo h128ms.draw STACK
echo h256ms.label "131 msec - 262 msec"
echo h256ms.min 0
echo h256ms.draw STACK
echo h256ms.colour 3F00BF
echo h512ms.label "262 msec - 524 msec"
echo h512ms.min 0
echo h512ms.draw STACK
echo h512ms.colour 5F009F
echo h1s.label "524 msec - 1 sec"
echo h1s.min 0
echo h1s.draw STACK
echo h1s.colour 7F007F
echo h2s.label "1 sec - 2 sec"
echo h2s.min 0
echo h2s.draw STACK
echo h2s.colour 9F005F
echo h4s.label "2 sec - 4 sec"
echo h4s.min 0
echo h4s.draw STACK
echo h4s.colour BF003F
echo h8s.label "4 sec - 8 sec"
echo h8s.min 0
echo h8s.draw STACK
echo h8s.colour DF001F
echo h16s.label "8 sec - ..."
echo h16s.min 0
echo h16s.draw STACK
echo h16s.colour FF0000
echo "graph_info Histogram of the reply times for queries."
;;
esac
exit 0
fi
# do the stats itself
get_state
# get the time elapsed
get_value "time.elapsed"
if test $value = 0 || test $value = "0.000000"; then
echo "error: time elapsed 0 or could not retrieve data"
exit 1
fi
elapsed="$value"
# print value for $1 / elapsed
print_qps ( ) {
mn=`echo $1 | sed $ABBREV | tr . _`
get_value $1
echo "$mn.value" `echo scale=6';' $value / $elapsed | bc `
}
# print qps if line already found in $2
print_qps_line ( ) {
mn=`echo $1 | sed $ABBREV | tr . _`
value="`echo $2 | sed -e 's/^.*=//'`"
echo "$mn.value" `echo scale=6';' $value / $elapsed | bc `
}
# print value for $1
print_value ( ) {
mn=`echo $1 | sed $ABBREV | tr . _`
get_value $1
echo "$mn.value" $value
}
case $id in
hits)
for x in thread0.num.queries thread1.num.queries thread2.num.queries \
thread3.num.queries thread4.num.queries thread5.num.queries \
thread6.num.queries thread7.num.queries total.num.queries \
total.num.cachehits num.query.tcp unwanted.queries \
unwanted.replies; do
if grep "^"$x"=" $state >/dev/null 2>&1; then
print_qps $x
fi
done
;;
queue)
for x in total.requestlist.avg total.requestlist.max \
total.requestlist.overwritten total.requestlist.exceeded; do
print_value $x
done
;;
memory)
for x in mem.total.sbrk mem.cache.rrset mem.cache.message \
mem.mod.iterator mem.mod.validator; do
print_value $x
done
;;
by_type)
for x in `grep "^num.query.type" $state`; do
nm=`echo $x | sed -e 's/=.*$//'`
print_qps_line $nm $x
done
;;
by_class)
for x in `grep "^num.query.class" $state`; do
nm=`echo $x | sed -e 's/=.*$//'`
print_qps_line $nm $x
done
;;
by_opcode)
for x in `grep "^num.query.opcode" $state`; do
nm=`echo $x | sed -e 's/=.*$//'`
print_qps_line $nm $x
done
;;
by_rcode)
for x in `grep "^num.answer.rcode" $state`; do
nm=`echo $x | sed -e 's/=.*$//'`
print_qps_line $nm $x
done
print_qps "num.answer.secure"
print_qps "num.answer.bogus"
print_qps "num.rrset.bogus"
;;
by_flags)
for x in num.query.flags.QR num.query.flags.AA num.query.flags.TC num.query.flags.RD num.query.flags.RA num.query.flags.Z num.query.flags.AD num.query.flags.CD num.query.edns.present num.query.edns.DO; do
print_qps $x
done
;;
histogram)
get_value total.num.cachehits
echo hcache.value `echo scale=6';' $value / $elapsed | bc `
r=0
for x in histogram.000000.000000.to.000000.000001 \
histogram.000000.000001.to.000000.000002 \
histogram.000000.000002.to.000000.000004 \
histogram.000000.000004.to.000000.000008 \
histogram.000000.000008.to.000000.000016 \
histogram.000000.000016.to.000000.000032 \
histogram.000000.000032.to.000000.000064 \
histogram.000000.000064.to.000000.000128 \
histogram.000000.000128.to.000000.000256 \
histogram.000000.000256.to.000000.000512 \
histogram.000000.000512.to.000000.001024 \
histogram.000000.001024.to.000000.002048 \
histogram.000000.002048.to.000000.004096 \
histogram.000000.004096.to.000000.008192 \
histogram.000000.008192.to.000000.016384 \
histogram.000000.016384.to.000000.032768 \
histogram.000000.032768.to.000000.065536; do
get_value $x
r=`expr $r + $value`
done
echo h64ms.value `echo scale=6';' $r / $elapsed | bc `
get_value histogram.000000.065536.to.000000.131072
echo h128ms.value `echo scale=6';' $value / $elapsed | bc `
get_value histogram.000000.131072.to.000000.262144
echo h256ms.value `echo scale=6';' $value / $elapsed | bc `
get_value histogram.000000.262144.to.000000.524288
echo h512ms.value `echo scale=6';' $value / $elapsed | bc `
get_value histogram.000000.524288.to.000001.000000
echo h1s.value `echo scale=6';' $value / $elapsed | bc `
get_value histogram.000001.000000.to.000002.000000
echo h2s.value `echo scale=6';' $value / $elapsed | bc `
get_value histogram.000002.000000.to.000004.000000
echo h4s.value `echo scale=6';' $value / $elapsed | bc `
get_value histogram.000004.000000.to.000008.000000
echo h8s.value `echo scale=6';' $value / $elapsed | bc `
r=0
for x in histogram.000008.000000.to.000016.000000 \
histogram.000016.000000.to.000032.000000 \
histogram.000032.000000.to.000064.000000 \
histogram.000064.000000.to.000128.000000 \
histogram.000128.000000.to.000256.000000 \
histogram.000256.000000.to.000512.000000 \
histogram.000512.000000.to.001024.000000 \
histogram.001024.000000.to.002048.000000 \
histogram.002048.000000.to.004096.000000 \
histogram.004096.000000.to.008192.000000 \
histogram.008192.000000.to.016384.000000 \
histogram.016384.000000.to.032768.000000 \
histogram.032768.000000.to.065536.000000 \
histogram.065536.000000.to.131072.000000 \
histogram.131072.000000.to.262144.000000 \
histogram.262144.000000.to.524288.000000; do
get_value $x
r=`expr $r + $value`
done
echo h16s.value `echo scale=6';' $r / $elapsed | bc `
;;
esac
+26 -15
View File
@@ -1,11 +1,12 @@
#!/bin/sh
# update-anchor.sh, update a trust anchor.
# this file is BSD licensed.
# Copyright 2008, W.C.A. Wijngaards
# This file is BSD licensed, see doc/LICENSE.
# which validating lookup to use.
ubhost=unbound-host
function usage()
usage ( )
{
echo "usage: update-anchor [-b] <zone name> <trust anchor file>"
echo " performs an update of trust anchor file"
@@ -21,7 +22,9 @@ function usage()
echo " name the files br.anchor se.anchor ..., and include them in"
echo " the validating resolver config file."
echo " put keys for the root in a file with the name root.anchor."
exit 1
echo ""
echo "Exit code 0 means anchors updated, 1 no changes, others are errors."
exit 2
}
if test $# -eq 0; then
@@ -39,10 +42,11 @@ if test $# -ne 2; then
usage
fi
function do_update() {
do_update ( ) {
# arguments: <zonename> <keyfile>
zonename="$1"
keyfile="$2"
tmp2=$tmpfile.2
tmpfile="/tmp/update-anchor.$$"
$ubhost -v $filearg "$keyfile" -t DNSKEY "$zonename" >$tmpfile
@@ -67,22 +71,22 @@ function do_update() {
if test $bindformat = "yes"; then
# are there any KSK keys on board?
echo 'trusted-keys {' > "$keyfile"
echo 'trusted-keys {' > "$tmp2"
if grep ' has DNSKEY record 257' $tmpfile >/dev/null 2>&1; then
# store KSK keys in anchor file
grep '(secure)$' $tmpfile | \
grep ' has DNSKEY record 257' | \
sed -e 's/ (secure)$/";/' | \
sed -e 's/ has DNSKEY record \([0-9]*\) \([0-9]*\) \([0-9]*\) /. \1 \2 \3 "/' | \
sed -e 's/^\.\././' >> "$keyfile"
sed -e 's/^\.\././' | sort >> "$tmp2"
else
# store all keys in the anchor file
grep '(secure)$' $tmpfile | \
sed -e 's/ (secure)$/";/' | \
sed -e 's/ has DNSKEY record \([0-9]*\) \([0-9]*\) \([0-9]*\) /. \1 \2 \3 "/' | \
sed -e 's/^\.\././' >> "$keyfile"
sed -e 's/^\.\././' | sort >> "$tmp2"
fi
echo '};' >> "$keyfile"
echo '};' >> "$tmp2"
else #not bindformat
# are there any KSK keys on board?
if grep ' has DNSKEY record 257' $tmpfile >/dev/null 2>&1; then
@@ -91,21 +95,30 @@ function do_update() {
grep ' has DNSKEY record 257' | \
sed -e 's/ (secure)$//' | \
sed -e 's/ has DNSKEY record /. IN DNSKEY /' | \
sed -e 's/^\.\././' > "$keyfile"
sed -e 's/^\.\././' | sort > "$tmp2"
else
# store all keys in the anchor file
grep '(secure)$' $tmpfile | \
sed -e 's/ (secure)$//' | \
sed -e 's/ has DNSKEY record /. IN DNSKEY /' | \
sed -e 's/^\.\././' > "$keyfile"
sed -e 's/^\.\././' | sort > "$tmp2"
fi
fi # endif-bindformat
echo "$zonename key file $keyfile updated."
# copy over if changed
diff $tmp2 $keyfile >/dev/null 2>&1
if test $? -eq 1; then # 0 means no change, 2 means trouble.
cat $tmp2 > $keyfile
no_updated=0
echo "$zonename key file $keyfile updated."
else
echo "$zonename key file $keyfile unchanged."
fi
rm -f $tmpfile
rm -f $tmpfile $tmp2
}
no_updated=1
if test X"$1" = "X-d"; then
tdir="$2"
echo "start updating in $2"
@@ -128,7 +141,5 @@ else
fi
kfile="$2"
do_update $zname $kfile
exit $?
fi
exit 0
exit $no_updated
+8 -82
View File
@@ -46,21 +46,6 @@
#include "util/config_file.h"
#include "util/net_help.h"
int
acl_list_cmp(const void* k1, const void* k2)
{
struct acl_addr* n1 = (struct acl_addr*)k1;
struct acl_addr* n2 = (struct acl_addr*)k2;
int r = sockaddr_cmp_addr(&n1->addr, n1->addrlen, &n2->addr,
n2->addrlen);
if(r != 0) return r;
if(n1->net < n2->net)
return -1;
if(n1->net > n2->net)
return 1;
return 0;
}
struct acl_list*
acl_list_create()
{
@@ -82,7 +67,6 @@ acl_list_delete(struct acl_list* acl)
if(!acl)
return;
regional_destroy(acl->region);
free(acl->tree);
free(acl);
}
@@ -96,13 +80,8 @@ acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
sizeof(struct acl_addr));
if(!node)
return 0;
node->node.key = node;
memcpy(&node->addr, addr, addrlen);
node->addrlen = addrlen;
node->net = net;
node->parent = NULL;
node->control = control;
if(!rbtree_insert(acl->tree, &node->node)) {
if(!addr_tree_insert(&acl->tree, &node->node, addr, addrlen, net)) {
if(complain_duplicates)
verbose(VERB_QUERY, "duplicate acl address ignored.");
}
@@ -124,6 +103,8 @@ acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
control = acl_deny;
else if(strcmp(s2, "refuse") == 0)
control = acl_refuse;
else if(strcmp(s2, "allow_snoop") == 0)
control = acl_allow_snoop;
else {
log_err("access control type %s unknown", str);
return 0;
@@ -153,42 +134,11 @@ read_acl_list(struct acl_list* acl, struct config_file* cfg)
return 1;
}
/** initialise parent pointers in the tree */
static void
acl_list_init_parents(struct acl_list* acl)
{
struct acl_addr* node, *prev = NULL, *p;
int m;
RBTREE_FOR(node, struct acl_addr*, acl->tree) {
node->parent = NULL;
if(!prev || prev->addrlen != node->addrlen) {
prev = node;
continue;
}
m = addr_in_common(&prev->addr, prev->net, &node->addr,
node->net, node->addrlen);
/* sort order like: ::/0, 1::/2, 1::/4, ... 2::/2 */
/* find the previous, or parent-parent-parent */
for(p = prev; p; p = p->parent)
if(p->net <= m) {
/* ==: since prev matched m, this is closest*/
/* <: prev matches more, but is not a parent,
* this one is a (grand)parent */
node->parent = p;
break;
}
prev = node;
}
}
int
acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg)
{
regional_free_all(acl->region);
free(acl->tree);
acl->tree = rbtree_create(acl_list_cmp);
if(!acl->tree)
return 0;
addr_tree_init(&acl->tree);
if(!read_acl_list(acl, cfg))
return 0;
/* insert defaults, with '0' to ignore them if they are duplicates */
@@ -204,7 +154,7 @@ acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg)
if(!acl_list_str_cfg(acl, "::ffff:127.0.0.1", "allow", 0))
return 0;
}
acl_list_init_parents(acl);
addr_tree_init_parents(&acl->tree);
return 1;
}
@@ -212,33 +162,9 @@ enum acl_access
acl_list_lookup(struct acl_list* acl, struct sockaddr_storage* addr,
socklen_t addrlen)
{
/* lookup in the tree */
rbnode_t* res = NULL;
struct acl_addr* result;
struct acl_addr key;
key.node.key = &key;
memcpy(&key.addr, addr, addrlen);
key.addrlen = addrlen;
key.net = (addr_is_ip6(addr, addrlen)?128:32);
if(rbtree_find_less_equal(acl->tree, &key, &res)) {
/* exact */
result = (struct acl_addr*)res;
return result->control;
} else {
/* smaller element (or no element) */
int m;
result = (struct acl_addr*)res;
if(!result || result->addrlen != addrlen)
return acl_deny;
/* count number of bits matched */
m = addr_in_common(&result->addr, result->net, addr,
key.net, addrlen);
while(result) { /* go up until addr is inside netblock */
if(result->net <= m)
return result->control;
result = result->parent;
}
}
struct acl_addr* r = (struct acl_addr*)addr_tree_lookup(&acl->tree,
addr, addrlen);
if(r) return r->control;
return acl_deny;
}
+8 -17
View File
@@ -42,7 +42,7 @@
#ifndef DAEMON_ACL_LIST_H
#define DAEMON_ACL_LIST_H
#include "util/rbtree.h"
#include "util/storage/dnstree.h"
struct config_file;
struct regional;
@@ -55,8 +55,10 @@ enum acl_access {
acl_deny = 0,
/** disallow access, send a polite 'REFUSED' reply */
acl_refuse,
/** allow full access */
acl_allow
/** allow full access for recursion (+RD) queries */
acl_allow,
/** allow full access for all queries, recursion and cache snooping */
acl_allow_snoop
};
/**
@@ -69,7 +71,7 @@ struct acl_list {
* Tree of the addresses that are allowed/blocked.
* contents of type acl_addr.
*/
rbtree_t* tree;
rbtree_t tree;
};
/**
@@ -77,16 +79,8 @@ struct acl_list {
* An address span with access control information
*/
struct acl_addr {
/** redblacktree node, key is this structure: addr and addrlen, net */
rbnode_t node;
/** parent node in acl tree that encompasses this entry */
struct acl_addr* parent;
/** address */
struct sockaddr_storage addr;
/** length of addr */
socklen_t addrlen;
/** netblock size */
int net;
/** node in address tree */
struct addr_tree_node node;
/** access control on this netblock */
enum acl_access control;
};
@@ -128,7 +122,4 @@ enum acl_access acl_list_lookup(struct acl_list* acl,
*/
size_t acl_list_get_mem(struct acl_list* acl);
/** compare two acl list entries */
int acl_list_cmp(const void* k1, const void* k2);
#endif /* DAEMON_ACL_LIST_H */
+856
View File
@@ -0,0 +1,856 @@
/*
* daemon/cachedump.c - dump the cache to text format.
*
* Copyright (c) 2008, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains functions to read and write the cache(s)
* to text format.
*/
#include "config.h"
#include "daemon/cachedump.h"
#include "daemon/remote.h"
#include "daemon/worker.h"
#include "services/cache/rrset.h"
#include "services/cache/dns.h"
#include "util/data/msgreply.h"
#include "util/regional.h"
#include "util/net_help.h"
#include "util/data/dname.h"
#include "iterator/iter_delegpt.h"
#include "iterator/iter_utils.h"
/** convert to ldns rr */
static ldns_rr*
to_rr(struct ub_packed_rrset_key* k, struct packed_rrset_data* d,
uint32_t now, size_t i, uint16_t type)
{
ldns_rr* rr = ldns_rr_new();
ldns_rdf* rdf;
ldns_status status;
size_t pos;
log_assert(i < d->count + d->rrsig_count);
if(!rr) {
return NULL;
}
ldns_rr_set_type(rr, type);
ldns_rr_set_class(rr, ntohs(k->rk.rrset_class));
if(d->rr_ttl[i] < now)
ldns_rr_set_ttl(rr, 0);
else ldns_rr_set_ttl(rr, d->rr_ttl[i] - now);
pos = 0;
status = ldns_wire2dname(&rdf, k->rk.dname, k->rk.dname_len, &pos);
if(status != LDNS_STATUS_OK) {
/* we drop detailed error in status */
ldns_rr_free(rr);
return NULL;
}
ldns_rr_set_owner(rr, rdf);
pos = 0;
status = ldns_wire2rdf(rr, d->rr_data[i], d->rr_len[i], &pos);
if(status != LDNS_STATUS_OK) {
/* we drop detailed error in status */
ldns_rr_free(rr);
return NULL;
}
return rr;
}
/** dump one rrset zonefile line */
static int
dump_rrset_line(SSL* ssl, struct ub_packed_rrset_key* k,
struct packed_rrset_data* d, uint32_t now, size_t i, uint16_t type)
{
char* s;
ldns_rr* rr = to_rr(k, d, now, i, type);
if(!rr) {
return ssl_printf(ssl, "BADRR\n");
}
s = ldns_rr2str(rr);
ldns_rr_free(rr);
if(!s) {
return ssl_printf(ssl, "BADRR\n");
}
if(!ssl_printf(ssl, "%s", s)) {
free(s);
return 0;
}
free(s);
return 1;
}
/** dump rrset key and data info */
static int
dump_rrset(SSL* ssl, struct ub_packed_rrset_key* k,
struct packed_rrset_data* d, uint32_t now)
{
size_t i;
/* rd lock held by caller */
if(!k || !d) return 1;
if(d->ttl < now) return 1; /* expired */
/* meta line */
if(!ssl_printf(ssl, ";rrset%s %u %u %u %d %d\n",
(k->rk.flags & PACKED_RRSET_NSEC_AT_APEX)?" nsec_apex":"",
(unsigned)(d->ttl - now),
(unsigned)d->count, (unsigned)d->rrsig_count,
(int)d->trust, (int)d->security
))
return 0;
for(i=0; i<d->count; i++) {
if(!dump_rrset_line(ssl, k, d, now, i, ntohs(k->rk.type)))
return 0;
}
for(i=0; i<d->rrsig_count; i++) {
if(!dump_rrset_line(ssl, k, d, now, i+d->count,
LDNS_RR_TYPE_RRSIG))
return 0;
}
return 1;
}
/** dump lruhash rrset cache */
static int
dump_rrset_lruhash(SSL* ssl, struct lruhash* h, uint32_t now)
{
struct lruhash_entry* e;
/* lruhash already locked by caller */
/* walk in order of lru; best first */
for(e=h->lru_start; e; e = e->lru_next) {
lock_rw_rdlock(&e->lock);
if(!dump_rrset(ssl, (struct ub_packed_rrset_key*)e->key,
(struct packed_rrset_data*)e->data, now)) {
lock_rw_unlock(&e->lock);
return 0;
}
lock_rw_unlock(&e->lock);
}
return 1;
}
/** dump rrset cache */
static int
dump_rrset_cache(SSL* ssl, struct worker* worker)
{
struct rrset_cache* r = worker->env.rrset_cache;
size_t slab;
if(!ssl_printf(ssl, "START_RRSET_CACHE\n")) return 0;
for(slab=0; slab<r->table.size; slab++) {
lock_quick_lock(&r->table.array[slab]->lock);
if(!dump_rrset_lruhash(ssl, r->table.array[slab],
*worker->env.now)) {
lock_quick_unlock(&r->table.array[slab]->lock);
return 0;
}
lock_quick_unlock(&r->table.array[slab]->lock);
}
return ssl_printf(ssl, "END_RRSET_CACHE\n");
}
/** dump message to rrset reference */
static int
dump_msg_ref(SSL* ssl, struct ub_packed_rrset_key* k)
{
ldns_rdf* rdf;
ldns_status status;
size_t pos;
char* nm, *tp, *cl;
pos = 0;
status = ldns_wire2dname(&rdf, k->rk.dname, k->rk.dname_len, &pos);
if(status != LDNS_STATUS_OK) {
return ssl_printf(ssl, "BADREF\n");
}
nm = ldns_rdf2str(rdf);
ldns_rdf_deep_free(rdf);
tp = ldns_rr_type2str(ntohs(k->rk.type));
cl = ldns_rr_class2str(ntohs(k->rk.rrset_class));
if(!nm || !cl || !tp) {
free(nm);
free(tp);
free(cl);
return ssl_printf(ssl, "BADREF\n");
}
if(!ssl_printf(ssl, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags)) {
free(nm);
free(tp);
free(cl);
return 0;
}
free(nm);
free(tp);
free(cl);
return 1;
}
/** dump message entry */
static int
dump_msg(SSL* ssl, struct query_info* k, struct reply_info* d,
uint32_t now)
{
size_t i;
char* nm, *tp, *cl;
ldns_rdf* rdf;
ldns_status status;
size_t pos;
if(!k || !d) return 1;
if(d->ttl < now) return 1; /* expired */
pos = 0;
status = ldns_wire2dname(&rdf, k->qname, k->qname_len, &pos);
if(status != LDNS_STATUS_OK) {
return 1; /* skip this entry */
}
nm = ldns_rdf2str(rdf);
ldns_rdf_deep_free(rdf);
tp = ldns_rr_type2str(k->qtype);
cl = ldns_rr_class2str(k->qclass);
if(!nm || !tp || !cl) {
free(nm);
free(tp);
free(cl);
return 1; /* skip this entry */
}
if(!rrset_array_lock(d->ref, d->rrset_count, now)) {
/* rrsets have timed out or do not exist */
free(nm);
free(tp);
free(cl);
return 1; /* skip this entry */
}
/* meta line */
if(!ssl_printf(ssl, "msg %s %s %s %d %d %u %d %u %u %u\n",
nm, cl, tp,
(int)d->flags, (int)d->qdcount,
(unsigned)(d->ttl-now), (int)d->security,
(unsigned)d->an_numrrsets,
(unsigned)d->ns_numrrsets,
(unsigned)d->ar_numrrsets)) {
free(nm);
free(tp);
free(cl);
rrset_array_unlock(d->ref, d->rrset_count);
return 0;
}
free(nm);
free(tp);
free(cl);
for(i=0; i<d->rrset_count; i++) {
if(!dump_msg_ref(ssl, d->rrsets[i])) {
rrset_array_unlock(d->ref, d->rrset_count);
return 0;
}
}
rrset_array_unlock(d->ref, d->rrset_count);
return 1;
}
/** copy msg to worker pad */
static int
copy_msg(struct regional* region, struct lruhash_entry* e,
struct query_info** k, struct reply_info** d)
{
struct reply_info* rep = (struct reply_info*)e->data;
*d = (struct reply_info*)regional_alloc_init(region, e->data,
sizeof(struct reply_info) +
sizeof(struct rrset_ref) * (rep->rrset_count-1) +
sizeof(struct ub_packed_rrset_key*) * rep->rrset_count);
if(!*d)
return 0;
(*d)->rrsets = (struct ub_packed_rrset_key**)(
(uint8_t*)(&((*d)->ref[0])) +
sizeof(struct rrset_ref) * rep->rrset_count);
*k = (struct query_info*)regional_alloc_init(region,
e->key, sizeof(struct query_info));
if(!*k)
return 0;
(*k)->qname = regional_alloc_init(region,
(*k)->qname, (*k)->qname_len);
return (*k)->qname != NULL;
}
/** dump lruhash msg cache */
static int
dump_msg_lruhash(SSL* ssl, struct worker* worker, struct lruhash* h)
{
struct lruhash_entry* e;
struct query_info* k;
struct reply_info* d;
/* lruhash already locked by caller */
/* walk in order of lru; best first */
for(e=h->lru_start; e; e = e->lru_next) {
regional_free_all(worker->scratchpad);
lock_rw_rdlock(&e->lock);
/* make copy of rrset in worker buffer */
if(!copy_msg(worker->scratchpad, e, &k, &d)) {
lock_rw_unlock(&e->lock);
return 0;
}
lock_rw_unlock(&e->lock);
/* release lock so we can lookup the rrset references
* in the rrset cache */
if(!dump_msg(ssl, k, d, *worker->env.now)) {
return 0;
}
}
return 1;
}
/** dump msg cache */
static int
dump_msg_cache(SSL* ssl, struct worker* worker)
{
struct slabhash* sh = worker->env.msg_cache;
size_t slab;
if(!ssl_printf(ssl, "START_MSG_CACHE\n")) return 0;
for(slab=0; slab<sh->size; slab++) {
lock_quick_lock(&sh->array[slab]->lock);
if(!dump_msg_lruhash(ssl, worker, sh->array[slab])) {
lock_quick_unlock(&sh->array[slab]->lock);
return 0;
}
lock_quick_unlock(&sh->array[slab]->lock);
}
return ssl_printf(ssl, "END_MSG_CACHE\n");
}
int
dump_cache(SSL* ssl, struct worker* worker)
{
if(!dump_rrset_cache(ssl, worker))
return 0;
if(!dump_msg_cache(ssl, worker))
return 0;
return ssl_printf(ssl, "EOF\n");
}
/** read a line from ssl into buffer */
static int
ssl_read_buf(SSL* ssl, ldns_buffer* buf)
{
return ssl_read_line(ssl, (char*)ldns_buffer_begin(buf),
ldns_buffer_capacity(buf));
}
/** check fixed text on line */
static int
read_fixed(SSL* ssl, ldns_buffer* buf, const char* str)
{
if(!ssl_read_buf(ssl, buf)) return 0;
return (strcmp((char*)ldns_buffer_begin(buf), str) == 0);
}
/** load an RR into rrset */
static int
load_rr(SSL* ssl, ldns_buffer* buf, struct regional* region,
struct ub_packed_rrset_key* rk, struct packed_rrset_data* d,
unsigned int i, int is_rrsig, int* go_on, uint32_t now)
{
ldns_rr* rr;
ldns_status status;
/* read the line */
if(!ssl_read_buf(ssl, buf))
return 0;
if(strncmp((char*)ldns_buffer_begin(buf), "BADRR\n", 6) == 0) {
*go_on = 0;
return 1;
}
log_info("rd %s", (char*)ldns_buffer_begin(buf));
status = ldns_rr_new_frm_str(&rr, (char*)ldns_buffer_begin(buf),
LDNS_DEFAULT_TTL, NULL, NULL);
if(status != LDNS_STATUS_OK) {
(void)ssl_printf(ssl, "error cannot parse rr :%s: %s\n",
ldns_get_errorstr_by_id(status),
(char*)ldns_buffer_begin(buf));
return 0;
}
if(is_rrsig && ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
(void)ssl_printf(ssl, "error expected rrsig but got %s\n",
(char*)ldns_buffer_begin(buf));
return 0;
}
/* convert ldns rr into packed_rr */
d->rr_ttl[i] = ldns_rr_ttl(rr) + now;
ldns_buffer_clear(buf);
ldns_buffer_skip(buf, 2);
status = ldns_rr_rdata2buffer_wire(buf, rr);
if(status != LDNS_STATUS_OK) {
(void)ssl_printf(ssl, "error cannot rr2wire :%s\n",
ldns_get_errorstr_by_id(status));
ldns_rr_free(rr);
return 0;
}
ldns_buffer_flip(buf);
ldns_buffer_write_u16_at(buf, 0, ldns_buffer_limit(buf) - 2);
d->rr_len[i] = ldns_buffer_limit(buf);
d->rr_data[i] = (uint8_t*)regional_alloc_init(region,
ldns_buffer_begin(buf), ldns_buffer_limit(buf));
if(!d->rr_data[i]) {
ldns_rr_free(rr);
(void)ssl_printf(ssl, "error out of memory\n");
return 0;
}
/* if first entry, fill the key structure */
if(i==0) {
rk->rk.type = htons(ldns_rr_get_type(rr));
rk->rk.rrset_class = htons(ldns_rr_get_class(rr));
ldns_buffer_clear(buf);
status = ldns_dname2buffer_wire(buf, ldns_rr_owner(rr));
ldns_buffer_flip(buf);
rk->rk.dname_len = ldns_buffer_limit(buf);
rk->rk.dname = regional_alloc_init(region,
ldns_buffer_begin(buf), ldns_buffer_limit(buf));
if(!rk->rk.dname) {
(void)ssl_printf(ssl, "error out of memory\n");
ldns_rr_free(rr);
return 0;
}
}
ldns_rr_free(rr);
return 1;
}
/** move entry into cache */
static int
move_into_cache(SSL* ssl, struct ub_packed_rrset_key* k,
struct packed_rrset_data* d, struct worker* worker)
{
struct ub_packed_rrset_key* ak;
struct packed_rrset_data* ad;
size_t s, i, num = d->count + d->rrsig_count;
struct rrset_ref ref;
uint8_t* p;
ak = alloc_special_obtain(&worker->alloc);
if(!ak) {
(void)ssl_printf(ssl, "error out of memory\n");
return 0;
}
ak->entry.data = NULL;
ak->rk = k->rk;
ak->entry.hash = rrset_key_hash(&k->rk);
ak->rk.dname = (uint8_t*)memdup(k->rk.dname, k->rk.dname_len);
if(!ak->rk.dname) {
(void)ssl_printf(ssl, "error out of memory\n");
ub_packed_rrset_parsedelete(ak, &worker->alloc);
return 0;
}
s = sizeof(*ad) + (sizeof(size_t) + sizeof(uint8_t*) +
sizeof(uint32_t))* num;
for(i=0; i<num; i++)
s += d->rr_len[i];
ad = (struct packed_rrset_data*)malloc(s);
if(!ad) {
ub_packed_rrset_parsedelete(ak, &worker->alloc);
return 0;
}
p = (uint8_t*)ad;
memmove(p, d, sizeof(*ad));
p += sizeof(*ad);
memmove(p, &d->rr_len[0], sizeof(size_t)*num);
p += sizeof(size_t)*num;
memmove(p, &d->rr_data[0], sizeof(uint8_t*)*num);
p += sizeof(uint8_t*)*num;
memmove(p, &d->rr_ttl[0], sizeof(uint32_t)*num);
p += sizeof(uint32_t)*num;
for(i=0; i<num; i++) {
memmove(p, d->rr_data[i], d->rr_len[i]);
p += d->rr_len[i];
}
packed_rrset_ptr_fixup(ad);
ak->entry.data = ad;
ref.key = ak;
ref.id = ak->id;
(void)rrset_cache_update(worker->env.rrset_cache, &ref,
&worker->alloc, *worker->env.now);
return 1;
}
/** load an rrset entry */
static int
load_rrset(SSL* ssl, ldns_buffer* buf, struct worker* worker)
{
char* s = (char*)ldns_buffer_begin(buf);
struct regional* region = worker->scratchpad;
struct ub_packed_rrset_key* rk;
struct packed_rrset_data* d;
unsigned int ttl, rr_count, rrsig_count, trust, security;
unsigned int i;
int go_on = 1;
regional_free_all(region);
rk = (struct ub_packed_rrset_key*)regional_alloc_zero(region,
sizeof(*rk));
d = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*d));
if(!rk || !d) {
(void) ssl_printf(ssl, "error out of memory\n");
return 0;
}
if(strncmp(s, ";rrset", 6) != 0) {
(void)ssl_printf(ssl, "error expected ';rrset' but got %s\n",
s);
return 0;
}
s += 6;
if(strncmp(s, " nsec_apex", 10) == 0) {
s += 10;
rk->rk.flags |= PACKED_RRSET_NSEC_AT_APEX;
}
if(sscanf(s, " %u %u %u %u %u", &ttl, &rr_count, &rrsig_count,
&trust, &security) != 5) {
(void)ssl_printf(ssl, "error bad rrset spec %s\n", s);
return 0;
}
if(rr_count == 0 && rrsig_count == 0)
return 0;
d->count = (size_t)rr_count;
d->rrsig_count = (size_t)rrsig_count;
d->security = (enum sec_status)security;
d->trust = (enum rrset_trust)trust;
d->ttl = (uint32_t)ttl + *worker->env.now;
d->rr_len = regional_alloc_zero(region,
sizeof(size_t)*(d->count+d->rrsig_count));
d->rr_ttl = regional_alloc_zero(region,
sizeof(uint32_t)*(d->count+d->rrsig_count));
d->rr_data = regional_alloc_zero(region,
sizeof(uint8_t*)*(d->count+d->rrsig_count));
if(!d->rr_len || !d->rr_ttl || !d->rr_data) {
(void) ssl_printf(ssl, "error out of memory\n");
return 0;
}
/* read the rr's themselves */
for(i=0; i<rr_count; i++) {
if(!load_rr(ssl, buf, region, rk, d, i, 0,
&go_on, *worker->env.now)) {
return 0;
}
}
for(i=0; i<rrsig_count; i++) {
if(!load_rr(ssl, buf, region, rk, d, i+rr_count, 1,
&go_on, *worker->env.now)) {
return 0;
}
}
if(!go_on) {
/* skip this entry */
return 1;
}
return move_into_cache(ssl, rk, d, worker);
}
/** load rrset cache */
static int
load_rrset_cache(SSL* ssl, struct worker* worker)
{
ldns_buffer* buf = worker->env.scratch_buffer;
if(!read_fixed(ssl, buf, "START_RRSET_CACHE")) return 0;
while(ssl_read_buf(ssl, buf) &&
strcmp((char*)ldns_buffer_begin(buf), "END_RRSET_CACHE")!=0) {
if(!load_rrset(ssl, buf, worker))
return 0;
}
return 1;
}
/** read qinfo from next three words */
static char*
load_qinfo(char* str, struct query_info* qinfo, ldns_buffer* buf,
struct regional* region, SSL* ssl)
{
/* s is part of the buf */
char* s = str;
ldns_rr* rr;
ldns_status status;
/* skip three words */
s = strchr(str, ' ');
if(s) s = strchr(s+1, ' ');
if(s) s = strchr(s+1, ' ');
if(!s) {
(void)ssl_printf(ssl, "error line too short, %s\n", str);
return NULL;
}
s[0] = 0;
s++;
/* parse them */
status = ldns_rr_new_question_frm_str(&rr, str, NULL, NULL);
if(status != LDNS_STATUS_OK) {
(void)ssl_printf(ssl, "error cannot parse: %s %s\n",
ldns_get_errorstr_by_id(status), str);
return NULL;
}
qinfo->qtype = ldns_rr_get_type(rr);
qinfo->qclass = ldns_rr_get_class(rr);
ldns_buffer_clear(buf);
status = ldns_dname2buffer_wire(buf, ldns_rr_owner(rr));
ldns_rr_free(rr);
if(status != LDNS_STATUS_OK) {
(void)ssl_printf(ssl, "error cannot dname2wire: %s\n",
ldns_get_errorstr_by_id(status));
return NULL;
}
ldns_buffer_flip(buf);
qinfo->qname_len = ldns_buffer_limit(buf);
qinfo->qname = (uint8_t*)regional_alloc_init(region,
ldns_buffer_begin(buf), ldns_buffer_limit(buf));
if(!qinfo->qname) {
(void)ssl_printf(ssl, "error out of memory\n");
return NULL;
}
return s;
}
/** load a msg rrset reference */
static int
load_ref(SSL* ssl, ldns_buffer* buf, struct worker* worker,
struct regional *region, struct ub_packed_rrset_key** rrset,
int* go_on)
{
char* s = (char*)ldns_buffer_begin(buf);
struct query_info qinfo;
unsigned int flags;
struct ub_packed_rrset_key* k;
/* read line */
if(!ssl_read_buf(ssl, buf))
return 0;
if(strncmp(s, "BADREF", 6) == 0) {
*go_on = 0; /* its bad, skip it and skip message */
return 1;
}
s = load_qinfo(s, &qinfo, buf, region, ssl);
if(!s) {
return 0;
}
if(sscanf(s, " %u", &flags) != 1) {
(void)ssl_printf(ssl, "error cannot parse flags: %s\n", s);
return 0;
}
/* lookup in cache */
k = rrset_cache_lookup(worker->env.rrset_cache, qinfo.qname,
qinfo.qname_len, qinfo.qtype, qinfo.qclass,
(uint32_t)flags, *worker->env.now, 0);
if(!k) {
/* not found or expired */
*go_on = 0;
return 1;
}
/* store in result */
*rrset = packed_rrset_copy_region(k, region, *worker->env.now);
lock_rw_unlock(&k->entry.lock);
return (*rrset != NULL);
}
/** load a msg entry */
static int
load_msg(SSL* ssl, ldns_buffer* buf, struct worker* worker)
{
struct regional* region = worker->scratchpad;
struct query_info qinf;
struct reply_info rep;
char* s = (char*)ldns_buffer_begin(buf);
unsigned int flags, qdcount, ttl, security, an, ns, ar;
size_t i;
int go_on = 1;
regional_free_all(region);
if(strncmp(s, "msg ", 4) != 0) {
(void)ssl_printf(ssl, "error expected msg but got %s\n", s);
return 0;
}
s += 4;
s = load_qinfo(s, &qinf, buf, region, ssl);
if(!s) {
return 0;
}
/* read remainder of line */
if(sscanf(s, " %u %u %u %u %u %u %u", &flags, &qdcount, &ttl,
&security, &an, &ns, &ar) != 7) {
(void)ssl_printf(ssl, "error cannot parse numbers: %s\n", s);
return 0;
}
rep.flags = (uint16_t)flags;
rep.qdcount = (uint16_t)qdcount;
rep.ttl = (uint32_t)ttl;
rep.security = (enum sec_status)security;
rep.an_numrrsets = (size_t)an;
rep.ns_numrrsets = (size_t)ns;
rep.ar_numrrsets = (size_t)ar;
rep.rrset_count = (size_t)an+(size_t)ns+(size_t)ar;
rep.rrsets = (struct ub_packed_rrset_key**)regional_alloc_zero(
region, sizeof(struct ub_packed_rrset_key*)*rep.rrset_count);
/* fill repinfo with references */
for(i=0; i<rep.rrset_count; i++) {
if(!load_ref(ssl, buf, worker, region, &rep.rrsets[i],
&go_on)) {
return 0;
}
}
if(!go_on)
return 1; /* skip this one, not all references satisfied */
if(!dns_cache_store(&worker->env, &qinf, &rep, 0)) {
(void)ssl_printf(ssl, "error out of memory\n");
return 0;
}
return 1;
}
/** load msg cache */
static int
load_msg_cache(SSL* ssl, struct worker* worker)
{
ldns_buffer* buf = worker->env.scratch_buffer;
if(!read_fixed(ssl, buf, "START_MSG_CACHE")) return 0;
while(ssl_read_buf(ssl, buf) &&
strcmp((char*)ldns_buffer_begin(buf), "END_MSG_CACHE")!=0) {
if(!load_msg(ssl, buf, worker))
return 0;
}
return 1;
}
int
load_cache(SSL* ssl, struct worker* worker)
{
if(!load_rrset_cache(ssl, worker))
return 0;
if(!load_msg_cache(ssl, worker))
return 0;
return read_fixed(ssl, worker->env.scratch_buffer, "EOF");
}
int print_deleg_lookup(SSL* ssl, struct worker* worker, uint8_t* nm,
size_t nmlen, int ATTR_UNUSED(nmlabs))
{
/* deep links into the iterator module */
struct delegpt* dp;
struct dns_msg* msg;
struct regional* region = worker->scratchpad;
char b[260];
struct query_info qinfo;
size_t i, n_ns, n_miss, n_addr, n_res, n_avail;
regional_free_all(region);
qinfo.qname = nm;
qinfo.qname_len = nmlen;
qinfo.qtype = LDNS_RR_TYPE_A;
qinfo.qclass = LDNS_RR_CLASS_IN;
dname_str(nm, b);
if(!ssl_printf(ssl, "The following name servers are used for lookup "
"of %s\n", b))
return 0;
while(1) {
dp = dns_cache_find_delegation(&worker->env, nm, nmlen,
qinfo.qtype, qinfo.qclass, region, &msg,
*worker->env.now);
if(!dp) {
return ssl_printf(ssl, "no delegation from "
"cache; goes to configured roots\n");
}
/* print the dp */
for(i=0; i<msg->rep->rrset_count; i++) {
struct ub_packed_rrset_key* k = msg->rep->rrsets[i];
struct packed_rrset_data* d =
(struct packed_rrset_data*)k->entry.data;
if(d->security == sec_status_bogus) {
if(!ssl_printf(ssl, "Address is BOGUS:\n"))
return 0;
}
if(!dump_rrset(ssl, k, d, 0))
return 0;
}
delegpt_count_ns(dp, &n_ns, &n_miss);
delegpt_count_addr(dp, &n_addr, &n_res, &n_avail);
/* since dp has not been used by iterator, all are available*/
if(!ssl_printf(ssl, "Delegation with %d names, of which %d "
"have no addresses in cache.\n"
"It provides %d IP addresses. %s\n",
(int)n_ns, (int)n_miss, (int)n_addr,
(dp->bogus?"It is BOGUS":"") ))
return 0;
/* go up? */
if(iter_dp_is_useless(&qinfo, BIT_RD, dp)) {
if(!ssl_printf(ssl, "cache delegation was "
"useless (no IP addresses)\n"))
return 0;
if(dname_is_root(nm)) {
/* goes to root config */
return ssl_printf(ssl, "no delegation from "
"cache; goes to configured roots\n");
} else {
/* useless, goes up */
nm = dp->name;
nmlen = dp->namelen;
dname_remove_label(&nm, &nmlen);
dname_str(nm, b);
if(!ssl_printf(ssl, "going up, lookup %s\n", b))
return 0;
continue;
}
} else
break;
}
return 1;
}
+107
View File
@@ -0,0 +1,107 @@
/*
* daemon/cachedump.h - dump the cache to text format.
*
* Copyright (c) 2008, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains functions to read and write the cache(s)
* to text format.
*
* The format of the file is as follows:
* [RRset cache]
* [Message cache]
* EOF -- fixed string "EOF" before end of the file.
*
* The RRset cache is:
* START_RRSET_CACHE
* [rrset]*
* END_RRSET_CACHE
*
* rrset is:
* ;rrset [nsec_apex] TTL rr_count rrsig_count trust security
* resource records, one per line, in zonefile format
* rrsig records, one per line, in zonefile format
* If the text conversion fails, BADRR is printed on the line.
*
* The Message cache is:
* START_MSG_CACHE
* [msg]*
* END_MSG_CACHE
*
* msg is:
* msg name class type flags qdcount ttl security an ns ar
* list of rrset references, one per line. If conversion fails, BADREF
* reference is:
* name class type flags
*
* Expired cache entries are not printed.
*/
#ifndef DAEMON_DUMPCACHE_H
#define DAEMON_DUMPCACHE_H
struct worker;
/**
* Dump cache(s) to text
* @param ssl: to print to
* @param worker: worker that is available (buffers, etc) and has
* ptrs to the caches.
* @return false on ssl print error.
*/
int dump_cache(SSL* ssl, struct worker* worker);
/**
* Load cache(s) from text
* @param ssl: to read from
* @param worker: worker that is available (buffers, etc) and has
* ptrs to the caches.
* @return false on ssl error.
*/
int load_cache(SSL* ssl, struct worker* worker);
/**
* Print the delegation used to lookup for this name.
* @param ssl: to read from
* @param worker: worker that is available (buffers, etc) and has
* ptrs to the caches.
* @param nm: name to lookup
* @param nmlen: length of name.
* @param nmlabs: labels in name.
* @return false on ssl error.
*/
int print_deleg_lookup(SSL* ssl, struct worker* worker, uint8_t* nm,
size_t nmlen, int nmlabs);
#endif /* DAEMON_DUMPCACHE_H */
+33 -21
View File
@@ -42,6 +42,7 @@
#include "config.h"
#include "daemon/daemon.h"
#include "daemon/worker.h"
#include "daemon/remote.h"
#include "daemon/acl_list.h"
#include "util/log.h"
#include "util/config_file.h"
@@ -54,6 +55,7 @@
#include "services/modstack.h"
#include "util/module.h"
#include "util/random.h"
#include "util/tube.h"
#include <signal.h>
/** How many quit requests happened. */
@@ -162,6 +164,9 @@ daemon_init()
signal_handling_record();
checklock_start();
ERR_load_crypto_strings();
ERR_load_SSL_strings();
OpenSSL_add_all_algorithms();
(void)SSL_library_init();
#ifdef HAVE_TZSET
/* init timezone info while we are not chrooted yet */
tzset();
@@ -180,6 +185,9 @@ daemon_init()
free(daemon);
return NULL;
}
if(gettimeofday(&daemon->time_boot, NULL) < 0)
log_err("gettimeofday: %s", strerror(errno));
daemon->time_last_stat = daemon->time_boot;
return daemon;
}
@@ -187,12 +195,24 @@ int
daemon_open_shared_ports(struct daemon* daemon)
{
log_assert(daemon);
if(daemon->cfg->port == daemon->listening_port)
return 1;
listening_ports_free(daemon->ports);
if(!(daemon->ports=listening_ports_open(daemon->cfg)))
return 0;
daemon->listening_port = daemon->cfg->port;
if(daemon->cfg->port != daemon->listening_port) {
listening_ports_free(daemon->ports);
if(!(daemon->ports=listening_ports_open(daemon->cfg)))
return 0;
daemon->listening_port = daemon->cfg->port;
}
if(!daemon->cfg->remote_control_enable && daemon->rc_port) {
listening_ports_free(daemon->rc_ports);
daemon->rc_ports = NULL;
daemon->rc_port = 0;
}
if(daemon->cfg->remote_control_enable &&
daemon->cfg->control_port != daemon->rc_port) {
listening_ports_free(daemon->rc_ports);
if(!(daemon->rc_ports=daemon_remote_open_ports(daemon->cfg)))
return 0;
daemon->rc_port = daemon->cfg->control_port;
}
return 1;
}
@@ -292,14 +312,8 @@ void close_other_pipes(struct daemon* daemon, int thr)
int i;
for(i=0; i<daemon->num; i++)
if(i!=thr) {
if(daemon->workers[i]->cmd_send_fd != -1) {
close(daemon->workers[i]->cmd_send_fd);
daemon->workers[i]->cmd_send_fd = -1;
}
if(daemon->workers[i]->cmd_recv_fd != -1) {
close(daemon->workers[i]->cmd_recv_fd);
daemon->workers[i]->cmd_recv_fd = -1;
}
tube_delete(daemon->workers[i]->cmd);
daemon->workers[i]->cmd = NULL;
}
}
@@ -316,8 +330,7 @@ thread_start(void* arg)
ub_thread_blocksigs();
#ifdef THREADS_DISABLED
/* close pipe ends used by main */
close(worker->cmd_send_fd);
worker->cmd_send_fd = -1;
tube_close_write(worker->cmd);
close_other_pipes(worker->daemon, worker->thread_num);
#endif
if(!worker_init(worker, worker->daemon->cfg, worker->daemon->ports, 0))
@@ -343,8 +356,7 @@ daemon_start_others(struct daemon* daemon)
thread_start, daemon->workers[i]);
#ifdef THREADS_DISABLED
/* close pipe end of child */
close(daemon->workers[i]->cmd_recv_fd);
daemon->workers[i]->cmd_recv_fd = -1;
tube_close_read(daemon->workers[i]->cmd);
#endif /* no threads */
}
}
@@ -362,8 +374,7 @@ daemon_stop_others(struct daemon* daemon)
/* skip i=0, is this thread */
/* use i=0 buffer for sending cmds; because we are #0 */
for(i=1; i<daemon->num; i++) {
worker_send_cmd(daemon->workers[i],
daemon->workers[0]->front->udp_buff, worker_cmd_quit);
worker_send_cmd(daemon->workers[i], worker_cmd_quit);
}
/* wait for them to quit */
for(i=1; i<daemon->num; i++) {
@@ -399,7 +410,7 @@ daemon_fork(struct daemon* daemon)
daemon_start_others(daemon);
/* Special handling for the main thread. This is the thread
* that handles signals.
* that handles signals and remote control.
*/
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports, 1))
fatal_exit("Could not initialize main thread");
@@ -449,6 +460,7 @@ daemon_delete(struct daemon* daemon)
return;
modstack_desetup(&daemon->mods, daemon->env);
listening_ports_free(daemon->ports);
listening_ports_free(daemon->rc_ports);
if(daemon->env) {
slabhash_delete(daemon->env->msg_cache);
rrset_cache_delete(daemon->env->rrset_cache);
+8
View File
@@ -68,6 +68,10 @@ struct daemon {
int listening_port;
/** listening ports, opened, to be shared by threads */
struct listen_port* ports;
/** port number fore remote that has ports opened. */
int rc_port;
/** listening ports for remote control */
struct listen_port* rc_ports;
/** num threads allocated */
int num;
/** the worker entries */
@@ -86,6 +90,10 @@ struct daemon {
struct acl_list* acl;
/** local authority zones */
struct local_zones* local_zones;
/** last time of statistics printout */
struct timeval time_last_stat;
/** time when daemon started */
struct timeval time_boot;
};
/**
+1327
View File
File diff suppressed because it is too large Load Diff
+160
View File
@@ -0,0 +1,160 @@
/*
* daemon/remote.h - remote control for the unbound daemon.
*
* Copyright (c) 2008, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains the remote control functionality for the daemon.
* The remote control can be performed using either the commandline
* unbound-control tool, or a SSLv3/TLS capable web browser.
* The channel is secured using SSLv3 or TLSv1, and certificates.
* Both the server and the client(control tool) have their own keys.
*/
#ifndef DAEMON_REMOTE_H
#define DAEMON_REMOTE_H
struct config_file;
struct listen_list;
struct listen_port;
struct worker;
struct comm_reply;
struct comm_point;
struct daemon_remote;
/** number of seconds timeout on incoming remote control handshake */
#define REMOTE_CONTROL_TCP_TIMEOUT 120
/**
* a busy control command connection, SSL state
*/
struct rc_state {
/** the next item in list */
struct rc_state* next;
/** the commpoint */
struct comm_point* c;
/** in the handshake part */
enum { rc_none, rc_hs_read, rc_hs_write } shake_state;
/** the ssl state */
SSL* ssl;
/** the rc this is part of */
struct daemon_remote* rc;
};
/**
* The remote control tool state.
* The state is only created for the first thread, other threads
* are called from this thread. Only the first threads listens to
* the control port. The other threads do not, but are called on the
* command channel(pipe) from the first thread.
*/
struct daemon_remote {
/** the worker for this remote control */
struct worker* worker;
/** commpoints for accepting remote control connections */
struct listen_list* accept_list;
/** number of active commpoints that are handling remote control */
int active;
/** max active commpoints */
int max_active;
/** current commpoints busy; should be a short list, malloced */
struct rc_state* busy_list;
/** the SSL context for creating new SSL streams */
SSL_CTX* ctx;
};
/**
* Create new remote control state for the daemon.
* @param worker: worker with communication base. and links to command channels.
* @return new state, or NULL on failure.
*/
struct daemon_remote* daemon_remote_create(struct worker* worker);
/**
* remote control state to delete.
* @param rc: state to delete.
*/
void daemon_remote_delete(struct daemon_remote* rc);
/**
* Open and create listening ports for remote control.
* @param cfg: config options.
* @return list of ports or NULL on failure.
* can be freed with listening_ports_free().
*/
struct listen_port* daemon_remote_open_ports(struct config_file* cfg);
/**
* Setup comm points for accepting remote control connections.
* @param rc: state
* @param ports: already opened ports.
* @return false on error.
*/
int daemon_remote_open_accept(struct daemon_remote* rc,
struct listen_port* ports);
/** handle remote control accept callbacks */
int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*);
/** handle remote control data callbacks */
int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*);
/**
* Print fixed line of text over ssl connection in blocking mode
* @param ssl: print to
* @param text: the text.
* @return false on connection failure.
*/
int ssl_print_text(SSL* ssl, const char* text);
/**
* printf style printing to the ssl connection
* @param ssl: the SSL connection to print to. Blocking.
* @param format: printf style format string.
* @return success or false on a network failure.
*/
int ssl_printf(SSL* ssl, const char* format, ...)
ATTR_FORMAT(printf, 2, 3);
/**
* Read until \n is encountered
* If SSL signals EOF, the string up to then is returned (without \n).
* @param ssl: the SSL connection to read from. blocking.
* @param buf: buffer to read to.
* @param max: size of buffer.
* @return false on connection failure.
*/
int ssl_read_line(SSL* ssl, char* buf, size_t max);
#endif /* DAEMON_REMOTE_H */
+213 -3
View File
@@ -42,11 +42,33 @@
#include "config.h"
#include "daemon/stats.h"
#include "daemon/worker.h"
#include "daemon/daemon.h"
#include "services/mesh.h"
#include "services/outside_network.h"
#include "util/config_file.h"
#include "util/tube.h"
#include "util/timehist.h"
#include "util/net_help.h"
#include "validator/validator.h"
void server_stats_init(struct server_stats* stats)
/** add timers and the values do not overflow or become negative */
static void
timeval_add(struct timeval* d, const struct timeval* add)
{
#ifndef S_SPLINT_S
d->tv_sec += add->tv_sec;
d->tv_usec += add->tv_usec;
while(d->tv_usec > 1000000 ) {
d->tv_usec -= 1000000;
d->tv_sec++;
}
#endif
}
void server_stats_init(struct server_stats* stats, struct config_file* cfg)
{
memset(stats, 0, sizeof(*stats));
stats->extended = cfg->stat_extended;
}
void server_stats_querymiss(struct server_stats* stats, struct worker* worker)
@@ -57,7 +79,8 @@ void server_stats_querymiss(struct server_stats* stats, struct worker* worker)
stats->max_query_list_size = worker->env.mesh->all.count;
}
void server_stats_log(struct server_stats* stats, int threadnum)
void server_stats_log(struct server_stats* stats, struct worker* worker,
int threadnum)
{
log_info("server stats for thread %d: %u queries, "
"%u answers from cache, %u recursions",
@@ -70,5 +93,192 @@ void server_stats_log(struct server_stats* stats, int threadnum)
stats->num_queries_missed_cache?
(double)stats->sum_query_list_size/
stats->num_queries_missed_cache : 0.0,
(unsigned)stats->num_query_list_exceeded);
(unsigned)worker->env.mesh->stats_dropped);
}
/** get rrsets bogus number from validator */
static size_t
get_rrset_bogus(struct worker* worker)
{
int m = modstack_find(&worker->env.mesh->mods, "validator");
struct val_env* ve;
size_t r;
if(m == -1)
return 0;
ve = (struct val_env*)worker->env.modinfo[m];
lock_basic_lock(&ve->bogus_lock);
r = ve->num_rrset_bogus;
if(!worker->env.cfg->stat_cumulative)
ve->num_rrset_bogus = 0;
lock_basic_unlock(&ve->bogus_lock);
return r;
}
void
server_stats_compile(struct worker* worker, struct stats_info* s)
{
int i;
s->svr = worker->stats;
s->mesh_num_states = worker->env.mesh->all.count;
s->mesh_num_reply_states = worker->env.mesh->num_reply_states;
s->mesh_jostled = worker->env.mesh->stats_jostled;
s->mesh_dropped = worker->env.mesh->stats_dropped;
s->mesh_replies_sent = worker->env.mesh->replies_sent;
s->mesh_replies_sum_wait = worker->env.mesh->replies_sum_wait;
s->mesh_time_median = timehist_quartile(worker->env.mesh->histogram,
0.50);
/* add in the values from the mesh */
s->svr.ans_secure += worker->env.mesh->ans_secure;
s->svr.ans_bogus += worker->env.mesh->ans_bogus;
s->svr.ans_rcode_nodata += worker->env.mesh->ans_nodata;
for(i=0; i<16; i++)
s->svr.ans_rcode[i] += worker->env.mesh->ans_rcode[i];
timehist_export(worker->env.mesh->histogram, s->svr.hist,
NUM_BUCKETS_HIST);
/* values from outside network */
s->svr.unwanted_replies = worker->back->unwanted_replies;
/* get and reset validator rrset bogus number */
s->svr.rrset_bogus = get_rrset_bogus(worker);
if(!worker->env.cfg->stat_cumulative) {
server_stats_init(&worker->stats, worker->env.cfg);
mesh_stats_clear(worker->env.mesh);
worker->back->unwanted_replies = 0;
}
}
void server_stats_obtain(struct worker* worker, struct worker* who,
struct stats_info* s)
{
uint8_t *reply = NULL;
uint32_t len = 0;
if(worker == who) {
/* just fill it in */
server_stats_compile(worker, s);
return;
}
/* communicate over tube */
verbose(VERB_ALGO, "write stats cmd");
worker_send_cmd(who, worker_cmd_stats);
verbose(VERB_ALGO, "wait for stats reply");
if(!tube_read_msg(worker->cmd, &reply, &len, 0))
fatal_exit("failed to read stats over cmd channel");
if(len != (uint32_t)sizeof(*s))
fatal_exit("stats on cmd channel wrong length %d %d",
(int)len, (int)sizeof(*s));
memcpy(s, reply, (size_t)len);
free(reply);
}
void server_stats_reply(struct worker* worker)
{
struct stats_info s;
server_stats_compile(worker, &s);
verbose(VERB_ALGO, "write stats replymsg");
if(!tube_write_msg(worker->daemon->workers[0]->cmd,
(uint8_t*)&s, sizeof(s), 0))
fatal_exit("could not write stat values over cmd channel");
}
void server_stats_add(struct stats_info* total, struct stats_info* a)
{
total->svr.num_queries += a->svr.num_queries;
total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache;
total->svr.sum_query_list_size += a->svr.sum_query_list_size;
/* the max size reached is upped to higher of both */
if(a->svr.max_query_list_size > total->svr.max_query_list_size)
total->svr.max_query_list_size = a->svr.max_query_list_size;
if(a->svr.extended) {
int i;
total->svr.qtype_big += a->svr.qtype_big;
total->svr.qclass_big += a->svr.qclass_big;
total->svr.qtcp += a->svr.qtcp;
total->svr.qbit_QR += a->svr.qbit_QR;
total->svr.qbit_AA += a->svr.qbit_AA;
total->svr.qbit_TC += a->svr.qbit_TC;
total->svr.qbit_RD += a->svr.qbit_RD;
total->svr.qbit_RA += a->svr.qbit_RA;
total->svr.qbit_Z += a->svr.qbit_Z;
total->svr.qbit_AD += a->svr.qbit_AD;
total->svr.qbit_CD += a->svr.qbit_CD;
total->svr.qEDNS += a->svr.qEDNS;
total->svr.qEDNS_DO += a->svr.qEDNS_DO;
total->svr.ans_rcode_nodata += a->svr.ans_rcode_nodata;
total->svr.ans_secure += a->svr.ans_secure;
total->svr.ans_bogus += a->svr.ans_bogus;
total->svr.rrset_bogus += a->svr.rrset_bogus;
total->svr.unwanted_replies += a->svr.unwanted_replies;
total->svr.unwanted_queries += a->svr.unwanted_queries;
for(i=0; i<STATS_QTYPE_NUM; i++)
total->svr.qtype[i] += a->svr.qtype[i];
for(i=0; i<STATS_QCLASS_NUM; i++)
total->svr.qclass[i] += a->svr.qclass[i];
for(i=0; i<STATS_OPCODE_NUM; i++)
total->svr.qopcode[i] += a->svr.qopcode[i];
for(i=0; i<STATS_RCODE_NUM; i++)
total->svr.ans_rcode[i] += a->svr.ans_rcode[i];
for(i=0; i<NUM_BUCKETS_HIST; i++)
total->svr.hist[i] += a->svr.hist[i];
}
total->mesh_num_states += a->mesh_num_states;
total->mesh_num_reply_states += a->mesh_num_reply_states;
total->mesh_jostled += a->mesh_jostled;
total->mesh_dropped += a->mesh_dropped;
total->mesh_replies_sent += a->mesh_replies_sent;
timeval_add(&total->mesh_replies_sum_wait, &a->mesh_replies_sum_wait);
/* the medians are averaged together, this is not as accurate as
* taking the median over all of the data, but is good and fast
* added up here, division later*/
total->mesh_time_median += a->mesh_time_median;
}
void server_stats_insquery(struct server_stats* stats, struct comm_point* c,
uint16_t qtype, uint16_t qclass, struct edns_data* edns)
{
uint16_t flags = ldns_buffer_read_u16_at(c->buffer, 2);
if(qtype < STATS_QTYPE_NUM)
stats->qtype[qtype]++;
else stats->qtype_big++;
if(qclass < STATS_QCLASS_NUM)
stats->qclass[qclass]++;
else stats->qclass_big++;
stats->qopcode[ LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) ]++;
if(c->type != comm_udp)
stats->qtcp++;
if( (flags&BIT_QR) )
stats->qbit_QR++;
if( (flags&BIT_AA) )
stats->qbit_AA++;
if( (flags&BIT_TC) )
stats->qbit_TC++;
if( (flags&BIT_RD) )
stats->qbit_RD++;
if( (flags&BIT_RA) )
stats->qbit_RA++;
if( (flags&BIT_Z) )
stats->qbit_Z++;
if( (flags&BIT_AD) )
stats->qbit_AD++;
if( (flags&BIT_CD) )
stats->qbit_CD++;
if(edns->edns_present) {
stats->qEDNS++;
if( (edns->bits & EDNS_DO) )
stats->qEDNS_DO++;
}
}
void server_stats_insrcode(struct server_stats* stats, ldns_buffer* buf)
{
if(stats->extended && ldns_buffer_limit(buf) != 0) {
int r = (int)LDNS_RCODE_WIRE( ldns_buffer_begin(buf) );
stats->ans_rcode[r] ++;
if(r == 0 && LDNS_ANCOUNT( ldns_buffer_begin(buf) ) == 0)
stats->ans_rcode_nodata ++;
}
}
+145 -4
View File
@@ -42,7 +42,20 @@
#ifndef DAEMON_STATS_H
#define DAEMON_STATS_H
#include "util/timehist.h"
struct worker;
struct config_file;
struct comm_point;
struct edns_data;
/** number of qtype that is stored for in array */
#define STATS_QTYPE_NUM 256
/** number of qclass that is stored for in array */
#define STATS_QCLASS_NUM 256
/** number of rcodes in stats */
#define STATS_RCODE_NUM 16
/** number of opcodes in stats */
#define STATS_OPCODE_NUM 16
/** per worker statistics */
struct server_stats {
@@ -58,20 +71,148 @@ struct server_stats {
size_t sum_query_list_size;
/** max value of query list size reached. */
size_t max_query_list_size;
/** number of times that the query_list_size was insufficient */
size_t num_query_list_exceeded;
/** Extended stats below (bool) */
int extended;
/** qtype stats */
size_t qtype[STATS_QTYPE_NUM];
/** bigger qtype values not in array */
size_t qtype_big;
/** qclass stats */
size_t qclass[STATS_QCLASS_NUM];
/** bigger qclass values not in array */
size_t qclass_big;
/** query opcodes */
size_t qopcode[STATS_OPCODE_NUM];
/** number of queries over TCP */
size_t qtcp;
/** number of queries with QR bit */
size_t qbit_QR;
/** number of queries with AA bit */
size_t qbit_AA;
/** number of queries with TC bit */
size_t qbit_TC;
/** number of queries with RD bit */
size_t qbit_RD;
/** number of queries with RA bit */
size_t qbit_RA;
/** number of queries with Z bit */
size_t qbit_Z;
/** number of queries with AD bit */
size_t qbit_AD;
/** number of queries with CD bit */
size_t qbit_CD;
/** number of queries with EDNS OPT record */
size_t qEDNS;
/** number of queries with EDNS with DO flag */
size_t qEDNS_DO;
/** answer rcodes */
size_t ans_rcode[STATS_RCODE_NUM];
/** answers with pseudo rcode 'nodata' */
size_t ans_rcode_nodata;
/** answers that were secure (AD) */
size_t ans_secure;
/** answers with bogus content */
size_t ans_bogus;
/** rrsets marked bogus by validator */
size_t rrset_bogus;
/** unwanted traffic received on server-facing ports */
size_t unwanted_replies;
/** unwanted traffic received on client-facing ports */
size_t unwanted_queries;
/** histogram data exported to array
* if the array is the same size, no data is lost, and
* if all histograms are same size (is so by default) then
* adding up works well. */
size_t hist[NUM_BUCKETS_HIST];
};
/**
* Statistics to send over the control pipe when asked
* This struct is made to be memcpied, sent in binary.
*/
struct stats_info {
/** the thread stats */
struct server_stats svr;
/** mesh stats: current number of states */
size_t mesh_num_states;
/** mesh stats: current number of reply (user) states */
size_t mesh_num_reply_states;
/** mesh stats: number of reply states overwritten with a new one */
size_t mesh_jostled;
/** mesh stats: number of incoming queries dropped */
size_t mesh_dropped;
/** mesh stats: replies sent */
size_t mesh_replies_sent;
/** mesh stats: sum of waiting times for the replies */
struct timeval mesh_replies_sum_wait;
/** mesh stats: median of waiting times for replies (in sec) */
double mesh_time_median;
};
/**
* Initialize server stats to 0.
* @param stats: what to init (this is alloced by the caller).
* @param cfg: with extended statistics option.
*/
void server_stats_init(struct server_stats* stats);
void server_stats_init(struct server_stats* stats, struct config_file* cfg);
/** add query if it missed the cache */
void server_stats_querymiss(struct server_stats* stats, struct worker* worker);
/** display the stats to the log */
void server_stats_log(struct server_stats* stats, int threadnum);
void server_stats_log(struct server_stats* stats, struct worker* worker,
int threadnum);
/**
* Obtain the stats info for a given thread. Uses pipe to communicate.
* @param worker: the worker that is executing (the first worker).
* @param who: on who to get the statistics info.
* @param s: the stats block to fill in.
*/
void server_stats_obtain(struct worker* worker, struct worker* who,
struct stats_info* s);
/**
* Compile stats into structure for this thread worker.
* Also clears the statistics counters (if that is set by config file).
* @param worker: the worker to compile stats for, also the executing worker.
* @param s: stats block.
*/
void server_stats_compile(struct worker* worker, struct stats_info* s);
/**
* Send stats over comm tube in reply to query cmd
* @param worker: this worker.
*/
void server_stats_reply(struct worker* worker);
/**
* Addup stat blocks.
* @param total: sum of the two entries.
* @param a: to add to it.
*/
void server_stats_add(struct stats_info* total, struct stats_info* a);
/**
* Add stats for this query
* @param stats: the stats
* @param c: commpoint with type and buffer.
* @param qtype: query type
* @param qclass: query class
* @param edns: edns record
*/
void server_stats_insquery(struct server_stats* stats, struct comm_point* c,
uint16_t qtype, uint16_t qclass, struct edns_data* edns);
/**
* Add rcode for this query.
* @param stats: the stats
* @param buf: buffer with rcode. If buffer is length0: not counted.
*/
void server_stats_insrcode(struct server_stats* stats, ldns_buffer* buf);
#endif /* DAEMON_STATS_H */
+135 -51
View File
@@ -52,6 +52,7 @@
#include "util/module.h"
#include <signal.h>
#include <fcntl.h>
#include <openssl/crypto.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
@@ -84,8 +85,9 @@ static void usage()
printf("-d do not fork into the background.\n");
printf("-v verbose (more times to increase verbosity)\n");
printf("Version %s\n", PACKAGE_VERSION);
printf("libevent %s, libldns %s\n",
event_get_version(), ldns_version());
printf("libevent %s, libldns %s, %s\n",
event_get_version(), ldns_version(),
SSLeay_version(SSLEAY_VERSION));
printf("BSD licensed, see LICENSE in source package for details.\n");
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
}
@@ -141,6 +143,21 @@ checkrlimits(struct config_file* cfg)
log_warn("increased limit(open files) from %u to %u",
(unsigned)avail, (unsigned)total+10);
}
if(total > 1024 &&
strncmp(event_get_version(), "mini-event", 10) == 0) {
log_err("too many file descriptors requested. The builtin"
"mini-event cannot handle more than 1024. Config "
"for less fds or compile with libevent");
fatal_exit("configuration needs too many file descriptors");
}
if(perthread > 64 &&
strncmp(event_get_version(), "winsock-event", 13) == 0) {
log_err("too many file descriptors requested. The winsock"
" event handler cannot handle more than 64 per "
" thread. Config for less fds or compile with "
" libevent");
fatal_exit("configuration needs too many file descriptors");
}
#else
(void)cfg;
#endif /* HAVE_GETRLIMIT */
@@ -244,23 +261,21 @@ writepid (const char* pidfile, pid_t pid)
/**
* check old pid file.
* @param cfg: the config settings
* @param pidfile: the file name of the pid file.
* @param inchroot: if pidfile is inchroot and we can thus expect to
* be able to delete it.
*/
static void
checkoldpid(struct config_file* cfg)
checkoldpid(char* pidfile, int inchroot)
{
pid_t old;
char* file = cfg->pidfile;
if(cfg->chrootdir && cfg->chrootdir[0] &&
strncmp(file, cfg->chrootdir, strlen(cfg->chrootdir))==0) {
file += strlen(cfg->chrootdir);
}
if((old = readpid(file)) != -1) {
if((old = readpid(pidfile)) != -1) {
/* see if it is still alive */
if(kill(old, 0) == 0 || errno == EPERM)
log_warn("unbound is already running as pid %u.",
(unsigned)old);
else log_warn("did not exit gracefully last time (%u)",
else if(inchroot)
log_warn("did not exit gracefully last time (%u)",
(unsigned)old);
}
}
@@ -268,7 +283,7 @@ checkoldpid(struct config_file* cfg)
/** detach from command line */
static void
detach(struct config_file* cfg)
detach(void)
{
#ifdef HAVE_WORKING_FORK
int fd;
@@ -277,7 +292,6 @@ detach(struct config_file* cfg)
case 0:
break;
case -1:
unlink(cfg->pidfile);
fatal_exit("fork failed: %s", strerror(errno));
default:
/* exit interactive session */
@@ -295,15 +309,13 @@ detach(struct config_file* cfg)
if (fd > 2)
(void)close(fd);
}
#else
(void)cfg;
#endif /* HAVE_WORKING_FORK */
}
/** daemonize, drop user priviliges and chroot if needed */
static void
do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode,
char** cfgfile)
perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
const char** cfgfile)
{
#ifdef HAVE_GETPWNAM
uid_t uid;
@@ -313,7 +325,6 @@ do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode,
memset(&gid, 112, sizeof(gid));
log_assert(cfg);
/* daemonize last to be able to print error to user */
if(cfg->username && cfg->username[0]) {
struct passwd *pwd;
if((pwd = getpwnam(cfg->username)) == NULL)
@@ -323,6 +334,65 @@ do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode,
endpwent();
}
#endif
/* init syslog (as root) if needed, before daemonize, otherwise
* a fork error could not be printed since daemonize closed stderr.*/
if(cfg->use_syslog)
log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir);
/* if using a logfile, we cannot open it because the logfile would
* be created with the wrong permissions, we cannot chown it because
* we cannot chown system logfiles, so we do not open at all.
* So, using a logfile, the user does not see errors unless -d is
* given to unbound on the commandline. */
#ifdef HAVE_KILL
/* check old pid file before forking */
if(cfg->pidfile && cfg->pidfile[0]) {
/* calculate position of pidfile */
if(cfg->pidfile[0] == '/')
daemon->pidfile = strdup(cfg->pidfile);
else daemon->pidfile = fname_after_chroot(cfg->pidfile,
cfg, 1);
if(!daemon->pidfile)
fatal_exit("pidfile alloc: out of memory");
checkoldpid(daemon->pidfile,
/* true if pidfile is inside chrootdir, or nochroot */
!(cfg->chrootdir && cfg->chrootdir[0]) ||
(cfg->chrootdir && cfg->chrootdir[0] &&
strncmp(daemon->pidfile, cfg->chrootdir,
strlen(cfg->chrootdir))==0));
}
#endif
/* daemonize because pid is needed by the writepid func */
if(!debug_mode && cfg->do_daemonize) {
detach();
}
/* write new pidfile (while still root, so can be outside chroot) */
#ifdef HAVE_KILL
if(cfg->pidfile && cfg->pidfile[0]) {
writepid(daemon->pidfile, getpid());
if(!(cfg->chrootdir && cfg->chrootdir[0]) ||
(cfg->chrootdir && cfg->chrootdir[0] &&
strncmp(daemon->pidfile, cfg->chrootdir,
strlen(cfg->chrootdir))==0)) {
/* delete of pidfile could potentially work,
* chown to get permissions */
if(cfg->username && cfg->username[0]) {
if(chown(daemon->pidfile, uid, gid) == -1) {
fatal_exit("cannot chown %u.%u %s: %s",
(unsigned)uid, (unsigned)gid,
daemon->pidfile, strerror(errno));
}
}
}
}
#else
(void)daemon;
#endif
/* box into the chroot */
#ifdef HAVE_CHROOT
if(cfg->chrootdir && cfg->chrootdir[0]) {
if(chdir(cfg->chrootdir)) {
@@ -337,10 +407,22 @@ do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode,
if(strncmp(*cfgfile, cfg->chrootdir,
strlen(cfg->chrootdir)) == 0)
(*cfgfile) += strlen(cfg->chrootdir);
/* adjust stored pidfile for chroot */
if(daemon->pidfile && daemon->pidfile[0] &&
strncmp(daemon->pidfile, cfg->chrootdir,
strlen(cfg->chrootdir))==0) {
char* old = daemon->pidfile;
daemon->pidfile = strdup(old+strlen(cfg->chrootdir));
free(old);
if(!daemon->pidfile)
log_err("out of memory in pidfile adjust");
}
}
#else
(void)cfgfile;
#endif
/* change to working directory inside chroot */
if(cfg->directory && cfg->directory[0]) {
char* dir = cfg->directory;
if(cfg->chrootdir && cfg->chrootdir[0] &&
@@ -355,43 +437,36 @@ do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode,
verbose(VERB_QUERY, "chdir to %s", dir);
}
}
/* drop permissions after chroot, getpwnam, pidfile, syslog done*/
#ifdef HAVE_GETPWNAM
if(cfg->username && cfg->username[0]) {
#ifdef HAVE_SETRESGID
if(setresgid(gid,gid,gid) != 0)
#elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID)
if(setregid(gid,gid) != 0)
#else /* use setgid */
if(setgid(gid) != 0)
#endif /* HAVE_SETRESGID */
fatal_exit("unable to set group id of %s: %s",
cfg->username, strerror(errno));
#ifdef HAVE_SETRESUID
if(setresuid(uid,uid,uid) != 0)
#elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID)
if(setreuid(uid,uid) != 0)
#else /* use setuid */
if(setuid(uid) != 0)
#endif /* HAVE_SETRESUID */
fatal_exit("unable to set user id of %s: %s",
cfg->username, strerror(errno));
verbose(VERB_QUERY, "drop user privileges, run as %s",
cfg->username);
}
#endif
#ifdef HAVE_KILL
/* check old pid file before forking */
if(cfg->pidfile && cfg->pidfile[0]) {
checkoldpid(cfg);
}
#endif
/* init logfile just before fork */
log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir);
if(!debug_mode && cfg->do_daemonize) {
detach(cfg);
}
#ifdef HAVE_KILL
if(cfg->pidfile && cfg->pidfile[0]) {
char* pf = cfg->pidfile;
if(cfg->chrootdir && cfg->chrootdir[0] &&
strncmp(pf, cfg->chrootdir, strlen(cfg->chrootdir))==0)
pf += strlen(cfg->chrootdir);
writepid(pf, getpid());
if(!(daemon->pidfile = strdup(pf)))
log_err("pidf: malloc failed");
}
#else
(void)daemon;
#endif
/* file logging inited after chroot,chdir,setuid is done so that
* it would succeed on SIGHUP as well */
if(!cfg->use_syslog)
log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir);
}
/**
@@ -402,16 +477,16 @@ do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode,
* @param debug_mode: if set, do not daemonize.
*/
static void
run_daemon(char* cfgfile, int cmdline_verbose, int debug_mode)
run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode)
{
struct config_file* cfg = NULL;
struct daemon* daemon = NULL;
int done_chroot = 0;
int done_setup = 0;
if(!(daemon = daemon_init()))
fatal_exit("alloc failure");
while(!daemon->need_to_exit) {
if(done_chroot)
if(done_setup)
verbose(VERB_OPS, "Restart of %s.", PACKAGE_STRING);
else verbose(VERB_OPS, "Start of %s.", PACKAGE_STRING);
@@ -429,9 +504,9 @@ run_daemon(char* cfgfile, int cmdline_verbose, int debug_mode)
/* prepare */
if(!daemon_open_shared_ports(daemon))
fatal_exit("could not open ports");
if(!done_chroot) {
do_chroot(daemon, cfg, debug_mode, &cfgfile);
done_chroot = 1;
if(!done_setup) {
perform_setup(daemon, cfg, debug_mode, &cfgfile);
done_setup = 1;
} else log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir);
/* work */
daemon_fork(daemon);
@@ -442,8 +517,17 @@ run_daemon(char* cfgfile, int cmdline_verbose, int debug_mode)
config_delete(cfg);
}
verbose(VERB_ALGO, "Exit cleanup.");
if(daemon->pidfile)
/* this unlink may not work if the pidfile is located outside
* of the chroot/workdir or we no longer have permissions */
if(daemon->pidfile) {
int fd;
/* truncate pidfile */
fd = open(daemon->pidfile, O_WRONLY | O_TRUNC, 0644);
if(fd != -1)
close(fd);
/* delete pidfile */
unlink(daemon->pidfile);
}
daemon_delete(daemon);
}
@@ -462,7 +546,7 @@ int
main(int argc, char* argv[])
{
int c;
char* cfgfile = CONFIGFILE;
const char* cfgfile = CONFIGFILE;
int cmdline_verbose = 0;
int debug_mode = 0;
+118 -76
View File
@@ -45,6 +45,7 @@
#include "util/random.h"
#include "daemon/worker.h"
#include "daemon/daemon.h"
#include "daemon/remote.h"
#include "daemon/acl_list.h"
#include "util/netevent.h"
#include "util/config_file.h"
@@ -63,6 +64,7 @@
#include "util/data/msgencode.h"
#include "util/data/dname.h"
#include "util/fptr_wlist.h"
#include "util/tube.h"
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
@@ -190,17 +192,12 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker),
}
void
worker_send_cmd(struct worker* worker, ldns_buffer* buffer,
enum worker_commands cmd)
worker_send_cmd(struct worker* worker, enum worker_commands cmd)
{
ldns_buffer_clear(buffer);
/* like DNS message, length data */
ldns_buffer_write_u16(buffer, sizeof(uint32_t));
ldns_buffer_write_u32(buffer, (uint32_t)cmd);
ldns_buffer_flip(buffer);
if(!write_socket(worker->cmd_send_fd, ldns_buffer_begin(buffer),
ldns_buffer_limit(buffer)))
log_err("write socket: %s", strerror(errno));
uint32_t c = (uint32_t)htonl(cmd);
if(!tube_write_msg(worker->cmd, (uint8_t*)&c, sizeof(c), 0)) {
log_err("worker send cmd %d failed", (int)cmd);
}
}
int
@@ -214,7 +211,7 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
e.qsent = NULL;
if(error != 0) {
mesh_report_reply(worker->env.mesh, &e, 0, reply_info);
mesh_report_reply(worker->env.mesh, &e, reply_info, error);
worker_mem_report(worker, NULL);
return 0;
}
@@ -225,11 +222,12 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
/* error becomes timeout for the module as if this reply
* never arrived. */
mesh_report_reply(worker->env.mesh, &e, 0, reply_info);
mesh_report_reply(worker->env.mesh, &e, reply_info,
NETEVENT_TIMEOUT);
worker_mem_report(worker, NULL);
return 0;
}
mesh_report_reply(worker->env.mesh, &e, 1, reply_info);
mesh_report_reply(worker->env.mesh, &e, reply_info, NETEVENT_NOERROR);
worker_mem_report(worker, NULL);
return 0;
}
@@ -244,7 +242,7 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate);
if(error != 0) {
mesh_report_reply(worker->env.mesh, e, 0, reply_info);
mesh_report_reply(worker->env.mesh, e, reply_info, error);
worker_mem_report(worker, sq);
return 0;
}
@@ -256,11 +254,12 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
/* error becomes timeout for the module as if this reply
* never arrived. */
verbose(VERB_ALGO, "worker: bad reply handled as timeout");
mesh_report_reply(worker->env.mesh, e, 0, reply_info);
mesh_report_reply(worker->env.mesh, e, reply_info,
NETEVENT_TIMEOUT);
worker_mem_report(worker, sq);
return 0;
}
mesh_report_reply(worker->env.mesh, e, 1, reply_info);
mesh_report_reply(worker->env.mesh, e, reply_info, NETEVENT_NOERROR);
worker_mem_report(worker, sq);
return 0;
}
@@ -318,33 +317,37 @@ worker_check_request(ldns_buffer* pkt, struct worker* worker)
return 0;
}
int
worker_handle_control_cmd(struct comm_point* c, void* arg, int error,
struct comm_reply* ATTR_UNUSED(reply_info))
void
worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg,
size_t len, int error, void* arg)
{
struct worker* worker = (struct worker*)arg;
enum worker_commands cmd;
if(error != NETEVENT_NOERROR) {
free(msg);
if(error == NETEVENT_CLOSED)
comm_base_exit(worker->base);
else log_info("control event: %d", error);
return 0;
return;
}
if(ldns_buffer_limit(c->buffer) != sizeof(uint32_t)) {
fatal_exit("bad control msg length %d",
(int)ldns_buffer_limit(c->buffer));
if(len != sizeof(uint32_t)) {
fatal_exit("bad control msg length %d", (int)len);
}
cmd = ldns_buffer_read_u32(c->buffer);
cmd = ldns_read_uint32(msg);
free(msg);
switch(cmd) {
case worker_cmd_quit:
verbose(VERB_ALGO, "got control cmd quit");
comm_base_exit(worker->base);
break;
case worker_cmd_stats:
verbose(VERB_ALGO, "got control cmd stats");
server_stats_reply(worker);
break;
default:
log_err("bad command %d", (int)cmd);
break;
}
return 0;
}
/** check if a delegation is secure */
@@ -440,6 +443,10 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
&msg->qinfo, id, flags, edns);
regional_free_all(worker->scratchpad);
if(worker->stats.extended) {
worker->stats.ans_bogus++;
worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL]++;
}
return 1;
case sec_status_secure:
/* all rrsets are secure */
@@ -469,6 +476,10 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
&msg->qinfo, id, flags, edns);
}
regional_free_all(worker->scratchpad);
if(worker->stats.extended) {
if(secure) worker->stats.ans_secure++;
server_stats_insrcode(&worker->stats, repinfo->c->buffer);
}
return 1;
}
@@ -556,6 +567,10 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
rrset_array_unlock_touch(worker->env.rrset_cache,
worker->scratchpad, rep->ref, rep->rrset_count);
regional_free_all(worker->scratchpad);
if(worker->stats.extended) {
worker->stats.ans_bogus ++;
worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++;
}
return 1;
} else if( rep->security == sec_status_unchecked && must_validate) {
verbose(VERB_ALGO, "Cache reply: unchecked entry needs "
@@ -589,6 +604,10 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad,
rep->ref, rep->rrset_count);
regional_free_all(worker->scratchpad);
if(worker->stats.extended) {
if(secure) worker->stats.ans_secure++;
server_stats_insrcode(&worker->stats, repinfo->c->buffer);
}
/* go and return this buffer to the client */
return 1;
}
@@ -703,6 +722,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
repinfo->addrlen);
if(acl == acl_deny) {
comm_point_drop_reply(repinfo);
if(worker->stats.extended)
worker->stats.unwanted_queries++;
return 0;
} else if(acl == acl_refuse) {
ldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE);
@@ -714,6 +735,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
log_addr(VERB_ALGO, "refused query from",
&repinfo->addr, repinfo->addrlen);
log_buf(VERB_ALGO, "refuse", c->buffer);
if(worker->stats.extended)
worker->stats.unwanted_queries++;
return 1;
}
if((ret=worker_check_request(c->buffer, worker)) != 0) {
@@ -733,6 +756,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
server_stats_insrcode(&worker->stats, c->buffer);
return 1;
}
if(qinfo.qtype == LDNS_RR_TYPE_AXFR ||
@@ -741,12 +765,17 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer),
LDNS_RCODE_REFUSED);
if(worker->stats.extended) {
worker->stats.qtype[qinfo.qtype]++;
server_stats_insrcode(&worker->stats, c->buffer);
}
return 1;
}
if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) {
verbose(VERB_ALGO, "worker parse edns: formerror.");
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), ret);
server_stats_insrcode(&worker->stats, c->buffer);
return 1;
}
if(edns.edns_present && edns.edns_version != 0) {
@@ -779,15 +808,38 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
ldns_buffer_flip(c->buffer);
return 1;
}
if(worker->stats.extended)
server_stats_insquery(&worker->stats, c, qinfo.qtype,
qinfo.qclass, &edns);
if(c->type != comm_udp)
edns.udp_size = 65535; /* max size for TCP replies */
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
&edns, c->buffer)) {
server_stats_insrcode(&worker->stats, c->buffer);
return 1;
}
if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns,
c->buffer, worker->scratchpad)) {
return (ldns_buffer_limit(c->buffer) != 0);
if(ldns_buffer_limit(c->buffer) == 0) {
comm_point_drop_reply(repinfo);
return 0;
}
server_stats_insrcode(&worker->stats, c->buffer);
return 1;
}
if(!(LDNS_RD_WIRE(ldns_buffer_begin(c->buffer))) &&
acl != acl_allow_snoop ) {
ldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE);
ldns_buffer_write_at(c->buffer, 4,
(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer),
LDNS_RCODE_REFUSED);
ldns_buffer_flip(c->buffer);
server_stats_insrcode(&worker->stats, c->buffer);
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
&repinfo->addr, repinfo->addrlen);
return 1;
}
h = query_info_hash(&qinfo);
if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) {
@@ -817,16 +869,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
server_stats_querymiss(&worker->stats, worker);
/* grab a work request structure for this new request */
if(worker->env.mesh->all.count > worker->request_size) {
verbose(VERB_ALGO, "Too many requests active. "
"dropping incoming query.");
worker->stats.num_query_list_exceeded++;
comm_point_drop_reply(repinfo);
return 0;
} else if(worker->env.mesh->num_reply_addrs>worker->request_size*16) {
if(worker->env.mesh->num_reply_addrs>worker->request_size*16) {
/* protect our memory usage from storing reply addresses */
verbose(VERB_ALGO, "Too many requests queued. "
"dropping incoming query.");
worker->stats.num_query_list_exceeded++;
worker->env.mesh->stats_dropped++;
comm_point_drop_reply(repinfo);
return 0;
}
@@ -890,12 +937,13 @@ worker_restart_timer(struct worker* worker)
void worker_stat_timer_cb(void* arg)
{
struct worker* worker = (struct worker*)arg;
server_stats_log(&worker->stats, worker->thread_num);
server_stats_log(&worker->stats, worker, worker->thread_num);
mesh_stats(worker->env.mesh, "mesh has");
worker_mem_report(worker, NULL);
if(!worker->daemon->cfg->stat_cumulative) {
server_stats_init(&worker->stats);
server_stats_init(&worker->stats, worker->env.cfg);
mesh_stats_clear(worker->env.mesh);
worker->back->unwanted_replies = 0;
}
/* start next timer */
worker_restart_timer(worker);
@@ -916,24 +964,10 @@ worker_create(struct daemon* daemon, int id, int* ports, int n)
}
worker->daemon = daemon;
worker->thread_num = id;
worker->cmd_send_fd = -1;
worker->cmd_recv_fd = -1;
if(id != 0) {
int sv[2];
/* create socketpair to communicate with worker */
if(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
free(worker);
log_err("socketpair: %s", strerror(errno));
return NULL;
}
if(!fd_set_nonblock(sv[0]) || !fd_set_nonblock(sv[1])) {
close(sv[0]);
close(sv[1]);
free(worker);
return NULL;
}
worker->cmd_send_fd = sv[0];
worker->cmd_recv_fd = sv[1];
if(!(worker->cmd = tube_create())) {
free(worker->ports);
free(worker);
return NULL;
}
return worker;
}
@@ -976,8 +1010,18 @@ worker_init(struct worker* worker, struct config_file *cfg,
return 0;
}
#endif /* LIBEVENT_SIGNAL_PROBLEM */
if(!(worker->rc = daemon_remote_create(worker))) {
worker_delete(worker);
return 0;
}
if(!daemon_remote_open_accept(worker->rc,
worker->daemon->rc_ports)) {
worker_delete(worker);
return 0;
}
} else { /* !do_sigs */
worker->comsig = 0;
worker->comsig = NULL;
worker->rc = NULL;
}
seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^
(((unsigned int)worker->thread_num)<<17);
@@ -1002,21 +1046,19 @@ worker_init(struct worker* worker, struct config_file *cfg,
cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
cfg->do_tcp?cfg->outgoing_num_tcp:0,
worker->daemon->env->infra_cache, worker->rndstate,
cfg->use_caps_bits_for_id, worker->ports, worker->numports);
cfg->use_caps_bits_for_id, worker->ports, worker->numports,
cfg->unwanted_threshold, &worker_alloc_cleanup, worker);
if(!worker->back) {
log_err("could not create outgoing sockets");
worker_delete(worker);
return 0;
}
if(worker->thread_num != 0) {
/* start listening to commands */
if(!(worker->cmd_com=comm_point_create_local(worker->base,
worker->cmd_recv_fd, cfg->msg_buffer_size,
worker_handle_control_cmd, worker))) {
log_err("could not create control compt.");
worker_delete(worker);
return 0;
}
/* start listening to commands */
if(!tube_setup_bg_listen(worker->cmd, worker->base,
&worker_handle_control_cmd, worker)) {
log_err("could not create control compt.");
worker_delete(worker);
return 0;
}
worker->stat_timer = comm_timer_create(worker->base,
worker_stat_timer_cb, worker);
@@ -1034,7 +1076,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
}
worker->request_size = cfg->num_queries_per_thread;
server_stats_init(&worker->stats);
server_stats_init(&worker->stats, cfg);
alloc_init(&worker->alloc, &worker->daemon->superalloc,
worker->thread_num);
alloc_set_id_cleanup(&worker->alloc, &worker_alloc_cleanup, worker);
@@ -1080,7 +1122,7 @@ worker_delete(struct worker* worker)
if(!worker)
return;
if(worker->env.mesh && verbosity >= VERB_OPS) {
server_stats_log(&worker->stats, worker->thread_num);
server_stats_log(&worker->stats, worker, worker->thread_num);
mesh_stats(worker->env.mesh, "mesh has");
worker_mem_report(worker, NULL);
}
@@ -1089,21 +1131,14 @@ worker_delete(struct worker* worker)
listen_delete(worker->front);
outside_network_delete(worker->back);
comm_signal_delete(worker->comsig);
comm_point_delete(worker->cmd_com);
tube_delete(worker->cmd);
comm_timer_delete(worker->stat_timer);
daemon_remote_delete(worker->rc);
free(worker->ports);
if(worker->thread_num == 0)
log_set_time(NULL);
comm_base_delete(worker->base);
ub_randfree(worker->rndstate);
/* close fds after deleting commpoints, to be sure.
Also epoll does not like closing fd before event_del */
if(worker->cmd_send_fd != -1)
close(worker->cmd_send_fd);
worker->cmd_send_fd = -1;
if(worker->cmd_recv_fd != -1)
close(worker->cmd_recv_fd);
worker->cmd_recv_fd = -1;
alloc_clear(&worker->alloc);
regional_destroy(worker->scratchpad);
free(worker);
@@ -1199,6 +1234,13 @@ int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
return 0;
}
void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
{
log_assert(0);
}
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
{
log_assert(0);
+19 -15
View File
@@ -58,11 +58,15 @@ struct daemon;
struct listen_port;
struct ub_randstate;
struct regional;
struct tube;
struct daemon_remote;
/** worker commands */
enum worker_commands {
/** make the worker quit */
worker_cmd_quit
worker_cmd_quit,
/** obtain statistics */
worker_cmd_stats
};
/**
@@ -76,10 +80,8 @@ struct worker {
struct daemon* daemon;
/** thread id */
ub_thread_t thr_id;
/** fd 0 of socketpair, write commands for worker to this one */
int cmd_send_fd;
/** fd 1 of socketpair, worker listens on this one */
int cmd_recv_fd;
/** pipe, for commands for this worker */
struct tube* cmd;
/** the event base this worker works with */
struct comm_base* base;
/** the frontside listening interface where request events come in */
@@ -96,6 +98,8 @@ struct worker {
struct comm_point* cmd_com;
/** timer for statistics */
struct comm_timer* stat_timer;
/** remote control state (for first thread only) */
struct daemon_remote* rc;
/** number of requests that can be handled by this worker */
size_t request_size;
@@ -151,11 +155,9 @@ void worker_delete(struct worker* worker);
/**
* Send a command to a worker. Uses blocking writes.
* @param worker: worker to send command to.
* @param buffer: an empty buffer to use.
* @param cmd: command to send.
*/
void worker_send_cmd(struct worker* worker, ldns_buffer* buffer,
enum worker_commands cmd);
void worker_send_cmd(struct worker* worker, enum worker_commands cmd);
/**
* Worker signal handler function. User argument is the worker itself.
@@ -198,14 +200,16 @@ struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen,
struct module_qstate* q);
/**
* process control messages from the main thread.
* @param c: comm point to read from.
* @param arg: worker.
* @param error: error status of comm point.
* @param reply_info: not used.
* process control messages from the main thread. Frees the control
* command message.
* @param tube: tube control message came on.
* @param msg: message contents. Is freed.
* @param len: length of message.
* @param error: if error (NETEVENT_*) happened.
* @param arg: user argument
*/
int worker_handle_control_cmd(struct comm_point* c, void* arg, int error,
struct comm_reply* reply_info);
void worker_handle_control_cmd(struct tube* tube, uint8_t* msg, size_t len,
int error, void* arg);
/** handles callbacks from listening event interface */
int worker_handle_request(struct comm_point* c, void* arg, int error,
+400
View File
@@ -1,3 +1,403 @@
13 November 2008: Wouter
- added fedora init and specfile to contrib (by Paul Wouters).
- added configure check for ldns 1.4.0 (using its compat funcs).
- neater comments in worker.h.
- removed doc/plan and updated doc/TODO.
- silenced EHOSTDOWN (verbosity 2 or higher to see it).
- review comments from Jelte, Matthijs. Neater code.
12 November 2008: Wouter
- add unbound-control manpage to makedist replace list.
11 November 2008: Wouter
- unit test for negative cache, stress tests the refcounting.
- fix for refcounting error that could cause fptr_wlist fatal exit
in the negative cache rbtree (upcoming 1.1 feature). (Thanks to
Attila Nagy for testing).
- nicer comments in cachedump about failed RR to string conversion.
- fix 32bit wrap around when printing large (4G and more) mem usage
for extended statistics.
10 November 2008: Wouter
- fixup the getaddrinfo compat code rename.
8 November 2008: Wouter
- added configure check for eee build warning.
7 November 2008: Wouter
- fix bug 217: fixed, setreuid and setregid do not work on MacOSX10.4.
- detect nonblocking problems in network stack in configure script.
6 November 2008: Wouter
- dname_priv must decompress the name before comparison.
- iana portlist updated.
5 November 2008: Wouter
- fixed possible memory leak in key_entry_key deletion.
Would leak a couple bytes when trust anchors were replaced.
- if query and reply qname overlap, the bytes are skipped not copied.
- fixed file descriptor leak when messages were jostled out that
had outstanding (TCP) replies.
- DNAMEs used from cache have their synthesized CNAMEs initialized
properly.
- fixed file descriptor leak for localzone type deny (for TCP).
- fixed memleak at exit for nsec3 negative cached zones.
- fixed memleak for the keyword 'nodefault' when reading config.
- made verbosity of 'edns incapable peer' warning higher, so you
do not get spammed by it.
- caught elusive Bad file descriptor error bug, that would print the
error while unnecessarily try to listen to a closed fd. Fixed.
4 November 2008: Wouter
- fixed -Wwrite-strings warnings that result in better code.
3 November 2008: Wouter
- fixup build process for Mac OSX linker, use ldns b32 compat funcs.
- generated configure with autoconf-2.61.
- iana portlist updated.
- detect if libssl needs libdl. For static linking with libssl.
- changed to use new algorithm identifiers for sha256/sha512
from ldns 1.4.0 (need very latest version).
- updated the included ldns tarball.
- proper detection of SHA256 and SHA512 functions (not just sizes).
23 October 2008: Wouter
- a little more debug info for failure on signer names. prints names.
22 October 2008: Wouter
- CFLAGS are picked up by configure from the environment.
- iana portlist updated.
- updated ldns to use 1.4.0-pre20081022 so it picks up CFLAGS too.
- new stub-prime: yesno option. Default is off, so it does not prime.
can be turned on to get same behaviour as previous unbound release.
- made automated test that checks if builtin root hints are uptodate.
- finished draft-wijngaards-dnsext-resolver-side-mitigation
implementation. The unwanted-reply-threshold can be set.
- fixup so fptr_whitelist test in alloc.c works.
21 October 2008: Wouter
- fix update-anchors.sh, so it does not report different RR order
as an update. Sorts the keys in the file. Updated copyright.
- fixup testbound on windows, the command control pipe doesn't exist.
- skip 08hostlib test on windows, no fork() available.
- made unbound-remote work on windows.
20 October 2008: Wouter
- quench a log message that is debug only.
- iana portlist updated.
- do not query bogus nameservers. It is like nameservers that have
the NS or A or AAAA record bogus are listed as donotquery.
- if server selection is faced with only bad choices, it will
attempt to get more options to be fetched.
- changed bogus-ttl default value from 900 to 60 seconds.
In anticipation that operator caused failures are more likely than
actual attacks at this time. And thus repeated validation helps
the operators get the problem fixed sooner. It makes validation
failures go away sooner (60 seconds after the zone is fixed).
Also it is likely to try different nameserver targets every minute,
so that if a zone is bad on one server but not another, it is
likely to pick up the 'correct' one after a couple minutes,
and if the TTL is big enough that solves validation for the zone.
- fixup unbound-control compilation on windows.
17 October 2008: Wouter
- port Leopard/G5: fixup type conversion size_t/uint32.
please ranlib, stop file without symbols warning.
- harden referral path now also validates the root after priming.
It looks up the root NS authoritatively as well as the root servers
and attemps to validate the entries.
16 October 2008: Wouter
- Fixup negative TTL values appearing (reported by Attila Nagy).
15 October 2008: Wouter
- better documentation for 0x20; remove fallback TODO, it is done.
- harden-referral-path feature includes A, AAAA queries for glue,
as well as very careful NS caching (only when doing NS query).
A, AAAA use the delegation from the NS-query.
14 October 2008: Wouter
- fwd_three.tpkg test was flaky. If the three requests hit the
wrong threads by chance (or bad OS) then the test would fail.
Made less flaky by increasing number of retries.
- stub_udp.tpkg changed to work, give root hints. fixed ldns_dname_abs.
- ldns tarball is snapshot of ldns r2759 (1.4.0-pre-20081014).
Which includes the ldns_dname_absolute fix.
- fwd_three test remains flaky now that unbound does not stop
listening when full. Thus, removed timeout problem.
It may be serviced by three threads, or maybe by one.
Mostly only useful for lock-check testing now.
13 October 2008: Wouter
- fixed recursion servers deployed as authoritative detection, so
that as a last resort, a +RD query is sent there to get the
correct answer.
- iana port list update.
- ldns tarball is snapshot of ldns r2759 (1.4.0-pre-20081013).
10 October 2008: Wouter
- fixup tests - the negative cache contained the correct NSEC3s for
two tests that are supposed to fail to validate.
9 October 2008: Wouter
- negative cache caps max iterations of NSEC3 done.
- NSEC3 negative cache for qtype DS works.
8 October 2008: Wouter
- NSEC negative cache for DS.
6 October 2008: Wouter
- jostle-timeout option, so you can config for slow links.
- 0x20 fallback code. Tries 3xnumber of nameserver addresses
queries that must all be the same. Sent to random nameservers.
- documented choices for DoS, EDNS, 0x20.
2 October 2008: Wouter
- fixup unlink of pidfile.
- fixup SHA256 algorithm collation code.
- contrib/update-anchor.sh does not overwrite anchors if not needed.
exits 0 when a restart is needed, other values if not.
so, update-anchor.sh -d mydir && /etc/rc.d/unbound restart
can restart unbound exactly when needed.
30 September 2008: Wouter
- fixup SHA256 DS downgrade, no longer possible to downgrade to SHA1.
- tests for sha256 support and downgrade resistance.
- RSASHA256 and RSASHA512 support (using the draft in dnsext),
using the drafted protocol numbers.
- when using stub on localhost (127.0.0.1@10053) unbound works.
Like when running NSD to host a local zone, on the same machine.
The noprime feature. manpages more explanation. Added a test for it.
- shorthand for reverse PTR, local-data-ptr: "1.2.3.4 www.ex.com"
29 September 2008: Wouter
- EDNS lameness detection, if EDNS packets are dropped this is
detected, eventually.
- multiple query timeout rtt backoff does not backoff too much.
26 September 2008: Wouter
- tests for remote-control.
- small memory leak in exception during remote control fixed.
- fixup for lock checking but not unchecking in remote control.
- iana portlist updated.
23 September 2008: Wouter
- Msg cache is loaded. A cache load enables cache responses.
- unbound-control flush [name], flush_type and flush_zone.
22 September 2008: Wouter
- dump_cache and load_cache statements in unbound-control.
RRsets are dumped and loaded correctly.
Msg cache is dumped.
19 September 2008: Wouter
- locking on the localdata structure.
- add and remove local zone and data with unbound-control.
- ldns trunk snapshot updated, make tests work again.
18 September 2008: Wouter
- fixup error in time calculation.
- munin plugin improvements.
- nicer abbreviations for high query types values (ixfr, axfr, any...)
- documented the statistics output in unbound-control man page.
- extended statistics prints out histogram, over unbound-control.
17 September 2008: Wouter
- locking for threadsafe bogus rrset counter.
- ldns trunk no longer exports b32 functions, provide compat.
- ldns tarball updated.
- testcode/ldns-testpkts.c const fixups.
- fixed rcode stat printout.
- munin plugin in contrib.
- stats always printout uptime, because stats plugins need it.
16 September 2008: Wouter
- extended-statistics: yesno config option.
- unwanted replies spoof nearmiss detector.
- iana portlist updated.
15 September 2008: Wouter
- working start, stop, reload commands for unbound-control.
- test for unbound-control working; better exit value for control.
- verbosity control via unbound-control.
- unbound-control stats.
12 September 2008: Wouter
- removed browser control mentions. Proto speccy.
11 September 2008: Wouter
- set nonblocking on new TCP streams, because linux does not inherit
the socket options to the accepted socket.
- fix TCP timeouts.
- SSL protected connection between server and unbound-control.
10 September 2008: Wouter
- remove memleak in privacy addresses on reloads and quits.
- remote control work.
9 September 2008: Wouter
- smallapp/unbound-control-setup.sh script to set up certificates.
4 September 2008: Wouter
- scrubber scrubs away private addresses.
- test for private addresses. man page entry.
- code refactored for name and address tree lookups.
3 September 2008: Wouter
- options for 'DNS Rebinding' protection: private-address and
private-domain.
- dnstree for reuse of routines that help with domain, addr lookups.
- private-address and private-domain config option read, stored.
2 September 2008: Wouter
- DoS protection features. Queries are jostled out to make room.
- testbound can pass time, increasing the internal timer.
- do not mark unsigned additionals bogus, leave unchecked, which
is removed too.
1 September 2008: Wouter
- disallow nonrecursive queries for cache snooping by default.
You can allow is using access-control: <subnet> allow_snoop.
The defaults do allow access no authoritative data without RD bit.
- two tests for it and fixups of tests for nonrec refused.
29 August 2008: Wouter
- version 1.1 number in trunk.
- harden-referral-path option for query for NS records.
Default turns off expensive, experimental option.
28 August 2008: Wouter
- fixup logfile handling; it is created with correct permissions
again. (from bugfix#199).
Some errors are not written to logfile (pidfile writing, forking),
and these are only visible by using the -d commandline flag.
27 August 2008: Wouter
- daemon(3) is causing problems for people. Reverting the patch.
bug#200, and 199 and 203 contain sideline discussion on it.
- bug#199 fixed: pidfile can be outside chroot. openlog is done before
chroot and drop permissions.
- config option to set size of aggressive negative cache,
neg-cache-size.
- bug#203 fixed: dlv has been implemented.
26 August 2008: Wouter
- test for insecure zone when DLV is in use, also does negative cache.
- test for trustanchor when DLV is in use (the anchor works).
- test for DLV used for a zone below a trustanchor.
- added scrub filter for overreaching NSEC records and unit test.
- iana portlist update
- use of setresuid or setreuid when available.
- use daemon(3) if available.
25 August 2008: Wouter
- realclean patch from Robert Edmonds.
22 August 2008: Wouter
- nicer debuglogging of DLV.
- test with secure delegation inside the DLV repository.
21 August 2008: Wouter
- negative cache code linked into validator, for DLV use.
negative cache works for DLV.
- iana portlist update.
- dlv-anchor option for unit tests.
- fixup NSEC_AT_APEX classification for short typemaps.
- ldns-testns has subdomain checks, for unit tests.
20 August 2008: Wouter
- negative cache code, reviewed.
18 August 2008: Wouter
- changes info: in logfile to notice: info: or debug: depending on
the verbosity of the statements. Better logfile message
classification.
- bug #208: extra rc.d unbound flexibility for freebsd/nanobsd.
15 August 2008: Wouter
- DLV nsec code fixed for better detection of closest existing
enclosers from NSEC responses.
- DLV works, straight to the dlv repository, so not for production.
- Iana port update.
14 August 2008: Wouter
- synthesize DLV messages from the rrset cache, like done for DS.
13 August 2008: Wouter
- bug #203: nicer do-auto log message when user sets incompatible
options.
- bug #204: variable name ameliorated in log.c.
- bug #206: in iana_update, no egrep, but awk use.
- ldns snapshot r2699 taken (includes DLV type).
- DLV work, config file element, trust anchor read in.
12 August 2008: Wouter
- finished adjusting testset to provide qtype NS answers.
11 August 2008: Wouter
- Fixup rrset security updates overwriting 2181 trust status.
This makes validated to be insecure data just as worthless as
nonvalidated data, and 2181 rules prevent cache overwrites to them.
- Fix assertion fail on bogus key handling.
- dnssec lameness detection works on first query at trust apex.
- NS queries get proper cache and dnssec lameness treatment.
- fixup compilation without pthreads on linux.
8 August 2008: Wouter
- NS queries are done after every referral.
validator is used on those NS records (if anchors enabled).
7 August 2008: Wouter
- Scrubber more strict. CNAME chains, DNAMEs from cache, other
irrelevant rrsets removed.
- 1.0.2 released from 1.0 support branch.
- fixup update-anchor.sh to work both in BSD shell and bash.
5 August 2008: Wouter
- fixup DS test so apex nodata works again.
4 August 2008: Wouter
- iana port update.
- TODO update.
- fix bug 201: null ptr deref on cleanup while udp pkts wait for port.
- added explanatory text for outgoing-port-permit in manpage.
30 July 2008: Wouter
- fixup bug qtype DS for unsigned zone and signed parent validation.
25 July 2008: Wouter
- added original copyright statement of OpenBSD arc4random code.
- created tube signaling solution on windows, as a pipe replacement.
this makes background asynchronous resolution work on windows.
- removed very insecure socketpair compat code. It also did not
work with event_waiting. Solved by pipe replacement.
- unbound -h prints openssl version number as well.
22 July 2008: Wouter
- moved pipe actions to util/tube.c. easier porting and shared code.
- check _raw() commpoint callbacks with fptr_wlist.
- iana port update.
21 July 2008: Wouter
- #198: nicer entropy warning message. manpage OS hints.
19 July 2008: Wouter
- #198: fixup man page to suggest chroot entropy fix.
18 July 2008: Wouter
- branch for 1.0 support.
- trunk work on tube.c.
17 July 2008: Wouter
- fix bug #196, compile outside source tree.
- fix bug #195, add --with-username=user configure option.
- print error and exit if started with config that requires more
fds than the builtin minievent can handle.
16 July 2008: Wouter
- made svn tag 1.0.1, trunk now 1.0.2
- sha256 checksums enabled in makedist.sh
15 July 2008: Wouter
- Follow draft-ietf-dnsop-default-local-zones-06 added reverse
IPv6 example prefix to AS112 default blocklist.
+3
View File
@@ -55,6 +55,9 @@ This software is under BSD license, see LICENSE for details.
* --with-chroot-dir=path
Set default chroot directory,
the default is /usr/local/etc/unbound.
* --with-username=user
Set default user name to change to,
the default is the "unbound" user.
* 'make test' attempts to run a series of tests, depending on the support
programs that are installed.
+24 -37
View File
@@ -2,9 +2,6 @@ TODO items. These are interesting todo items.
o understand synthesized DNAMEs, so those TTL=0 packets are cached properly.
o NSEC/NSEC3 aggressive negative caching, so that updates to NSEC/NSEC3
will result in proper negative responses.
o get serverselection algorithm out of local optimum.
make subtargets to get rtt info for a couple of targets, like fetch-policy.
or send out multiple queries to multiple servers.
o (option) where port 53 is used for send and receive, no other ports are used.
o (option) to not send replies to clients after a timeout of (say 5 secs) has
passed, but keep task active for later retries by client.
@@ -17,8 +14,6 @@ o (option) store primed key data in a overlaid keyhints file (sort of like draft
o windows version, auto update feature, a query to check for the version.
o command the server with TSIG inband. get-config, clearcache,
get stats, get memstats, get ..., reload, clear one zone from cache
o watch for spoof nearmisses. Keep counter of nearmisses and print that
in the stats lines, operator can determine what level is a redalert.
o NSID rfc 5001 support.
o timers rfc 5011 support.
o Treat YXDOMAIN from a DNAME properly, in iterator (not throwaway), validator.
@@ -26,51 +21,43 @@ o make timeout backoffs randomized (a couple percent random) to spread traffic.
o inspect date on executable, then warn user in log if its more than 1 year.
o (option) proactively prime root, stubs and trust anchors, feature.
early failure, faster on first query, but more traffic.
o On Windows use CryptGenRandom() to get random seed for arc4random.
o library add convenience functions for A, AAAA, PTR, getaddrinfo, libresolve.
o library add function to validate input from app that is signed.
o add dynamic-update requests (making a dynupd request) to libunbound api.
o in an ipv6 connected only environment unbound cannot use outgoing IP6
to send to ip4to6 mapped hosts, need ip4to6map of NS and disable
V6ONLY socket option.
o SIG(0) and TSIG.
o support OPT record placement on recv anywhere in the additional section.
o add local-file: config with authority features.
o (option) to make local-data answers be secure for libunbound (default=no)
o (option) to make chroot: copy all needed files into jail (or make jail)
perhaps also print reminder to link /dev/random and sysloghack.
o (option) for extended statistics. If enabled (not by default) collect print
rcode, uptime, spoofnearmisses, cache size, qtype,
bits(RD, CD, DO, EDNS-present, AD)query, (Secure, Bogus)reply.
perhaps also see which slow auth servers cause >1sec values.
stats-file possible with key: value or key=value lines in it.
stats on SIGUSR1. addup stats over threads.
o overhaul outside-network servicedquery to merge with udpwait and tcpwait,
to make timers in servicedquery independent of udpwait queues.
o 0x20 fallback so it can be enabled without trouble.
o check into rebinding ports for efficiency, configure time test.
o DLV is considered.
o EVP hardware crypto support.
o option to ignore all inception and expiration dates for rrsigs.
o option to use builtin ldns explicitly. Or stop shipping builtin tarball.
o cleaner code; return and func statements on newline.
o memcached module that sits before validator module; checks for memcached
data (on local lan), stores recursion lookup. Provides one cache for
multiple resolver machines, coherent reply content in anycast setup.
o no openssl_add_all_algorithms, but only the ones necessary, less space.
Features soon after 1.0.
o EDNS fallback after timeout (firewall drops all edns traffic problem).
o IPv6 reverse, IP4 reverse local-data shorthand for PTR records (?).
cumbersome to reverse notate by hand for the operator.
o zone name appending for local-data. Perhaps read zonefiles. Perhaps it is
too much authority feature creep.
For 1.x; features that have been requested during the beta test.
o command channel for couple of tasks. Like rndc.
o see delegation; what servers would be used to get data for a name.
o force stats display; easier than parsing logfiles.
stats display added over threads, displayed in rddtool easy format.
o flush names or domains (all under a name) from the cache. Include NSes.
And the A, AAAA for its NSes.
o add/del static preload data to change the domain redirections.
o and maybe also start, stop, reload.
o on windows version, libunbound uses a NamedPipe, examine security status
make sure the OS makes it safe like on unix.
*** Features features, for later
* dTLS, TLS, look to need special port numbers, cert storage, recent libssl.
* aggressive negative caching for NSEC, NSEC3.
* multiple queries per question, server exploration, server selection.
* NSID support.
* support TSIG on queries, for validating resolver deployment.
* private TTL
* retry-mode, where a bogus result triggers a retry-mode query, where a list
of responses over a time interval is collected, and each is validated.
or try in TCP mode. Do not 'try all servers several times', since we must
not create packet storms with operator errors.
* draft-timers
* Windows port features
o on windows version, implement that OS ancillary data capabilities for
interface-automatic. IPPKTINFO, IP6PKTINFO for WSARecvMsg, WSASendMsg.
o local-zone directive with authority service, full authority server
is a non-goal.
o configure option to force use of builtin ldns tarball.
+66
View File
@@ -0,0 +1,66 @@
Specification for the unbound-control protocol.
Server listens on 953 TCP (localhost by default). Client connects,
SSLv3 or TLSv1 connection setup (server selfsigned certificate,
client has cert signed by server certificate).
Query and Response
------------------
Client sends
UBCT [commandline] \n
fixed string UBCT, then an ascii text line, with a command,
some whitespace allowed. Line ends with '\n'.
Server executes command. And sends reply in ascii text over channel,
closes the channel when done.
in case of error the first line of the response is:
error <descriptive text possible> \n
or the remainder is data of the response, for many commands the
response is 'ok\n'.
Queries and responses
---------------------
stop
stops the server.
reload
reloads the config file, and flushes the cache.
verbosity <new value>
Change logging verbosity to new value.
stats
output is a list of [name]=[value] lines.
clears the counters.
dump_cache
output is a text representation of the cache contents.
data ends with a line 'EOF' before connection close.
load_cache
client sends cache contents (like from dump_cache), which is stored
in the cache. end of data indicated with a line with 'EOF' on it.
The data is sent after the query line.
flush <name>
flushes some information regarding the name from the cache.
removes the A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV, NAPTR types.
Does not remove other types.
flush_type <name> <RR type>
removes rrtype entry from the cache.
flush_zone <name>
removes name and everything below that name from the cache.
has to search through the cache item by item, so this is slow.
lookup <name>
see what servers would be queried for a lookup of the given name.
local_zone_remove <name of local-zone entry>
the local-zone entry is removed.
All data from the local zone is also deleted.
If it did not exist, nothing happens.
local_zone <name of local zone> <type>
As the config file entry. Adds new local zone or updates
existing zone type.
local_data_remove <name>
Removes local-data (all types) name.
local_data <resource record string>
Add new local data record (on the rest of the line).
local_data_add www.example.com. IN A 192.0.2.2
if no local_zone exists for it; a transparent zone with the same
name as the data is created.
+92 -16
View File
@@ -22,6 +22,10 @@ server:
# enable cumulative statistics, without clearing them after printing.
# statistics-cumulative: no
# enable extended statistics (query types, answer codes, status)
# printed from unbound-control. default off, because of speed.
# extended-statistics: no
# number of threads to create. 1 disables threading.
# num-threads: 1
@@ -35,7 +39,7 @@ server:
# interface: 2001:DB8::5
# enable this feature to copy the source address of queries to reply.
# Socket options not be supported on all platforms. experimental.
# Socket options are not supported on all platforms. experimental.
# interface-automatic: no
# port to answer queries from
@@ -85,6 +89,9 @@ server:
# the number of queries that a thread gets to service.
# num-queries-per-thread: 1024
# if very busy, 50% queries run to completion, 50% get timeout in msec
# jostle-timeout: 200
# the amount of memory to use for the RRset cache.
# plain value in bytes or you can append k, m or G. default is "4Mb".
# rrset-cache-size: 4m
@@ -134,13 +141,14 @@ server:
# control which clients are allowed to make (recursive) queries
# to this server. Specify classless netblocks with /size and action.
# By default everything is refused, except for localhost.
# Choose deny (drop message), refuse (polite error reply), allow.
# Choose deny (drop message), refuse (polite error reply),
# allow (recursive ok), allow_snoop (recursive and nonrecursive ok)
# access-control: 0.0.0.0/0 refuse
# access-control: 127.0.0.0/8 allow
# access-control: ::0/0 refuse
# access-control: ::1 allow
# access-control: ::ffff:127.0.0.1 allow
# if given, a chroot(2) is done to the given directory.
# i.e. you can chroot to the working directory, for example,
# for extra security, but make sure all files are in that directory.
@@ -150,15 +158,17 @@ server:
# chroot has been performed the now defunct portion of the config
# file path is removed to be able to reread the config after a reload.
#
# All other file paths (working dir, pidfile, logfile, roothints,
# All other file paths (working dir, logfile, roothints, and
# key files) can be specified in several ways:
# o as an absolute path relative to the new root.
# o as a relative path to the working directory.
# o as an absolute path relative to the original root.
# In the last case the path is adjusted to remove the unused portion.
#
# Additionally, unbound may need to access /dev/random (for entropy)
# and to /dev/log (if you use syslog) from inside the chroot.
# The pid file can be absolute and outside of the chroot, it is
# written just prior to performing the chroot and dropping permissions.
#
# Additionally, unbound may need to access /dev/random (for entropy).
# How to do this is specific to your OS.
#
# If you give "" no chroot is performed. The path must not end in a /.
@@ -167,7 +177,7 @@ server:
# if given, user privileges are dropped (after binding port),
# and the given username is assumed. Default is user "unbound".
# If you give "" no privileges are dropped.
# username: "unbound"
# username: "@UNBOUND_USERNAME@"
# the working directory. The relative files in this config are
# relative to this directory. If you give "" the working directory
@@ -182,7 +192,7 @@ server:
# log to, with identity "unbound". If yes, it overrides the logfile.
# use-syslog: yes
# the pid file.
# the pid file. Can be an absolute path outside of chroot/work dir.
# pidfile: "@UNBOUND_PIDFILE@"
# file to read root hints from.
@@ -225,15 +235,40 @@ server:
# trigger insecure mode for that zone (like without a trustanchor).
# Default on, which insists on dnssec data for trust-anchored zones.
# harden-dnssec-stripped: yes
# Harden the referral path by performing additional queries for
# infrastructure data. Validates the replies (if possible).
# Default off, because the lookups burden the server. Experimental
# implementation of draft-wijngaards-dnsext-resolver-side-mitigation.
# harden-referral-path: no
# Use 0x20-encoded random bits in the query to foil spoof attempts.
# Disabled by default, because some caching forwarders may not
# support this (if you have forward-zones). Most authority servers do.
# This feature is an experimental implementation of draft dns-0x20.
# It is known that some authority servers do not support 0x20, and
# resolution will fail for them. A solution is on the TODO list.
# use-caps-for-id: no
# Enforce privacy of these addresses. Strips them away from answers.
# It may cause DNSSEC validation to additionally mark it as bogus.
# Protects against 'DNS Rebinding' (uses browser as network proxy).
# Only 'private-domain' and 'local-data' names are allowed to have
# these private addresses. No default.
# private-address: 10.0.0.0/8
# private-address: 172.16.0.0/12
# private-address: 192.168.0.0/16
# private-address: 192.254.0.0/16
# private-address: fd00::/8
# private-address: fe80::/10
# Allow the domain (and its subdomains) to contain private addresses.
# local-data statements are allowed to contain private addresses too.
# private-domain: "example.com"
# If nonzero, unwanted replies are not only reported in statistics,
# but also a running total is kept per thread. If it reaches the
# threshold, a warning is printed and a defensive action is taken,
# the cache is cleared to flush potential poison out of it.
# A suggested value is 10000000, the default is 0 (turned off).
# unwanted-reply-threshold: 0
# Do not query the following addresses. No DNS queries are sent there.
# List one address per entry. List classless netblocks with /size,
# do-not-query-address: 127.0.0.1/8
@@ -247,6 +282,11 @@ server:
# separated by spaces. "iterator" or "validator iterator"
# module-config: "validator iterator"
# File with DLV trusted keys. Same format as trust-anchor-file.
# There can be only one DLV configured, it is trusted from root down.
# Download https://secure.isc.org/ops/dlv/dlv.isc.org.key
# dlv-anchor-file: "dlv.isc.org.key"
# File with trusted keys for validation. Specify more than one file
# with several entries, one file per entry.
# Zone file format, with DS and DNSKEY entries.
@@ -263,7 +303,7 @@ server:
# but has a different file format. Format is BIND-9 style format,
# the trusted-keys { name flag proto algo "key"; }; clauses are read.
# trusted-keys-file: ""
# Override the date for validation with a specific fixed date.
# Do not set this unless you are debugging signature inception
# and expiration. "" or "0" turns the feature off.
@@ -271,7 +311,7 @@ server:
# The time to live for bogus data, rrsets and messages. This avoids
# some of the revalidation, until the time interval expires. in secs.
# val-bogus-ttl: 900
# val-bogus-ttl: 60
# Should additional section of secure message also be kept clean of
# unsecure data. Useful to shield the users of this validator from
@@ -300,6 +340,10 @@ server:
# the number of slabs must be a power of 2.
# more slabs reduce lock contention, but fragment memory usage.
# key-cache-slabs: 4
# the amount of memory to use for the negative cache (used for DLV).
# plain value in bytes or you can append k, m or G. default is "1Mb".
# neg-cache-size: 1m
# a number of locally served zones can be configured.
# local-zone: <zone> <type>
@@ -330,15 +374,47 @@ server:
# (this makes example.com, www.example.com, etc, all go to 192.0.2.3)
# local-zone: "example.com" redirect
# local-data: "example.com A 192.0.2.3"
#
# Shorthand to make PTR records, "IPv4 name" or "IPv6 name".
# You can also add PTR records using local-data directly, but then
# you need to do the reverse notation yourself.
# local-data-ptr: "192.0.2.3 www.example.com"
# Remote control config section.
remote-control:
# Enable remote control with unbound-control(8) here.
# set up the keys and certificates with unbound-control-setup.
# control-enable: no
# what interfaces are listened to for remote control.
# give 0.0.0.0 and ::0 to listen to all interfaces.
# control-interface: 127.0.0.1
# control-interface: ::1
# port number for remote control operations.
# control-port: 953
# unbound server key file.
# server-key-file: "@UNBOUND_RUN_DIR@/unbound_server.key"
# unbound server certificate file.
# server-cert-file: "@UNBOUND_RUN_DIR@/unbound_server.pem"
# unbound-control key file.
# control-key-file: "@UNBOUND_RUN_DIR@/unbound_control.key"
# unbound-control certificate file.
# control-cert-file: "@UNBOUND_RUN_DIR@/unbound_control.pem"
# Stub zones.
# Create entries like below, to make all queries for 'example.com' and
# 'example.org' go to the given list of nameservers. list zero or more
# nameservers by hostname or by ipaddress.
# nameservers by hostname or by ipaddress. If you set stub-prime to yes,
# the list is treated as priming hints (default is no).
# stub-zone:
# name: "example.com"
# stub-addr: 192.0.2.68
# stub-prime: "no"
# stub-zone:
# name: "example.org"
# stub-host: ns.example.com.
-324
View File
@@ -1,324 +0,0 @@
Plan for Unbound.
Split into a set of boxes. Every box will take about 3 weeks to a month
to complete. The first set of of boxes (approx 5 months) will need coding
by a limited set of people. But after every box, a 0.x release is done,
which is then tested and code review is done.
Every box:
* implement the features
* documentation of those features
* test-framework for the new features
* tests for the new features
* speed test of this stage
* release of 0.x version (0.x for development only)
* a teleconference(jabber) held to discuss.
* code review internal couple of days, external a week or so,
while we continue the next box.
Roughly the boxes are as follows:
0.0 initial setup - results in network code that forwards queries
and returns the reply (no cache), but also testbed, svn, maillist.
One query at a time (nonblocking IO though).
0.1 threads - results in threaded forwarder
0.2 LRU hashtable, results in basic caching forwarder (no DNS parse)
0.3 First functionality - results in caching forwarder (with DNS parse,
query compare, RR specific updates).
0.4 Basic resolver - module layout, iterator module, scrubber module,
results in resolver that can service multiple queries per thread.
This stage takes longer, due to complexity in the iterator module.
Twice as long; one box for module layout, one box for iterator module.
0.5 Validator - validator module.
0.6 Bigger and better - Operational useful features (config, log, memory)
0.7 Put to a limited audience.
gamma/alpha core functionality test release, to a small audience.
partial functionality. For more extensive use and testing.
0.8 Local zones feature - localzones stubzones fwdzones, no leak rfc1918.
views support; for selective recursive service.
0.9 Library use - resolver validator lib (and test apps)
0.10 Corner cases - be able to resolve in the wild. Run fuzzers.
Run as many tests as we can think of.
Go through logs and check for long, unresolved cases
Use profiler.
0.11 Beta release. Run shadow for a resolver in production for several
weeks.
0.12 Features features
aggressive negative caching for NSEC, NSEC3.
multiple queries per question, server exploration, server selection.
option to use real entropy for randomness (mix it in once in a while).
check query, option to enforce qdsection checking (forgery-resilience).
NSID support.
Be able to prime roots using several queries (only NS on first).
For boxes 0.5-1.0 the planning is to be revised, at the 0.5 stage external
coders are welcome. Since the project is bigger, there is room for them.
This is a summary of the items. Below more detailed work items are spelled
out with a (tentative) directory structure for the project.
Styleguide:
* write working stuff. (it starts to work with no features)
* write tests immediately for every function, every feature.
* document as you go. (doxygen comments, manpages and readme).
* copyright every file BSD. comments every file. clean coding in C.
* every day discuss state of the nation for 10 minutes.
*** Initial setup
* setup svn repo. Makefile with automatic dependencies and configure script.
* link with ldns.
* listen_dnsport and outside_network services, (unit) tests for them.
* use libevent to listen on fds.
* setup test infrastructure (tpkg on checkin; testbed on labs test machines).
* daemon version that forwards queries. (listen, send) Tests for it.
* test by having the outside_net service grab answers from a
file instead of network, file of id priority answerpacket.
and what query to give this answer to, highprio matches first.
*** Threads
* first simple config file reading/writing and tests on config file.
(config option is forwarder: yes/no. Cache size. That sort of thing.)
(very simple format)
* First simple logging (to a file).
* Threads
* check if pthread lib is the one to use (sys specific is faster?).
* make config option to have threads.
* alloc threadable.
* locks.c
* Tests with and without threads.
* alloc_service. Tests for alloc service (unit tests in internal structs).
* threading for the network services.
* Make sure threading/libevent starts working on all test machines.
Use configure to turn off threading/libevent/...
-- use libevent packaged together if not in system.
-- maybe also for pthreads/...
* threaded forwarder version.
* speed test of threaded version.
*** LRU hashtable.
* mini msg/reply structure for LRU hashtable test, simple replay format.
* hashtable+LRU structure. Tests on structure.
* tests on enter/remove, finding items.
* tests on LRU movements.
* Test on speed of finding items.
* slabbed hashtable+LRU structure.
* Test locking; perhaps by having sleeps in some threads to force
locks to contend. helgrind.
* daemon upgraded to be a caching forwarder. So it stores all in cache.
Replies from cache. Tests on fake-caching forwarder functionality.
* timeout of data test
* finding data in cache.
* finding data not in cache.
* lru falloff of data.
* Speed test of fake-caching forwarder.
*** First functionality
* implement dname type and unit tests on it. (all corner cases, random cases)
* implement rrset type and tests. (all corner cases, random cases).
* msg-reply structure. unit tests of structure.
* Test of those rrset pointers
* daemon upgraded to be a caching forwarder. So it stores all in cache.
Replies from cache. Tests on caching forwarder functionality.
* timeout of data test
* finding data in cache.
* finding data not in cache.
* lru falloff of data.
* Test update of one rrset in cached packet.
* Speed test of caching forwarder.
*** Basic Resolver
* Create module interface and module caller algorithm.
* Daemon config to use modules. Test the module caller.
* Create basic iterator and scrubber modules.
* Test every state of the iterator by passing test data into
it.
* And scrubber.
* Daemon config as cache(iterator).
* Test daemon
* Speed test.
*** Validator
* Create validator
* Test validator on various conditions. By having stored set of
domains and RRs in those domains to return to validator.
* Validating resolver.
* Test resolver.
* Speed test.
*** Put to a limited audience
* The alpha/gamma core functionality, svn access to limited audience.
* Support features and requests as they arise.
* Provide real-world experiences.
*** Bigger and Better
* Config file syntax checker program. Tests on checker.
* Logging first class feature with config options.
X with logfile turnover to avoid Gbs of logs.
* use syslog optional.
* donotqueryaddresses with trie for blocking entire netblocks.
* Memory overhaul, special allocators for hashtable caches, and mesh qstates.
* keep a preallocated list of region-chunks per worker thread.
* allocate region struct and cleanup list in region itself; use
linked list cleanup list. unit test on this. do not call region
to avoid name-collision with nsd regions, 'regional'.
* read root hints from file.
* failover to next server in 1 second, instead of 100 seconds on one server.
X failure to return answer, w. reason (donotq, noanswer servers, cannot
find servers, validationfail w.classification, error),
with threadno, starttime and endtime and qname/type/class, prime/qflags,
from-clients, from-internal, has-subrequests, a nice error report,
so that an excerpt from those times can be made from the logs.
logfileparsing tool that makes these excerpts and emails them.
Not done; user can change verbosity and kill -HUP.
* clear cache as a callback from the new-rrset-id routine.
X make overload mode work; phase 0 all ok, phase 1 some threads close ports,
to let other threads pick up work. phase 2, all threads closed, so all open
the ports again and drop all non-cache-reply queries.
Keep mutexed num-overloaded-threads counter. thread incs it when it hits
max number of user queries serviced in mesh. threads decs it when it
falls below 90% of the max. if incs, and not all threads closed, phase 1,
else, phase 2 start is broadcast over command pipes. if decs, open ports
if phase 1, start servicing, phase is 0 again. Make robust against delays.
readme: max about 1 second worth of incoming queries, 10k perhaps,
or 1/number of seconds it takes start up of 10k.
Not done. Implement drop when full.
* the source includes a copy of the ldns lib for ease of building by
new users. Detect system installed ldns, if installed ldns is OK; use
dynamic linking against it, otherwise static linking against packaged ldns.
* no greedy TTL algo (and test).
* maximum TTL, cap incoming values, and config option.
*** Local zones feature.
* Build in local zone features. First the total stop for1912.
* Then 'local content' for minimal serving of localhost.localdomain,
and so on.
* Remember jakob's diagram. views support, selective recursive service:
* acl for allowed recursion (RD=1), then drop or refused query.
like 10.0.0.0/8 allow, 0.0.0.0/0 refuse, ... in-order.
perhaps also, same list to disallow RD=0 access, like;
allow_recursion, drop_recursion, refuse_recursion, drop_all
* static answers for queries, fixed RRs from cfg, option
query for that RR returns answer with that RR.
* blacklist (return fixed nxdomain for domain and below), option
can be used to block AS112 traffic, option to unblock a zone.
* after checking acl, do iter: static, blacklist, forwards, recurse.
* Forward-local-zone to NSD.
- in package, autoforkexec on localhost to do so.
- not included. Not necessary for localhost and AS112 service.
* forward local zone to remote server.
- not included. Not necessary for localhost and AS112 service.
* stub zones - send queries for a zone to configged nameserver.
- Can be used for complicated setups. So, run auth server on a
different port or pc, and stub it on the resolver. Resolver is
not auth for zones, but resolution works. This enforces the split
of recursive and auth servers.
* test local zones
* for speed
* for correctness on corner cases
*** Library use
* Create library that can do:
* resolver
* validator
* validating resolver.
* Test application that links the library. (Like /usr/bin/host+validating).
* Test it.
*** Corner cases
* Try to setup corner cases of (mis)configured DNS service/websites.
* Resolve msoft, google, yahoo, etc weird websites.
* Try to resolve many many different queries, perhaps compared with bind.
* create module testers, specific for the modules
* read a file with cache contents and settings, provide fake
environment for module-handle-state-X functions, then check
resulting module state structure to correct answer.
* speed test cache responses.
* using two servers, compare answer differences between bind and unbound.
this gives false differences due to changes in the rest of internet.
*** Beta release.
* Run shadow for a resolver in production for several weeks.
* Check logs for errors, long queries.
* Run in valgrind, speed profiling (as production shadow).
*** Features features
* aggressive negative caching for NSEC, NSEC3.
* multiple queries per question, server exploration, server selection.
* NSID support.
* support TSIG on queries, for validating resolver deployment.
* Nicer statistics
* private TTL, dTLS features.
* retry-mode, where a bogus result triggers a retry-mode query, where a list
of responses over a time interval is collected, and each is validated.
or try in TCP mode. Do not 'try all servers several times', since we must
not create packet storms with operator errors.
* draft-timers, DLV features.
treeshrew/
validator/ *.c *.h
module takes qname, qtype, asks next module for answer
and validates that answer.
iterator/ *.c *.h
module takes qname, qtype, iterative DNS queries
never asks next module.
services/
- Routines that provide the callback services for modules.
alloc_service: L1, L2 alloc service
outside_network: pending queries helpers.
pending query structure
listen_dnsport: listen port53 service.
request structure
type_caches/
rrset_cache
msg_cache
rrset and msg cache check local zones.
infra_cache
trusted_key_cache
util/
- Various components from which to build the rest.
storage/
rbtree: redblack tree, for L1 use.
- copy from NSD.
hashtable and hashfunc: for L1 use.
locked_hashtable: for L2 use. -- not needed.
fragment_hashtable: for L2 use.
fragment_rbtree: for L2 use.
slab_allocator: perhaps to support alloc service.
(in util/ itself)
locks: selected lock,unlock (spinlock/mutex).
config: reads, stores config file
netio: register callbacks to select().
- use libevent (!)
- copy from NSD.
log: error and log handling.
module.h: module interface
misc: time() wrapper for speed.
data/
msg_reply: qname/qtype/CD/qclass/reply store.
packed_rrset: main datatype
dname: compare, printf, parse
testcode/
main programs that do unit tests, using testdata
testdata/
daemon/
unbound.c for validating caching recursive dns server.
scheduler.c for the modules.
libunbound/
app linkable. Can be configged to do whatever,
validator, iterator, validating iterator, forwarding stub.
libforwardbound/
app linkable forwarding stub. Small lib.
ask_cachor/ *.c *.h
module takes qname, qtype, returns answer from msgcache.
could ask cached for answer (and wait for network, 10 ms).
if not in cache, asks next module.
cachord/
main.c, simple udp proto, query or store msg in cache.
supports option to save cache to disk (absolute time ttls).
+37
View File
@@ -206,3 +206,40 @@ o Case preservation
The casing from the query name is used in preference to the casing
of the authority server. This is the same as BIND. RFC4343 allows either
behaviour.
o Denial of service protection
If many queries are made, and they are made to names for which the
authority servers do not respond, then the requestlist for unbound
fills up fast. This results in denial of service for new queries.
To combat this the first 50% of the requestlist can run to completion.
The last 50% of the requestlist get (200 msec) at least and are replaced
by newer queries when older (LIFO).
When a new query comes in, and a place in the first 50% is available, this
is preferred. Otherwise, it can replace older queries out of the last 50%.
Thus, even long queries get a 50% chance to be resolved. And many 'short'
one or two round-trip resolves can be done in the last 50% of the list.
The timeout can be configured.
o EDNS fallback. Is done according to the EDNS RFC (and update draft-00).
Unbound assumes EDNS 0 support for the first query. Then it can detect
support (if the servers replies) or non-support (on a NOTIMPL or FORMERR).
Some middleboxes drop EDNS 0 queries, mainly when forwarding, not when
routing packets. To detect this, when timeouts keep happening, as the
timeout approached 5-10 seconds, and EDNS status has not been detected yet,
a single probe query is sent. This probe has a sub-second timeout, and
if the server responds (quickly) without EDNS, this is cached for 15 min.
This works very well when detecting an address that you use much - like
a forwarder address - which is where the middleboxes need to be detected.
Otherwise, it results in a 5 second wait time before EDNS timeout is
detected, which is slow but it works at least.
It minimizes the chances of a dropped query making a (DNSSEC) EDNS server
falsely EDNS-nonsupporting, and thus DNSSEC-bogus, works well with
middleboxes, and can detect the occasional authority that drops EDNS.
o 0x20 backoff.
The draft describes to back off to the next server, and go through all
servers several times. Unbound goes on get the full list of nameserver
addresses, and then makes 3 * number of addresses queries.
They are sent to a random server, but no one address more than 4 times.
It succeeds if one has 0x20 intact, or else all are equal.
Otherwise, servfail is returned to the client.
+307
View File
@@ -0,0 +1,307 @@
.TH "unbound-control" "8" "@date@" "NLnet Labs" "unbound @version@"
.\"
.\" unbound-control.8 -- unbound remote control manual
.\"
.\" Copyright (c) 2008, NLnet Labs. All rights reserved.
.\"
.\" See LICENSE for the license.
.\"
.\"
.SH "NAME"
.LP
unbound-control
\- Unbound remote server control utility.
.SH "SYNOPSIS"
.B unbound-control
.RB [ \-h ]
.RB [ \-c
.IR cfgfile ]
.RB [ \-s
.IR server ]
.IR command
.SH "DESCRIPTION"
.B Unbound-control
Performs remote administration on the \fIunbound\fR(8) DNS server.
It reads the configuration file, contacts the unbound server over SSL
sends the command and displays the result.
.P
The available options are:
.TP
.B \-h
Show the version and commandline option help.
.TP
.B \-c \fIcfgfile
The config file to read with settings. If not given the default
config file @ub_conf_file@ is used.
.TP
.B \-s \fIserver[@port]
IPv4 or IPv6 address of the server to contact. If not given, the
address is read from the config file.
.SH "COMMANDS"
There are several commands that the server understands.
.TP
.B start
Start the server. Simply execs \fIunbound\fR(8). The unbound executable
is searched for in the \fBPATH\fR set in the environment. It is started
with the config file specified using \fI\-c\fR or the default config file.
.TP
.B stop
Stop the server. The server daemon exits.
.TP
.B reload
Reload the server. This flushes the cache and reads the config file fresh.
.TP
.B verbosity \fInumber
Change verbosity value for logging. Same values as \fBverbosity\fR keyword in
\fIunbound.conf\fR(5). This new setting lasts until the server is issued
a reload (taken from config file again), or the next verbosity control command.
.TP
.B stats
Print statistics. Resets the internal counters to zero, this can be
controlled using the \fBstatistics\-cumulative\fR config statement.
Statistics are printed with one [name]: [value] per line.
.TP
.B local_zone \fIname\fR \fItype
Add new local zone with name and type. Like \fBlocal\-zone\fR config statement.
If the zone already exists, the type is changed to the given argument.
.TP
.B local_zone_remove \fIname
Remove the local zone with the given name. Removes all local data inside
it. If the zone does not exist, the command succeeds.
.TP
.B local_data \fIRR data...
Add new local data, the given resource record. Like \fBlocal\-data\fR
config statement, except for when no covering zone exists. In that case
this remote control command creates a transparent zone with the same
name as this record. This command is not good at returning detailed syntax
errors.
.TP
.B local_data_remove \fIname
Remove all RR data from local name. If the name already has no items,
nothing happens. Often results in NXDOMAIN for the name (in a static zone),
but if the name has become an empty nonterminal (there is still data in
domain names below the removed name), NOERROR nodata answers are the
result for that name.
.TP
.B dump_cache
The contents of the cache is printed in a text format to stdout. You can
redirect it to a file to store the cache in a file.
.TP
.B load_cache
The contents of the cache is loaded from stdin. Uses the same format as
dump_cache uses. Loading the cache with old, or wrong data can result
in old or wrong data returned to clients.
.TP
.B lookup \fIname
Print to stdout the name servers that would be used to look up the
name specified.
.TP
.B flush \fIname
Remove the name from the cache. Removes the types
A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV and NAPTR.
Because that is fast to do. Other record types can be removed using
.B flush_type
or
.B flush_zone\fR.
.TP
.B flush_type \fIname\fR \fItype
Remove the name, type information from the cache.
.TP
.B flush_zone \fIname
Remove all information at or below the name from the cache.
The rrsets and key entries are removed so that new lookups will be performed.
This needs to walk and inspect the entire cache, and is a slow operation.
.SH "EXIT CODE"
The unbound-control program exits with status code 1 on error, 0 on success.
.SH "SET UP"
The setup requires a self\-signed certificate and private keys for both
the server and client. The script \fIunbound\-control\-setup\fR generates
these in the default run directory, or with \-d in another directory.
The script preserves private keys present in the directory.
After running the script as root, turn on \fBcontrol-enable\fR in
\fIunbound.conf\fR.
.SH "STATISTIC COUNTERS"
The \fIstats\fR command shows a number of statistic counters.
.TP
.I threadX.num.queries
number of queries received by thread
.TP
.I threadX.num.cachehits
number of queries that were successfully answered using a cache lookup
.TP
.I threadX.num.cachemiss
number of queries that needed recursive processing
.TP
.I threadX.num.recursivereplies
The number of replies sent to queries that needed recursive processing. Could be smaller than threadX.num.cachemiss if due to timeouts no replies were sent for some queries.
.TP
.I threadX.requestlist.avg
The average number of requests in the internal recursive processing request list on insert of a new incoming recursive processing query.
.TP
.I threadX.requestlist.max
Maximum size attained by the internal recursive processing request list.
.TP
.I threadX.requestlist.overwritten
Number of requests in the request list that were overwritten by newer entries. This happens if there is a flood of queries that recursive processing and the server has a hard time.
.TP
.I threadX.requestlist.exceeded
Queries that were dropped because the request list was full. This happens if a flood of queries need recursive processing, and the server can not keep up.
.TP
.I threadX.requestlist.current.all
Current size of the request list, includes internally generated queries (such
as priming queries and glue lookups).
.TP
.I threadX.requestlist.current.user
Current size of the request list, only the requests from client queries.
.TP
.I threadX.recursion.time.avg
Average time it took to answer queries that needed recursive processing. Note that queries that were answered from the cache are not in this average.
.TP
.I threadX.recursion.time.median
The median of the time it took to answer queries that needed recursive
processing. The median means that 50% of the user queries were answered in
less than this time. Because of big outliers (usually queries to non
responsive servers), the average can be bigger than the median. This median
has been calculated by interpolation from a histogram.
.TP
.I total.num.queries
summed over threads.
.TP
.I total.num.cachehits
summed over threads.
.TP
.I total.num.cachemiss
summed over threads.
.TP
.I total.num.recursivereplies
summed over threads.
.TP
.I total.requestlist.avg
averaged over threads.
.TP
.I total.requestlist.max
the maximum of the thread requestlist.max values.
.TP
.I total.requestlist.overwritten
summed over threads.
.TP
.I total.requestlist.exceeded
summed over threads.
.TP
.I total.requestlist.current.all
summed over threads.
.TP
.I total.recursion.time.median
averaged over threads.
.TP
.I time.now
current time in seconds since 1970.
.TP
.I time.up
uptime since server boot in seconds.
.TP
.I time.elapsed
time since last statistics printout, in seconds.
.SH EXTENDED STATISTICS
.TP
.I mem.total.sbrk
If sbrk(2) is available, an estimate of the heap size of the program in number of bytes. Close to the total memory used by the program, as reported by top and ps. Could be wrong if the OS allocates memory non\-contiguously.
.TP
.I mem.cache.rrset
Memory in bytes in use by the RRset cache.
.TP
.I mem.cache.message
Memory in bytes in use by the message cache.
.TP
.I mem.mod.iterator
Memory in bytes in use by the iterator module.
.TP
.I mem.mod.validator
Memory in bytes in use by the validator module. Includes the key cache and
negative cache.
.TP
.I histogram.<sec>.<usec>.to.<sec>.<usec>
Shows a histogram, summed over all threads. Every element counts the
recursive queries whose reply time fit between the lower and upper bound.
Times larger or equal to the lowerbound, and smaller than the upper bound.
There are 40 buckets, with bucket sizes doubling.
.TP
.I num.query.type.A
The total number of queries over all threads with query type A.
Printed for the other query types as well, but only for the types for which
queries were received, thus =0 entries are omitted for brevity.
.TP
.I num.query.type.other
Number of queries with query types 256-65535.
.TP
.I num.query.class.IN
The total number of queries over all threads with query class IN (internet).
Also printed for other classes (such as CH (CHAOS) sometimes used for
debugging), or NONE, ANY, used by dynamic update.
num.query.class.other is printed for classes 256-65535.
.TP
.I num.query.opcode.QUERY
The total number of queries over all threads with query opcode QUERY.
Also printed for other opcodes, UPDATE, ...
.TP
.I num.query.tcp
Number of queries that were made using TCP towards the unbound server.
.TP
.I num.query.flags.RD
The number of queries that had the RD flag set in the header.
Also printed for flags QR, AA, TC, RA, Z, AD, CD.
Note that queries with flags QR, AA or TC may have been rejected
because of that.
.TP
.I num.query.edns.present
number of queries that had an EDNS OPT record present.
.TP
.I num.query.edns.DO
number of queries that had an EDNS OPT record with the DO (DNSSEC OK) bit set.
These queries are also included in the num.query.edns.present number.
.TP
.I num.answer.rcode.NXDOMAIN
The number of answers to queries, from cache or from recursion, that had the
return code NXDOMAIN. Also printed for the other return codes.
.TP
.I num.answer.rcode.nodata
The number of answers to queries that had the pseudo return code nodata.
This means the actual return code was NOERROR, but additionally, no data was
carried in the answer (making what is called a NOERROR/NODATA answer).
These queries are also included in the num.answer.rcode.NOERROR number.
Common for AAAA lookups when an A record exists, and no AAAA.
.TP
.I num.answer.secure
Number of answers that were secure. The answer validated correctly.
The AD bit might have been set in some of these answers, where the client
signalled (with DO or AD bit in the query) that they were ready to accept
the AD bit in the answer.
.TP
.I num.answer.bogus
Number of answers that were bogus. These answers resulted in SERVFAIL
to the client because the answer failed validation.
.TP
.I num.rrset.bogus
The number of rrsets marked bogus by the validator. Increased for every
RRset inspection that fails.
.TP
.I unwanted.queries
Number of queries that were refused or dropped because they failed the
access control settings.
.TP
.I unwanted.replies
Replies that were unwanted or unsolicited. Could have been random traffic,
delayed duplicates, very late answers, or could be spoofing attempts.
Some low level of late answers and delayed duplicates are to be expected
with the UDP protocol. Very high values could indicate a threat (spoofing).
.SH "FILES"
.TP
.I @ub_conf_file@
unbound configuration file.
.TP
.I @UNBOUND_RUN_DIR@
directory with private keys (unbound_server.key and unbound_control.key) and
self-signed certificates (unbound_server.pem and unbound_control.pem).
.SH "SEE ALSO"
\fIunbound.conf\fR(5),
\fIunbound\fR(8).
+180 -19
View File
@@ -49,7 +49,11 @@ example.conf file with all the options.
# unbound.conf(5) config file for unbound(8).
server:
directory: "/etc/unbound"
username: unbound # make sure it can write to pidfile.
username: unbound
# make sure unbound can access entropy from inside the chroot.
# e.g. on linux the use these commands (on BSD, devfs(8) is used):
# mount --bind -n /dev/random /etc/unbound/dev/random
# and mount --bind -n /dev/log /etc/unbound/dev/log
chroot: "/etc/unbound"
# logfile: "/etc/unbound/unbound.log" #uncomment to use logfile.
pidfile: "/etc/unbound/unbound.pid"
@@ -84,14 +88,18 @@ Default is level 1. The verbosity can also be increased from the commandline,
see
\fIunbound\fR(8).
.TP
.B statistics-interval: \fI<seconds>
.B statistics\-interval: \fI<seconds>
The number of seconds between printing statistics to the log for every thread.
Disable with value 0 or "". Default is disabled.
.TP
.B statistics-cumulative: \fI<yes or no>
.B statistics\-cumulative: \fI<yes or no>
If enabled, statistics are cumulative since starting unbound, without clearing
the statistics counters after logging the statistics. Default is no.
.TP
.B extended\-statistics: \fI<yes or no>
If enabled, extended statistics are printed from \fIunbound\-control\fR(8).
Default is off, because keeping track of more statistics takes time.
.TP
.B num\-threads: \fI<number>
The number of threads to create to serve clients. Use 1 for no threading.
.TP
@@ -133,6 +141,12 @@ A larger number of permitted outgoing ports increases resilience against
spoofing attempts. Make sure these ports are not needed by other daemons.
By default only ports above 1024 that have not been assigned by IANA are used.
Give a port number or a range of the form "low-high", without spaces.
.IP
The \fBoutgoing\-port\-permit\fR and \fBoutgoing\-port\-avoid\fR statements
are processed in the line order of the config file, adding the permitted ports
and subtracting the avoided ports from the set of allowed ports. The
processing starts with the non IANA allocated ports above 1024 in the set
of allowed ports.
.TP
.B outgoing\-port\-avoid: \fI<port number or range>
Do not permit unbound to open this port or range of ports for use to send
@@ -168,10 +182,19 @@ reasonable guess.
.TP
.B num\-queries\-per\-thread: \fI<number>
The number of queries that every thread will service simultaneously.
If more queries arrive that need servicing, they are dropped. This forces
If more queries arrive that need servicing, and no queries can be jostled out
(see \fIjostle\-timeout\fR), then the queries are dropped. This forces
the client to resend after a timeout; allowing the server time to work on
the existing queries. Default 1024.
.TP
.B jostle\-timeout: \fI<msec>
Timeout used when the server is very busy. Set to a value that usually
results in one roundtrip to the authority servers. If too many queries
arrive, then 50% of the queries are allowed to run to completion, and
the other 50% are replaced with the new incoming query if they have already
spent more than their allowed time. This protects against denial of
service by slow queries or high query rates. Default 200 milliseconds.
.TP
.B rrset\-cache\-size: \fI<number>
Number of bytes size of the RRset cache. Default is 4 megabytes.
A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes
@@ -228,14 +251,36 @@ a daemon. Default is yes.
.TP
.B access\-control: \fI<IP netblock> <action>
The netblock is given as an IP4 or IP6 address with /size appended for a
classless network block. The action can be deny, refuse or allow.
Deny stops queries from hosts from that netblock.
Refuse stops queries too, but sends a DNS rcode REFUSED error message back.
Allow gives access to clients from that netblock.
By default only localhost is allowed, the rest is refused.
The default is refused, because that is protocol\-friendly. The DNS protocol
is not designed to handle dropped packets due to policy, and dropping may
result in (possibly excessive) retried queries.
classless network block. The action can be \fIdeny\fR, \fIrefuse\fR,
\fIallow\fR or \fIallow_snoop\fR.
.IP
The action \fIdeny\fR stops queries from hosts from that netblock.
.IP
The action \fIrefuse\fR stops queries too, but sends a DNS rcode REFUSED
error message back.
.IP
The action \fIallow\fR gives access to clients from that netblock.
It gives only access for recursion clients (which is
what almost all clients need). Nonrecursive queries are refused.
.IP
The \fIallow\fR action does allow nonrecursive queries to access the
local\-data that is configured. The reason is that this does not involve
the unbound server recursive lookup algorithm, and static data is served
in the reply. This supports normal operations where nonrecursive queries
are made for the authoritative data. For nonrecursive queries any replies
from the dynamic cache are refused.
.IP
The action \fIallow_snoop\fR gives nonrecursive access too. This give
both recursive and non recursive access. The name \fIallow_snoop\fR refers
to cache snooping, a technique to use nonrecursive queries to examine
the cache contents (for malicious acts). However, nonrecursive queries can
also be a valuable debugging tool (when you want to examine the cache
contents). In that case use \fIallow_snoop\fR for your administration host.
.IP
By default only localhost is \fIallow\fRed, the rest is \fIrefuse\fRd.
The default is \fIrefuse\fRd, because that is protocol\-friendly. The DNS
protocol is not designed to handle dropped packets due to policy, and
dropping may result in (possibly excessive) retried queries.
.TP
.B chroot: \fI<directory>
If chroot is enabled, you should pass the configfile (from the
@@ -243,22 +288,27 @@ commandline) as a full path from the original root. After the
chroot has been performed the now defunct portion of the config
file path is removed to be able to reread the config after a reload.
.IP
All other file paths (working dir, pidfile, logfile, roothints,
All other file paths (working dir, logfile, roothints, and
key files) can be specified in several ways:
as an absolute path relative to the new root,
as a relative path to the working directory, or
as an absolute path relative to the original root.
In the last case the path is adjusted to remove the unused portion.
.IP
The pidfile can be either a relative path to the working directory, or
an absolute path relative to the original root. It is written just prior
to chroot and dropping permissions. This allows the pidfile to be
/var/run/unbound.pid and the chroot to be /var/unbound, for example.
.IP
Additionally, unbound may need to access /dev/random (for entropy)
and to /dev/log (if you use syslog) from inside the chroot.
from inside the chroot.
.IP
If given a chroot is done to the given directory. The default is
"@UNBOUND_CHROOT_DIR@". If you give "" no chroot is performed.
.TP
.B username: \fI<name>
If given, after binding the port the user privileges are dropped. Default is
"unbound". If you give username: "" no user change is performed.
"@UNBOUND_USERNAME@". If you give username: "" no user change is performed.
.IP
If this user is not capable of binding the
port, reloads (by signal HUP) will still retain the opened ports.
@@ -356,15 +406,53 @@ removes DNSSEC data from packets, or a zone changes from signed to
unsigned to badly signed often. If turned off you run the risk of a
downgrade attack that disables security for a zone. Default is on.
.TP
.B harden\-referral\-path: \fI<yes or no>
Harden the referral path by performing additional queries for
infrastructure data. Validates the replies if trust anchors are configured
and the zones are signed. This enforces DNSSEC validation on nameserver
NS sets and the nameserver addresses that are encountered on the referral
path to the answer.
Default off, because it burdens the authority servers, and it is
not RFC standard, and could lead to performance problems because of the
extra query load that is generated. Experimental option.
.TP
.B use\-caps\-for\-id: \fI<yes or no>
Use 0x20-encoded random bits in the query to foil spoof attempts.
This perturbs the lowercase and uppercase of query names sent to
authority servers and checks if the reply still has the correct casing.
Disabled by default, because some caching forwarders may not
support this. It is known that some authority servers do not support 0x20,
and resolution will fail for them. A solution is on the TODO list.
Disabled by default.
This feature is an experimental implementation of draft dns\-0x20.
.TP
.B private\-address: \fI<IP address or subnet>
Give IPv4 of IPv6 addresses or classless subnets. These are addresses
on your private network, and are not allowed to be returned for public
internet names. Any occurence of such addresses are removed from
DNS answers. Additionally, the DNSSEC validator may mark the answers
bogus. This protects against so-called DNS Rebinding, where a user browser
is turned into a network proxy, allowing remote access through the browser
to other parts of your private network. Some names can be allowed to
contain your private addresses, by default all the \fBlocal\-data\fR
that you configured is allowed to, and you can specify additional
names using \fBprivate\-domain\fR. No private addresses are enabled
by default. We consider to enable this for the RFC1918 private IP
address space by default in later releases. That would enable private
addresses for 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 192.254.0.0/16
fd00::/8 and fe80::/10, since the RFC standards say these addresses
should not be visible on the public internet. Turning on 127.0.0.0/8
would hinder many spamblocklists as they use that.
.TP
.B private\-domain: \fI<domain name>
Allow this domain, and all its subdomains to contain private addresses.
Give multiple times to allow multiple domain names to contain private
addresses. Default is none.
.TP
.B unwanted\-reply\-threshold: \fI<number>
If set, a total number of unwanted replies is kept track of in every thread.
When it reaches the threshold, a defensive action is taken and a warning
is printed to the log. The defensive action is to clear the rrset and
message caches, hopefully flushing away any poison. A value of 10 million
is suggested. Default is 0 (turned off).
.TP
.B do\-not\-query\-address: \fI<IP address>
Do not query the given IP address. Can be IP4 or IP6. Append /num to
indicate a classless delegation netblock, for example like
@@ -401,6 +489,16 @@ with several entries, one file per entry. Like \fBtrust\-anchor\-file\fR
but has a different file format. Format is BIND\-9 style format,
the trusted\-keys { name flag proto algo "key"; }; clauses are read.
.TP
.B dlv\-anchor\-file: \fI<filename>
File with trusted keys for DLV (DNSSEC Lookaside Validation). Both DS and
DNSKEY entries can be used in the file, in the same format as for
\fItrust\-anchor\-file:\fR statements. Only one DLV can be configured, more
would be slow. The DLV configured is used as a root trusted DLV, this
means that it is a lookaside for the root. Default is "", or no dlv anchor file.
.TP
.B dlv\-anchor: \fI<"Resource Record">
Much like trust\-anchor, this is a DLV anchor with the DS or DNSKEY inline.
.TP
.B val\-override\-date: \fI<rrsig\-style date spec>
Default is "" or "0", which disables this debugging feature. If enabled by
giving a RRSIG style date, that date is used for verifying RRSIG inception
@@ -410,7 +508,7 @@ you are debugging signature inception and expiration.
.B val\-bogus\-ttl: \fI<number>
The time to live for bogus data. This is data that has failed validation;
due to invalid signatures or other checks. The TTL from that data cannot be
trusted, and this value is used instead. The value is in seconds, default 900.
trusted, and this value is used instead. The value is in seconds, default 60.
The time interval prevents repeated revalidation of bogus data.
.TP
.B val\-clean\-additional: \fI<yes or no>
@@ -447,6 +545,11 @@ Number of slabs in the key cache. Slabs reduce lock contention by threads.
Must be set to a power of 2. Setting (close) to the number of cpus is a
reasonable guess.
.TP
.B neg\-cache\-size: \fI<number>
Number of bytes size of the aggressive negative cache. Default is 1 megabyte.
A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes
or gigabytes (1024*1024 bytes in a megabyte).
.TP
.B local\-zone: \fI<zone> <type>
Configure a local zone. The type determines the answer to give if there is
no match from local\-data. The types are deny, refuse, static, transparent,
@@ -585,6 +688,57 @@ local\-data: 'example. TXT "text"'.
If you need more complicated authoritative data, with referrals, wildcards,
CNAME/DNAME support, or DNSSEC authoritative service, setup a stub\-zone for
it as detailed in the stub zone section below.
.TP 5
.B local\-data\-ptr: \fI"IPaddr name"
Configure local data shorthand for a PTR record with the reversed IPv4 or
IPv6 address and the host name. For example "192.0.2.4 www.example.com".
TTL can be inserted like this: "2001:DB8::4 7200 www.example.com"
.SS "Remote Control Options"
In the
.B remote\-control:
clause are the declarations for the remote control facility. If this is
enabled, the \fIunbound\-control\fR(8) utility can be used to send
commands to the running unbound server. The server uses these clauses
to setup SSLv3 / TLSv1 security for the connection. The
\fIunbound\-control\fR(8) utility also reads the \fBremote\-control\fR
section for options. To setup the correct self-signed certificates use the
\fIunbound\-control\-setup\fR(8) utility.
.TP 5
.B control\-enable: \fI<yes or no>
The option is used to enable remote control, default is "no".
If turned off, the server does not listen for control commands.
.TP 5
.B control\-interface: <ip address>
Give IPv4 or IPv6 addresses to listen on for control commands.
By default localhost (127.0.0.1 and ::1) is listened to.
Use 0.0.0.0 and ::0 to listen to all interfaces.
.TP 5
.B control\-port: <port number>
The port number to listen on for control commands, default is 953
(that is the same port number named uses to listen to rndc).
If you change this port number, and permissions have been dropped, a
reload is not sufficient to open the port again, you must then restart.
.TP 5
.B server\-key\-file: "<private key file>"
Path to the server private key, by default unbound_server.key.
This file is generated by the \fIunbound\-control\-setup\fR utility.
This file is used by the unbound server, but not by \fIunbound\-control\fR.
.TP 5
.B server\-cert\-file: "<certificate file.pem>"
Path to the server self signed certificate, by default unbound_server.pem.
This file is generated by the \fIunbound\-control\-setup\fR utility.
This file is used by the unbound server, and also by \fIunbound\-control\fR.
.TP 5
.B control\-key\-file: "<private key file>"
Path to the control client private key, by default unbound_control.key.
This file is generated by the \fIunbound\-control\-setup\fR utility.
This file is used by \fIunbound\-control\fR.
.TP 5
.B control\-cert\-file: "<certificate file.pem>"
Path to the control client certificate, by default unbound_control.pem.
This certificate has to be signed with the server certificate.
This file is generated by the \fIunbound\-control\-setup\fR utility.
This file is used by \fIunbound\-control\fR.
.SS "Stub Zone Options"
.LP
There may be multiple
@@ -619,6 +773,12 @@ Name of stub zone nameserver. Is itself resolved before it is used.
.B stub\-addr: \fI<IP address>
IP address of stub zone nameserver. Can be IP 4 or IP 6.
To use a nondefault port for DNS communication append '@' with the port number.
.TP
.B stub\-prime: \fI<yes or no>
This option is by default off. If enabled it performs NS set priming,
which is similar to root hints, where it starts using the list of nameservers
currently published by the zone. Thus, if the hint list is slightly outdated,
the resolver picks up a correct list online.
.SS "Forward Zone Options"
.LP
There may be multiple
@@ -664,6 +824,7 @@ server:
infra\-cache\-lame\-size: 1k
key\-cache\-size: 100k
key\-cache\-slabs: 1
neg\-cache\-size: 10k
num\-queries\-per\-thread: 30
target\-fetch\-policy: "2 1 0 0 0 0"
harden\-large\-queries: "yes"
+18 -12
View File
@@ -74,7 +74,8 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
copy->nslist->resolved = ns->resolved;
}
for(a = dp->target_list; a; a = a->next_target) {
if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen))
if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen,
a->bogus))
return NULL;
}
return copy;
@@ -127,7 +128,7 @@ delegpt_find_ns(struct delegpt* dp, uint8_t* name, size_t namelen)
int
delegpt_add_target(struct delegpt* dp, struct regional* region,
uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
socklen_t addrlen)
socklen_t addrlen, int bogus)
{
struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen);
if(!ns) {
@@ -135,12 +136,12 @@ delegpt_add_target(struct delegpt* dp, struct regional* region,
return 1;
}
ns->resolved = 1;
return delegpt_add_addr(dp, region, addr, addrlen);
return delegpt_add_addr(dp, region, addr, addrlen, bogus);
}
int
delegpt_add_addr(struct delegpt* dp, struct regional* region,
struct sockaddr_storage* addr, socklen_t addrlen)
struct sockaddr_storage* addr, socklen_t addrlen, int bogus)
{
struct delegpt_addr* a = (struct delegpt_addr*)regional_alloc(region,
sizeof(struct delegpt_addr));
@@ -154,11 +155,11 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region,
memcpy(&a->addr, addr, addrlen);
a->addrlen = addrlen;
a->attempts = 0;
a->bogus = bogus;
return 1;
}
/** count NS and number missing */
static void
void
delegpt_count_ns(struct delegpt* dp, size_t* numns, size_t* missing)
{
struct delegpt_ns* ns;
@@ -171,8 +172,7 @@ delegpt_count_ns(struct delegpt* dp, size_t* numns, size_t* missing)
}
}
/** count addresses, and number in result and available lists */
static void
void
delegpt_count_addr(struct delegpt* dp, size_t* numaddr, size_t* numres,
size_t* numavail)
{
@@ -213,10 +213,14 @@ void delegpt_log(enum verbosity_value v, struct delegpt* dp)
if(verbosity >= VERB_ALGO) {
for(ns = dp->nslist; ns; ns = ns->next) {
dname_str(ns->name, buf);
log_info(" %s%s", buf, (ns->resolved?"*":""));
log_info(" %s%s%s", buf, (ns->resolved?"*":""),
(dp->bogus?" BOGUS":"") );
}
for(a = dp->target_list; a; a = a->next_target) {
log_addr(VERB_ALGO, " ", &a->addr, a->addrlen);
if(a->bogus)
log_addr(VERB_ALGO, " BOGUS ",
&a->addr, a->addrlen);
else log_addr(VERB_ALGO, " ", &a->addr, a->addrlen);
}
}
}
@@ -312,6 +316,8 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
struct packed_rrset_data* nsdata = (struct packed_rrset_data*)
ns_rrset->entry.data;
size_t i;
if(nsdata->security == sec_status_bogus)
dp->bogus = 1;
for(i=0; i<nsdata->count; i++) {
if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */
if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) !=
@@ -341,7 +347,7 @@ delegpt_add_rrset_A(struct delegpt* dp, struct regional* region,
memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE);
if(!delegpt_add_target(dp, region, ak->rk.dname,
ak->rk.dname_len, (struct sockaddr_storage*)&sa,
len))
len, (d->security==sec_status_bogus) ))
return 0;
}
return 1;
@@ -364,7 +370,7 @@ delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region,
memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE);
if(!delegpt_add_target(dp, region, ak->rk.dname,
ak->rk.dname_len, (struct sockaddr_storage*)&sa,
len))
len, (d->security==sec_status_bogus) ))
return 0;
}
return 1;
+17 -2
View File
@@ -70,6 +70,9 @@ struct delegpt {
struct delegpt_addr* usable_list;
/** the list of returned targets; subset of target_list */
struct delegpt_addr* result_list;
/** if true, the NS RRset was bogus. All info is bad. */
int bogus;
};
/**
@@ -108,6 +111,9 @@ struct delegpt_addr {
int attempts;
/** rtt stored here in the selection algorithm */
int sel_rtt;
/** if true, the A or AAAA RR was bogus, so this address is bad.
* Also check the dp->bogus to see if everything is bogus. */
int bogus;
};
/**
@@ -164,11 +170,12 @@ int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional,
* @param namelen: length of name.
* @param addr: the address.
* @param addrlen: the length of addr.
* @param bogus: security status for the address, pass true if bogus.
* @return false on error.
*/
int delegpt_add_target(struct delegpt* dp, struct regional* regional,
uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
socklen_t addrlen);
socklen_t addrlen, int bogus);
/**
* Add A RRset to delegpt.
@@ -206,10 +213,11 @@ int delegpt_add_rrset(struct delegpt* dp, struct regional* regional,
* @param regional: where to allocate the info.
* @param addr: the address.
* @param addrlen: the length of addr.
* @param bogus: if address is bogus.
* @return false on error.
*/
int delegpt_add_addr(struct delegpt* dp, struct regional* regional,
struct sockaddr_storage* addr, socklen_t addrlen);
struct sockaddr_storage* addr, socklen_t addrlen, int bogus);
/**
* Find NS record in name list of delegation point.
@@ -228,6 +236,13 @@ struct delegpt_ns* delegpt_find_ns(struct delegpt* dp, uint8_t* name,
*/
void delegpt_log(enum verbosity_value v, struct delegpt* dp);
/** count NS and number missing for logging */
void delegpt_count_ns(struct delegpt* dp, size_t* numns, size_t* missing);
/** count addresses, and number in result and available lists, for logging */
void delegpt_count_addr(struct delegpt* dp, size_t* numaddr, size_t* numres,
size_t* numavail);
/**
* Add all usable targets to the result list.
* @param dp: delegation point.
+7 -84
View File
@@ -48,21 +48,6 @@
#include "util/config_file.h"
#include "util/net_help.h"
int
donotq_cmp(const void* k1, const void* k2)
{
struct iter_donotq_addr* n1 = (struct iter_donotq_addr*)k1;
struct iter_donotq_addr* n2 = (struct iter_donotq_addr*)k2;
int r = sockaddr_cmp_addr(&n1->addr, n1->addrlen, &n2->addr,
n2->addrlen);
if(r != 0) return r;
if(n1->net < n2->net)
return -1;
if(n1->net > n2->net)
return 1;
return 0;
}
struct iter_donotq*
donotq_create()
{
@@ -84,7 +69,6 @@ donotq_delete(struct iter_donotq* dq)
if(!dq)
return;
regional_destroy(dq->region);
free(dq->tree);
free(dq);
}
@@ -93,16 +77,11 @@ static int
donotq_insert(struct iter_donotq* dq, struct sockaddr_storage* addr,
socklen_t addrlen, int net)
{
struct iter_donotq_addr* node = regional_alloc(dq->region,
sizeof(struct iter_donotq_addr));
struct addr_tree_node* node = (struct addr_tree_node*)regional_alloc(
dq->region, sizeof(*node));
if(!node)
return 0;
node->node.key = node;
memcpy(&node->addr, addr, addrlen);
node->addrlen = addrlen;
node->net = net;
node->parent = NULL;
if(!rbtree_insert(dq->tree, &node->node)) {
if(!addr_tree_insert(&dq->tree, node, addr, addrlen, net)) {
verbose(VERB_QUERY, "duplicate donotquery address ignored.");
}
return 1;
@@ -140,41 +119,11 @@ read_donotq(struct iter_donotq* dq, struct config_file* cfg)
return 1;
}
/** initialise parent pointers in the tree */
static void
donotq_init_parents(struct iter_donotq* donotq)
{
struct iter_donotq_addr* node, *prev = NULL, *p;
int m;
RBTREE_FOR(node, struct iter_donotq_addr*, donotq->tree) {
node->parent = NULL;
if(!prev || prev->addrlen != node->addrlen) {
prev = node;
continue;
}
m = addr_in_common(&prev->addr, prev->net, &node->addr,
node->net, node->addrlen);
/* sort order like: ::/0, 1::/2, 1::/4, ... 2::/2 */
/* find the previous, or parent-parent-parent */
for(p = prev; p; p = p->parent)
if(p->net <= m) {
/* ==: since prev matched m, this is closest*/
/* <: prev matches more, but is not a parent,
* this one is a (grand)parent */
node->parent = p;
break;
}
prev = node;
}
}
int
donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
{
free(dq->tree);
dq->tree = rbtree_create(donotq_cmp);
if(!dq->tree)
return 0;
regional_free_all(dq->region);
addr_tree_init(&dq->tree);
if(!read_donotq(dq, cfg))
return 0;
if(cfg->donotquery_localhost) {
@@ -185,7 +134,7 @@ donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
return 0;
}
}
donotq_init_parents(dq);
addr_tree_init_parents(&dq->tree);
return 1;
}
@@ -193,33 +142,7 @@ int
donotq_lookup(struct iter_donotq* donotq, struct sockaddr_storage* addr,
socklen_t addrlen)
{
/* lookup in the tree */
rbnode_t* res = NULL;
struct iter_donotq_addr* result;
struct iter_donotq_addr key;
key.node.key = &key;
memcpy(&key.addr, addr, addrlen);
key.addrlen = addrlen;
key.net = (addr_is_ip6(addr, addrlen)?128:32);
if(rbtree_find_less_equal(donotq->tree, &key, &res)) {
/* exact */
return 1;
} else {
/* smaller element (or no element) */
int m;
result = (struct iter_donotq_addr*)res;
if(!result || result->addrlen != addrlen)
return 0;
/* count number of bits matched */
m = addr_in_common(&result->addr, result->net, addr,
key.net, addrlen);
while(result) { /* go up until addr is inside netblock */
if(result->net <= m)
return 1;
result = result->parent;
}
}
return 0;
return addr_tree_lookup(&donotq->tree, addr, addrlen) != NULL;
}
size_t
+4 -23
View File
@@ -42,7 +42,7 @@
#ifndef ITERATOR_ITER_DONOTQ_H
#define ITERATOR_ITER_DONOTQ_H
#include "util/rbtree.h"
#include "util/storage/dnstree.h"
struct iter_env;
struct config_file;
struct regional;
@@ -55,26 +55,10 @@ struct iter_donotq {
struct regional* region;
/**
* Tree of the address spans that are blocked.
* contents of type iter_donotq_addr.
* contents of type addr_tree_node. Each node is an address span
* that must not be used to send queries to.
*/
rbtree_t* tree;
};
/**
* Iterator donotquery address.
* An address span that must not be used to send queries to.
*/
struct iter_donotq_addr {
/** redblacktree node, key is this structure: addr and addrlen, net */
rbnode_t node;
/** address */
struct sockaddr_storage addr;
/** length of addr */
socklen_t addrlen;
/** netblock size */
int net;
/** parent node in donotq tree that encompasses this entry */
struct iter_donotq_addr* parent;
rbtree_t tree;
};
/**
@@ -114,7 +98,4 @@ int donotq_lookup(struct iter_donotq* donotq, struct sockaddr_storage* addr,
*/
size_t donotq_get_mem(struct iter_donotq* donotq);
/** compare two donotq entries */
int donotq_cmp(const void* k1, const void* k2);
#endif /* ITERATOR_ITER_DONOTQ_H */
+1 -1
View File
@@ -203,7 +203,7 @@ read_fwds_addr(struct iter_forwards* fwd, struct config_stub* s,
s->name, p->str);
return 0;
}
if(!delegpt_add_addr(dp, fwd->region, &addr, addrlen)) {
if(!delegpt_add_addr(dp, fwd->region, &addr, addrlen, 0)) {
log_err("out of memory");
return 0;
}
+42 -102
View File
@@ -48,21 +48,6 @@
#include "util/net_help.h"
#include "util/data/dname.h"
int
stub_cmp(const void* k1, const void* k2)
{
int m;
struct iter_hints_stub* n1 = (struct iter_hints_stub*)k1;
struct iter_hints_stub* n2 = (struct iter_hints_stub*)k2;
if(n1->hint_class != n2->hint_class) {
if(n1->hint_class < n2->hint_class)
return -1;
return 1;
}
return dname_lab_cmp(n1->name, n1->namelabs, n2->name, n2->namelabs,
&m);
}
struct iter_hints*
hints_create()
{
@@ -84,7 +69,6 @@ hints_delete(struct iter_hints* hints)
if(!hints)
return;
regional_destroy(hints->region);
free(hints->tree);
free(hints);
}
@@ -102,7 +86,7 @@ ah(struct delegpt* dp, struct regional* r, const char* sv, const char* ip)
if(!delegpt_add_ns(dp, r, ldns_rdf_data(rdf)) ||
!extstrtoaddr(ip, &addr, &addrlen) ||
!delegpt_add_target(dp, r, ldns_rdf_data(rdf), ldns_rdf_size(rdf),
&addr, addrlen)) {
&addr, addrlen, 0)) {
ldns_rdf_deep_free(rdf);
return 0;
}
@@ -156,55 +140,26 @@ compile_time_root_prime(struct regional* r, int do_ip4, int do_ip6)
/** insert new hint info into hint structure */
static int
hints_insert(struct iter_hints* hints, uint16_t c, struct delegpt* dp)
hints_insert(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
int noprime)
{
struct iter_hints_stub* node = regional_alloc(hints->region,
sizeof(struct iter_hints_stub));
uint8_t* nm;
if(!node)
return 0;
node->node.key = node;
node->hint_class = c;
node->name = regional_alloc_init(hints->region, dp->name, dp->namelen);
if(!node->name)
nm = regional_alloc_init(hints->region, dp->name, dp->namelen);
if(!nm)
return 0;
node->namelen = dp->namelen;
node->namelabs = dp->namelabs;
node->dp = dp;
if(!rbtree_insert(hints->tree, &node->node)) {
node->noprime = (uint8_t)noprime;
if(!name_tree_insert(&hints->tree, &node->node, nm, dp->namelen,
dp->namelabs, c)) {
log_err("second hints ignored.");
}
return 1;
}
/** initialise parent pointers in the tree */
static void
init_parents(struct iter_hints* hints)
{
struct iter_hints_stub* node, *prev = NULL, *p;
int m;
RBTREE_FOR(node, struct iter_hints_stub*, hints->tree) {
node->parent = NULL;
if(!prev || prev->hint_class != node->hint_class) {
prev = node;
continue;
}
(void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
node->namelabs, &m); /* we know prev is smaller */
/* sort order like: . com. bla.com. zwb.com. net. */
/* find the previous, or parent-parent-parent */
for(p = prev; p; p = p->parent)
/* looking for name with few labels, a parent */
if(p->namelabs <= m) {
/* ==: since prev matched m, this is closest*/
/* <: prev matches more, but is not a parent,
* this one is a (grand)parent */
node->parent = p;
break;
}
prev = node;
}
}
/** set stub name */
static int
read_stubs_name(struct iter_hints* hints, struct config_stub* s,
@@ -269,7 +224,7 @@ read_stubs_addr(struct iter_hints* hints, struct config_stub* s,
s->name, p->str);
return 0;
}
if(!delegpt_add_addr(dp, hints->region, &addr, addrlen)) {
if(!delegpt_add_addr(dp, hints->region, &addr, addrlen, 0)) {
log_err("out of memory");
return 0;
}
@@ -292,7 +247,7 @@ read_stubs(struct iter_hints* hints, struct config_file* cfg)
!read_stubs_host(hints, s, dp) ||
!read_stubs_addr(hints, s, dp))
return 0;
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp))
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, !s->isprime))
return 0;
delegpt_log(VERB_QUERY, dp);
}
@@ -361,7 +316,8 @@ read_root_hints(struct iter_hints* hints, char* fname)
if(!delegpt_add_target(dp, hints->region,
ldns_rdf_data(ldns_rr_owner(rr)),
ldns_rdf_size(ldns_rr_owner(rr)),
(struct sockaddr_storage*)&sa, len)) {
(struct sockaddr_storage*)&sa, len,
0)) {
log_err("out of memory reading root hints");
goto stop_read;
}
@@ -376,7 +332,8 @@ read_root_hints(struct iter_hints* hints, char* fname)
if(!delegpt_add_target(dp, hints->region,
ldns_rdf_data(ldns_rr_owner(rr)),
ldns_rdf_size(ldns_rr_owner(rr)),
(struct sockaddr_storage*)&sa, len)) {
(struct sockaddr_storage*)&sa, len,
0)) {
log_err("out of memory reading root hints");
goto stop_read;
}
@@ -397,7 +354,7 @@ read_root_hints(struct iter_hints* hints, char* fname)
log_warn("root hints %s: no NS content", fname);
return 1;
}
if(!hints_insert(hints, c, dp)) {
if(!hints_insert(hints, c, dp, 0)) {
return 0;
}
delegpt_log(VERB_QUERY, dp);
@@ -435,10 +392,8 @@ read_root_hints_list(struct iter_hints* hints, struct config_file* cfg)
int
hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg)
{
free(hints->tree);
hints->tree = rbtree_create(stub_cmp);
if(!hints->tree)
return 0;
regional_free_all(hints->region);
name_tree_init(&hints->tree);
/* read root hints */
if(!read_root_hints_list(hints, cfg))
@@ -455,11 +410,11 @@ hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg)
verbose(VERB_ALGO, "no config, using builtin root hints.");
if(!dp)
return 0;
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp))
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0))
return 0;
}
init_parents(hints);
name_tree_init_parents(&hints->tree);
return 1;
}
@@ -467,56 +422,41 @@ struct delegpt*
hints_lookup_root(struct iter_hints* hints, uint16_t qclass)
{
uint8_t rootlab = 0;
struct iter_hints_stub key, *stub;
key.node.key = &key;
key.hint_class = qclass;
key.name = &rootlab;
key.namelen = 1;
key.namelabs = 1;
stub = (struct iter_hints_stub*)rbtree_search(hints->tree, &key);
struct iter_hints_stub *stub;
stub = (struct iter_hints_stub*)name_tree_find(&hints->tree,
&rootlab, 1, 1, qclass);
if(!stub)
return NULL;
return stub->dp;
}
struct delegpt*
struct iter_hints_stub*
hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
uint16_t qclass, struct delegpt* cache_dp)
{
size_t len;
int labs;
struct iter_hints_stub *r;
/* first lookup the stub */
rbnode_t* res = NULL;
struct iter_hints_stub *result;
struct iter_hints_stub key;
key.node.key = &key;
key.hint_class = qclass;
key.name = qname;
key.namelabs = dname_count_size_labels(qname, &key.namelen);
if(rbtree_find_less_equal(hints->tree, &key, &res)) {
/* exact */
result = (struct iter_hints_stub*)res;
} else {
/* smaller element (or no element) */
int m;
result = (struct iter_hints_stub*)res;
if(!result || result->hint_class != qclass)
return NULL;
/* count number of labels matched */
(void)dname_lab_cmp(result->name, result->namelabs, key.name,
key.namelabs, &m);
while(result) { /* go up until qname is subdomain of stub */
if(result->namelabs <= m)
break;
result = result->parent;
}
if(!result)
return NULL;
}
labs = dname_count_size_labels(qname, &len);
r = (struct iter_hints_stub*)name_tree_lookup(&hints->tree, qname,
len, labs, qclass);
if(!r) return NULL;
/*
* If the stub is same as the delegation we got
* And has noprime set, we need to 'prime' to use this stub instead.
*/
if(r->noprime && query_dname_compare(cache_dp->name, r->dp->name)==0)
return r; /* use this stub instead of cached dp */
/*
* If our cached delegation point is above the hint, we need to prime.
*/
if(dname_strict_subdomain(result->dp->name, result->dp->namelabs,
if(dname_strict_subdomain(r->dp->name, r->dp->namelabs,
cache_dp->name, cache_dp->namelabs))
return result->dp; /* need to prime this stub */
return r; /* need to prime this stub */
return NULL;
}
+8 -18
View File
@@ -42,7 +42,7 @@
#ifndef ITERATOR_ITER_HINTS_H
#define ITERATOR_ITER_HINTS_H
#include "util/rbtree.h"
#include "util/storage/dnstree.h"
struct iter_env;
struct config_file;
struct delegpt;
@@ -60,28 +60,21 @@ struct iter_hints {
* a lookup on class, name will return an exact match or the closest
* match which gives the ancestor needed.
* contents of type iter_hints_stub. The class IN root is in here.
* uses name_tree_node from dnstree.h.
*/
rbtree_t* tree;
rbtree_t tree;
};
/**
* Iterator hints for a particular stub.
*/
struct iter_hints_stub {
/** redblacktree node, key is this structure: class and name */
rbnode_t node;
/** name */
uint8_t* name;
/** length of name */
size_t namelen;
/** number of labels in name */
int namelabs;
/** tree sorted by name, class */
struct name_tree_node node;
/** delegation point with hint information for this stub. */
struct delegpt* dp;
/** pointer to parent in stub hint tree (or NULL if none) */
struct iter_hints_stub* parent;
/** class of hints. host order. */
uint16_t hint_class;
/** does the stub need to forego priming (like on other ports) */
uint8_t noprime;
};
/**
@@ -124,7 +117,7 @@ struct delegpt* hints_lookup_root(struct iter_hints* hints, uint16_t qclass);
* @return: A priming delegation point if there is a stub hint that must
* be primed, otherwise null.
*/
struct delegpt* hints_lookup_stub(struct iter_hints* hints,
struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints,
uint8_t* qname, uint16_t qclass, struct delegpt* dp);
/**
@@ -134,7 +127,4 @@ struct delegpt* hints_lookup_stub(struct iter_hints* hints,
*/
size_t hints_get_mem(struct iter_hints* hints);
/** compare two hint entries */
int stub_cmp(const void* k1, const void* k2);
#endif /* ITERATOR_ITER_HINTS_H */
+255
View File
@@ -0,0 +1,255 @@
/*
* iterator/iter_priv.c - iterative resolver private address and domain store
*
* Copyright (c) 2008, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains functions to assist the iterator module.
* Keep track of the private addresses and lookup fast.
*/
#include "config.h"
#include "iterator/iter_priv.h"
#include "util/regional.h"
#include "util/log.h"
#include "util/config_file.h"
#include "util/data/dname.h"
#include "util/data/msgparse.h"
#include "util/net_help.h"
#include "util/storage/dnstree.h"
struct iter_priv* priv_create()
{
struct iter_priv* priv = (struct iter_priv*)calloc(1, sizeof(*priv));
if(!priv)
return NULL;
priv->region = regional_create();
if(!priv->region) {
priv_delete(priv);
return NULL;
}
addr_tree_init(&priv->a);
name_tree_init(&priv->n);
return priv;
}
void priv_delete(struct iter_priv* priv)
{
if(!priv) return;
regional_destroy(priv->region);
free(priv);
}
/** Read private-addr declarations from config */
static int read_addrs(struct iter_priv* priv, struct config_file* cfg)
{
/* parse addresses, report errors, insert into tree */
struct config_strlist* p;
struct addr_tree_node* n;
struct sockaddr_storage addr;
int net;
socklen_t addrlen;
for(p = cfg->private_address; p; p = p->next) {
log_assert(p->str);
if(!netblockstrtoaddr(p->str, UNBOUND_DNS_PORT, &addr,
&addrlen, &net)) {
log_err("cannot parse private-address: %s", p->str);
return 0;
}
n = (struct addr_tree_node*)regional_alloc(priv->region,
sizeof(*n));
if(!n) {
log_err("out of memory");
return 0;
}
if(!addr_tree_insert(&priv->a, n, &addr, addrlen, net)) {
verbose(VERB_QUERY, "ignoring duplicate "
"private-address: %s", p->str);
}
}
return 1;
}
/** Read private-domain declarations from config */
static int read_names(struct iter_priv* priv, struct config_file* cfg)
{
/* parse names, report errors, insert into tree */
struct config_strlist* p;
struct name_tree_node* n;
uint8_t* nm;
size_t nm_len;
int nm_labs;
ldns_rdf* rdf;
for(p = cfg->private_domain; p; p = p->next) {
log_assert(p->str);
rdf = ldns_dname_new_frm_str(p->str);
if(!rdf) {
log_err("cannot parse private-domain: %s", p->str);
return 0;
}
nm = ldns_rdf_data(rdf);
nm_labs = dname_count_size_labels(nm, &nm_len);
nm = (uint8_t*)regional_alloc_init(priv->region, nm, nm_len);
ldns_rdf_deep_free(rdf);
if(!nm) {
log_err("out of memory");
return 0;
}
n = (struct name_tree_node*)regional_alloc(priv->region,
sizeof(*n));
if(!n) {
log_err("out of memory");
return 0;
}
if(!name_tree_insert(&priv->n, n, nm, nm_len, nm_labs,
LDNS_RR_CLASS_IN)) {
verbose(VERB_QUERY, "ignoring duplicate "
"private-domain: %s", p->str);
}
}
return 1;
}
int priv_apply_cfg(struct iter_priv* priv, struct config_file* cfg)
{
/* empty the current contents */
regional_free_all(priv->region);
addr_tree_init(&priv->a);
name_tree_init(&priv->n);
/* read new contents */
if(!read_addrs(priv, cfg))
return 0;
if(!read_names(priv, cfg))
return 0;
/* prepare for lookups */
addr_tree_init_parents(&priv->a);
name_tree_init_parents(&priv->n);
return 1;
}
/**
* See if an address is blocked.
* @param priv: structure for address storage.
* @param addr: address to check
* @param addrlen: length of addr.
* @return: true if the address must not be queried. false if unlisted.
*/
static int
priv_lookup_addr(struct iter_priv* priv, struct sockaddr_storage* addr,
socklen_t addrlen)
{
return addr_tree_lookup(&priv->a, addr, addrlen) != NULL;
}
/**
* See if a name is whitelisted.
* @param priv: structure for address storage.
* @param pkt: the packet (for compression ptrs).
* @param name: name to check.
* @param name_len: uncompressed length of the name to check.
* @param dclass: class to check.
* @return: true if the name is OK. false if unlisted.
*/
static int
priv_lookup_name(struct iter_priv* priv, ldns_buffer* pkt,
uint8_t* name, size_t name_len, uint16_t dclass)
{
size_t len;
uint8_t decomp[256];
int labs;
if(name_len >= sizeof(decomp))
return 0;
dname_pkt_copy(pkt, decomp, name);
labs = dname_count_size_labels(decomp, &len);
log_assert(name_len == len);
return name_tree_lookup(&priv->n, decomp, len, labs, dclass) != NULL;
}
size_t priv_get_mem(struct iter_priv* priv)
{
if(!priv) return 0;
return sizeof(*priv) + regional_get_mem(priv->region);
}
int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt,
struct rrset_parse* rrset)
{
/* see if it is a private name, that is allowed to have any */
if(priv_lookup_name(priv, pkt, rrset->dname, rrset->dname_len,
ntohs(rrset->rrset_class))) {
return 0;
} else {
/* so its a public name, check the address */
struct sockaddr_storage addr;
socklen_t len;
struct rr_parse* rr;
if(rrset->type == LDNS_RR_TYPE_A) {
struct sockaddr_in* sa = (struct sockaddr_in*)&addr;
len = (socklen_t)sizeof(*sa);
memset(sa, 0, len);
sa->sin_family = AF_INET;
sa->sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
for(rr = rrset->rr_first; rr; rr = rr->next) {
if(ldns_read_uint16(rr->ttl_data+4)
!= INET_SIZE)
continue;
memmove(&sa->sin_addr, rr->ttl_data+4+2,
INET_SIZE);
if(priv_lookup_addr(priv, &addr, len))
return 1;
}
} else if(rrset->type == LDNS_RR_TYPE_AAAA) {
struct sockaddr_in6* sa = (struct sockaddr_in6*)&addr;
len = (socklen_t)sizeof(*sa);
memset(sa, 0, len);
sa->sin6_family = AF_INET6;
sa->sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
for(rr = rrset->rr_first; rr; rr = rr->next) {
if(ldns_read_uint16(rr->ttl_data+4)
!= INET6_SIZE)
continue;
memmove(&sa->sin6_addr, rr->ttl_data+4+2,
INET6_SIZE);
if(priv_lookup_addr(priv, &addr, len))
return 1;
}
}
}
return 0;
}
+109
View File
@@ -0,0 +1,109 @@
/*
* iterator/iter_priv.h - iterative resolver private address and domain store
*
* Copyright (c) 2008, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains functions to assist the iterator module.
* Keep track of the private addresses and lookup fast.
*/
#ifndef ITERATOR_ITER_PRIV_H
#define ITERATOR_ITER_PRIV_H
#include "util/rbtree.h"
struct iter_env;
struct config_file;
struct regional;
struct rrset_parse;
/**
* Iterator priv structure
*/
struct iter_priv {
/** regional for allocation */
struct regional* region;
/**
* Tree of the address spans that are blocked.
* contents of type addr_tree_node.
* No further data need, only presence or absence.
*/
rbtree_t a;
/**
* Tree of the domains spans that are allowed to contain
* the blocked address spans.
* contents of type name_tree_node.
* No further data need, only presence or absence.
*/
rbtree_t n;
};
/**
* Create priv structure
* @return new structure or NULL on error.
*/
struct iter_priv* priv_create();
/**
* Delete priv structure.
* @param priv: to delete.
*/
void priv_delete(struct iter_priv* priv);
/**
* Process priv config.
* @param priv: where to store.
* @param cfg: config options.
* @return 0 on error.
*/
int priv_apply_cfg(struct iter_priv* priv, struct config_file* cfg);
/**
* See if rrset is bad.
* @param priv: structure for private address storage.
* @param pkt: packet to decompress rrset name in.
* @param rrset: the rrset to examine, A or AAAA.
* @return true if the rrset is bad and should be removed.
*/
int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt,
struct rrset_parse* rrset);
/**
* Get memory used by priv structure.
* @param priv: structure for address storage.
* @return bytes in use.
*/
size_t priv_get_mem(struct iter_priv* priv);
#endif /* ITERATOR_ITER_PRIV_H */
+5 -5
View File
@@ -116,7 +116,7 @@ response_type_from_server(int rdset,
/* make sure its not recursive when we don't want it to */
if( (msg->rep->flags&BIT_RA) &&
!(msg->rep->flags&BIT_AA) && !rdset)
return RESPONSE_TYPE_LAME;
return RESPONSE_TYPE_REC_LAME;
return RESPONSE_TYPE_ANSWER;
}
@@ -200,7 +200,7 @@ response_type_from_server(int rdset,
/* we do our own recursion, thank you */
if( (msg->rep->flags&BIT_RA) &&
!(msg->rep->flags&BIT_AA) && !rdset)
return RESPONSE_TYPE_LAME;
return RESPONSE_TYPE_REC_LAME;
return RESPONSE_TYPE_ANSWER;
}
}
@@ -222,13 +222,13 @@ response_type_from_server(int rdset,
* deployed and is responding nonAA */
if( (msg->rep->flags&BIT_RA) &&
!(msg->rep->flags&BIT_AA) && !rdset)
return RESPONSE_TYPE_LAME;
return RESPONSE_TYPE_REC_LAME;
/* Or if a lame server is deployed,
* which gives ns==zone delegation from cache
* without AA bit as well, with nodata nosoa*/
if(msg->rep->an_numrrsets==0 &&
!(msg->rep->flags&BIT_AA) && !rdset)
return RESPONSE_TYPE_LAME;
return RESPONSE_TYPE_REC_LAME;
return RESPONSE_TYPE_ANSWER;
}
/* If we are getting a referral upwards (or to
@@ -259,6 +259,6 @@ response_type_from_server(int rdset,
* be an entirely empty message) */
/* check if recursive answer; saying it has empty cache */
if( (msg->rep->flags&BIT_RA) && !(msg->rep->flags&BIT_AA) && !rdset)
return RESPONSE_TYPE_LAME;
return RESPONSE_TYPE_REC_LAME;
return RESPONSE_TYPE_ANSWER;
}
+8 -1
View File
@@ -81,7 +81,14 @@ enum response_type {
* 'lame' means that this particular response indicates that
* the nameserver knew nothing about the question.
*/
RESPONSE_TYPE_LAME
RESPONSE_TYPE_LAME,
/**
* Recursion lame means that the nameserver is some sort of
* open recursor, and not authoritative for the question.
* It may know something, but not authoritatively.
*/
RESPONSE_TYPE_REC_LAME
};
/**
+117 -6
View File
@@ -41,6 +41,8 @@
*/
#include "config.h"
#include "iterator/iter_scrub.h"
#include "iterator/iterator.h"
#include "iterator/iter_priv.h"
#include "services/cache/rrset.h"
#include "util/log.h"
#include "util/net_help.h"
@@ -320,7 +322,7 @@ scrub_normalize(ldns_buffer* pkt, struct msg_parse* msg,
{
uint8_t* sname = qinfo->qname;
size_t snamelen = qinfo->qname_len;
struct rrset_parse* rrset, *prev;
struct rrset_parse* rrset, *prev, *nsset=NULL;
if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR &&
FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN)
@@ -416,7 +418,10 @@ scrub_normalize(ldns_buffer* pkt, struct msg_parse* msg,
}
/* Mark the additional names from relevant rrset as OK. */
mark_additional_rrset(pkt, msg, rrset);
/* only for RRsets that match the query name, other ones
* will be removed by sanitize, so no additional for them */
if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) == 0)
mark_additional_rrset(pkt, msg, rrset);
prev = rrset;
rrset = rrset->rrset_all_next;
@@ -424,6 +429,24 @@ scrub_normalize(ldns_buffer* pkt, struct msg_parse* msg,
/* Mark additional names from AUTHORITY */
while(rrset && rrset->section == LDNS_SECTION_AUTHORITY) {
if(rrset->type==LDNS_RR_TYPE_DNAME ||
rrset->type==LDNS_RR_TYPE_CNAME ||
rrset->type==LDNS_RR_TYPE_A ||
rrset->type==LDNS_RR_TYPE_AAAA) {
remove_rrset("normalize: removing irrelevant "
"RRset:", pkt, msg, prev, &rrset);
continue;
}
/* only one NS set allowed in authority section */
if(rrset->type==LDNS_RR_TYPE_NS) {
if(nsset == NULL) {
nsset = rrset;
} else {
remove_rrset("normalize: removing irrelevant "
"RRset:", pkt, msg, prev, &rrset);
continue;
}
}
mark_additional_rrset(pkt, msg, rrset);
prev = rrset;
rrset = rrset->rrset_all_next;
@@ -447,6 +470,13 @@ scrub_normalize(ldns_buffer* pkt, struct msg_parse* msg,
continue;
}
}
if(rrset->type==LDNS_RR_TYPE_DNAME ||
rrset->type==LDNS_RR_TYPE_CNAME ||
rrset->type==LDNS_RR_TYPE_NS) {
remove_rrset("normalize: removing irrelevant "
"RRset:", pkt, msg, prev, &rrset);
continue;
}
prev = rrset;
rrset = rrset->rrset_all_next;
}
@@ -490,6 +520,35 @@ store_rrset(ldns_buffer* pkt, struct msg_parse* msg, struct module_env* env,
env->alloc, now);
}
/**
* Check if right hand name in NSEC is within zone
* @param rrset: the NSEC rrset
* @param zonename: the zone name.
* @return true if BAD.
*/
static int sanitize_nsec_is_overreach(struct rrset_parse* rrset,
uint8_t* zonename)
{
struct rr_parse* rr;
uint8_t* rhs;
size_t len;
log_assert(rrset->type == LDNS_RR_TYPE_NSEC);
for(rr = rrset->rr_first; rr; rr = rr->next) {
rhs = rr->ttl_data+4+2;
len = ldns_read_uint16(rr->ttl_data+4);
if(!(len=dname_valid(rhs, len))) {
/* malformed domain name in rdata */
return 1;
}
if(!dname_subdomain_c(rhs, zonename)) {
/* overreaching */
return 1;
}
}
/* all NSEC RRs OK */
return 0;
}
/**
* Given a response event, remove suspect RRsets from the response.
* "Suspect" rrsets are potentially poison. Note that this routine expects
@@ -498,18 +557,49 @@ store_rrset(ldns_buffer* pkt, struct msg_parse* msg, struct module_env* env,
*
* @param pkt: packet.
* @param msg: msg to normalize.
* @param qinfo: the question originally asked.
* @param zonename: name of server zone.
* @param env: module environment with config and cache.
* @param ie: iterator environment with private address data.
* @return 0 on error.
*/
static int
scrub_sanitize(ldns_buffer* pkt, struct msg_parse* msg, uint8_t* zonename,
struct module_env* env)
scrub_sanitize(ldns_buffer* pkt, struct msg_parse* msg,
struct query_info* qinfo, uint8_t* zonename, struct module_env* env,
struct iter_env* ie)
{
struct rrset_parse* rrset, *prev;
prev = NULL;
rrset = msg->rrset_first;
/* the first DNAME is allowed to stay. It needs checking before
* it can be used from the cache. After normalization, an initial
* DNAME will have a correctly synthesized CNAME after it. */
if(rrset && rrset->type == LDNS_RR_TYPE_DNAME &&
rrset->section == LDNS_SECTION_ANSWER &&
pkt_strict_sub(pkt, qinfo->qname, rrset->dname) &&
pkt_sub(pkt, rrset->dname, zonename)) {
prev = rrset; /* DNAME allowed to stay in answer section */
rrset = rrset->rrset_all_next;
}
/* remove all records from the answer section that are
* not the same domain name as the query domain name.
* The answer section should contain rrsets with the same name
* as the question. For DNAMEs a CNAME has been synthesized.
* Wildcards have the query name in answer section.
* ANY queries get query name in answer section.
* Remainders of CNAME chains are cut off and resolved by iterator. */
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) != 0) {
remove_rrset("sanitize: removing extraneous answer "
"RRset:", pkt, msg, prev, &rrset);
continue;
}
prev = rrset;
rrset = rrset->rrset_all_next;
}
/* At this point, we brutally remove ALL rrsets that aren't
* children of the originating zone. The idea here is that,
* as far as we know, the server that we contacted is ONLY
@@ -517,7 +607,21 @@ scrub_sanitize(ldns_buffer* pkt, struct msg_parse* msg, uint8_t* zonename,
* be authoriative for any other zones, and of course, MAY
* NOT be authoritative for some subdomains of the originating
* zone. */
prev = NULL;
rrset = msg->rrset_first;
while(rrset) {
/* remove private addresses */
if( (rrset->type == LDNS_RR_TYPE_A ||
rrset->type == LDNS_RR_TYPE_AAAA) &&
priv_rrset_bad(ie->priv, pkt, rrset)) {
/* set servfail, so the classification becomes
* THROWAWAY, instead of LAME or other unwanted */
FLAGS_SET_RCODE(msg->flags, LDNS_RCODE_SERVFAIL);
remove_rrset("sanitize: removing public name with "
"private address", pkt, msg, prev, &rrset);
continue;
}
/* skip DNAME records -- they will always be followed by a
* synthesized CNAME, which will be relevant.
@@ -549,6 +653,13 @@ scrub_sanitize(ldns_buffer* pkt, struct msg_parse* msg, uint8_t* zonename,
continue;
}
}
/* check if right hand side of NSEC is within zone */
if(rrset->type == LDNS_RR_TYPE_NSEC &&
sanitize_nsec_is_overreach(rrset, zonename)) {
remove_rrset("sanitize: removing overreaching NSEC "
"RRset:", pkt, msg, prev, &rrset);
continue;
}
prev = rrset;
rrset = rrset->rrset_all_next;
}
@@ -558,7 +669,7 @@ scrub_sanitize(ldns_buffer* pkt, struct msg_parse* msg, uint8_t* zonename,
int
scrub_message(ldns_buffer* pkt, struct msg_parse* msg,
struct query_info* qinfo, uint8_t* zonename, struct regional* region,
struct module_env* env)
struct module_env* env, struct iter_env* ie)
{
/* basic sanity checks */
log_nametypeclass(VERB_ALGO, "scrub for", zonename, LDNS_RR_TYPE_NS,
@@ -589,7 +700,7 @@ scrub_message(ldns_buffer* pkt, struct msg_parse* msg,
if(!scrub_normalize(pkt, msg, qinfo, region))
return 0;
/* delete all out-of-zone information */
if(!scrub_sanitize(pkt, msg, zonename, env))
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie))
return 0;
return 1;
}
+3 -1
View File
@@ -46,6 +46,7 @@ struct msg_parse;
struct query_info;
struct regional;
struct module_env;
struct iter_env;
/**
* Cleanup the passed dns message.
@@ -57,10 +58,11 @@ struct module_env;
* Used to determine out of bailiwick information.
* @param regional: where to allocate (new) parts of the message.
* @param env: module environment with config settings and cache.
* @param ie: iterator module environment data.
* @return: false if the message is total waste. true if scrubbed with success.
*/
int scrub_message(ldns_buffer* pkt, struct msg_parse* msg,
struct query_info* qinfo, uint8_t* zonename, struct regional* regional,
struct module_env* env);
struct module_env* env, struct iter_env* ie);
#endif /* ITERATOR_ITER_SCRUB_H */
+95 -16
View File
@@ -46,6 +46,7 @@
#include "iterator/iter_fwd.h"
#include "iterator/iter_donotq.h"
#include "iterator/iter_delegpt.h"
#include "iterator/iter_priv.h"
#include "services/cache/infra.h"
#include "services/cache/dns.h"
#include "services/cache/rrset.h"
@@ -123,6 +124,12 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
log_err("Could not set donotqueryaddresses");
return 0;
}
if(!iter_env->priv)
iter_env->priv = priv_create();
if(!iter_env->priv || !priv_apply_cfg(iter_env->priv, cfg)) {
log_err("Could not set private addresses");
return 0;
}
iter_env->supports_ipv6 = cfg->do_ip6;
return 1;
}
@@ -133,9 +140,9 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
uint8_t* name, size_t namelen, uint16_t qtype, uint32_t now,
struct delegpt_addr* a)
{
int rtt;
int lame;
int dnsseclame;
int rtt, lame, reclame, dnsseclame;
if(a->bogus)
return -1; /* address of server is bogus */
if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) {
return -1; /* server is on the donotquery list */
}
@@ -144,12 +151,15 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
}
/* check lameness - need zone , class info */
if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen,
name, namelen, qtype, &lame, &dnsseclame, &rtt, now)) {
name, namelen, qtype, &lame, &dnsseclame, &reclame,
&rtt, now)) {
if(lame)
return -1; /* server is lame */
else if(rtt >= USEFUL_SERVER_TOP_TIMEOUT)
return -1; /* server is unresponsive */
else if(dnsseclame)
else if(reclame)
return rtt+USEFUL_SERVER_TOP_TIMEOUT*2; /* nonpref */
else if(dnsseclame )
return rtt+USEFUL_SERVER_TOP_TIMEOUT; /* nonpref */
else return rtt;
}
@@ -165,6 +175,8 @@ iter_fill_rtt(struct iter_env* iter_env, struct module_env* env,
{
int got_it = 0;
struct delegpt_addr* a;
if(dp->bogus)
return 0; /* NS bogus, all bogus, nothing found */
for(a=dp->result_list; a; a = a->next_result) {
a->sel_rtt = iter_filter_unsuitable(iter_env, env,
name, namelen, qtype, now, a);
@@ -195,6 +207,10 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env,
&low_rtt);
if(got_num == 0)
return 0;
if(low_rtt >= USEFUL_SERVER_TOP_TIMEOUT &&
delegpt_count_missing_targets(dp) > 0)
return 0; /* we want more choice. The best choice is a bad one.
return 0 to force the caller to fetch more */
got_num = 0;
a = dp->result_list;
@@ -233,7 +249,8 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env,
struct delegpt_addr*
iter_server_selection(struct iter_env* iter_env,
struct module_env* env, struct delegpt* dp,
uint8_t* name, size_t namelen, uint16_t qtype, int* dnssec_expected)
uint8_t* name, size_t namelen, uint16_t qtype, int* dnssec_expected,
int* chase_to_rd)
{
int sel;
int selrtt;
@@ -243,8 +260,12 @@ iter_server_selection(struct iter_env* iter_env,
if(num == 0)
return NULL;
if(selrtt >= USEFUL_SERVER_TOP_TIMEOUT)
if(selrtt >= USEFUL_SERVER_TOP_TIMEOUT*2) {
*chase_to_rd = 1;
}
if(selrtt >= USEFUL_SERVER_TOP_TIMEOUT) {
*dnssec_expected = 0;
}
if(num == 1) {
a = dp->result_list;
if(++a->attempts < OUTBOUND_MSG_RETRY)
@@ -365,7 +386,8 @@ iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
}
int
iter_dp_is_useless(struct module_qstate* qstate, struct delegpt* dp)
iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
struct delegpt* dp)
{
struct delegpt_ns* ns;
/* check:
@@ -378,18 +400,17 @@ iter_dp_is_useless(struct module_qstate* qstate, struct delegpt* dp)
* o the query is for one of the nameservers in dp,
* and that nameserver is a glue-name for this dp.
*/
if(!(qstate->query_flags&BIT_RD))
if(!(qflags&BIT_RD))
return 0;
/* either available or unused targets */
if(dp->usable_list || dp->result_list)
return 0;
/* see if query is for one of the nameservers, which is glue */
if( (qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA) &&
dname_subdomain_c(qstate->qinfo.qname, dp->name) &&
delegpt_find_ns(dp, qstate->qinfo.qname,
qstate->qinfo.qname_len))
if( (qinfo->qtype == LDNS_RR_TYPE_A ||
qinfo->qtype == LDNS_RR_TYPE_AAAA) &&
dname_subdomain_c(qinfo->qname, dp->name) &&
delegpt_find_ns(dp, qinfo->qname, qinfo->qname_len))
return 1;
for(ns = dp->nslist; ns; ns = ns->next) {
@@ -406,14 +427,15 @@ iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
struct dns_msg* msg, uint16_t dclass)
{
/* information not available, !env->anchors can be common */
if(!env || !env->anchors || !dp || !dp->name || !msg || !msg->rep)
if(!env || !env->anchors || !dp || !dp->name)
return 0;
/* a trust anchor exists with this name, RRSIGs expected */
if(anchor_find(env->anchors, dp->name, dp->namelabs, dp->namelen,
dclass))
return 1;
/* see if DS rrset was given, in AUTH section */
if(reply_find_rrset_section_ns(msg->rep, dp->name, dp->namelen,
if(msg && msg->rep &&
reply_find_rrset_section_ns(msg->rep, dp->name, dp->namelen,
LDNS_RR_TYPE_DS, dclass))
return 1;
return 0;
@@ -476,3 +498,60 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
return 1;
return 0;
}
/**
* check equality of two rrsets
* @param k1: rrset
* @param k2: rrset
* @return true if equal
*/
static int
rrset_equal(struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2)
{
struct packed_rrset_data* d1 = (struct packed_rrset_data*)
k1->entry.data;
struct packed_rrset_data* d2 = (struct packed_rrset_data*)
k2->entry.data;
size_t i, t;
if(k1->rk.dname_len != k2->rk.dname_len ||
k1->rk.flags != k2->rk.flags ||
k1->rk.type != k2->rk.type ||
k1->rk.rrset_class != k2->rk.rrset_class ||
query_dname_compare(k1->rk.dname, k2->rk.dname) != 0)
return 0;
if(d1->ttl != d2->ttl ||
d1->count != d2->count ||
d1->rrsig_count != d2->rrsig_count ||
d1->trust != d2->trust ||
d1->security != d2->security)
return 0;
t = d1->count + d1->rrsig_count;
for(i=0; i<t; i++) {
if(d1->rr_len[i] != d2->rr_len[i] ||
d1->rr_ttl[i] != d2->rr_ttl[i] ||
memcmp(d1->rr_data[i], d2->rr_data[i],
d1->rr_len[i]) != 0)
return 0;
}
return 1;
}
int
reply_equal(struct reply_info* p, struct reply_info* q)
{
size_t i;
if(p->flags != q->flags ||
p->qdcount != q->qdcount ||
p->ttl != q->ttl ||
p->security != q->security ||
p->an_numrrsets != q->an_numrrsets ||
p->ns_numrrsets != q->ns_numrrsets ||
p->ar_numrrsets != q->ar_numrrsets ||
p->rrset_count != q->rrset_count)
return 0;
for(i=0; i<p->rrset_count; i++) {
if(!rrset_equal(p->rrsets[i], q->rrsets[i]))
return 0;
}
return 1;
}
+18 -3
View File
@@ -77,12 +77,15 @@ int iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg);
* @param qtype: query type that we want to send.
* @param dnssec_expected: set to 0, if a known dnssec-lame server is selected
* these are not preferred, but are used as a last resort.
* @param chase_to_rd: set to 1 if a known recursion lame server is selected
* these are not preferred, but are used as a last resort.
* @return best target or NULL if no target.
* if not null, that target is removed from the result list in the dp.
*/
struct delegpt_addr* iter_server_selection(struct iter_env* iter_env,
struct module_env* env, struct delegpt* dp, uint8_t* name,
size_t namelen, uint16_t qtype, int* dnssec_expected);
size_t namelen, uint16_t qtype, int* dnssec_expected,
int* chase_to_rd);
/**
* Allocate dns_msg from parsed msg, in regional.
@@ -135,10 +138,12 @@ void iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp);
/**
* See if delegation is useful or offers immediately no targets for
* further recursion.
* @param qstate: query state with RD flag and query name.
* @param qinfo: query name and type
* @param qflags: query flags with RD flag
* @param dp: delegpt to check.
*/
int iter_dp_is_useless(struct module_qstate* qstate, struct delegpt* dp);
int iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
struct delegpt* dp);
/**
* See if delegation is expected to have DNSSEC information (RRSIGs) in
@@ -178,4 +183,14 @@ int iter_msg_has_dnssec(struct dns_msg* msg);
int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
enum response_type type, uint16_t dclass);
/**
* Check if two replies are equal
* For fallback procedures
* @param p: reply one. The reply has rrset data pointers in region.
* Does not check rrset-IDs
* @param q: reply two
* @return if one and two are equal.
*/
int reply_equal(struct reply_info* p, struct reply_info* q);
#endif /* ITERATOR_ITER_UTILS_H */
+278 -20
View File
@@ -49,6 +49,8 @@
#include "iterator/iter_delegpt.h"
#include "iterator/iter_resptype.h"
#include "iterator/iter_scrub.h"
#include "iterator/iter_priv.h"
#include "validator/val_neg.h"
#include "services/cache/dns.h"
#include "services/cache/infra.h"
#include "util/module.h"
@@ -58,6 +60,7 @@
#include "util/data/dname.h"
#include "util/data/msgencode.h"
#include "util/fptr_wlist.h"
#include "util/config_file.h"
int
iter_init(struct module_env* env, int id)
@@ -84,6 +87,7 @@ iter_deinit(struct module_env* env, int id)
return;
iter_env = (struct iter_env*)env->modinfo[id];
free(iter_env->target_fetch_policy);
priv_delete(iter_env->priv);
hints_delete(iter_env->hints);
forwards_delete(iter_env->fwds);
donotq_delete(iter_env->donotq);
@@ -427,13 +431,14 @@ handle_cname_response(struct module_qstate* qstate, struct iter_qstate* iq,
* request.
* @param subq_ret: if newly allocated, the subquerystate, or NULL if it does
* not need initialisation.
* @param v: if true, validation is done on the subquery.
* @return false on error (malloc).
*/
static int
generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
uint16_t qclass, struct module_qstate* qstate, int id,
struct iter_qstate* iq, enum iter_state initial_state,
enum iter_state final_state, struct module_qstate** subq_ret)
enum iter_state final_state, struct module_qstate** subq_ret, int v)
{
struct module_qstate* subq = NULL;
struct iter_qstate* subiq = NULL;
@@ -453,7 +458,8 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
* the resolution chain, which might have a validator. We are
* uninterested in validating things not on the direct resolution
* path. */
qflags |= BIT_CD;
if(!v)
qflags |= BIT_CD;
/* attach subquery, lookup existing or make a new one */
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
@@ -521,7 +527,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq,
* the normal INIT state logic (which would cause an infloop). */
if(!generate_sub_request((uint8_t*)"\000", 1, LDNS_RR_TYPE_NS,
qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE,
&subq)) {
&subq, 0)) {
log_err("out of memory priming root");
return 0;
}
@@ -532,6 +538,8 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq,
subiq->dp = dp;
/* there should not be any target queries. */
subiq->num_target_queries = 0;
subiq->dnssec_expected = iter_indicates_dnssec(
qstate->env, subiq->dp, NULL, subq->qinfo.qclass);
}
/* this module stops, our submodule starts, and does the query. */
@@ -558,12 +566,27 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq,
{
/* Lookup the stub hint. This will return null if the stub doesn't
* need to be re-primed. */
struct delegpt* stub_dp = hints_lookup_stub(ie->hints, qname, qclass,
iq->dp);
struct iter_hints_stub* stub = hints_lookup_stub(ie->hints,
qname, qclass, iq->dp);
struct delegpt* stub_dp;
struct module_qstate* subq;
/* The stub (if there is one) does not need priming. */
if(!stub_dp)
if(!stub)
return 0;
stub_dp = stub->dp;
/* is it a noprime stub (always use) */
if(stub->noprime) {
iq->dp = delegpt_copy(stub_dp, qstate->region);
if(!iq->dp) {
log_err("out of memory priming stub");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
return 1; /* return 1 to make module stop, with error */
}
log_nametypeclass(VERB_DETAIL, "use stub", stub_dp->name,
LDNS_RR_TYPE_NS, qclass);
return 0;
}
/* Otherwise, we need to (re)prime the stub. */
log_nametypeclass(VERB_DETAIL, "priming stub", stub_dp->name,
@@ -573,7 +596,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq,
* redundant INIT state processing. */
if(!generate_sub_request(stub_dp->name, stub_dp->namelen,
LDNS_RR_TYPE_NS, qclass, qstate, id, iq,
QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq)) {
QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0)) {
log_err("out of memory priming stub");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
return 1; /* return 1 to make module stop, with error */
@@ -598,6 +621,8 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq,
* missing targets. */
subiq->num_target_queries = 0;
subiq->wait_priming_stub = 1;
subiq->dnssec_expected = iter_indicates_dnssec(
qstate->env, subiq->dp, NULL, subq->qinfo.qclass);
}
/* this module stops, our submodule starts, and does the query. */
@@ -605,6 +630,107 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq,
return 1;
}
/**
* Generate A and AAAA checks for glue that is in-zone for the referral
* we just got to obtain authoritative information on the adresses.
*
* @param qstate: the qtstate that triggered the need to prime.
* @param iq: iterator query state.
* @param id: module id.
*/
static void
generate_a_aaaa_check(struct module_qstate* qstate, struct iter_qstate* iq,
int id)
{
struct module_qstate* subq;
size_t i;
struct reply_info* rep = iq->response->rep;
struct ub_packed_rrset_key* s;
log_assert(iq->dp);
/* walk through additional, and check if in-zone,
* only relevant A, AAAA are left after scrub anyway */
for(i=rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) {
s = rep->rrsets[i];
/* check *ALL* addresses that are transmitted in additional*/
/* is it an address ? */
if( !(ntohs(s->rk.type)==LDNS_RR_TYPE_A ||
ntohs(s->rk.type)==LDNS_RR_TYPE_AAAA)) {
continue;
}
/* is this query the same as the A/AAAA check for it */
if(qstate->qinfo.qtype == ntohs(s->rk.type) &&
qstate->qinfo.qclass == ntohs(s->rk.rrset_class) &&
query_dname_compare(qstate->qinfo.qname,
s->rk.dname)==0 &&
(qstate->query_flags&BIT_RD) &&
!(qstate->query_flags&BIT_CD))
continue;
/* generate subrequest for it */
log_nametypeclass(VERB_ALGO, "schedule addr fetch",
s->rk.dname, ntohs(s->rk.type),
ntohs(s->rk.rrset_class));
if(!generate_sub_request(s->rk.dname, s->rk.dname_len,
ntohs(s->rk.type), ntohs(s->rk.rrset_class),
qstate, id, iq,
INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1)) {
log_err("out of memory generating ns check");
return;
}
/* ignore subq - not need for more init */
}
}
/**
* Generate a NS check request to obtain authoritative information
* on an NS rrset.
*
* @param qstate: the qtstate that triggered the need to prime.
* @param iq: iterator query state.
* @param id: module id.
*/
static void
generate_ns_check(struct module_qstate* qstate, struct iter_qstate* iq, int id)
{
struct module_qstate* subq;
log_assert(iq->dp);
/* is this query the same as the nscheck? */
if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS &&
query_dname_compare(iq->dp->name, qstate->qinfo.qname)==0 &&
(qstate->query_flags&BIT_RD) && !(qstate->query_flags&BIT_CD)){
/* spawn off A, AAAA queries for in-zone glue to check */
generate_a_aaaa_check(qstate, iq, id);
return;
}
log_nametypeclass(VERB_ALGO, "schedule ns fetch",
iq->dp->name, LDNS_RR_TYPE_NS, iq->qchase.qclass);
if(!generate_sub_request(iq->dp->name, iq->dp->namelen,
LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq,
INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1)) {
log_err("out of memory generating ns check");
return;
}
if(subq) {
struct iter_qstate* subiq =
(struct iter_qstate*)subq->minfo[id];
/* make copy to avoid use of stub dp by different qs/threads */
/* refetch glue to start higher up the tree */
subiq->refetch_glue = 1;
subiq->dp = delegpt_copy(iq->dp, subq->region);
if(!subiq->dp) {
log_err("out of memory generating ns check, copydp");
fptr_ok(fptr_whitelist_modenv_kill_sub(
qstate->env->kill_sub));
(*qstate->env->kill_sub)(subq);
return;
}
}
}
/**
* See if the query needs forwarding.
*
@@ -686,6 +812,13 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
msg = dns_cache_lookup(qstate->env, iq->qchase.qname,
iq->qchase.qname_len, iq->qchase.qtype,
iq->qchase.qclass, qstate->region, qstate->env->scratch);
if(!msg && qstate->env->neg_cache) {
/* lookup in negative cache; may result in
* NOERROR/NODATA or NXDOMAIN answers that need validation */
msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase,
qstate->region, qstate->env->rrset_cache,
qstate->env->scratch_buffer, *qstate->env->now);
}
if(msg) {
/* handle positive cache response */
enum response_type type = response_type_from_cache(msg,
@@ -789,7 +922,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
* could be useless but lead to loops (bumping into the
* same server reply) if useless-checked.
*/
if(iter_dp_is_useless(qstate, iq->dp)) {
if(iter_dp_is_useless(&qstate->qinfo, qstate->query_flags,
iq->dp)) {
if(dname_is_root(iq->dp->name)) {
/* use safety belt */
verbose(VERB_QUERY, "Cache has root NS but "
@@ -921,7 +1055,7 @@ generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq,
{
struct module_qstate* subq;
if(!generate_sub_request(name, namelen, qtype, qclass, qstate,
id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq))
id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0))
return 0;
if(subq) {
struct iter_qstate* subiq =
@@ -930,6 +1064,9 @@ generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq,
verbose(VERB_ALGO, "refetch of target glue");
subiq->refetch_glue = 1;
subiq->dp = delegpt_copy(iq->dp, subq->region);
subiq->dnssec_expected = iter_indicates_dnssec(
qstate->env, subiq->dp, NULL,
subq->qinfo.qclass);
}
}
log_nametypeclass(VERB_QUERY, "new target", name, qtype, qclass);
@@ -1081,11 +1218,41 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
tf_policy = ie->target_fetch_policy[iq->depth];
}
/* if in 0x20 fallback get as many targets as possible */
if(iq->caps_fallback) {
int extra = 0;
size_t naddr, nres, navail;
if(!query_for_targets(qstate, iq, ie, id, -1, &extra)) {
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += extra;
if(iq->num_target_queries > 0) {
/* wait to get all targets, we want to try em */
verbose(VERB_ALGO, "wait for all targets for fallback");
return 0;
}
/* did we do enough fallback queries already? */
delegpt_count_addr(iq->dp, &naddr, &nres, &navail);
/* the current caps_server is the number of fallbacks sent.
* the original query is one that matched too, so we have
* caps_server+1 number of matching queries now */
if(iq->caps_server+1 >= naddr*3) {
/* we're done, process the response */
verbose(VERB_ALGO, "0x20 fallback had %d responses "
"match for %d wanted, done.",
(int)iq->caps_server+1, (int)naddr*3);
iq->caps_fallback = 0;
iq->state = QUERY_RESP_STATE;
return 1;
}
verbose(VERB_ALGO, "0x20 fallback number %d",
(int)iq->caps_server);
/* if there is a policy to fetch missing targets
* opportunistically, do it. we rely on the fact that once a
* query (or queries) for a missing name have been issued,
* they will not be show up again. */
if(tf_policy != 0) {
} else if(tf_policy != 0) {
int extra = 0;
verbose(VERB_ALGO, "attempt to get extra %d targets",
tf_policy);
@@ -1101,7 +1268,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
/* Select the next usable target, filtering out unsuitable targets. */
target = iter_server_selection(ie, qstate->env, iq->dp,
iq->dp->name, iq->dp->namelen, iq->qchase.qtype,
&iq->dnssec_expected);
&iq->dnssec_expected, &iq->chase_to_rd);
/* If no usable target was selected... */
if(!target) {
@@ -1166,7 +1333,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
outq = (*qstate->env->send_query)(
iq->qchase.qname, iq->qchase.qname_len,
iq->qchase.qtype, iq->qchase.qclass,
iq->chase_flags, EDNS_DO|BIT_CD,
iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), EDNS_DO|BIT_CD,
&target->addr, target->addrlen, qstate);
if(!outq) {
verbose(VERB_OPS, "error sending query to auth server; "
@@ -1203,11 +1370,14 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
enum response_type type;
iq->num_current_queries--;
if(iq->response == NULL) {
iq->chase_to_rd = 0;
verbose(VERB_ALGO, "query response was timeout");
return next_state(iq, QUERYTARGETS_STATE);
}
type = response_type_from_server((int)(iq->chase_flags&BIT_RD),
type = response_type_from_server(
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
iq->response, &iq->qchase, iq->dp);
iq->chase_to_rd = 0;
if(type == RESPONSE_TYPE_REFERRAL && (iq->chase_flags&BIT_RD)) {
/* When forwarding (RD bit is set), we handle referrals
* differently. No queries should be sent elsewhere */
@@ -1215,6 +1385,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
}
if(iq->dnssec_expected && !(iq->chase_flags&BIT_RD)
&& type != RESPONSE_TYPE_LAME
&& type != RESPONSE_TYPE_REC_LAME
&& type != RESPONSE_TYPE_THROWAWAY
&& type != RESPONSE_TYPE_UNTYPED) {
/* a possible answer, see if it is missing DNSSEC */
@@ -1251,10 +1422,27 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
* delegation point, and back to the QUERYTARGETS_STATE. */
verbose(VERB_DETAIL, "query response was REFERRAL");
/* Store the referral under the current query */
if(!iter_dns_store(qstate->env, &iq->response->qinfo,
iq->response->rep, 1))
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
/* if hardened, only store referral if we asked for it */
if(!qstate->env->cfg->harden_referral_path ||
( qstate->qinfo.qtype == LDNS_RR_TYPE_NS
&& (qstate->query_flags&BIT_RD)
&& !(qstate->query_flags&BIT_CD)
/* we know that all other NS rrsets are scrubbed
* away, thus on referral only one is left.
* see if that equals the query name... */
&& reply_find_rrset_section_ns(iq->response->rep,
qstate->qinfo.qname, qstate->qinfo.qname_len,
LDNS_RR_TYPE_NS, qstate->qinfo.qclass)
)) {
/* Store the referral under the current query */
if(!iter_dns_store(qstate->env, &iq->response->qinfo,
iq->response->rep, 1))
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
if(qstate->env->neg_cache)
val_neg_addreferral(qstate->env->neg_cache,
iq->response->rep, iq->dp->name);
}
/* Reset the event state, setting the current delegation
* point to the referral. */
@@ -1273,6 +1461,13 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
iq->dnssec_expected = iter_indicates_dnssec(qstate->env,
iq->dp, iq->response, iq->qchase.qclass);
/* spawn off NS and addr to auth servers for the NS we just
* got in the referral. This gets authoritative answer
* (answer section trust level) rrset.
* right after, we detach the subs, answer goes to cache. */
if(qstate->env->cfg->harden_referral_path)
generate_ns_check(qstate, iq, id);
/* stop current outstanding queries.
* FIXME: should the outstanding queries be waited for and
* handled? Say by a subquery that inherits the outbound_entry.
@@ -1338,11 +1533,24 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
if(!infra_set_lame(qstate->env->infra_cache,
&qstate->reply->addr, qstate->reply->addrlen,
iq->dp->name, iq->dp->namelen,
*qstate->env->now, dnsseclame,
*qstate->env->now, dnsseclame, 0,
iq->qchase.qtype))
log_err("mark host lame: out of memory");
} else log_err("%slame response from cache",
dnsseclame?"DNSSEC ":"");
} else if(type == RESPONSE_TYPE_REC_LAME) {
/* Cache the LAMEness. */
verbose(VERB_DETAIL, "query response REC_LAME: "
"recursive but not authoritative server");
if(qstate->reply) {
/* need addr for lameness cache, but we may have
* gotten this from cache, so test to be sure */
if(!infra_set_lame(qstate->env->infra_cache,
&qstate->reply->addr, qstate->reply->addrlen,
iq->dp->name, iq->dp->namelen,
*qstate->env->now, 0, 1, iq->qchase.qtype))
log_err("mark host lame: out of memory");
}
} else if(type == RESPONSE_TYPE_THROWAWAY) {
/* LAME and THROWAWAY responses are handled the same way.
* In this case, the event is just sent directly back to
@@ -1436,6 +1644,24 @@ processPrimeResponse(struct module_qstate* qstate, int id)
qstate->return_msg = NULL;
}
/* validate the root or stub after priming (if enabled).
* This is the same query as the prime query, but with validation.
* Now that we are primed, the additional queries that validation
* may need can be resolved, such as DLV. */
if(qstate->env->cfg->harden_referral_path) {
struct module_qstate* subq = NULL;
log_nametypeclass(VERB_ALGO, "schedule prime validation",
qstate->qinfo.qname, qstate->qinfo.qtype,
qstate->qinfo.qclass);
if(!generate_sub_request(qstate->qinfo.qname,
qstate->qinfo.qname_len, qstate->qinfo.qtype,
qstate->qinfo.qclass, qstate, id, iq,
INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1)) {
log_err("out of memory generating prime check");
}
generate_a_aaaa_check(qstate, iq, id);
}
/* This event is finished. */
qstate->ext_state[id] = module_finished;
return 0;
@@ -1681,7 +1907,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
if(event == module_event_noreply || event == module_event_error) {
goto handle_it;
}
if(event != module_event_reply || !qstate->reply) {
if( (event != module_event_reply && event != module_event_capsfail)
|| !qstate->reply) {
log_err("Bad event combined with response");
outbound_list_remove(&iq->outlist, outbound);
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
@@ -1712,7 +1939,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
/* normalize and sanitize: easy to delete items from linked lists */
if(!scrub_message(pkt, prs, &iq->qchase, iq->dp->name,
qstate->env->scratch, qstate->env))
qstate->env->scratch, qstate->env, ie))
goto handle_it;
/* allocate response dns_msg in region */
@@ -1725,6 +1952,37 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
if(verbosity >= VERB_ALGO)
log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo,
iq->response->rep);
if(event == module_event_capsfail) {
if(!iq->caps_fallback) {
/* start fallback */
iq->caps_fallback = 1;
iq->caps_server = 0;
iq->caps_reply = iq->response->rep;
iq->state = QUERYTARGETS_STATE;
iq->num_current_queries--;
verbose(VERB_DETAIL, "Capsforid: starting fallback");
goto handle_it;
} else {
/* check if reply is the same, otherwise, fail */
if(!reply_equal(iq->response->rep, iq->caps_reply)) {
verbose(VERB_DETAIL, "Capsforid fallback: "
"getting different replies, failed");
outbound_list_remove(&iq->outlist, outbound);
(void)error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
return;
}
/* continue the fallback procedure at next server */
iq->caps_server++;
iq->state = QUERYTARGETS_STATE;
iq->num_current_queries--;
verbose(VERB_DETAIL, "Capsforid: reply is equal. "
"go to next fallback");
goto handle_it;
}
}
iq->caps_fallback = 0; /* if we were in fallback, 0x20 is OK now */
handle_it:
outbound_list_remove(&iq->outlist, outbound);
+13
View File
@@ -50,6 +50,7 @@ struct iter_hints;
struct iter_forwards;
struct iter_donotq;
struct iter_prep_list;
struct iter_priv;
/** max number of query restarts. Determines max number of CNAME chain. */
#define MAX_RESTART_COUNT 8
@@ -92,6 +93,9 @@ struct iter_env {
/** A set of inetaddrs that should never be queried. */
struct iter_donotq* donotq;
/** private address space and private domains */
struct iter_priv* priv;
/** The maximum dependency depth that this resolver will pursue. */
int max_dependency_depth;
@@ -206,6 +210,8 @@ struct iter_qstate {
struct query_info qchase;
/** query flags to use when chasing the answer (i.e. RD flag) */
uint16_t chase_flags;
/** true if we set RD bit because of last resort recursion lame query*/
int chase_to_rd;
/**
* This is the current delegation point for an in-progress query. This
@@ -214,6 +220,13 @@ struct iter_qstate {
*/
struct delegpt* dp;
/** state for 0x20 fallback when capsfail happens, 0 not a fallback */
int caps_fallback;
/** state for capsfail: current server number to try */
size_t caps_server;
/** state for capsfail: stored query for comparisons */
struct reply_info* caps_reply;
/** Current delegation message - returned for non-RD queries */
struct dns_msg* deleg_msg;
BIN
View File
Binary file not shown.
+5 -4
View File
@@ -47,6 +47,7 @@
#include "libunbound/unbound.h"
#include "util/data/packed_rrset.h"
struct libworker;
struct tube;
/**
* The context structure
@@ -59,12 +60,12 @@ struct ub_ctx {
/* --- pipes --- */
/** mutex on query write pipe */
lock_basic_t qqpipe_lock;
/** the query write pipe, [0] read from, [1] write on */
int qqpipe[2];
/** the query write pipe */
struct tube* qq_pipe;
/** mutex on result read pipe */
lock_basic_t rrpipe_lock;
/** the result read pipe, [0] read from, [1] write on */
int rrpipe[2];
/** the result read pipe */
struct tube* rr_pipe;
/* --- shared data --- */
/** mutex for access to env.cfg, finalized and dothread */
+20 -66
View File
@@ -54,6 +54,7 @@
#include "util/log.h"
#include "util/random.h"
#include "util/net_help.h"
#include "util/tube.h"
#include "services/modstack.h"
#include "services/localzone.h"
#include "services/cache/infra.h"
@@ -95,45 +96,28 @@ ub_ctx_create()
return NULL;
}
seed = 0;
if(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx->qqpipe) == -1) {
ub_randfree(ctx->seed_rnd);
free(ctx);
return NULL;
}
if(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx->rrpipe) == -1) {
if((ctx->qq_pipe = tube_create()) == NULL) {
int e = errno;
close(ctx->qqpipe[0]);
close(ctx->qqpipe[1]);
ub_randfree(ctx->seed_rnd);
free(ctx);
errno = e;
return NULL;
}
#ifndef USE_WINSOCK
if(!fd_set_nonblock(ctx->rrpipe[0]) ||
!fd_set_nonblock(ctx->rrpipe[1]) ||
!fd_set_nonblock(ctx->qqpipe[0]) ||
!fd_set_nonblock(ctx->qqpipe[1])) {
if((ctx->rr_pipe = tube_create()) == NULL) {
int e = errno;
close(ctx->rrpipe[0]);
close(ctx->rrpipe[1]);
close(ctx->qqpipe[0]);
close(ctx->qqpipe[1]);
tube_delete(ctx->qq_pipe);
ub_randfree(ctx->seed_rnd);
free(ctx);
errno = e;
return NULL;
}
#endif /* !USE_WINSOCK - it is a pipe(nonsocket) on windows) */
lock_basic_init(&ctx->qqpipe_lock);
lock_basic_init(&ctx->rrpipe_lock);
lock_basic_init(&ctx->cfglock);
ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env));
if(!ctx->env) {
close(ctx->rrpipe[0]);
close(ctx->rrpipe[1]);
close(ctx->qqpipe[0]);
close(ctx->qqpipe[1]);
tube_delete(ctx->qq_pipe);
tube_delete(ctx->rr_pipe);
ub_randfree(ctx->seed_rnd);
free(ctx);
errno = ENOMEM;
@@ -141,10 +125,8 @@ ub_ctx_create()
}
ctx->env->cfg = config_create_forlib();
if(!ctx->env->cfg) {
close(ctx->rrpipe[0]);
close(ctx->rrpipe[1]);
close(ctx->qqpipe[0]);
close(ctx->qqpipe[1]);
tube_delete(ctx->qq_pipe);
tube_delete(ctx->rr_pipe);
free(ctx->env);
ub_randfree(ctx->seed_rnd);
free(ctx);
@@ -180,11 +162,11 @@ ub_ctx_delete(struct ub_ctx* ctx)
uint32_t cmd = UB_LIBCMD_QUIT;
lock_basic_unlock(&ctx->cfglock);
lock_basic_lock(&ctx->qqpipe_lock);
(void)libworker_write_msg(ctx->qqpipe[1], (uint8_t*)&cmd,
(void)tube_write_msg(ctx->qq_pipe, (uint8_t*)&cmd,
(uint32_t)sizeof(cmd), 0);
lock_basic_unlock(&ctx->qqpipe_lock);
lock_basic_lock(&ctx->rrpipe_lock);
while(libworker_read_msg(ctx->rrpipe[0], &msg, &len, 0)) {
while(tube_read_msg(ctx->rr_pipe, &msg, &len, 0)) {
/* discard all results except a quit confirm */
if(context_serial_getcmd(msg, len) == UB_LIBCMD_QUIT) {
free(msg);
@@ -222,18 +204,8 @@ ub_ctx_delete(struct ub_ctx* ctx)
lock_basic_destroy(&ctx->qqpipe_lock);
lock_basic_destroy(&ctx->rrpipe_lock);
lock_basic_destroy(&ctx->cfglock);
if(ctx->qqpipe[0] != -1)
close(ctx->qqpipe[0]);
if(ctx->qqpipe[1] != -1)
close(ctx->qqpipe[1]);
if(ctx->rrpipe[0] != -1)
close(ctx->rrpipe[0]);
if(ctx->rrpipe[1] != -1)
close(ctx->rrpipe[1]);
ctx->qqpipe[0] = -1;
ctx->qqpipe[1] = -1;
ctx->rrpipe[0] = -1;
ctx->rrpipe[1] = -1;
tube_delete(ctx->qq_pipe);
tube_delete(ctx->rr_pipe);
if(ctx->env) {
slabhash_delete(ctx->env->msg_cache);
rrset_cache_delete(ctx->env->rrset_cache);
@@ -376,35 +348,17 @@ ub_ctx_async(struct ub_ctx* ctx, int dothread)
return UB_NOERROR;
}
/** perform a select() on the result read pipe */
static int
pollit(struct ub_ctx* ctx, struct timeval* t)
{
fd_set r;
#ifndef S_SPLINT_S
FD_ZERO(&r);
FD_SET(FD_SET_T ctx->rrpipe[0], &r);
#endif
if(select(ctx->rrpipe[0]+1, &r, NULL, NULL, t) == -1) {
return 0;
}
errno = 0;
return FD_ISSET(ctx->rrpipe[0], &r);
}
int
ub_poll(struct ub_ctx* ctx)
{
struct timeval t;
memset(&t, 0, sizeof(t));
/* no need to hold lock while testing for readability. */
return pollit(ctx, &t);
return tube_poll(ctx->rr_pipe);
}
int
ub_fd(struct ub_ctx* ctx)
{
return ctx->rrpipe[0];
return tube_read_fd(ctx->rr_pipe);
}
/** process answer from bg worker */
@@ -501,7 +455,7 @@ ub_process(struct ub_ctx* ctx)
while(1) {
msg = NULL;
lock_basic_lock(&ctx->rrpipe_lock);
r = libworker_read_msg(ctx->rrpipe[0], &msg, &len, 1);
r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1);
lock_basic_unlock(&ctx->rrpipe_lock);
if(r == 0)
return UB_PIPE;
@@ -527,7 +481,7 @@ ub_wait(struct ub_ctx* ctx)
uint8_t* msg;
uint32_t len;
/* this is basically the same loop as _process(), but with changes.
* holds the rrpipe lock and waits with pollit */
* holds the rrpipe lock and waits with tube_wait */
while(1) {
lock_basic_lock(&ctx->rrpipe_lock);
lock_basic_lock(&ctx->cfglock);
@@ -544,9 +498,9 @@ ub_wait(struct ub_ctx* ctx)
* o possibly decrementing num_async
* do callback without lock
*/
r = pollit(ctx, NULL);
r = tube_wait(ctx->rr_pipe);
if(r) {
r = libworker_read_msg(ctx->rrpipe[0], &msg, &len, 1);
r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1);
if(r == 0) {
lock_basic_unlock(&ctx->rrpipe_lock);
return UB_PIPE;
@@ -667,7 +621,7 @@ ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype,
lock_basic_unlock(&ctx->cfglock);
lock_basic_lock(&ctx->qqpipe_lock);
if(!libworker_write_msg(ctx->qqpipe[1], msg, len, 0)) {
if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) {
lock_basic_unlock(&ctx->qqpipe_lock);
free(msg);
return UB_PIPE;
@@ -705,7 +659,7 @@ ub_cancel(struct ub_ctx* ctx, int async_id)
}
/* send cancel to background worker */
lock_basic_lock(&ctx->qqpipe_lock);
if(!libworker_write_msg(ctx->qqpipe[1], msg, len, 0)) {
if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) {
lock_basic_unlock(&ctx->qqpipe_lock);
free(msg);
return UB_PIPE;
+56 -270
View File
@@ -60,6 +60,7 @@
#include "util/data/dname.h"
#include "util/data/msgreply.h"
#include "util/data/msgencode.h"
#include "util/tube.h"
/** handle new query command for bg worker */
static void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len);
@@ -78,10 +79,7 @@ libworker_delete(struct libworker* w)
ub_randfree(w->env->rnd);
free(w->env);
}
free(w->cmd_msg);
outside_network_delete(w->back);
comm_point_delete(w->cmd_com);
comm_point_delete(w->res_com);
comm_base_delete(w->base);
free(w);
}
@@ -161,7 +159,8 @@ libworker_setup(struct ub_ctx* ctx, int is_bg)
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
cfg->do_tcp?cfg->outgoing_num_tcp:0,
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
ports, numports);
ports, numports, cfg->unwanted_threshold,
&libworker_alloc_cleanup, w);
if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock);
}
@@ -230,130 +229,19 @@ libworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len)
}
/** handle control command coming into server */
int
libworker_handle_control_cmd(struct comm_point* c, void* arg,
int ATTR_UNUSED(err), struct comm_reply* ATTR_UNUSED(rep))
void
libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
uint8_t* msg, size_t len, int err, void* arg)
{
struct libworker* w = (struct libworker*)arg;
ssize_t r;
if(w->cmd_read < sizeof(w->cmd_len)) {
/* complete reading the length of control msg */
r = read(c->fd, ((uint8_t*)&w->cmd_len) + w->cmd_read,
sizeof(w->cmd_len) - w->cmd_read);
if(r==0) {
/* error has happened or */
/* parent closed pipe, must have exited somehow */
/* it is of no use to go on, exit */
comm_base_exit(w->base);
return 0;
}
if(r==-1) {
if(errno != EAGAIN && errno != EINTR) {
log_err("rpipe error: %s", strerror(errno));
}
/* nothing to read now, try later */
return 0;
}
w->cmd_read += r;
if(w->cmd_read < sizeof(w->cmd_len)) {
/* not complete, try later */
return 0;
}
w->cmd_msg = (uint8_t*)calloc(1, w->cmd_len);
if(!w->cmd_msg) {
log_err("malloc failure");
w->cmd_read = 0;
return 0;
}
}
/* cmd_len has been read, read remainder */
r = read(c->fd, w->cmd_msg + w->cmd_read - sizeof(w->cmd_len),
w->cmd_len - (w->cmd_read - sizeof(w->cmd_len)));
if(r==0) {
/* error has happened or */
/* parent closed pipe, must have exited somehow */
if(err != 0) {
free(msg);
/* it is of no use to go on, exit */
comm_base_exit(w->base);
return 0;
return;
}
if(r==-1) {
/* nothing to read now, try later */
if(errno != EAGAIN && errno != EINTR) {
log_err("rpipe error: %s", strerror(errno));
}
return 0;
}
w->cmd_read += r;
if(w->cmd_read < sizeof(w->cmd_len) + w->cmd_len) {
/* not complete, try later */
return 0;
}
w->cmd_read = 0;
libworker_do_cmd(w, w->cmd_msg, w->cmd_len); /* also frees the buf */
w->cmd_msg = NULL;
return 0;
}
/** handle opportunity to write result back */
int
libworker_handle_result_write(struct comm_point* c, void* arg,
int ATTR_UNUSED(err), struct comm_reply* ATTR_UNUSED(rep))
{
struct libworker* w = (struct libworker*)arg;
struct libworker_res_list* item = w->res_list;
ssize_t r;
if(!item) {
comm_point_stop_listening(c);
return 0;
}
if(w->res_write < sizeof(item->len)) {
r = write(c->fd, ((uint8_t*)&item->len) + w->res_write,
sizeof(item->len) - w->res_write);
if(r == -1) {
if(errno != EAGAIN && errno != EINTR) {
log_err("wpipe error: %s", strerror(errno));
}
return 0; /* try again later */
}
if(r == 0) {
/* error on pipe, must have exited somehow */
/* it is of no use to go on, exit */
comm_base_exit(w->base);
return 0;
}
w->res_write += r;
if(w->res_write < sizeof(item->len))
return 0;
}
r = write(c->fd, item->buf + w->res_write - sizeof(item->len),
item->len - (w->res_write - sizeof(item->len)));
if(r == -1) {
if(errno != EAGAIN && errno != EINTR) {
log_err("wpipe error: %s", strerror(errno));
}
return 0; /* try again later */
}
if(r == 0) {
/* error on pipe, must have exited somehow */
/* it is of no use to go on, exit */
comm_base_exit(w->base);
return 0;
}
w->res_write += r;
if(w->res_write < sizeof(item->len) + item->len)
return 0;
/* done this result, remove it */
free(item->buf);
item->buf = NULL;
w->res_list = w->res_list->next;
free(item);
if(!w->res_list) {
w->res_last = NULL;
comm_point_stop_listening(c);
}
w->res_write = 0;
return 0;
libworker_do_cmd(w, msg, len); /* also frees the buf */
}
/** the background thread func */
@@ -362,7 +250,6 @@ libworker_dobg(void* arg)
{
/* setup */
uint32_t m;
int fd;
struct libworker* w = (struct libworker*)arg;
struct ub_ctx* ctx = w->ctx;
log_thread_set(&w->thread_num);
@@ -370,27 +257,20 @@ libworker_dobg(void* arg)
/* we are forked */
w->is_bg_thread = 0;
/* close non-used parts of the pipes */
if(ctx->qqpipe[1] != -1) {
close(ctx->qqpipe[1]);
ctx->qqpipe[1] = -1;
}
if(ctx->rrpipe[0] != -1) {
close(ctx->rrpipe[0]);
ctx->rrpipe[0] = -1;
}
tube_close_write(ctx->qq_pipe);
tube_close_read(ctx->rr_pipe);
#endif
if(!w) {
log_err("libunbound bg worker init failed, nomem");
return NULL;
}
if(!(w->cmd_com=comm_point_create_raw(w->base, ctx->qqpipe[0], 0,
libworker_handle_control_cmd, w))) {
log_err("libunbound bg worker init failed, no cmdcom");
if(!tube_setup_bg_listen(ctx->qq_pipe, w->base,
libworker_handle_control_cmd, w)) {
log_err("libunbound bg worker init failed, no bglisten");
return NULL;
}
if(!(w->res_com=comm_point_create_raw(w->base, ctx->rrpipe[1], 1,
libworker_handle_result_write, w))) {
log_err("libunbound bg worker init failed, no rescom");
if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) {
log_err("libunbound bg worker init failed, no bgwrite");
return NULL;
}
@@ -398,14 +278,17 @@ libworker_dobg(void* arg)
comm_base_dispatch(w->base);
/* cleanup */
fd = ctx->rrpipe[1];
ctx->rrpipe[1] = -1;
m = UB_LIBCMD_QUIT;
tube_remove_bg_listen(w->ctx->qq_pipe);
tube_remove_bg_write(w->ctx->rr_pipe);
libworker_delete(w);
close(ctx->qqpipe[0]);
ctx->qqpipe[0] = -1;
(void)libworker_write_msg(fd, (uint8_t*)&m, (uint32_t)sizeof(m), 0);
close(fd);
(void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m,
(uint32_t)sizeof(m), 0);
#ifdef THREADS_DISABLED
/* close pipes from forked process before exit */
tube_close_read(ctx->qq_pipe);
tube_close_write(ctx->rr_pipe);
#endif
return NULL;
}
@@ -434,10 +317,8 @@ int libworker_bg(struct ub_ctx* ctx)
w = libworker_setup(ctx, 1);
if(!w) fatal_exit("out of memory");
/* close non-used parts of the pipes */
close(ctx->qqpipe[1]);
close(ctx->rrpipe[0]);
ctx->qqpipe[1] = -1;
ctx->rrpipe[0] = -1;
tube_close_write(ctx->qq_pipe);
tube_close_read(ctx->rr_pipe);
(void)libworker_dobg(w);
exit(0);
break;
@@ -654,7 +535,6 @@ add_bg_result(struct libworker* w, struct ctx_query* q, ldns_buffer* pkt,
{
uint8_t* msg = NULL;
uint32_t len = 0;
struct libworker_res_list* item;
/* serialize and delete unneeded q */
if(w->is_bg_thread) {
@@ -676,24 +556,10 @@ add_bg_result(struct libworker* w, struct ctx_query* q, ldns_buffer* pkt,
log_err("out of memory for async answer");
return;
}
item = (struct libworker_res_list*)malloc(sizeof(*item));
if(!item) {
free(msg);
if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) {
log_err("out of memory for async answer");
return;
}
item->buf = msg;
item->len = len;
item->next = NULL;
/* add at back of list, since the first one may be partially written */
if(w->res_last)
w->res_last->next = item;
else w->res_list = item;
w->res_last = item;
if(w->res_list == w->res_last) {
/* first added item, start the write process */
comm_point_start_listening(w->res_com, -1, -1);
}
}
/** callback with bg results */
@@ -830,7 +696,7 @@ libworker_handle_reply(struct comm_point* c, void* arg, int error,
e.qsent = NULL;
if(error != 0) {
mesh_report_reply(lw->env->mesh, &e, 0, reply_info);
mesh_report_reply(lw->env->mesh, &e, reply_info, error);
return 0;
}
/* sanity check. */
@@ -840,10 +706,11 @@ libworker_handle_reply(struct comm_point* c, void* arg, int error,
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
/* error becomes timeout for the module as if this reply
* never arrived. */
mesh_report_reply(lw->env->mesh, &e, 0, reply_info);
mesh_report_reply(lw->env->mesh, &e, reply_info,
NETEVENT_TIMEOUT);
return 0;
}
mesh_report_reply(lw->env->mesh, &e, 1, reply_info);
mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR);
return 0;
}
@@ -855,7 +722,7 @@ libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
struct libworker* lw = (struct libworker*)e->qstate->env->worker;
if(error != 0) {
mesh_report_reply(lw->env->mesh, e, 0, reply_info);
mesh_report_reply(lw->env->mesh, e, reply_info, error);
return 0;
}
/* sanity check. */
@@ -865,110 +732,20 @@ libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
/* error becomes timeout for the module as if this reply
* never arrived. */
mesh_report_reply(lw->env->mesh, e, 0, reply_info);
mesh_report_reply(lw->env->mesh, e, reply_info,
NETEVENT_TIMEOUT);
return 0;
}
mesh_report_reply(lw->env->mesh, e, 1, reply_info);
mesh_report_reply(lw->env->mesh, e, reply_info, NETEVENT_NOERROR);
return 0;
}
int
libworker_write_msg(int fd, uint8_t* buf, uint32_t len, int nonblock)
{
ssize_t r;
/* test */
if(nonblock) {
r = write(fd, &len, sizeof(len));
if(r == -1) {
if(errno==EINTR || errno==EAGAIN)
return -1;
log_err("msg write failed: %s", strerror(errno));
return -1; /* can still continue, perhaps */
}
} else r = 0;
if(!fd_set_block(fd))
return 0;
/* write remainder */
if(r != (ssize_t)sizeof(len)) {
if(write(fd, (char*)(&len)+r, sizeof(len)-r) == -1) {
log_err("msg write failed: %s", strerror(errno));
(void)fd_set_nonblock(fd);
return 0;
}
}
if(write(fd, buf, len) == -1) {
log_err("msg write failed: %s", strerror(errno));
(void)fd_set_nonblock(fd);
return 0;
}
if(!fd_set_nonblock(fd))
return 0;
return 1;
}
int
libworker_read_msg(int fd, uint8_t** buf, uint32_t* len, int nonblock)
{
ssize_t r;
/* test */
*len = 0;
if(nonblock) {
r = read(fd, len, sizeof(*len));
if(r == -1) {
if(errno==EINTR || errno==EAGAIN)
return -1;
log_err("msg read failed: %s", strerror(errno));
return -1; /* we can still continue, perhaps */
}
if(r == 0) /* EOF */
return 0;
} else r = 0;
if(!fd_set_block(fd))
return 0;
/* read remainder */
if(r != (ssize_t)sizeof(*len)) {
if((r=read(fd, (char*)(len)+r, sizeof(*len)-r)) == -1) {
log_err("msg read failed: %s", strerror(errno));
(void)fd_set_nonblock(fd);
return 0;
}
if(r == 0) /* EOF */ {
(void)fd_set_nonblock(fd);
return 0;
}
}
*buf = (uint8_t*)malloc(*len);
if(!*buf) {
log_err("out of memory");
(void)fd_set_nonblock(fd);
return 0;
}
if((r=read(fd, *buf, *len)) == -1) {
log_err("msg read failed: %s", strerror(errno));
(void)fd_set_nonblock(fd);
free(*buf);
return 0;
}
if(r == 0) { /* EOF */
(void)fd_set_nonblock(fd);
free(*buf);
return 0;
}
if(!fd_set_nonblock(fd)) {
free(*buf);
return 0;
}
return 1;
}
/* --- fake callbacks for fptr_wlist to work --- */
int worker_handle_control_cmd(struct comm_point* ATTR_UNUSED(c),
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
struct comm_reply* ATTR_UNUSED(reply_info))
void worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
{
log_assert(0);
return 0;
}
int worker_handle_request(struct comm_point* ATTR_UNUSED(c),
@@ -995,6 +772,22 @@ int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
return 0;
}
int remote_accept_callback(struct comm_point* ATTR_UNUSED(c),
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
struct comm_reply* ATTR_UNUSED(repinfo))
{
log_assert(0);
return 0;
}
int remote_control_callback(struct comm_point* ATTR_UNUSED(c),
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
struct comm_reply* ATTR_UNUSED(repinfo))
{
log_assert(0);
return 0;
}
void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
{
log_assert(0);
@@ -1025,13 +818,6 @@ worker_alloc_cleanup(void* ATTR_UNUSED(arg))
log_assert(0);
}
int
acl_list_cmp(const void* ATTR_UNUSED(k1), const void* ATTR_UNUSED(k2))
{
log_assert(0);
return 0;
}
void worker_stat_timer_cb(void* ATTR_UNUSED(arg))
{
log_assert(0);
+5 -70
View File
@@ -55,8 +55,8 @@ struct outbound_entry;
struct module_qstate;
struct comm_point;
struct comm_reply;
struct libworker_res_list;
struct regional;
struct tube;
/**
* The library-worker status structure
@@ -81,37 +81,6 @@ struct libworker {
struct outside_network* back;
/** random() table for this worker. */
struct ub_randstate* rndstate;
/** commpoint to listen to commands */
struct comm_point* cmd_com;
/** are we currently reading a command, 0 if not, else bytecount */
size_t cmd_read;
/** size of current read command, may be partially read */
uint32_t cmd_len;
/** the current read command content, malloced, can be partially read*/
uint8_t* cmd_msg;
/** commpoint to write results back */
struct comm_point* res_com;
/** are we curently writing a result, 0 if not, else bytecount into
* the res_list first entry. */
size_t res_write;
/** list of outstanding results to be written back */
struct libworker_res_list* res_list;
/** last in list */
struct libworker_res_list* res_last;
};
/**
* List of results (arbitrary command serializations) to write back
*/
struct libworker_res_list {
/** next in list */
struct libworker_res_list* next;
/** serialized buffer to write */
uint8_t* buf;
/** length to write */
uint32_t len;
};
/**
@@ -180,46 +149,12 @@ int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
struct comm_reply* reply_info);
/** handle control command coming into server */
int libworker_handle_control_cmd(struct comm_point* c, void* arg,
int err, struct comm_reply* rep);
void libworker_handle_control_cmd(struct tube* tube, uint8_t* msg, size_t len,
int err, void* arg);
/** handle opportunity to write result back */
int libworker_handle_result_write(struct comm_point* c, void* arg,
int err, struct comm_reply* rep);
/**
* Write length bytes followed by message.
* @param fd: the socket to write on. Is nonblocking.
* Set to blocking by the function,
* and back to non-blocking at exit of function.
* @param buf: the message.
* @param len: length of message.
* @param nonblock: if set to true, the first write is nonblocking.
* If the first write fails the function returns -1.
* If set false, the first write is blocking.
* @return: all remainder writes are nonblocking.
* return 0 on error, in that case blocking/nonblocking of socket is
* unknown.
* return 1 if all OK.
*/
int libworker_write_msg(int fd, uint8_t* buf, uint32_t len, int nonblock);
/**
* Read length bytes followed by message.
* @param fd: the socket to write on. Is nonblocking.
* Set to blocking by the function,
* and back to non-blocking at exit of function.
* @param buf: the message, malloced.
* @param len: length of message, returned.
* @param nonblock: if set to true, the first read is nonblocking.
* If the first read fails the function returns -1.
* If set false, the first read is blocking.
* @return: all remainder reads are nonblocking.
* return 0 on error, in that case blocking/nonblocking of socket is
* unknown. On EOF 0 is returned.
* return 1 if all OK.
*/
int libworker_read_msg(int fd, uint8_t** buf, uint32_t* len, int nonblock);
void libworker_handle_result_write(struct tube* tube, uint8_t* msg, size_t len,
int err, void* arg);
/**
* fill result from parsed message, on error fills servfail
+5
View File
@@ -215,6 +215,7 @@ replace_all doc/README
replace_all doc/unbound.8.in
replace_all doc/unbound.conf.5.in
replace_all doc/unbound-checkconf.8.in
replace_all doc/unbound-control.8.in
replace_all doc/unbound-host.1
replace_all doc/libunbound.3.in
@@ -237,15 +238,19 @@ cleanup
case $OSTYPE in
linux*)
sha=`sha1sum unbound-$version.tar.gz | awk '{ print $1 }'`
sha256=`sha256sum unbound-$version.tar.gz | awk '{ print $1 }'`
;;
freebsd*)
sha=`sha1 unbound-$version.tar.gz | awk '{ print $5 }'`
sha256=`sha256 unbound-$version.tar.gz | awk '{ print $5 }'`
;;
*)
sha=`sha1sum unbound-$version.tar.gz | awk '{ print $1 }'`
sha256=`sha256sum unbound-$version.tar.gz | awk '{ print $1 }'`
;;
esac
echo $sha > unbound-$version.tar.gz.sha1
echo $sha256 > unbound-$version.tar.gz.sha256
info "Unbound distribution created successfully."
info "SHA1sum: $sha"
+38 -65
View File
@@ -101,41 +101,6 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
slabhash_insert(env->msg_cache, hash, &e->entry, rep, env->alloc);
}
/** allocate rrset in region - no more locks needed */
static struct ub_packed_rrset_key*
copy_rrset(struct ub_packed_rrset_key* key, struct regional* region,
uint32_t now)
{
struct ub_packed_rrset_key* ck = regional_alloc(region,
sizeof(struct ub_packed_rrset_key));
struct packed_rrset_data* d;
struct packed_rrset_data* data = (struct packed_rrset_data*)
key->entry.data;
size_t dsize, i;
if(!ck)
return NULL;
ck->id = key->id;
memset(&ck->entry, 0, sizeof(ck->entry));
ck->entry.hash = key->entry.hash;
ck->entry.key = ck;
ck->rk = key->rk;
ck->rk.dname = regional_alloc_init(region, key->rk.dname,
key->rk.dname_len);
if(!ck->rk.dname)
return NULL;
dsize = packed_rrset_sizeof(data);
d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize);
if(!d)
return NULL;
ck->entry.data = d;
packed_rrset_ptr_fixup(d);
/* make TTLs relative - once per rrset */
for(i=0; i<d->count + d->rrsig_count; i++)
d->rr_ttl[i] -= now;
d->ttl -= now;
return ck;
}
/** find closest NS or DNAME and returns the rrset (locked) */
static struct ub_packed_rrset_key*
find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
@@ -171,7 +136,7 @@ addr_to_additional(struct ub_packed_rrset_key* rrset, struct regional* region,
struct dns_msg* msg, uint32_t now)
{
if((msg->rep->rrsets[msg->rep->rrset_count] =
copy_rrset(rrset, region, now))) {
packed_rrset_copy_region(rrset, region, now))) {
msg->rep->ar_numrrsets++;
msg->rep->rrset_count++;
}
@@ -271,7 +236,7 @@ find_add_ds(struct module_env* env, struct regional* region,
if(rrset) {
/* add it to auth section. This is the second rrset. */
if((msg->rep->rrsets[msg->rep->rrset_count] =
copy_rrset(rrset, region, now))) {
packed_rrset_copy_region(rrset, region, now))) {
msg->rep->ns_numrrsets++;
msg->rep->rrset_count++;
}
@@ -279,11 +244,9 @@ find_add_ds(struct module_env* env, struct regional* region,
}
}
/** create referral message with NS and query */
static struct dns_msg*
create_msg(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
struct regional* region, struct ub_packed_rrset_key* nskey,
struct packed_rrset_data* nsdata, uint32_t now)
struct dns_msg*
dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype,
uint16_t qclass, struct regional* region, size_t capacity)
{
struct dns_msg* msg = (struct dns_msg*)regional_alloc(region,
sizeof(struct dns_msg));
@@ -296,32 +259,31 @@ create_msg(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
msg->qinfo.qtype = qtype;
msg->qinfo.qclass = qclass;
/* non-packed reply_info, because it needs to grow the array */
msg->rep = (struct reply_info*)regional_alloc(region,
msg->rep = (struct reply_info*)regional_alloc_zero(region,
sizeof(struct reply_info)-sizeof(struct rrset_ref));
if(!msg->rep)
return NULL;
memset(msg->rep, 0,
sizeof(struct reply_info)-sizeof(struct rrset_ref));
msg->rep->flags = BIT_QR; /* with QR, no AA */
msg->rep->qdcount = 1;
/* allocate the array to as much as we could need:
* NS rrset + DS/NSEC rrset +
* A rrset for every NS RR
* AAAA rrset for every NS RR
*/
msg->rep->rrsets = (struct ub_packed_rrset_key**)
regional_alloc(region,
(2 + nsdata->count*2)*sizeof(struct ub_packed_rrset_key*));
capacity*sizeof(struct ub_packed_rrset_key*));
if(!msg->rep->rrsets)
return NULL;
msg->rep->rrsets[0] = copy_rrset(nskey, region, now);
if(!msg->rep->rrsets[0])
return NULL;
msg->rep->ns_numrrsets++;
msg->rep->rrset_count++;
return msg;
}
int
dns_msg_authadd(struct dns_msg* msg, struct regional* region,
struct ub_packed_rrset_key* rrset, uint32_t now)
{
if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
packed_rrset_copy_region(rrset, region, now)))
return 0;
msg->rep->ns_numrrsets++;
return 1;
}
struct delegpt*
dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
size_t qnamelen, uint16_t qtype, uint16_t qclass,
@@ -346,9 +308,14 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
}
/* create referral message */
if(msg) {
*msg = create_msg(qname, qnamelen, qtype, qclass, region,
nskey, nsdata, now);
if(!*msg) {
/* allocate the array to as much as we could need:
* NS rrset + DS/NSEC rrset +
* A rrset for every NS RR
* AAAA rrset for every NS RR
*/
*msg = dns_msg_create(qname, qnamelen, qtype, qclass, region,
2 + nsdata->count*2);
if(!*msg || !dns_msg_authadd(*msg, region, nskey, now)) {
lock_rw_unlock(&nskey->entry.lock);
log_err("find_delegation: out of memory");
return NULL;
@@ -414,7 +381,8 @@ tomsg(struct module_env* env, struct msgreply_entry* e, struct reply_info* r,
if(!rrset_array_lock(r->ref, r->rrset_count, now))
return NULL;
for(i=0; i<msg->rep->rrset_count; i++) {
msg->rep->rrsets[i] = copy_rrset(r->rrsets[i], region, now);
msg->rep->rrsets[i] = packed_rrset_copy_region(r->rrsets[i],
region, now);
if(!msg->rep->rrsets[i]) {
rrset_array_unlock(r->ref, r->rrset_count);
return NULL;
@@ -446,7 +414,7 @@ rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
msg->rep->ns_numrrsets = 0;
msg->rep->ar_numrrsets = 0;
msg->rep->rrset_count = 1;
msg->rep->rrsets[0] = copy_rrset(rrset, region, now);
msg->rep->rrsets[0] = packed_rrset_copy_region(rrset, region, now);
if(!msg->rep->rrsets[0]) /* copy CNAME */
return NULL;
return msg;
@@ -465,6 +433,10 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
size_t newlen, dtarglen;
if(now > d->ttl)
return NULL;
/* only allow validated (with DNSSEC) DNAMEs used from cache
* for insecure DNAMEs, query again. */
if(d->security != sec_status_secure)
return NULL;
msg = gen_dns_msg(region, q, 2); /* DNAME + CNAME RRset */
if(!msg)
return NULL;
@@ -476,7 +448,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
msg->rep->ns_numrrsets = 0;
msg->rep->ar_numrrsets = 0;
msg->rep->rrset_count = 1;
msg->rep->rrsets[0] = copy_rrset(rrset, region, now);
msg->rep->rrsets[0] = packed_rrset_copy_region(rrset, region, now);
if(!msg->rep->rrsets[0]) /* copy DNAME */
return NULL;
/* synth CNAME rrset */
@@ -511,7 +483,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
return NULL;
ck->rk.dname_len = q->qname_len;
ck->entry.hash = rrset_key_hash(&ck->rk);
newd = (struct packed_rrset_data*)regional_alloc(region,
newd = (struct packed_rrset_data*)regional_alloc_zero(region,
sizeof(struct packed_rrset_data) + sizeof(size_t) +
sizeof(uint8_t*) + sizeof(uint32_t) + sizeof(uint16_t)
+ newlen);
@@ -591,8 +563,9 @@ dns_cache_lookup(struct module_env* env,
lock_rw_unlock(&rrset->entry.lock);
}
/* construct DS, DNSKEY messages from rrset cache. */
if((qtype == LDNS_RR_TYPE_DS || qtype == LDNS_RR_TYPE_DNSKEY) &&
/* construct DS, DNSKEY, DLV messages from rrset cache. */
if((qtype == LDNS_RR_TYPE_DS || qtype == LDNS_RR_TYPE_DNSKEY ||
qtype == LDNS_RR_TYPE_DLV) &&
(rrset=rrset_cache_lookup(env->rrset_cache, qname, qnamelen,
qtype, qclass, 0, now, 0))) {
/* if the rrset is from the additional section, and the
+26
View File
@@ -137,4 +137,30 @@ struct dns_msg* dns_cache_lookup(struct module_env* env,
int cache_fill_missing(struct module_env* env, uint16_t qclass,
struct regional* region, struct delegpt* dp);
/**
* Utility, create new, unpacked data structure for cache response.
* QR bit set, no AA. Query set as indicated. Space for number of rrsets.
* @param qname: query section name
* @param qnamelen: len of qname
* @param qtype: query section type
* @param qclass: query section class
* @param region: where to alloc.
* @param capacity: number of rrsets space to create in the array.
* @return new dns_msg struct or NULL on mem fail.
*/
struct dns_msg* dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype,
uint16_t qclass, struct regional* region, size_t capacity);
/**
* Add rrset to authority section in unpacked dns_msg message. Must have enough
* space left, does not grow the array.
* @param msg: msg to put it in.
* @param region: region to alloc in
* @param rrset: to add in authority section
* @param now: now.
* @return true if worked, false on fail
*/
int dns_msg_authadd(struct dns_msg* msg, struct regional* region,
struct ub_packed_rrset_key* rrset, uint32_t now);
#endif /* SERVICES_CACHE_DNS_H */
+33 -13
View File
@@ -208,13 +208,15 @@ new_host_entry(struct infra_cache* infra, struct sockaddr_storage* addr,
data->ttl = tm + infra->host_ttl;
data->lameness = NULL;
data->edns_version = 0;
data->edns_lame_known = 0;
rtt_init(&data->rtt);
return &key->entry;
}
int
infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
socklen_t addrlen, uint32_t timenow, int* edns_vs, int* to)
socklen_t addrlen, uint32_t timenow, int* edns_vs,
uint8_t* edns_lame_known, int* to)
{
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
addrlen, 0);
@@ -231,6 +233,7 @@ infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
rtt_init(&data->rtt);
/* do not touch lameness, it may be valid still */
data->edns_version = 0;
data->edns_lame_known = 0;
}
}
if(!e) {
@@ -240,6 +243,7 @@ infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
data = (struct infra_host_data*)e->data;
*to = rtt_timeout(&data->rtt);
*edns_vs = data->edns_version;
*edns_lame_known = data->edns_lame_known;
slabhash_insert(infra->hosts, e->hash, e, data, NULL);
return 1;
}
@@ -247,6 +251,7 @@ infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
data = (struct infra_host_data*)e->data;
*to = rtt_timeout(&data->rtt);
*edns_vs = data->edns_version;
*edns_lame_known = data->edns_lame_known;
lock_rw_unlock(&e->lock);
return 1;
}
@@ -261,7 +266,7 @@ hash_lameness(uint8_t* name, size_t namelen)
int
infra_lookup_lame(struct infra_host_data* host,
uint8_t* name, size_t namelen, uint32_t timenow,
int* dlame, int* alame, int* olame)
int* dlame, int* rlame, int* alame, int* olame)
{
struct lruhash_entry* e;
struct infra_lame_key k;
@@ -282,10 +287,11 @@ infra_lookup_lame(struct infra_host_data* host,
return 0;
}
*dlame = d->isdnsseclame;
*rlame = d->rec_lame;
*alame = d->lame_type_A;
*olame = d->lame_other;
lock_rw_unlock(&e->lock);
return *dlame || *alame || *olame;
return *dlame || *rlame || *alame || *olame;
}
size_t
@@ -332,7 +338,7 @@ int
infra_set_lame(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t* name, size_t namelen, uint32_t timenow, int dnsseclame,
uint16_t qtype)
int reclame, uint16_t qtype)
{
struct infra_host_data* data;
struct lruhash_entry* e;
@@ -364,8 +370,9 @@ infra_set_lame(struct infra_cache* infra,
k->entry.data = (void*)d;
d->ttl = timenow + infra->lame_ttl;
d->isdnsseclame = dnsseclame;
d->lame_type_A = (!dnsseclame && qtype == LDNS_RR_TYPE_A);
d->lame_other = (!dnsseclame && qtype != LDNS_RR_TYPE_A);
d->rec_lame = reclame;
d->lame_type_A = (!dnsseclame && !reclame && qtype == LDNS_RR_TYPE_A);
d->lame_other = (!dnsseclame && !reclame && qtype != LDNS_RR_TYPE_A);
k->namelen = namelen;
e = infra_lookup_host_nottl(infra, addr, addrlen, 1);
if(!e) {
@@ -399,11 +406,12 @@ infra_set_lame(struct infra_cache* infra,
}
} else {
/* lookup existing lameness entry (if any) and merge data */
int dlame, alame, olame;
int dlame, rlame, alame, olame;
if(infra_lookup_lame(data, name, namelen, timenow,
&dlame, &alame, &olame)) {
&dlame, &rlame, &alame, &olame)) {
/* merge data into new structure */
if(dlame) d->isdnsseclame = 1;
if(rlame) d->rec_lame = 1;
if(alame) d->lame_type_A = 1;
if(olame) d->lame_other = 1;
}
@@ -438,7 +446,7 @@ infra_update_tcp_works(struct infra_cache* infra,
int
infra_rtt_update(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
int roundtrip, uint32_t timenow)
int roundtrip, int orig_rtt, uint32_t timenow)
{
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
addrlen, 1);
@@ -454,7 +462,7 @@ infra_rtt_update(struct infra_cache* infra,
data = (struct infra_host_data*)e->data;
data->ttl = timenow + infra->host_ttl;
if(roundtrip == -1)
rtt_lost(&data->rtt);
rtt_lost(&data->rtt, orig_rtt);
else rtt_update(&data->rtt, roundtrip);
if(data->rtt.rto > 0)
rto = data->rtt.rto;
@@ -483,6 +491,7 @@ infra_edns_update(struct infra_cache* infra,
data = (struct infra_host_data*)e->data;
data->ttl = timenow + infra->host_ttl;
data->edns_version = edns_version;
data->edns_lame_known = 1;
if(needtoinsert)
slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
@@ -494,38 +503,49 @@ int
infra_get_lame_rtt(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t* name, size_t namelen, uint16_t qtype,
int* lame, int* dnsseclame, int* rtt, uint32_t timenow)
int* lame, int* dnsseclame, int* reclame, int* rtt, uint32_t timenow)
{
struct infra_host_data* host;
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
addrlen, 0);
int dlm, alm, olm;
int dlm, rlm, alm, olm;
if(!e)
return 0;
host = (struct infra_host_data*)e->data;
*rtt = rtt_unclamped(&host->rtt);
/* check lameness first, if so, ttl on host does not matter anymore */
if(infra_lookup_lame(host, name, namelen, timenow, &dlm, &alm, &olm)) {
if(infra_lookup_lame(host, name, namelen, timenow,
&dlm, &rlm, &alm, &olm)) {
if(alm && qtype == LDNS_RR_TYPE_A) {
lock_rw_unlock(&e->lock);
*lame = 1;
*dnsseclame = 0;
*reclame = 0;
return 1;
} else if(olm && qtype != LDNS_RR_TYPE_A) {
lock_rw_unlock(&e->lock);
*lame = 1;
*dnsseclame = 0;
*reclame = 0;
return 1;
} else if(dlm) {
lock_rw_unlock(&e->lock);
*lame = 0;
*dnsseclame = 1;
*reclame = 0;
return 1;
} else if(rlm) {
lock_rw_unlock(&e->lock);
*lame = 0;
*dnsseclame = 0;
*reclame = 1;
return 1;
}
/* no lameness for this type of query */
}
*lame = 0;
*dnsseclame = 0;
*reclame = 0;
if(timenow > host->ttl) {
lock_rw_unlock(&e->lock);
return 0;
+20 -5
View File
@@ -70,6 +70,10 @@ struct infra_host_data {
struct lruhash* lameness;
/** edns version that the host supports, -1 means no EDNS */
int edns_version;
/** if the EDNS lameness is already known or not.
* EDNS lame is when EDNS queries or replies are dropped,
* and cause a timeout */
uint8_t edns_lame_known;
};
/**
@@ -94,6 +98,8 @@ struct infra_lame_data {
/** is the host lame (does not serve the zone authoritatively),
* or is the host dnssec lame (does not serve DNSSEC data) */
int isdnsseclame;
/** is the host recursion lame (not AA, but RA) */
int rec_lame;
/** the host is lame (not authoritative) for A records */
int lame_type_A;
/** the host is lame (not authoritative) for other query types */
@@ -166,11 +172,14 @@ struct infra_host_data* infra_lookup_host(struct infra_cache* infra,
* @param addrlen: length of addr.
* @param timenow: what time it is now.
* @param edns_vs: edns version it supports, is returned.
* @param edns_lame_known: if EDNS lame (EDNS is dropped in transit) has
* already been probed, is returned.
* @param to: timeout to use, is returned.
* @return: 0 on error.
*/
int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
socklen_t addrlen, uint32_t timenow, int* edns_vs, int* to);
socklen_t addrlen, uint32_t timenow, int* edns_vs,
uint8_t* edns_lame_known, int* to);
/**
* Check for lameness of this server for a particular zone.
@@ -180,13 +189,14 @@ int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
* @param namelen: length of domain name.
* @param timenow: what time it is now.
* @param dlame: if the function returns true, is set true if dnssec lame.
* @param rlame: if the function returns true, is set true if recursion lame.
* @param alame: if the function returns true, is set true if qtype A lame.
* @param olame: if the function returns true, is set true if qtype other lame.
* @return: 0 if not lame or unknown or timed out, 1 if lame
*/
int infra_lookup_lame(struct infra_host_data* host,
uint8_t* name, size_t namelen, uint32_t timenow,
int* dlame, int* alame, int* olame);
int* dlame, int* rlame, int* alame, int* olame);
/**
* Set a host to be lame for the given zone.
@@ -198,13 +208,15 @@ int infra_lookup_lame(struct infra_host_data* host,
* @param timenow: what time it is now.
* @param dnsseclame: if true the host is set dnssec lame.
* if false, the host is marked lame (not serving the zone).
* @param reclame: if true host is a recursor not AA server.
* if false, dnsseclame or marked lame.
* @param qtype: the query type for which it is lame.
* @return: 0 on error.
*/
int infra_set_lame(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t* name, size_t namelen, uint32_t timenow, int dnsseclame,
uint16_t qtype);
int reclame, uint16_t qtype);
/**
* Update rtt information for the host.
@@ -213,12 +225,14 @@ int infra_set_lame(struct infra_cache* infra,
* @param addrlen: length of addr.
* @param roundtrip: estimate of roundtrip time in milliseconds or -1 for
* timeout.
* @param orig_rtt: original rtt for the query that timed out (roundtrip==-1).
* ignored if roundtrip != -1.
* @param timenow: what time it is now.
* @return: 0 on error. new rto otherwise.
*/
int infra_rtt_update(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
int roundtrip, uint32_t timenow);
int roundtrip, int orig_rtt, uint32_t timenow);
/**
* Update information for the host, store that a TCP transaction works.
@@ -253,6 +267,7 @@ int infra_edns_update(struct infra_cache* infra,
* @param lame: if function returns true, this returns lameness of the zone.
* @param dnsseclame: if function returns true, this returns if the zone
* is dnssec-lame.
* @param reclame: if function returns true, this is if it is recursion lame.
* @param rtt: if function returns true, this returns avg rtt of the server.
* The rtt value is unclamped and reflects recent timeouts.
* @param timenow: what time it is now.
@@ -261,7 +276,7 @@ int infra_edns_update(struct infra_cache* infra,
int infra_get_lame_rtt(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t* name, size_t namelen, uint16_t qtype,
int* lame, int* dnsseclame, int* rtt, uint32_t timenow);
int* lame, int* dnsseclame, int* reclame, int* rtt, uint32_t timenow);
/**
* Get memory used by the infra cache.
+37 -6
View File
@@ -124,10 +124,15 @@ need_to_update_rrset(void* nd, void* cd, uint32_t timenow, int equal)
{
struct packed_rrset_data* newd = (struct packed_rrset_data*)nd;
struct packed_rrset_data* cached = (struct packed_rrset_data*)cd;
/* o store if rrset has been validated */
if( newd->security > cached->security) {
/* o store if rrset has been validated
* everything better than bogus data
* secure is preferred */
if( newd->security == sec_status_secure &&
cached->security != sec_status_secure)
return 1;
if( cached->security == sec_status_bogus &&
newd->security != sec_status_bogus && !equal)
return 1;
}
/* o if current RRset is more trustworthy - insert it */
if( newd->trust > cached->trust ) {
/* if the cached rrset is bogus, and this one equal,
@@ -329,9 +334,13 @@ rrset_update_sec_status(struct rrset_cache* r,
}
/* update the cached rrset */
if(updata->security > cachedata->security) {
cachedata->trust = updata->trust;
size_t i;
if(updata->trust > cachedata->trust)
cachedata->trust = updata->trust;
cachedata->security = updata->security;
cachedata->ttl = updata->ttl + now;
for(i=0; i<cachedata->count+cachedata->rrsig_count; i++)
cachedata->rr_ttl[i] = updata->rr_ttl[i]+now;
}
lock_rw_unlock(&e->lock);
}
@@ -358,9 +367,31 @@ rrset_check_sec_status(struct rrset_cache* r,
}
if(cachedata->security > updata->security) {
updata->security = cachedata->security;
if(cachedata->security == sec_status_bogus)
if(cachedata->security == sec_status_bogus) {
size_t i;
updata->ttl = cachedata->ttl - now;
updata->trust = cachedata->trust;
for(i=0; i<cachedata->count+cachedata->rrsig_count; i++)
if(cachedata->rr_ttl[i] < now)
updata->rr_ttl[i] = 0;
else updata->rr_ttl[i] =
cachedata->rr_ttl[i]-now;
}
if(cachedata->trust > updata->trust)
updata->trust = cachedata->trust;
}
lock_rw_unlock(&e->lock);
}
void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen,
uint16_t type, uint16_t dclass, uint32_t flags)
{
struct ub_packed_rrset_key key;
key.entry.key = &key;
key.rk.dname = nm;
key.rk.dname_len = nmlen;
key.rk.rrset_class = htons(dclass);
key.rk.type = htons(type);
key.rk.flags = flags;
key.entry.hash = rrset_key_hash(&key.rk);
slabhash_remove(&r->table, key.entry.hash, &key);
}
+12
View File
@@ -209,6 +209,18 @@ void rrset_update_sec_status(struct rrset_cache* r,
void rrset_check_sec_status(struct rrset_cache* r,
struct ub_packed_rrset_key* rrset, uint32_t now);
/**
* Remove an rrset from the cache, by name and type and flags
* @param r: rrset cache
* @param nm: name of rrset
* @param nmlen: length of name
* @param type: type of rrset
* @param dclass: class of rrset, host order
* @param flags: flags of rrset, host order
*/
void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen,
uint16_t type, uint16_t dclass, uint32_t flags);
/** mark rrset to be deleted, set id=0 */
void rrset_markdel(void* key);
+13 -15
View File
@@ -190,14 +190,7 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
return s;
}
/**
* Create and bind TCP listening socket
* @param addr: address info ready to make socket.
* @param v6only: enable ip6 only flag on ip6 sockets.
* @param noproto: if error caused by lack of protocol support.
* @return: the socket. -1 on error.
*/
static int
int
create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto)
{
int s;
@@ -532,19 +525,24 @@ listen_create(struct comm_base* base, struct listen_port* ports,
return front;
}
void
listen_delete(struct listen_dnsport* front)
void
listen_list_delete(struct listen_list* list)
{
struct listen_list *p, *pn;
if(!front)
return;
p = front->cps;
struct listen_list *p = list, *pn;
while(p) {
pn = p->next;
comm_point_delete(p->com);
free(p);
p = pn;
}
}
void
listen_delete(struct listen_dnsport* front)
{
if(!front)
return;
listen_list_delete(front->cps);
ldns_buffer_free(front->udp_buff);
free(front);
}
@@ -605,7 +603,7 @@ listening_ports_open(struct config_file* cfg)
return NULL;
}
if(do_auto && (!do_ip4 || !do_ip6)) {
log_warn("interface_automatic option does not work when IP4 or IP6 is not enabled. Disabling option.");
log_warn("interface_automatic option does not work when either do-ip4 or do-ip6 is not enabled. Disabling option.");
do_auto = 0;
}
/* create ip4 and ip6 ports so that return addresses are nice. */
+17
View File
@@ -46,6 +46,7 @@
#include "util/netevent.h"
struct listen_list;
struct config_file;
struct addrinfo;
/**
* Listening for queries structure.
@@ -155,6 +156,13 @@ void listen_resume(struct listen_dnsport* listen);
*/
void listen_delete(struct listen_dnsport* listen);
/**
* delete listen_list of commpoints. Calls commpointdelete() on items.
* This may close the fds or not depending on flags.
* @param list: to delete.
*/
void listen_list_delete(struct listen_list* list);
/**
* get memory size used by the listening structs
* @param listen: listening structure.
@@ -178,4 +186,13 @@ size_t listen_get_mem(struct listen_dnsport* listen);
int create_udp_sock(int family, int socktype, struct sockaddr* addr,
socklen_t addrlen, int v6only, int* inuse, int* noproto);
/**
* Create and bind TCP listening socket
* @param addr: address info ready to make socket.
* @param v6only: enable ip6 only flag on ip6 sockets.
* @param noproto: if error caused by lack of protocol support.
* @return: the socket. -1 on error.
*/
int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto);
#endif /* LISTEN_DNSPORT_H */
+305 -39
View File
@@ -57,6 +57,9 @@ local_zones_create()
if(!zones)
return NULL;
rbtree_init(&zones->ztree, &local_zone_cmp);
lock_quick_init(&zones->lock);
lock_protect(&zones->lock, &zones->ztree, sizeof(zones->ztree));
/* also lock protects the rbnode's in struct local_zone */
return zones;
}
@@ -73,6 +76,7 @@ local_zones_delete(struct local_zones* zones)
{
if(!zones)
return;
lock_quick_destroy(&zones->lock);
/* walk through zones and delete them all */
traverse_postorder(&zones->ztree, lzdel, NULL);
free(zones);
@@ -83,6 +87,7 @@ local_zone_delete(struct local_zone* z)
{
if(!z)
return;
lock_rw_destroy(&z->lock);
regional_destroy(z->region);
free(z->name);
free(z);
@@ -137,14 +142,13 @@ parse_dname(const char* str, uint8_t** res, size_t* len, int* labs)
return 1;
}
/** enter a new zone with allocated dname */
/** create a new localzone */
static struct local_zone*
lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len,
int labs, enum localzone_type t, uint16_t dclass)
local_zone_create(uint8_t* nm, size_t len, int labs,
enum localzone_type t, uint16_t dclass)
{
struct local_zone* z = (struct local_zone*)calloc(1, sizeof(*z));
if(!z) {
log_err("out of memory");
return NULL;
}
z->node.key = z;
@@ -153,19 +157,40 @@ lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len,
z->name = nm;
z->namelen = len;
z->namelabs = labs;
lock_rw_init(&z->lock);
z->region = regional_create();
if(!z->region) {
log_err("out of memory");
free(z);
return NULL;
}
rbtree_init(&z->data, &local_data_cmp);
/* add to rbtree */
if(!rbtree_insert(&zones->ztree, &z->node)) {
log_warn("duplicate local-zone");
local_zone_delete(z);
lock_protect(&z->lock, &z->parent, sizeof(*z)-sizeof(rbnode_t));
/* also the zones->lock protects node, parent, name*, class */
return z;
}
/** enter a new zone with allocated dname returns with WRlock */
static struct local_zone*
lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len,
int labs, enum localzone_type t, uint16_t c)
{
struct local_zone* z = local_zone_create(nm, len, labs, t, c);
if(!z) {
log_err("out of memory");
return NULL;
}
/* add to rbtree */
lock_quick_lock(&zones->lock);
lock_rw_wrlock(&z->lock);
if(!rbtree_insert(&zones->ztree, &z->node)) {
log_warn("duplicate local-zone");
lock_rw_unlock(&z->lock);
local_zone_delete(z);
lock_quick_unlock(&zones->lock);
return NULL;
}
lock_quick_unlock(&zones->lock);
return z;
}
@@ -183,17 +208,7 @@ lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
log_err("bad zone name %s %s", name, type);
return NULL;
}
if(strcmp(type, "deny") == 0)
t = local_zone_deny;
else if(strcmp(type, "refuse") == 0)
t = local_zone_refuse;
else if(strcmp(type, "static") == 0)
t = local_zone_static;
else if(strcmp(type, "transparent") == 0)
t = local_zone_transparent;
else if(strcmp(type, "redirect") == 0)
t = local_zone_redirect;
else {
if(!local_zone_str2type(type, &t)) {
log_err("bad lz_enter_zone type %s %s", name, type);
free(nm);
return NULL;
@@ -373,18 +388,24 @@ insert_rr(struct regional* region, struct packed_rrset_data* pd,
return 1;
}
/** find a data node by exact name */
static struct local_data*
lz_find_node(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs)
{
struct local_data key;
key.node.key = &key;
key.name = nm;
key.namelen = nmlen;
key.namelabs = nmlabs;
return (struct local_data*)rbtree_search(&z->data, &key.node);
}
/** find a node, create it if not and all its empty nonterminal parents */
static int
lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
int nmlabs, struct local_data** res)
{
struct local_data key;
struct local_data* ld;
key.node.key = &key;
key.name = nm;
key.namelen = nmlen;
key.namelabs = nmlabs;
ld = (struct local_data*)rbtree_search(&z->data, &key.node);
struct local_data* ld = lz_find_node(z, nm, nmlen, nmlabs);
if(!ld) {
/* create a domain name to store rr. */
ld = (struct local_data*)regional_alloc_zero(z->region,
@@ -480,16 +501,24 @@ lz_enter_rr_str(struct local_zones* zones, const char* rr, ldns_buffer* buf)
size_t len;
int labs;
struct local_zone* z;
int r;
if(!get_rr_nameclass(rr, &rr_name, &rr_class)) {
log_err("bad rr %s", rr);
return 0;
}
labs = dname_count_size_labels(rr_name, &len);
lock_quick_lock(&zones->lock);
z = local_zones_lookup(zones, rr_name, len, labs, rr_class);
if(!z)
if(!z) {
lock_quick_unlock(&zones->lock);
fatal_exit("internal error: no zone for rr %s", rr);
}
lock_rw_wrlock(&z->lock);
lock_quick_unlock(&zones->lock);
free(rr_name);
return lz_enter_rr_into_zone(z, buf, rr);
r = lz_enter_rr_into_zone(z, buf, rr);
lock_rw_unlock(&z->lock);
return r;
}
/** parse local-zone: statements */
@@ -497,9 +526,12 @@ static int
lz_enter_zones(struct local_zones* zones, struct config_file* cfg)
{
struct config_str2list* p;
struct local_zone* z;
for(p = cfg->local_zones; p; p = p->next) {
if(!lz_enter_zone(zones, p->str, p->str2, LDNS_RR_CLASS_IN))
if(!(z=lz_enter_zone(zones, p->str, p->str2,
LDNS_RR_CLASS_IN)))
return 0;
lock_rw_unlock(&z->lock);
}
return 1;
}
@@ -515,10 +547,13 @@ lz_exists(struct local_zones* zones, const char* name)
log_err("bad name %s", name);
return 0;
}
lock_quick_lock(&zones->lock);
if(rbtree_search(&zones->ztree, &z.node)) {
lock_quick_unlock(&zones->lock);
free(z.name);
return 1;
}
lock_quick_unlock(&zones->lock);
free(z.name);
return 0;
}
@@ -545,7 +580,7 @@ lz_nodefault(struct config_file* cfg, const char* name)
/** enter AS112 default zone */
static int
add_as112_default(struct local_zones* zones, struct config_file* cfg,
ldns_buffer* buf, char* name)
ldns_buffer* buf, const char* name)
{
struct local_zone* z;
char str[1024]; /* known long enough */
@@ -555,11 +590,16 @@ add_as112_default(struct local_zones* zones, struct config_file* cfg,
return 0;
snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. "
"nobody.invalid. 1 3600 1200 604800 10800", name);
if(!lz_enter_rr_into_zone(z, buf, str))
if(!lz_enter_rr_into_zone(z, buf, str)) {
lock_rw_unlock(&z->lock);
return 0;
}
snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name);
if(!lz_enter_rr_into_zone(z, buf, str))
if(!lz_enter_rr_into_zone(z, buf, str)) {
lock_rw_unlock(&z->lock);
return 0;
}
lock_rw_unlock(&z->lock);
return 1;
}
@@ -585,8 +625,10 @@ lz_enter_defaults(struct local_zones* zones, struct config_file* cfg,
!lz_enter_rr_into_zone(z, buf,
"localhost. 10800 IN AAAA ::1")) {
log_err("out of memory adding default zone");
if(z) { lock_rw_unlock(&z->lock); }
return 0;
}
lock_rw_unlock(&z->lock);
}
/* reverse ip4 zone */
if(!lz_exists(zones, "127.in-addr.arpa.") &&
@@ -601,8 +643,10 @@ lz_enter_defaults(struct local_zones* zones, struct config_file* cfg,
!lz_enter_rr_into_zone(z, buf,
"1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
log_err("out of memory adding default zone");
if(z) { lock_rw_unlock(&z->lock); }
return 0;
}
lock_rw_unlock(&z->lock);
}
/* reverse ip6 zone */
if(!lz_exists(zones, "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.") &&
@@ -617,8 +661,10 @@ lz_enter_defaults(struct local_zones* zones, struct config_file* cfg,
!lz_enter_rr_into_zone(z, buf,
"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. 10800 IN PTR localhost.")) {
log_err("out of memory adding default zone");
if(z) { lock_rw_unlock(&z->lock); }
return 0;
}
lock_rw_unlock(&z->lock);
}
if ( !add_as112_default(zones, cfg, buf, "10.in-addr.arpa.") ||
!add_as112_default(zones, cfg, buf, "16.172.in-addr.arpa.") ||
@@ -661,10 +707,13 @@ init_parents(struct local_zones* zones)
{
struct local_zone* node, *prev = NULL, *p;
int m;
lock_quick_lock(&zones->lock);
RBTREE_FOR(node, struct local_zone*, &zones->ztree) {
lock_rw_wrlock(&node->lock);
node->parent = NULL;
if(!prev || prev->dclass != node->dclass) {
prev = node;
lock_rw_unlock(&node->lock);
continue;
}
(void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
@@ -681,7 +730,9 @@ init_parents(struct local_zones* zones)
break;
}
prev = node;
lock_rw_unlock(&node->lock);
}
lock_quick_unlock(&zones->lock);
}
/** enter implicit transparent zone for local-data: without local-zone: */
@@ -711,6 +762,7 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
return 0;
}
labs = dname_count_size_labels(rr_name, &len);
lock_quick_lock(&zones->lock);
if(!local_zones_lookup(zones, rr_name, len, labs, rr_class)) {
if(!have_name) {
dclass = rr_class;
@@ -725,6 +777,7 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
/* process other classes later */
free(rr_name);
have_other_classes = 1;
lock_quick_unlock(&zones->lock);
continue;
}
/* find smallest shared topdomain */
@@ -735,9 +788,11 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
match = m;
}
} else free(rr_name);
lock_quick_unlock(&zones->lock);
}
if(have_name) {
uint8_t* n2;
struct local_zone* z;
/* allocate zone of smallest shared topdomain to contain em */
n2 = nm;
dname_remove_labels(&n2, &nmlen, nmlabs - match);
@@ -749,10 +804,11 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
}
log_nametypeclass(VERB_ALGO, "implicit transparent local-zone",
n2, 0, dclass);
if(!lz_enter_zone_dname(zones, n2, nmlen, match,
local_zone_transparent, dclass)) {
if(!(z=lz_enter_zone_dname(zones, n2, nmlen, match,
local_zone_transparent, dclass))) {
return 0;
}
lock_rw_unlock(&z->lock);
}
if(have_other_classes) {
/* restart to setup other class */
@@ -854,6 +910,20 @@ local_zones_lookup(struct local_zones* zones,
}
}
struct local_zone*
local_zones_find(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass)
{
struct local_zone key;
key.node.key = &key;
key.dclass = dclass;
key.name = name;
key.namelen = len;
key.namelabs = labs;
/* exact */
return (struct local_zone*)rbtree_search(&zones->ztree, &key);
}
/** print all RRsets in local zone */
static void
local_zone_out(struct local_zone* z)
@@ -872,8 +942,10 @@ local_zone_out(struct local_zone* z)
void local_zones_print(struct local_zones* zones)
{
struct local_zone* z;
lock_quick_lock(&zones->lock);
log_info("number of auth zones %u", (unsigned)zones->ztree.count);
RBTREE_FOR(z, struct local_zone*, &zones->ztree) {
lock_rw_rdlock(&z->lock);
switch(z->type) {
case local_zone_deny:
log_nametypeclass(0, "deny zone",
@@ -901,7 +973,9 @@ void local_zones_print(struct local_zones* zones)
break;
}
local_zone_out(z);
lock_rw_unlock(&z->lock);
}
lock_quick_unlock(&zones->lock);
}
/** encode answer consisting of 1 rrset */
@@ -1032,10 +1106,202 @@ local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
* - look at zone type for negative response. */
int labs = dname_count_labels(qinfo->qname);
struct local_data* ld;
struct local_zone* z = local_zones_lookup(zones, qinfo->qname,
struct local_zone* z;
int r;
lock_quick_lock(&zones->lock);
z = local_zones_lookup(zones, qinfo->qname,
qinfo->qname_len, labs, qinfo->qclass);
if(!z) return 0;
if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld))
if(!z) {
lock_quick_unlock(&zones->lock);
return 0;
}
lock_rw_rdlock(&z->lock);
lock_quick_unlock(&zones->lock);
if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld)) {
lock_rw_unlock(&z->lock);
return 1;
return lz_zone_answer(z, qinfo, edns, buf, temp, ld);
}
r = lz_zone_answer(z, qinfo, edns, buf, temp, ld);
lock_rw_unlock(&z->lock);
return r;
}
int local_zone_str2type(const char* type, enum localzone_type* t)
{
if(strcmp(type, "deny") == 0)
*t = local_zone_deny;
else if(strcmp(type, "refuse") == 0)
*t = local_zone_refuse;
else if(strcmp(type, "static") == 0)
*t = local_zone_static;
else if(strcmp(type, "transparent") == 0)
*t = local_zone_transparent;
else if(strcmp(type, "redirect") == 0)
*t = local_zone_redirect;
else return 0;
return 1;
}
/** iterate over the kiddies of the given name and set their parent ptr */
static void
set_kiddo_parents(struct local_zone* z, struct local_zone* match,
struct local_zone* newp)
{
/* both zones and z are locked already */
/* in the sorted rbtree, the kiddies of z are located after z */
/* z must be present in the tree */
struct local_zone* p = z;
p = (struct local_zone*)rbtree_next(&p->node);
while(p!=(struct local_zone*)RBTREE_NULL &&
p->dclass == z->dclass && dname_strict_subdomain(p->name,
p->namelabs, z->name, z->namelabs)) {
/* update parent ptr */
/* only when matches with existing parent pointer, so that
* deeper child structures are not touched, i.e.
* update of x, and a.x, b.x, f.b.x, g.b.x, c.x, y
* gets to update a.x, b.x and c.x */
lock_rw_wrlock(&p->lock);
if(p->parent == match)
p->parent = newp;
lock_rw_unlock(&p->lock);
p = (struct local_zone*)rbtree_next(&p->node);
}
}
struct local_zone* local_zones_add_zone(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass,
enum localzone_type tp)
{
/* create */
struct local_zone* z = local_zone_create(name, len, labs, tp, dclass);
if(!z) return NULL;
lock_rw_wrlock(&z->lock);
/* find the closest parent */
z->parent = local_zones_find(zones, name, len, labs, dclass);
/* insert into the tree */
if(!rbtree_insert(&zones->ztree, &z->node)) {
/* duplicate entry! */
lock_rw_unlock(&z->lock);
local_zone_delete(z);
log_err("internal: duplicate entry in local_zones_add_zone");
return NULL;
}
/* set parent pointers right */
set_kiddo_parents(z, z->parent, z);
lock_rw_unlock(&z->lock);
return z;
}
void local_zones_del_zone(struct local_zones* zones, struct local_zone* z)
{
/* fix up parents in tree */
lock_rw_wrlock(&z->lock);
set_kiddo_parents(z, z, z->parent);
/* remove from tree */
(void)rbtree_delete(&zones->ztree, z);
/* delete the zone */
lock_rw_unlock(&z->lock);
local_zone_delete(z);
}
int
local_zones_add_RR(struct local_zones* zones, const char* rr, ldns_buffer* buf)
{
uint8_t* rr_name;
uint16_t rr_class;
size_t len;
int labs;
struct local_zone* z;
int r;
if(!get_rr_nameclass(rr, &rr_name, &rr_class)) {
return 0;
}
labs = dname_count_size_labels(rr_name, &len);
lock_quick_lock(&zones->lock);
z = local_zones_lookup(zones, rr_name, len, labs, rr_class);
if(!z) {
z = local_zones_add_zone(zones, rr_name, len, labs, rr_class,
local_zone_transparent);
if(!z) {
lock_quick_unlock(&zones->lock);
return 0;
}
}
lock_rw_wrlock(&z->lock);
lock_quick_unlock(&zones->lock);
free(rr_name);
r = lz_enter_rr_into_zone(z, buf, rr);
lock_rw_unlock(&z->lock);
return r;
}
/** returns true if the node is terminal so no deeper domain names exist */
static int
is_terminal(struct local_data* d)
{
/* for empty nonterminals, the deeper domain names are sorted
* right after them, so simply check the next name in the tree
*/
struct local_data* n = (struct local_data*)rbtree_next(&d->node);
if(n == (struct local_data*)RBTREE_NULL)
return 1; /* last in tree, no deeper node */
if(dname_strict_subdomain(n->name, n->namelabs, d->name, d->namelabs))
return 0; /* there is a deeper node */
return 1;
}
/** delete empty terminals from tree when final data is deleted */
static void
del_empty_term(struct local_zone* z, struct local_data* d,
uint8_t* name, size_t len, int labs)
{
while(d && d->rrsets == NULL && is_terminal(d)) {
/* is this empty nonterminal? delete */
/* note, no memory recycling in zone region */
(void)rbtree_delete(&z->data, d);
/* go up and to the next label */
if(dname_is_root(name))
return;
dname_remove_label(&name, &len);
labs--;
d = lz_find_node(z, name, len, labs);
}
}
void local_zones_del_data(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass)
{
/* find zone */
struct local_zone* z;
struct local_data* d;
lock_quick_lock(&zones->lock);
z = local_zones_lookup(zones, name, len, labs, dclass);
if(!z) {
/* no such zone, we're done */
lock_quick_unlock(&zones->lock);
return;
}
lock_rw_wrlock(&z->lock);
lock_quick_unlock(&zones->lock);
/* find the domain */
d = lz_find_node(z, name, len, labs);
/* no memory recycling for zone deletions ... */
d->rrsets = NULL;
/* did we delete the soa record ? */
if(query_dname_compare(d->name, z->name) == 0)
z->soa = NULL;
/* cleanup the empty nonterminals for this name */
del_empty_term(z, d, name, len, labs);
lock_rw_unlock(&z->lock);
}
+83
View File
@@ -42,6 +42,7 @@
#ifndef SERVICES_LOCALZONE_H
#define SERVICES_LOCALZONE_H
#include "util/rbtree.h"
#include "util/locks.h"
struct ub_packed_rrset_key;
struct regional;
struct config_file;
@@ -74,6 +75,8 @@ enum localzone_type {
* This tree is fixed at startup, so, readonly, no locks or mutexes necessary.
*/
struct local_zones {
/** lock on the localzone tree */
lock_quick_t lock;
/** rbtree of struct local_zone */
rbtree_t ztree;
};
@@ -97,6 +100,12 @@ struct local_zone {
* uses 'dclass' to not conflict with c++ keyword class. */
uint16_t dclass;
/** lock on the data in the structure
* For the node, parent, name, namelen, namelabs, dclass, you
* need to also hold the zones_tree lock to change them (or to
* delete this zone) */
lock_rw_t lock;
/** how to process zone */
enum localzone_type type;
@@ -151,6 +160,7 @@ void local_zones_delete(struct local_zones* zones);
/**
* Apply config settings; setup the local authoritative data.
* Takes care of locking.
* @param zones: is set up.
* @param cfg: config data.
* @return false on error.
@@ -182,6 +192,7 @@ void local_zone_delete(struct local_zone* z);
/**
* Lookup zone that contains the given name, class.
* User must lock the tree or result zone.
* @param zones: the zones tree
* @param name: dname to lookup
* @param len: length of name.
@@ -194,12 +205,14 @@ struct local_zone* local_zones_lookup(struct local_zones* zones,
/**
* Debug helper. Print all zones
* Takes care of locking.
* @param zones: the zones tree
*/
void local_zones_print(struct local_zones* zones);
/**
* Answer authoritatively for local zones.
* Takes care of locking.
* @param zones: the stored zones (shared, read only).
* @param qinfo: query info (parsed).
* @param edns: edns info (parsed).
@@ -212,4 +225,74 @@ void local_zones_print(struct local_zones* zones);
int local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
struct edns_data* edns, ldns_buffer* buf, struct regional* temp);
/**
* Parse the string into localzone type.
*
* @param str: string to parse
* @param t: local zone type returned here.
* @return 0 on parse error.
*/
int local_zone_str2type(const char* str, enum localzone_type* t);
/**
* Find zone that with exactly given name, class.
* User must lock the tree or result zone.
* @param zones: the zones tree
* @param name: dname to lookup
* @param len: length of name.
* @param labs: labelcount of name.
* @param dclass: class to lookup.
* @return the exact local_zone or NULL.
*/
struct local_zone* local_zones_find(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass);
/**
* Add a new zone. Caller must hold the zones lock.
* Adjusts the other zones as well (parent pointers) after insertion.
* The zone must NOT exist (returns NULL and logs error).
* @param zones: the zones tree
* @param name: dname to add
* @param len: length of name.
* @param labs: labelcount of name.
* @param dclass: class to add.
* @param tp: type.
* @return local_zone or NULL on error, caller must printout memory error.
*/
struct local_zone* local_zones_add_zone(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass,
enum localzone_type tp);
/**
* Delete a zone. Caller must hold the zones lock.
* Adjusts the other zones as well (parent pointers) after insertion.
* @param zones: the zones tree
* @param zone: the zone to delete from tree. Also deletes zone from memory.
*/
void local_zones_del_zone(struct local_zones* zones, struct local_zone* zone);
/**
* Add RR data into the localzone data.
* Looks up the zone, if no covering zone, a transparent zone with the
* name of the RR is created.
* @param zones: the zones tree. Not locked by caller.
* @param rr: string with on RR.
* @param buf: buffer for scratch.
* @return false on failure.
*/
int local_zones_add_RR(struct local_zones* zones, const char* rr,
ldns_buffer* buf);
/**
* Remove data from domain name in the tree.
* All types are removed. No effect if zone or name does not exist.
* @param zones: zones tree.
* @param name: dname to remove
* @param len: length of name.
* @param labs: labelcount of name.
* @param dclass: class to remove.
*/
void local_zones_del_data(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass);
#endif /* SERVICES_LOCALZONE_H */
+206 -52
View File
@@ -54,6 +54,71 @@
#include "util/timehist.h"
#include "util/fptr_wlist.h"
#include "util/alloc.h"
#include "util/config_file.h"
/** subtract timers and the values do not overflow or become negative */
static void
timeval_subtract(struct timeval* d, const struct timeval* end, const struct timeval* start)
{
#ifndef S_SPLINT_S
time_t end_usec = end->tv_usec;;
d->tv_sec = end->tv_sec - start->tv_sec;
while(end_usec < start->tv_usec) {
end_usec += 1000000;
d->tv_sec--;
}
d->tv_usec = end_usec - start->tv_usec;
#endif
}
/** add timers and the values do not overflow or become negative */
static void
timeval_add(struct timeval* d, const struct timeval* add)
{
#ifndef S_SPLINT_S
d->tv_sec += add->tv_sec;
d->tv_usec += add->tv_usec;
while(d->tv_usec > 1000000 ) {
d->tv_usec -= 1000000;
d->tv_sec++;
}
#endif
}
/** divide sum of timers to get average */
static void
timeval_divide(struct timeval* avg, const struct timeval* sum, size_t d)
{
#ifndef S_SPLINT_S
size_t leftover;
if(d == 0) {
avg->tv_sec = 0;
avg->tv_usec = 0;
return;
}
avg->tv_sec = sum->tv_sec / d;
avg->tv_usec = sum->tv_usec / d;
/* handle fraction from seconds divide */
leftover = sum->tv_sec - avg->tv_sec*d;
avg->tv_usec += (leftover*1000000)/d;
#endif
}
/** histogram compare of time values */
static int
timeval_smaller(const struct timeval* x, const struct timeval* y)
{
#ifndef S_SPLINT_S
if(x->tv_sec < y->tv_sec)
return 1;
else if(x->tv_sec == y->tv_sec) {
if(x->tv_usec <= y->tv_usec)
return 1;
else return 0;
}
else return 0;
#endif
}
int
mesh_state_compare(const void* ap, const void* bp)
@@ -108,6 +173,16 @@ mesh_create(struct module_stack* stack, struct module_env* env)
mesh->num_reply_addrs = 0;
mesh->num_reply_states = 0;
mesh->num_detached_states = 0;
mesh->num_forever_states = 0;
mesh->stats_jostled = 0;
mesh->stats_dropped = 0;
mesh->max_reply_states = env->cfg->num_queries_per_thread;
mesh->max_forever_states = (mesh->max_reply_states+1)/2;
#ifndef S_SPLINT_S
mesh->jostle_max.tv_sec = (time_t)(env->cfg->jostle_time / 1000);
mesh->jostle_max.tv_usec = (time_t)((env->cfg->jostle_time % 1000)
*1000);
#endif
return mesh;
}
@@ -130,6 +205,40 @@ mesh_delete(struct mesh_area* mesh)
free(mesh);
}
int mesh_make_new_space(struct mesh_area* mesh)
{
struct mesh_state* m = mesh->jostle_last;
/* free space is available */
if(mesh->num_reply_states < mesh->max_reply_states)
return 1;
/* try to kick out a jostle-list item */
if(m && m->reply_list && m->list_select == mesh_jostle_list) {
/* how old is it? */
struct timeval age;
timeval_subtract(&age, mesh->env->now_tv,
&m->reply_list->start_time);
if(timeval_smaller(&mesh->jostle_max, &age)) {
/* its a goner */
log_nametypeclass(VERB_ALGO, "query jostled out to "
"make space for a new one",
m->s.qinfo.qname, m->s.qinfo.qtype,
m->s.qinfo.qclass);
/* notify supers */
if(m->super_set.count > 0) {
verbose(VERB_ALGO, "notify supers of failure");
m->s.return_msg = NULL;
m->s.return_rcode = LDNS_RCODE_SERVFAIL;
mesh_walk_supers(mesh, m);
}
mesh->stats_jostled ++;
mesh_state_delete(&m->s);
return 1;
}
}
/* no space for new item */
return 0;
}
void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, struct edns_data* edns, struct comm_reply* rep,
uint16_t qid)
@@ -138,6 +247,16 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
int was_detached = 0;
int was_noreply = 0;
int added = 0;
/* does this create a new reply state? */
if(!s || s->list_select == mesh_no_list) {
if(!mesh_make_new_space(mesh)) {
verbose(VERB_ALGO, "Too many queries. dropping "
"incoming query.");
comm_point_drop_reply(rep);
mesh->stats_dropped ++;
return;
}
}
/* see if it already exists, if not, create one */
if(!s) {
struct rbnode_t* n;
@@ -178,6 +297,19 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
mesh->num_reply_states ++;
}
mesh->num_reply_addrs++;
if(s->list_select == mesh_no_list) {
/* move to either the forever or the jostle_list */
if(mesh->num_forever_states < mesh->max_forever_states) {
mesh->num_forever_states ++;
mesh_list_insert(s, &mesh->forever_first,
&mesh->forever_last);
s->list_select = mesh_forever_list;
} else {
mesh_list_insert(s, &mesh->jostle_first,
&mesh->jostle_last);
s->list_select = mesh_jostle_list;
}
}
if(added)
mesh_run(mesh, s, module_event_new, NULL);
}
@@ -191,6 +323,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
int was_detached = 0;
int was_noreply = 0;
int added = 0;
/* there are no limits on the number of callbacks */
/* see if it already exists, if not, create one */
if(!s) {
struct rbnode_t* n;
@@ -229,11 +363,16 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
}
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
int is_ok, struct comm_reply* reply)
struct comm_reply* reply, int what)
{
enum module_ev event = module_event_reply;
e->qstate->reply = reply;
mesh_run(mesh, e->qstate->mesh_info,
is_ok?module_event_reply:module_event_noreply, e);
if(what != NETEVENT_NOERROR) {
event = module_event_noreply;
if(what == NETEVENT_CAPSFAIL)
event = module_event_capsfail;
}
mesh_run(mesh, e->qstate->mesh_info, event, e);
}
struct mesh_state*
@@ -257,6 +396,8 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
mstate->node.key = mstate;
mstate->run_node.key = mstate;
mstate->reply_list = NULL;
mstate->list_select = mesh_no_list;
mstate->replies_sent = 0;
rbtree_init(&mstate->super_set, &mesh_state_ref_compare);
rbtree_init(&mstate->sub_set, &mesh_state_ref_compare);
mstate->num_activated = 0;
@@ -295,6 +436,14 @@ mesh_state_cleanup(struct mesh_state* mstate)
int i;
if(!mstate)
return;
/* drop unsent replies */
if(!mstate->replies_sent) {
struct mesh_reply* rep;
for(rep=mstate->reply_list; rep; rep=rep->next) {
comm_point_drop_reply(&rep->query_reply);
}
}
/* de-init modules */
mesh = mstate->s.env->mesh;
for(i=0; i<mesh->mods.num; i++) {
@@ -317,6 +466,14 @@ mesh_state_delete(struct module_qstate* qstate)
mstate = qstate->mesh_info;
mesh = mstate->s.env->mesh;
mesh_detach_subs(&mstate->s);
if(mstate->list_select == mesh_forever_list) {
mesh->num_forever_states --;
mesh_list_remove(mstate, &mesh->forever_first,
&mesh->forever_last);
} else if(mstate->list_select == mesh_jostle_list) {
mesh_list_remove(mstate, &mesh->jostle_first,
&mesh->jostle_last);
}
if(!mstate->reply_list && !mstate->cb_list
&& mstate->super_set.count == 0) {
log_assert(mesh->num_detached_states > 0);
@@ -414,53 +571,6 @@ int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub)
return 1;
}
/** subtract timers and the values do not overflow or become negative */
static void
timeval_subtract(struct timeval* d, struct timeval* end, struct timeval* start)
{
#ifndef S_SPLINT_S
d->tv_sec = end->tv_sec - start->tv_sec;
while(end->tv_usec < start->tv_usec) {
end->tv_usec += 1000000;
d->tv_sec--;
}
d->tv_usec = end->tv_usec - start->tv_usec;
#endif
}
/** add timers and the values do not overflow or become negative */
static void
timeval_add(struct timeval* d, struct timeval* add)
{
#ifndef S_SPLINT_S
d->tv_sec += add->tv_sec;
d->tv_usec += add->tv_usec;
while(d->tv_usec > 1000000 ) {
d->tv_usec -= 1000000;
d->tv_sec++;
}
#endif
}
/** divide sum of timers to get average */
static void
timeval_divide(struct timeval* avg, struct timeval* sum, size_t d)
{
#ifndef S_SPLINT_S
size_t leftover;
if(d == 0) {
avg->tv_sec = 0;
avg->tv_usec = 0;
return;
}
avg->tv_sec = sum->tv_sec / d;
avg->tv_usec = sum->tv_usec / d;
/* handle fraction from seconds divide */
leftover = sum->tv_sec - avg->tv_sec*d;
avg->tv_usec += (leftover*1000000)/d;
#endif
}
/**
* callback results to mesh cb entry
* @param m: mesh state to send it for.
@@ -523,6 +633,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
if(m->s.env->need_to_validate && !(r->qflags&BIT_CD) && rep &&
rep->security <= sec_status_bogus) {
rcode = LDNS_RCODE_SERVFAIL;
if(m->s.env->cfg->stat_extended)
m->s.env->mesh->ans_bogus++;
}
if(rep && rep->security == sec_status_secure)
secure = 1;
@@ -575,6 +687,15 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
m->s.env->mesh->replies_sent++;
timeval_add(&m->s.env->mesh->replies_sum_wait, &duration);
timehist_insert(m->s.env->mesh->histogram, &duration);
if(m->s.env->cfg->stat_extended) {
uint16_t rc = FLAGS_GET_RCODE(ldns_buffer_read_u16_at(r->
query_reply.c->buffer, 2));
if(secure) m->s.env->mesh->ans_secure++;
m->s.env->mesh->ans_rcode[ rc ] ++;
if(rc == 0 && LDNS_ANCOUNT(ldns_buffer_begin(r->
query_reply.c->buffer)) == 0)
m->s.env->mesh->ans_nodata++;
}
}
void mesh_query_done(struct mesh_state* mstate)
@@ -588,6 +709,7 @@ void mesh_query_done(struct mesh_state* mstate)
mesh_send_reply(mstate, mstate->s.return_rcode, rep, r, prev);
prev = r;
}
mstate->replies_sent = 1;
for(c = mstate->cb_list; c; c = c->next) {
mesh_do_callback(mstate, mstate->s.return_rcode, rep, c);
}
@@ -785,11 +907,14 @@ mesh_stats(struct mesh_area* mesh, const char* str)
{
verbose(VERB_DETAIL, "%s %u recursion states (%u with reply, "
"%u detached), %u waiting replies, %u recursion replies "
"sent", str, (unsigned)mesh->all.count,
"sent, %d replies dropped, %d states jostled out",
str, (unsigned)mesh->all.count,
(unsigned)mesh->num_reply_states,
(unsigned)mesh->num_detached_states,
(unsigned)mesh->num_reply_addrs,
(unsigned)mesh->replies_sent);
(unsigned)mesh->replies_sent,
(unsigned)mesh->stats_dropped,
(unsigned)mesh->stats_jostled);
if(mesh->replies_sent > 0) {
struct timeval avg;
timeval_divide(&avg, &mesh->replies_sum_wait,
@@ -809,7 +934,13 @@ mesh_stats_clear(struct mesh_area* mesh)
mesh->replies_sent = 0;
mesh->replies_sum_wait.tv_sec = 0;
mesh->replies_sum_wait.tv_usec = 0;
mesh->stats_jostled = 0;
mesh->stats_dropped = 0;
timehist_clear(mesh->histogram);
mesh->ans_secure = 0;
mesh->ans_bogus = 0;
memset(&mesh->ans_rcode[0], 0, sizeof(size_t)*16);
mesh->ans_nodata = 0;
}
size_t
@@ -850,3 +981,26 @@ mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo,
return 1;
return 0;
}
void mesh_list_insert(struct mesh_state* m, struct mesh_state** fp,
struct mesh_state** lp)
{
/* insert as last element */
m->prev = *lp;
m->next = NULL;
if(*lp)
(*lp)->next = m;
else *fp = m;
*lp = m;
}
void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
struct mesh_state** lp)
{
if(m->next)
m->next->prev = m->prev;
else *lp = m->prev;
if(m->prev)
m->prev->next = m->next;
else *fp = m->next;
}
+71 -2
View File
@@ -89,13 +89,46 @@ struct mesh_area {
* an empty set of super-states, thus are 'toplevel' or detached
* internal opportunistic queries */
size_t num_detached_states;
/** number of reply states in the forever list */
size_t num_forever_states;
/** max total number of reply states to have */
size_t max_reply_states;
/** max forever number of reply states to have */
size_t max_forever_states;
/** stats, cumulative number of reply states jostled out */
size_t stats_jostled;
/** stats, cumulative number of incoming client msgs dropped */
size_t stats_dropped;
/** number of replies sent */
size_t replies_sent;
/** sum of waiting times for the replies */
struct timeval replies_sum_wait;
/** histogram of time values */
struct timehist* histogram;
/** (extended stats) secure replies */
size_t ans_secure;
/** (extended stats) bogus replies */
size_t ans_bogus;
/** (extended stats) rcodes in replies */
size_t ans_rcode[16];
/** (extended stats) rcode nodata in replies */
size_t ans_nodata;
/** double linked list of the run-to-completion query states.
* These are query states with a reply */
struct mesh_state* forever_first;
/** last entry in run forever list */
struct mesh_state* forever_last;
/** double linked list of the query states that can be jostled out
* by new queries if too old. These are query states with a reply */
struct mesh_state* jostle_first;
/** last entry in jostle list - this is the entry that is newest */
struct mesh_state* jostle_last;
/** timeout for jostling. if age is lower, it does not get jostled. */
struct timeval jostle_max;
};
/**
@@ -127,6 +160,17 @@ struct mesh_state {
rbtree_t sub_set;
/** number of activations for the mesh state */
size_t num_activated;
/** previous in linked list for reply states */
struct mesh_state* prev;
/** next in linked list for reply states */
struct mesh_state* next;
/** if this state is in the forever list, jostle list, or neither */
enum mesh_list_select { mesh_no_list, mesh_forever_list,
mesh_jostle_list } list_select;
/** true if replies have been sent out (at end for alignment) */
uint8_t replies_sent;
};
/**
@@ -248,11 +292,11 @@ int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
*
* @param mesh: the query mesh.
* @param e: outbound entry, with query state to run and reply pointer.
* @param is_ok: if true, reply is OK, otherwise a timeout happened.
* @param reply: the comm point reply info.
* @param what: NETEVENT_* error code (if not 0, what is wrong, TIMEOUT).
*/
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
int is_ok, struct comm_reply* reply);
struct comm_reply* reply, int what);
/* ------------------- Functions for module environment --------------- */
@@ -457,4 +501,29 @@ int mesh_state_compare(const void* ap, const void* bp);
/** compare two mesh references */
int mesh_state_ref_compare(const void* ap, const void* bp);
/**
* Make space for another recursion state for a reply in the mesh
* @param mesh: mesh area
* @return false if no space is available.
*/
int mesh_make_new_space(struct mesh_area* mesh);
/**
* Insert mesh state into a double linked list. Inserted at end.
* @param m: mesh state.
* @param fp: pointer to the first-elem-pointer of the list.
* @param lp: pointer to the last-elem-pointer of the list.
*/
void mesh_list_insert(struct mesh_state* m, struct mesh_state** fp,
struct mesh_state** lp);
/**
* Remove mesh state from a double linked list. Remove from any position.
* @param m: mesh state.
* @param fp: pointer to the first-elem-pointer of the list.
* @param lp: pointer to the last-elem-pointer of the list.
*/
void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
struct mesh_state** lp);
#endif /* SERVICES_MESH_H */
+11
View File
@@ -165,3 +165,14 @@ modstack_desetup(struct module_stack* stack, struct module_env* env)
free(stack->mod);
stack->mod = NULL;
}
int
modstack_find(struct module_stack* stack, const char* name)
{
int i;
for(i=0; i<stack->num; i++) {
if(strcmp(stack->mod[i]->name, name) == 0)
return i;
}
return -1;
}
+8
View File
@@ -96,4 +96,12 @@ int modstack_setup(struct module_stack* stack, const char* module_conf,
*/
void modstack_desetup(struct module_stack* stack, struct module_env* env);
/**
* Find index of module by name.
* @param stack: to look in
* @param name: the name to look for
* @return -1 on failure, otherwise index number.
*/
int modstack_find(struct module_stack* stack, const char* name);
#endif /* SERVICES_MODSTACK_H */
+107 -18
View File
@@ -329,6 +329,18 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
if(!p) {
verbose(VERB_QUERY, "received unwanted or unsolicited udp reply dropped.");
log_buf(VERB_ALGO, "dropped message", c->buffer);
outnet->unwanted_replies++;
if(outnet->unwanted_threshold && ++outnet->unwanted_total
>= outnet->unwanted_threshold) {
log_warn("unwanted reply total reached threshold (%u)"
" you may be under attack."
" defensive action: clearing the cache",
(unsigned)outnet->unwanted_threshold);
fptr_ok(fptr_whitelist_alloc_cleanup(
outnet->unwanted_action));
(*outnet->unwanted_action)(outnet->unwanted_param);
outnet->unwanted_total = 0;
}
return 0;
}
@@ -337,6 +349,18 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
if(p->pc->cp != c) {
verbose(VERB_QUERY, "received reply id,addr on wrong port. "
"dropped.");
outnet->unwanted_replies++;
if(outnet->unwanted_threshold && ++outnet->unwanted_total
>= outnet->unwanted_threshold) {
log_warn("unwanted reply total reached threshold (%u)"
" you may be under attack."
" defensive action: clearing the cache",
(unsigned)outnet->unwanted_threshold);
fptr_ok(fptr_whitelist_alloc_cleanup(
outnet->unwanted_action));
(*outnet->unwanted_action)(outnet->unwanted_param);
outnet->unwanted_total = 0;
}
return 0;
}
comm_timer_disable(p->timer);
@@ -442,7 +466,8 @@ outside_network_create(struct comm_base *base, size_t bufsize,
size_t num_ports, char** ifs, int num_ifs, int do_ip4,
int do_ip6, size_t num_tcp, struct infra_cache* infra,
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
int numavailports)
int numavailports, size_t unwanted_threshold,
void (*unwanted_action)(void*), void* unwanted_param)
{
struct outside_network* outnet = (struct outside_network*)
calloc(1, sizeof(struct outside_network));
@@ -457,6 +482,9 @@ outside_network_create(struct comm_base *base, size_t bufsize,
outnet->infra = infra;
outnet->rnd = rnd;
outnet->svcd_overhead = 0;
outnet->unwanted_threshold = unwanted_threshold;
outnet->unwanted_action = unwanted_action;
outnet->unwanted_param = unwanted_param;
outnet->use_caps_for_id = use_caps_for_id;
if(numavailports == 0) {
log_err("no outgoing ports available");
@@ -668,6 +696,23 @@ pending_delete(struct outside_network* outnet, struct pending* p)
{
if(!p)
return;
if(outnet && outnet->udp_wait_first &&
(p->next_waiting || p == outnet->udp_wait_last) ) {
/* delete from waiting list, if it is in the waiting list */
struct pending* prev = NULL, *x = outnet->udp_wait_first;
while(x && x != p) {
prev = x;
x = x->next_waiting;
}
if(x) {
log_assert(x == p);
if(prev)
prev->next_waiting = p->next_waiting;
else outnet->udp_wait_first = p->next_waiting;
if(outnet->udp_wait_last == p)
outnet->udp_wait_last = prev;
}
}
if(outnet) {
(void)rbtree_delete(outnet->pending, p->node.key);
}
@@ -1065,9 +1110,11 @@ serviced_delete(struct serviced_query* sq)
if(sq->pending) {
/* clear up the pending query */
if(sq->status == serviced_query_UDP_EDNS ||
sq->status == serviced_query_UDP) {
sq->status == serviced_query_UDP ||
sq->status == serviced_query_PROBE_EDNS) {
struct pending* p = (struct pending*)sq->pending;
portcomm_loweruse(sq->outnet, p->pc);
if(p->pc)
portcomm_loweruse(sq->outnet, p->pc);
pending_delete(sq->outnet, p);
outnet_send_wait_udp(sq->outnet);
} else {
@@ -1164,18 +1211,30 @@ static int
serviced_udp_send(struct serviced_query* sq, ldns_buffer* buff)
{
int rtt, vs;
uint8_t edns_lame_known;
uint32_t now = *sq->outnet->now_secs;
if(!infra_host(sq->outnet->infra, &sq->addr, sq->addrlen, now, &vs,
&rtt))
&edns_lame_known, &rtt))
return 0;
if(sq->status == serviced_initial) {
if(vs != -1)
if(edns_lame_known == 0 && rtt > 5000) {
/* perform EDNS lame probe - check if server is
* EDNS lame (EDNS queries to it are dropped) */
verbose(VERB_ALGO, "serviced query: send probe to see "
" if use of EDNS causes timeouts");
rtt /= 10;
sq->status = serviced_query_PROBE_EDNS;
} else if(vs != -1) {
sq->status = serviced_query_UDP_EDNS;
else sq->status = serviced_query_UDP;
} else {
sq->status = serviced_query_UDP;
}
}
serviced_encode(sq, buff, sq->status == serviced_query_UDP_EDNS);
sq->last_sent_time = *sq->outnet->now_tv;
sq->last_rtt = rtt;
sq->edns_lame_known = (int)edns_lame_known;
verbose(VERB_ALGO, "serviced query UDP timeout=%d msec", rtt);
sq->pending = pending_udp_query(sq->outnet, buff, &sq->addr,
sq->addrlen, rtt, serviced_udp_callback, sq);
@@ -1251,22 +1310,23 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
== LDNS_RCODE_NOERROR ||
LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
== LDNS_RCODE_NXDOMAIN)) {
verbose(VERB_OPS, "no qname in reply to check 0x20ID");
log_addr(VERB_OPS, "from server",
verbose(VERB_DETAIL, "no qname in reply to check 0x20ID");
log_addr(VERB_DETAIL, "from server",
&sq->addr, sq->addrlen);
log_buf(VERB_OPS, "for packet", c->buffer);
log_buf(VERB_DETAIL, "for packet", c->buffer);
error = NETEVENT_CLOSED;
c = NULL;
} else if(ldns_buffer_read_u16_at(c->buffer, 4) > 0 &&
!serviced_check_qname(c->buffer, sq->qbuf,
sq->qbuflen)) {
verbose(VERB_OPS, "wrong 0x20-ID in reply qname, "
"answer dropped");
log_addr(VERB_OPS, "from server",
verbose(VERB_DETAIL, "wrong 0x20-ID in reply qname");
log_addr(VERB_DETAIL, "from server",
&sq->addr, sq->addrlen);
log_buf(VERB_OPS, "for packet", c->buffer);
error = NETEVENT_CLOSED;
c = NULL;
log_buf(VERB_DETAIL, "for packet", c->buffer);
error = NETEVENT_CAPSFAIL;
/* and cleanup too */
pkt_dname_tolower(c->buffer,
ldns_buffer_at(c->buffer, 12));
} else {
verbose(VERB_ALGO, "good 0x20-ID in reply qname");
/* cleanup caps, prettier cache contents. */
@@ -1372,9 +1432,17 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
sq->pending = NULL; /* removed after callback */
if(error == NETEVENT_TIMEOUT) {
int rto = 0;
if(sq->status == serviced_query_PROBE_EDNS) {
/* non-EDNS probe failed; not an EDNS lame server */
if(!infra_edns_update(outnet->infra, &sq->addr,
sq->addrlen, 0, (uint32_t)now.tv_sec)) {
log_err("Out of memory caching edns works");
}
sq->status = serviced_query_UDP_EDNS;
}
sq->retry++;
if(!(rto=infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
-1, (uint32_t)now.tv_sec)))
-1, sq->last_rtt, (uint32_t)now.tv_sec)))
log_err("out of memory in UDP exponential backoff");
if(sq->retry < OUTBOUND_UDP_RETRY) {
log_name_addr(VERB_ALGO, "retry query", sq->qbuf+10,
@@ -1419,6 +1487,25 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
return 0;
}
/* yay! an answer */
if(sq->status == serviced_query_PROBE_EDNS) {
/* probe without EDNS succeeds, so we conclude that this
* host likely has EDNS packets dropped */
log_addr(VERB_DETAIL, "timeouts, concluded that connection to "
"host drops EDNS packets", &sq->addr, sq->addrlen);
if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
-1, (uint32_t)now.tv_sec)) {
log_err("Out of memory caching no edns for host");
}
sq->status = serviced_query_UDP;
} else if(sq->status == serviced_query_UDP_EDNS &&
!sq->edns_lame_known) {
/* now we know that edns queries received answers store that */
if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
0, (uint32_t)now.tv_sec)) {
log_err("Out of memory caching edns works");
}
sq->edns_lame_known = 1;
}
if(now.tv_sec > sq->last_sent_time.tv_sec ||
(now.tv_sec == sq->last_sent_time.tv_sec &&
now.tv_usec > sq->last_sent_time.tv_usec)) {
@@ -1428,7 +1515,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
verbose(VERB_ALGO, "measured roundtrip at %d msec", roundtime);
log_assert(roundtime >= 0);
if(!infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
roundtime, (uint32_t)now.tv_sec))
roundtime, sq->last_rtt, (uint32_t)now.tv_sec))
log_err("out of memory noting rtt.");
}
serviced_callbacks(sq, error, c, rep);
@@ -1611,7 +1698,8 @@ serviced_get_mem(struct serviced_query* sq)
for(sb = sq->cblist; sb; sb = sb->next)
s += sizeof(*sb);
if(sq->status == serviced_query_UDP_EDNS ||
sq->status == serviced_query_UDP) {
sq->status == serviced_query_UDP ||
sq->status == serviced_query_PROBE_EDNS) {
s += sizeof(struct pending);
s += comm_timer_get_mem(NULL);
} else {
@@ -1626,3 +1714,4 @@ serviced_get_mem(struct serviced_query* sq)
}
return s;
}
+23 -2
View File
@@ -77,6 +77,17 @@ struct outside_network {
/** use x20 bits to encode additional ID random bits */
int use_caps_for_id;
/** number of unwanted replies received (for statistics) */
size_t unwanted_replies;
/** cumulative total of unwanted replies (for defense) */
size_t unwanted_total;
/** threshold when to take defensive action. If 0 then never. */
size_t unwanted_threshold;
/** what action to take, called when defensive action is needed */
void (*unwanted_action)(void*);
/** user param for action */
void* unwanted_param;
/** linked list of available commpoints, unused file descriptors,
* for use as outgoing UDP ports. cp.fd=-1 in them. */
struct port_comm* unused_fds;
@@ -292,7 +303,9 @@ struct serviced_query {
/** TCP with EDNS sent */
serviced_query_TCP_EDNS,
/** TCP without EDNS sent */
serviced_query_TCP
serviced_query_TCP,
/** probe to test EDNS lameness (EDNS is dropped) */
serviced_query_PROBE_EDNS
}
/** variable with current status */
status;
@@ -302,6 +315,10 @@ struct serviced_query {
int retry;
/** time last UDP was sent */
struct timeval last_sent_time;
/** rtt of last (UDP) message */
int last_rtt;
/** do we know edns probe status already, for UDP_EDNS queries */
int edns_lame_known;
/** outside network this is part of */
struct outside_network* outnet;
/** list of interested parties that need callback on results. */
@@ -326,13 +343,17 @@ struct serviced_query {
* @param use_caps_for_id: enable to use 0x20 bits to encode id randomness.
* @param availports: array of available ports.
* @param numavailports: number of available ports in array.
* @param unwanted_threshold: when to take defensive action.
* @param unwanted_action: the action to take.
* @param unwanted_param: user parameter to action.
* @return: the new structure (with no pending answers) or NULL on error.
*/
struct outside_network* outside_network_create(struct comm_base* base,
size_t bufsize, size_t num_ports, char** ifs, int num_ifs,
int do_ip4, int do_ip6, size_t num_tcp, struct infra_cache* infra,
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
int numavailports);
int numavailports, size_t unwanted_threshold,
void (*unwanted_action)(void*), void* unwanted_param);
/**
* Delete outside_network structure.
+48 -78
View File
@@ -216,64 +216,35 @@ is_dir(const char* fname)
return 1;
}
/** convert a filename to full pathname in original filesys
* @param fname: the path name to convert.
* Must not be null or empty.
* @param cfg: config struct for chroot and chdir (if set).
* @param use_chdir: if false, only chroot is applied.
* @return pointer to static buffer which is: [chroot][chdir]fname
*/
static char*
fname_after_chroot(const char* fname, struct config_file* cfg, int use_chdir)
{
static char buf[1024];
int slashit = 0;
buf[0] = 0;
if(cfg->chrootdir && cfg->chrootdir[0] &&
strncmp(cfg->chrootdir, fname, strlen(cfg->chrootdir)) == 0) {
/* already full pathname, return it */
strncpy(buf, fname, sizeof(buf)-1);
buf[sizeof(buf)-1] = 0;
return buf;
}
/* chroot */
if(cfg->chrootdir && cfg->chrootdir[0]) {
/* start with chrootdir */
strncpy(buf, cfg->chrootdir, sizeof(buf)-1);
slashit = 1;
}
/* chdir */
if(fname[0] == '/' || !use_chdir) {
/* full path, no chdir */
} else if(cfg->directory && cfg->directory[0]) {
/* prepend chdir */
if(slashit && cfg->directory[0] != '/')
strncat(buf, "/", sizeof(buf)-strlen(buf)-1);
if(strncmp(cfg->chrootdir, cfg->directory,
strlen(cfg->chrootdir)) == 0)
strncat(buf, cfg->directory+strlen(cfg->chrootdir),
sizeof(buf)-strlen(buf)-1);
else strncat(buf, cfg->directory, sizeof(buf)-strlen(buf)-1);
slashit = 1;
}
/* fname */
if(slashit && fname[0] != '/')
strncat(buf, "/", sizeof(buf)-strlen(buf)-1);
strncat(buf, fname, sizeof(buf)-strlen(buf)-1);
buf[sizeof(buf)-1] = 0;
return buf;
}
/** get base dir of a fname */
static char*
basedir(const char* fname, struct config_file* cfg)
basedir(char* fname)
{
char* d = fname_after_chroot(fname, cfg, 1);
char* rev = strrchr(d, '/');
char* rev;
if(!fname) fatal_exit("out of memory");
rev = strrchr(fname, '/');
if(!rev) return NULL;
if(d == rev) return NULL;
if(fname == rev) return NULL;
rev[0] = 0;
return d;
return fname;
}
/** check chroot for a file string */
static void
check_chroot_string(const char* desc, char** ss,
const char* chrootdir, struct config_file* cfg)
{
char* str = *ss;
if(str && str[0]) {
*ss = fname_after_chroot(str, cfg, 1);
if(!*ss) fatal_exit("out of memory");
if(!is_file(*ss)) {
fatal_exit("%s: \"%s\" does not exist in chrootdir %s",
desc, str, chrootdir);
}
/* put in a new full path for continued checking */
free(str);
}
}
/** check file list, every file must be inside the chroot location */
@@ -282,24 +253,14 @@ check_chroot_filelist(const char* desc, struct config_strlist* list,
const char* chrootdir, struct config_file* cfg)
{
struct config_strlist* p;
char* old;
for(p=list; p; p=p->next) {
if(p->str && p->str[0]) {
if(!is_file(fname_after_chroot(p->str, cfg, 1))) {
fatal_exit("%s: \"%s\" does not exist in chrootdir %s",
desc, p->str, chrootdir);
}
old = p->str;
/* put in a new full path for continued checking */
p->str = strdup(fname_after_chroot(p->str, cfg, 1));
free(old);
}
check_chroot_string(desc, &p->str, chrootdir, cfg);
}
}
/** check configuration for errors */
static void
morechecks(struct config_file* cfg, char* fname)
morechecks(struct config_file* cfg, const char* fname)
{
warn_hosts("stub-host", cfg->stubs);
warn_hosts("forward-host", cfg->forwards);
@@ -336,21 +297,28 @@ morechecks(struct config_file* cfg, char* fname)
fatal_exit("config file %s is not inside chroot %s",
buf, cfg->chrootdir);
}
if(cfg->directory && cfg->directory[0] && !is_dir(
fname_after_chroot(cfg->directory, cfg, 0))) {
fatal_exit("bad chdir directory");
if(cfg->directory && cfg->directory[0]) {
char* ad = fname_after_chroot(cfg->directory, cfg, 0);
if(!ad) fatal_exit("out of memory");
if(!is_dir(ad)) fatal_exit("bad chdir directory");
free(ad);
}
if( (cfg->chrootdir && cfg->chrootdir[0]) ||
(cfg->directory && cfg->directory[0])) {
if(cfg->pidfile && cfg->pidfile[0] &&
basedir(cfg->pidfile, cfg) &&
!is_dir(basedir(cfg->pidfile, cfg))) {
fatal_exit("pidfile directory does not exist");
if(cfg->pidfile && cfg->pidfile[0]) {
char* ad = (cfg->pidfile[0]=='/')?strdup(cfg->pidfile):
fname_after_chroot(cfg->pidfile, cfg, 1);
char* bd = basedir(ad);
if(bd && !is_dir(bd))
fatal_exit("pidfile directory does not exist");
free(ad);
}
if(cfg->logfile && cfg->logfile[0] &&
basedir(cfg->logfile, cfg) &&
!is_dir(basedir(cfg->logfile, cfg))) {
fatal_exit("logfile directory does not exist");
if(cfg->logfile && cfg->logfile[0]) {
char* ad = fname_after_chroot(cfg->logfile, cfg, 1);
char* bd = basedir(ad);
if(bd && !is_dir(bd))
fatal_exit("logfile directory does not exist");
free(ad);
}
}
@@ -360,6 +328,8 @@ morechecks(struct config_file* cfg, char* fname)
cfg->trust_anchor_file_list, cfg->chrootdir, cfg);
check_chroot_filelist("trusted-keys-file",
cfg->trusted_keys_file_list, cfg->chrootdir, cfg);
check_chroot_string("dlv-anchor-file", &cfg->dlv_anchor_file,
cfg->chrootdir, cfg);
/* remove chroot setting so that modules are not stripping pathnames*/
free(cfg->chrootdir);
cfg->chrootdir = NULL;
@@ -383,7 +353,7 @@ morechecks(struct config_file* cfg, char* fname)
/** check config file */
static void
checkconf(char* cfgfile)
checkconf(const char* cfgfile)
{
struct config_file* cfg = config_create();
if(!cfg)
@@ -409,7 +379,7 @@ extern char* optarg;
int main(int argc, char* argv[])
{
int c;
char* f;
const char* f;
log_ident_set("unbound-checkconf");
log_init(NULL, 0, NULL);
checklock_start();
+151
View File
@@ -0,0 +1,151 @@
#!/bin/sh
#
# unbound-control-setup.sh - set up SSL certificates for unbound-control
#
# Copyright (c) 2008, NLnet Labs. All rights reserved.
#
# This software is open source.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of the NLNET LABS nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# settings:
# directory for files
DESTDIR=/usr/local/etc/unbound
# issuer and subject name for certificates
SERVERNAME=unbound
CLIENTNAME=unbound-control
# validity period for certificates
DAYS=7200
# size of keys in bits
BITS=1024
# base name for unbound server keys
SVR_BASE=unbound_server
# base name for unbound-control keys
CTL_BASE=unbound_control
# end of options
# functions:
error ( ) {
echo "$0 fatal error: $1"
exit 1
}
# check arguments:
while test $# -ne 0; do
case $1 in
-d)
if test $# -eq 1; then error "need argument for -d"; fi
DESTDIR="$2"
shift
;;
*)
echo "unbound-control-setup.sh - setup SSL keys for unbound-control"
echo " -d dir use directory to store keys and certificates."
echo " default: $DESTDIR"
exit 1
;;
esac
shift
done
# go!:
echo "setup in directory $DESTDIR"
cd "$DESTDIR" || error "could not cd"
# create certificate keys; do not recreate if they already exist.
if test -f $SVR_BASE.key; then
echo "$SVR_BASE.key exists"
else
echo "generating $SVR_BASE.key"
openssl genrsa -out $SVR_BASE.key $BITS || error "could not genrsa"
fi
if test -f $CTL_BASE.key; then
echo "$CTL_BASE.key exists"
else
echo "generating $CTL_BASE.key"
openssl genrsa -out $CTL_BASE.key $BITS || error "could not genrsa"
fi
# create self-signed cert for server
cat >request.cfg <<EOF
[req]
default_bits=$BITS
default_md=sha1
prompt=no
distinguished_name=req_distinguished_name
[req_distinguished_name]
commonName=$SERVERNAME
EOF
test -f request.cfg || error "could not create request.cfg"
echo "create $SVR_BASE.pem (self signed certificate)"
openssl req -key $SVR_BASE.key -config request.cfg -new -x509 -days $DAYS -out $SVR_BASE.pem || error "could not create $SVR_BASE.pem"
# create trusted usage pem
openssl x509 -in $SVR_BASE.pem -addtrust serverAuth -out $SVR_BASE"_trust.pem"
# create client request and sign it, piped
cat >request.cfg <<EOF
[req]
default_bits=$BITS
default_md=sha1
prompt=no
distinguished_name=req_distinguished_name
[req_distinguished_name]
commonName=$CLIENTNAME
EOF
test -f request.cfg || error "could not create request.cfg"
echo "create $CTL_BASE.pem (signed client certificate)"
openssl req -key $CTL_BASE.key -config request.cfg -new | openssl x509 -req -days $DAYS -CA $SVR_BASE"_trust.pem" -CAkey $SVR_BASE.key -CAcreateserial -out $CTL_BASE.pem
test -f $CTL_BASE.pem || error "could not create $CTL_BASE.pem"
# create trusted usage pem
# openssl x509 -in $CTL_BASE.pem -addtrust clientAuth -out $CTL_BASE"_trust.pem"
# see details with openssl x509 -noout -text < $SVR_BASE.pem
# echo "create $CTL_BASE""_browser.pfx (web client certificate)"
# echo "create webbrowser PKCS#12 .PFX certificate file. In Firefox import in:"
# echo "preferences - advanced - encryption - view certificates - your certs"
# echo "empty password is used, simply click OK on the password dialog box."
# openssl pkcs12 -export -in $CTL_BASE"_trust.pem" -inkey $CTL_BASE.key -name "unbound remote control client cert" -out $CTL_BASE"_browser.pfx" -password "pass:" || error "could not create browser certificate"
# remove crap
rm -f request.cfg
rm -f $CTL_BASE"_trust.pem" $SVR_BASE"_trust.pem" $SVR_BASE"_trust.srl"
echo "Setup success. Certificates created. Enable in unbound.conf file to use"
exit 0
+374
View File
@@ -0,0 +1,374 @@
/*
* checkconf/unbound-control.c - remote control utility for unbound.
*
* Copyright (c) 2008, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* The remote control utility contacts the unbound server over ssl and
* sends the command, receives the answer, and displays the result
* from the commandline.
*/
#include "config.h"
#include "util/log.h"
#include "util/config_file.h"
#include "util/locks.h"
#include "util/net_help.h"
/** Give unbound-control usage, and exit (1). */
static void
usage()
{
printf("Usage: unbound-control [options] command\n");
printf(" Remote control utility for unbound server.\n");
printf("Options:\n");
printf(" -c file config file, default is %s\n", CONFIGFILE);
printf(" -s ip[@port] server address, if omitted config is used.\n");
printf(" -h show this usage help.\n");
printf("Commands:\n");
printf(" start start server; runs unbound(8)\n");
printf(" stop stops the server\n");
printf(" reload reloads the server\n");
printf(" stats print statistics\n");
printf(" verbosity [number] change logging detail\n");
printf(" local_zone [name] [type] add new local zone\n");
printf(" local_zone_remove [name] remove local zone and its contents\n");
printf(" local_data [RR data...] add local data, for example\n");
printf(" local_data www.example.com A 192.0.2.1\n");
printf(" local_data_remove [name] remove local RR data from name\n");
printf(" dump_cache print cache to stdout\n");
printf(" load_cache load cache from stdin\n");
printf(" lookup [name] print nameservers for name\n");
printf(" flush [name] flushes common types for name from cache\n");
printf(" types: A, AAAA, MX, PTR, NS,\n");
printf(" SOA, CNAME, DNAME, SRV, NAPTR\n");
printf(" flush_type [name] [type] flush name, type from cache\n");
printf(" flush_zone [name] flush everything at or under name\n");
printf(" from rr and dnssec caches\n");
printf("Version %s\n", PACKAGE_VERSION);
printf("BSD licensed, see LICENSE in source package for details.\n");
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
exit(1);
}
/** exit with ssl error */
static void ssl_err(const char* s)
{
fprintf(stderr, "error: %s\n", s);
ERR_print_errors_fp(stderr);
exit(1);
}
/** setup SSL context */
static SSL_CTX*
setup_ctx(struct config_file* cfg)
{
char* s_cert, *c_key, *c_cert;
SSL_CTX* ctx;
s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1);
c_key = fname_after_chroot(cfg->control_key_file, cfg, 1);
c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1);
if(!s_cert || !c_key || !c_cert)
fatal_exit("out of memory");
ctx = SSL_CTX_new(SSLv23_client_method());
if(!ctx)
ssl_err("could not allocate SSL_CTX pointer");
if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2))
ssl_err("could not set SSL_OP_NO_SSLv2");
if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) ||
!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)
|| !SSL_CTX_check_private_key(ctx))
ssl_err("Error setting up SSL_CTX client key and cert");
if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1)
ssl_err("Error setting up SSL_CTX verify, server cert");
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
free(s_cert);
free(c_key);
free(c_cert);
return ctx;
}
/** contact the server with TCP connect */
static int
contact_server(const char* svr, struct config_file* cfg)
{
struct sockaddr_storage addr;
socklen_t addrlen;
int fd;
/* use svr or the first config entry */
if(!svr) {
if(cfg->control_ifs)
svr = cfg->control_ifs->str;
else svr = "127.0.0.1";
/* config 0 addr (everything), means ask localhost */
if(strcmp(svr, "0.0.0.0") == 0)
svr = "127.0.0.1";
else if(strcmp(svr, "::0") == 0 ||
strcmp(svr, "0::0") == 0 ||
strcmp(svr, "0::") == 0 ||
strcmp(svr, "::") == 0)
svr = "::1";
}
if(strchr(svr, '@')) {
if(!extstrtoaddr(svr, &addr, &addrlen))
fatal_exit("could not parse IP@port: %s", svr);
} else {
if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen))
fatal_exit("could not parse IP: %s", svr);
}
fd = socket(addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET,
SOCK_STREAM, 0);
if(fd == -1) {
#ifndef USE_WINSOCK
fatal_exit("socket: %s", strerror(errno));
#else
fatal_exit("socket: %s", wsa_strerror(WSAGetLastError()));
#endif
}
if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
log_addr(0, "address", &addr, addrlen);
#ifndef USE_WINSOCK
log_err("connect: %s", strerror(errno));
#else
log_err("connect: %s", wsa_strerror(WSAGetLastError()));
#endif
exit(1);
}
return fd;
}
/** setup SSL on the connection */
static SSL*
setup_ssl(SSL_CTX* ctx, int fd)
{
SSL* ssl;
X509* x;
int r;
ssl = SSL_new(ctx);
if(!ssl)
ssl_err("could not SSL_new");
SSL_set_connect_state(ssl);
(void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
if(!SSL_set_fd(ssl, fd))
ssl_err("could not SSL_set_fd");
while(1) {
ERR_clear_error();
if( (r=SSL_do_handshake(ssl)) == 1)
break;
r = SSL_get_error(ssl, r);
if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE)
ssl_err("SSL handshake failed");
/* wants to be called again */
}
/* check authenticity of server */
if(SSL_get_verify_result(ssl) != X509_V_OK)
ssl_err("SSL verification failed");
x = SSL_get_peer_certificate(ssl);
if(!x)
ssl_err("Server presented no peer certificate");
X509_free(x);
return ssl;
}
/** send stdin to server */
static void
send_file(SSL* ssl, FILE* in, char* buf, size_t sz)
{
while(fgets(buf, (int)sz, in)) {
if(SSL_write(ssl, buf, (int)strlen(buf)) <= 0)
ssl_err("could not SSL_write contents");
}
}
/** send command and display result */
static int
go_cmd(SSL* ssl, int argc, char* argv[])
{
const char* pre="UBCT";
const char* space=" ";
const char* newline="\n";
int was_error = 0, first_line = 1;
int r, i;
char buf[1024];
if(SSL_write(ssl, pre, (int)strlen(pre)) <= 0)
ssl_err("could not SSL_write");
for(i=0; i<argc; i++) {
if(SSL_write(ssl, space, (int)strlen(space)) <= 0)
ssl_err("could not SSL_write");
if(SSL_write(ssl, argv[i], (int)strlen(argv[i])) <= 0)
ssl_err("could not SSL_write");
}
if(SSL_write(ssl, newline, (int)strlen(newline)) <= 0)
ssl_err("could not SSL_write");
if(argc == 1 && strcmp(argv[0], "load_cache") == 0) {
send_file(ssl, stdin, buf, sizeof(buf));
}
while(1) {
ERR_clear_error();
if((r = SSL_read(ssl, buf, (int)sizeof(buf)-1)) <= 0) {
if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) {
/* EOF */
break;
}
ssl_err("could not SSL_read");
}
buf[r] = 0;
printf("%s", buf);
if(first_line && strncmp(buf, "error", 5) == 0)
was_error = 1;
first_line = 0;
}
return was_error;
}
/** go ahead and read config, contact server and perform command and display */
static int
go(const char* cfgfile, char* svr, int argc, char* argv[])
{
struct config_file* cfg;
int fd, ret;
SSL_CTX* ctx;
SSL* ssl;
/* read config */
if(!(cfg = config_create()))
fatal_exit("out of memory");
if(!config_read(cfg, cfgfile))
fatal_exit("could not read config file");
if(!cfg->remote_control_enable)
log_warn("control-enable is 'no' in the config file.");
ctx = setup_ctx(cfg);
/* contact server */
fd = contact_server(svr, cfg);
ssl = setup_ssl(ctx, fd);
/* send command */
ret = go_cmd(ssl, argc, argv);
SSL_free(ssl);
close(fd);
SSL_CTX_free(ctx);
config_delete(cfg);
return ret;
}
/** getopt global, in case header files fail to declare it. */
extern int optind;
/** getopt global, in case header files fail to declare it. */
extern char* optarg;
/** Main routine for unbound-control */
int main(int argc, char* argv[])
{
int c, ret;
const char* cfgfile = CONFIGFILE;
char* svr = NULL;
#ifdef USE_WINSOCK
int r;
WSADATA wsa_data;
#endif
#ifdef USE_THREAD_DEBUG
/* stop the file output from unbound-control, overwites the servers */
extern int check_locking_order;
check_locking_order = 0;
#endif /* USE_THREAD_DEBUG */
log_ident_set("unbound-control");
log_init(NULL, 0, NULL);
checklock_start();
#ifdef USE_WINSOCK
if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0)
fatal_exit("WSAStartup failed: %s", wsa_strerror(r));
#endif
ERR_load_crypto_strings();
ERR_load_SSL_strings();
OpenSSL_add_all_algorithms();
(void)SSL_library_init();
if(!RAND_status()) {
/* try to seed it */
unsigned char buf[256];
unsigned int v, seed=(unsigned)time(NULL) ^ (unsigned)getpid();
size_t i;
for(i=0; i<256/sizeof(v); i++) {
memmove(buf+i*sizeof(v), &v, sizeof(v));
v = v*seed + (unsigned int)i;
}
RAND_seed(buf, 256);
log_warn("no entropy, seeding openssl PRNG with time\n");
}
/* parse the options */
while( (c=getopt(argc, argv, "c:s:h")) != -1) {
switch(c) {
case 'c':
cfgfile = optarg;
break;
case 's':
svr = optarg;
break;
case '?':
case 'h':
default:
usage();
}
}
argc -= optind;
argv += optind;
if(argc == 0)
usage();
if(argc >= 1 && strcmp(argv[0], "start")==0) {
if(execlp("unbound", "unbound", "-c", cfgfile,
(char*)NULL) < 0) {
fatal_exit("could not exec unbound: %s",
strerror(errno));
}
}
ret = go(cfgfile, svr, argc, argv);
#ifdef USE_WINSOCK
WSACleanup();
#endif
checklock_stop();
return ret;
}
+1 -1
View File
@@ -99,7 +99,7 @@ isip6(const char* nm, char** res)
{
struct in6_addr addr;
/* [nibble.]{32}.ip6.arpa. is less than 128 */
char* hex = "0123456789abcdef";
const char* hex = "0123456789abcdef";
char buf[128];
char *p;
int i;
+27 -11
View File
@@ -45,13 +45,13 @@
struct comm_reply;
struct comm_point;
struct module_qstate;
struct tube;
int worker_handle_control_cmd(struct comm_point* ATTR_UNUSED(c),
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
struct comm_reply* ATTR_UNUSED(reply_info))
void worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
{
log_assert(0);
return 0;
}
int worker_handle_request(struct comm_point* ATTR_UNUSED(c),
@@ -78,6 +78,22 @@ int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
return 0;
}
int remote_accept_callback(struct comm_point* ATTR_UNUSED(c),
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
struct comm_reply* ATTR_UNUSED(repinfo))
{
log_assert(0);
return 0;
}
int remote_control_callback(struct comm_point* ATTR_UNUSED(c),
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
struct comm_reply* ATTR_UNUSED(repinfo))
{
log_assert(0);
return 0;
}
void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
{
log_assert(0);
@@ -108,13 +124,6 @@ worker_alloc_cleanup(void* ATTR_UNUSED(arg))
log_assert(0);
}
int
acl_list_cmp(const void* ATTR_UNUSED(k1), const void* ATTR_UNUSED(k2))
{
log_assert(0);
return 0;
}
int libworker_send_packet(ldns_buffer* ATTR_UNUSED(pkt),
struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(timeout),
@@ -150,6 +159,13 @@ int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
return 0;
}
void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
{
log_assert(0);
}
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
{
log_assert(0);
+4 -4
View File
@@ -966,8 +966,8 @@ service_loop(int udp_s, int listen_s, struct ringbuf* ring,
/** delayer main service routine */
static void
service(char* bind_str, int bindport, char* serv_str, size_t memsize,
int delay_msec)
service(const char* bind_str, int bindport, const char* serv_str,
size_t memsize, int delay_msec)
{
struct sockaddr_storage bind_addr, srv_addr;
socklen_t bind_len, srv_len;
@@ -1098,8 +1098,8 @@ extern char* optarg;
int main(int argc, char** argv)
{
int c; /* defaults */
char* server = "127.0.0.1@53";
char* bindto = "0.0.0.0";
const char* server = "127.0.0.1@53";
const char* bindto = "0.0.0.0";
int bindport = 0;
size_t memsize = 10*1024*1024;
int delay = 100;
+65 -3
View File
@@ -61,6 +61,20 @@
/** Global variable: the scenario. Saved here for when event_init is done. */
static struct replay_scenario* saved_scenario = NULL;
/** add timers and the values do not overflow or become negative */
static void
timeval_add(struct timeval* d, const struct timeval* add)
{
#ifndef S_SPLINT_S
d->tv_sec += add->tv_sec;
d->tv_usec += add->tv_usec;
while(d->tv_usec > 1000000 ) {
d->tv_usec -= 1000000;
d->tv_sec++;
}
#endif
}
void
fake_event_init(struct replay_scenario* scen)
{
@@ -98,6 +112,7 @@ repevt_string(enum replay_event_type t)
case repevt_front_query: return "QUERY";
case repevt_front_reply: return "CHECK_ANSWER";
case repevt_timeout: return "TIMEOUT";
case repevt_time_passes: return "TIME_PASSES";
case repevt_back_reply: return "REPLY";
case repevt_back_query: return "CHECK_OUT_QUERY";
case repevt_error: return "ERROR";
@@ -381,11 +396,13 @@ fake_pending_callback(struct replay_runtime* runtime,
struct fake_pending* p = runtime->pending_list;
struct comm_reply repinfo;
struct comm_point c;
void* cb_arg = p->cb_arg;
comm_point_callback_t* cb = p->callback;
void* cb_arg;
comm_point_callback_t* cb;
memset(&c, 0, sizeof(c));
if(!p) fatal_exit("No pending queries.");
cb_arg = p->cb_arg;
cb = p->callback;
log_assert(todo->qname == NULL); /* or find that one */
c.buffer = ldns_buffer_new(runtime->bufsize);
c.type = comm_udp;
@@ -406,6 +423,19 @@ fake_pending_callback(struct replay_runtime* runtime,
ldns_buffer_free(c.buffer);
}
/** pass time */
static void
time_passes(struct replay_runtime* runtime, struct replay_moment* mom)
{
timeval_add(&runtime->now_tv, &mom->elapse);
runtime->now_secs = (uint32_t)runtime->now_tv.tv_sec;
#ifndef S_SPLINT_S
log_info("elapsed %d.%6.6d now %d.%6.6d",
(int)mom->elapse.tv_sec, (int)mom->elapse.tv_usec,
(int)runtime->now_tv.tv_sec, (int)runtime->now_tv.tv_usec);
#endif
}
/**
* Advance to the next moment.
*/
@@ -469,6 +499,10 @@ do_moment_and_advance(struct replay_runtime* runtime)
advance_moment(runtime);
fake_pending_callback(runtime, mom, NETEVENT_CLOSED);
break;
case repevt_time_passes:
time_passes(runtime, runtime->now);
advance_moment(runtime);
break;
default:
fatal_exit("testbound: unknown event type %d",
runtime->now->evt_type);
@@ -688,10 +722,12 @@ outside_network_create(struct comm_base* base, size_t bufsize,
struct infra_cache* ATTR_UNUSED(infra),
struct ub_randstate* ATTR_UNUSED(rnd),
int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports),
int ATTR_UNUSED(numavailports))
int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold),
void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param))
{
struct outside_network* outnet = calloc(1,
sizeof(struct outside_network));
(void)unwanted_action;
if(!outnet)
return NULL;
outnet->base = base;
@@ -945,6 +981,26 @@ struct comm_point* comm_point_create_local(struct comm_base* ATTR_UNUSED(base),
return calloc(1, 1);
}
struct comm_point* comm_point_create_raw(struct comm_base* ATTR_UNUSED(base),
int ATTR_UNUSED(fd), int ATTR_UNUSED(writing),
comm_point_callback_t* ATTR_UNUSED(callback),
void* ATTR_UNUSED(callback_arg))
{
/* no pipe comm possible */
return calloc(1, 1);
}
void comm_point_start_listening(struct comm_point* ATTR_UNUSED(c),
int ATTR_UNUSED(newfd), int ATTR_UNUSED(sec))
{
/* no bg write pipe comm possible */
}
void comm_point_stop_listening(struct comm_point* ATTR_UNUSED(c))
{
/* no bg write pipe comm possible */
}
/* only cmd com _local gets deleted */
void comm_point_delete(struct comm_point* c)
{
@@ -1096,4 +1152,10 @@ void comm_timer_delete(struct comm_timer* timer)
free(timer);
}
struct event_base* comm_base_internal(struct comm_base* ATTR_UNUSED(b))
{
/* no pipe comm possible in testbound */
return NULL;
}
/*********** End of Dummy routines ***********/
+2 -2
View File
@@ -168,7 +168,7 @@ static void usage(char* nm)
static int hverb = 0;
/** exit with error */
static void error_exit(char* str)
static void error_exit(const char* str)
{
printf("error: %s\n", str);
exit(1);
@@ -235,7 +235,7 @@ lab_cmp(const void *x, const void *y)
/** create label entry */
static struct labdata*
lab_create(char* name)
lab_create(const char* name)
{
struct labdata* lab = (struct labdata*)calloc(1, sizeof(*lab));
if(!lab) error_exit("out of memory");
+37 -13
View File
@@ -61,7 +61,7 @@ static bool isendline(char c)
* @param keyword: the keyword to match
* @return: true if keyword present. False otherwise, and str unchanged.
*/
static bool str_keyword(const char** str, const char* keyword)
static bool str_keyword(char** str, const char* keyword)
{
size_t len = strlen(keyword);
assert(str && keyword);
@@ -92,9 +92,9 @@ entry_add_reply(struct entry* entry)
}
/** parse MATCH line */
static void matchline(const char* line, struct entry* e)
static void matchline(char* line, struct entry* e)
{
const char* parse = line;
char* parse = line;
while(*parse) {
if(isendline(*parse))
return;
@@ -104,12 +104,16 @@ static void matchline(const char* line, struct entry* e)
e->match_qtype = true;
} else if(str_keyword(&parse, "qname")) {
e->match_qname = true;
} else if(str_keyword(&parse, "subdomain")) {
e->match_subdomain = true;
} else if(str_keyword(&parse, "all")) {
e->match_all = true;
} else if(str_keyword(&parse, "ttl")) {
e->match_ttl = true;
} else if(str_keyword(&parse, "DO")) {
e->match_do = true;
} else if(str_keyword(&parse, "noedns")) {
e->match_noedns = true;
} else if(str_keyword(&parse, "UDP")) {
e->match_transport = transport_udp;
} else if(str_keyword(&parse, "TCP")) {
@@ -129,9 +133,9 @@ static void matchline(const char* line, struct entry* e)
}
/** parse REPLY line */
static void replyline(const char* line, ldns_pkt *reply)
static void replyline(char* line, ldns_pkt *reply)
{
const char* parse = line;
char* parse = line;
while(*parse) {
if(isendline(*parse))
return;
@@ -194,10 +198,10 @@ static void replyline(const char* line, ldns_pkt *reply)
}
/** parse ADJUST line */
static void adjustline(const char* line, struct entry* e,
static void adjustline(char* line, struct entry* e,
struct reply_packet* pkt)
{
const char* parse = line;
char* parse = line;
while(*parse) {
if(isendline(*parse))
return;
@@ -227,9 +231,11 @@ static struct entry* new_entry()
e->match_opcode = false;
e->match_qtype = false;
e->match_qname = false;
e->match_subdomain = false;
e->match_all = false;
e->match_ttl = false;
e->match_do = false;
e->match_noedns = false;
e->match_serial = false;
e->ixfr_soa_serial = 0;
e->match_transport = transport_any;
@@ -410,7 +416,7 @@ read_entry(FILE* in, const char* name, int *lineno, uint32_t* default_ttl,
{
struct entry* current = NULL;
char line[MAX_LINE];
const char* parse;
char* parse;
ldns_pkt_section add_section = LDNS_SECTION_QUESTION;
struct reply_packet *cur_reply = NULL;
bool reading_hex = false;
@@ -436,7 +442,7 @@ read_entry(FILE* in, const char* name, int *lineno, uint32_t* default_ttl,
cur_reply = entry_add_reply(current);
continue;
} else if(str_keyword(&parse, "$ORIGIN")) {
get_origin(name, *lineno, origin, (char*)parse);
get_origin(name, *lineno, origin, parse);
continue;
} else if(str_keyword(&parse, "$TTL")) {
*default_ttl = (uint32_t)atoi(parse);
@@ -484,9 +490,12 @@ read_entry(FILE* in, const char* name, int *lineno, uint32_t* default_ttl,
/* it must be a RR, parse and add to packet. */
ldns_rr* n = NULL;
ldns_status status;
status = ldns_rr_new_frm_str(&n, parse, *default_ttl,
*origin, prev_rr);
if (status != LDNS_STATUS_OK)
if(add_section == LDNS_SECTION_QUESTION)
status = ldns_rr_new_question_frm_str(
&n, parse, *origin, prev_rr);
else status = ldns_rr_new_frm_str(&n, parse,
*default_ttl, *origin, prev_rr);
if(status != LDNS_STATUS_OK)
error("%s line %d:\n\t%s: %s", name, *lineno,
ldns_get_errorstr_by_id(status), parse);
ldns_pkt_push_rr(cur_reply->reply, add_section, n);
@@ -634,7 +643,7 @@ match_all(ldns_pkt* q, ldns_pkt* p, bool mttl)
{ verbose(3, "allmatch: nscount different"); return 0;}
if(ldns_pkt_arcount(q) != ldns_pkt_arcount(p))
{ verbose(3, "allmatch: arcount different"); return 0;}
if(!match_list(ldns_pkt_question(q), ldns_pkt_question(p), mttl))
if(!match_list(ldns_pkt_question(q), ldns_pkt_question(p), 0))
{ verbose(3, "allmatch: qd section different"); return 0;}
if(!match_list(ldns_pkt_answer(q), ldns_pkt_answer(p), mttl))
{ verbose(3, "allmatch: an section different"); return 0;}
@@ -672,6 +681,17 @@ find_match(struct entry* entries, ldns_pkt* query_pkt,
continue;
}
}
if(p->match_subdomain) {
if(!get_owner(query_pkt) || !get_owner(reply) ||
(ldns_dname_compare(get_owner(query_pkt),
get_owner(reply)) != 0 &&
!ldns_dname_is_subdomain(
get_owner(query_pkt), get_owner(reply))))
{
verbose(3, "bad subdomain\n");
continue;
}
}
if(p->match_serial && get_serial(query_pkt) != p->ixfr_soa_serial) {
verbose(3, "bad serial\n");
continue;
@@ -680,6 +700,10 @@ find_match(struct entry* entries, ldns_pkt* query_pkt,
verbose(3, "no DO bit set\n");
continue;
}
if(p->match_noedns && ldns_pkt_edns(query_pkt)) {
verbose(3, "bad; EDNS OPT present\n");
continue;
}
if(p->match_transport != transport_any && p->match_transport != transport) {
verbose(3, "bad transport\n");
continue;
+6
View File
@@ -42,10 +42,12 @@
; if you leave it out, any opcode matches this entry.
; 'qtype' makes the query match the qtype from the reply
; 'qname' makes the query match the qname from the reply
; 'subdomain' makes the query match subdomains of qname from the reply
; 'serial=1023' makes the query match if ixfr serial is 1023.
; 'all' has to match header byte for byte and all rrs in packet.
; 'ttl' used with all, rrs in packet must also have matching TTLs.
; 'DO' will match only queries with DO bit set.
; 'noedns' matches queries without EDNS OPT records.
MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl]
MATCH [UDP|TCP] DO
MATCH ...
@@ -157,6 +159,8 @@ struct entry {
bool match_qtype;
/** match qname with answer qname */
bool match_qname;
/** match qname as subdomain of answer qname */
bool match_subdomain;
/** match SOA serial number, from auth section */
bool match_serial;
/** match all of the packet */
@@ -165,6 +169,8 @@ struct entry {
bool match_ttl;
/** match DO bit */
bool match_do;
/** match absence of EDNS OPT record in query */
bool match_noedns;
/** match query serial with this value. */
uint32_t ixfr_soa_serial;
/** match on UDP/TCP */
+19 -1
View File
@@ -54,7 +54,7 @@
* @return: true if found, false if not.
*/
static int
parse_keyword(char** line, char* keyword)
parse_keyword(char** line, const char* keyword)
{
size_t len = (size_t)strlen(keyword);
if(strncmp(*line, keyword, len) == 0) {
@@ -221,6 +221,8 @@ replay_moment_read(char* remain, FILE* in, const char* name, int* lineno,
readentry = 1;
} else if(parse_keyword(&remain, "TIMEOUT")) {
mom->evt_type = repevt_timeout;
} else if(parse_keyword(&remain, "TIME_PASSES")) {
mom->evt_type = repevt_time_passes;
} else if(parse_keyword(&remain, "ERROR")) {
mom->evt_type = repevt_error;
} else {
@@ -242,6 +244,22 @@ replay_moment_read(char* remain, FILE* in, const char* name, int* lineno,
return NULL;
}
}
if(parse_keyword(&remain, "ELAPSE")) {
double sec;
errno = 0;
sec = strtod(remain, &remain);
if(sec == 0. && errno != 0) {
log_err("line %d: could not parse ELAPSE: %s (%s)",
*lineno, remain, strerror(errno));
free(mom);
return NULL;
}
#ifndef S_SPLINT_S
mom->elapse.tv_sec = (int)sec;
mom->elapse.tv_usec = (int)((sec - (double)mom->elapse.tv_sec)
*1000000. + 0.5);
#endif
}
if(readentry) {
mom->match = read_entry(in, name, lineno, ttl, or, prev);
+7
View File
@@ -58,6 +58,8 @@
* o CHECK_OUT_QUERY - followed by entry (if copy-id it is also reply).
* o REPLY - followed by entry
* o TIMEOUT
* o TIME_PASSES ELAPSE [seconds] - increase 'now' time counter, can be
* a floating point number.
* o ERROR
* ; following entry starts on the next line, ENTRY_BEGIN.
* ; more STEP items
@@ -149,6 +151,8 @@ struct replay_moment {
repevt_front_reply,
/** timeout */
repevt_timeout,
/** time passes */
repevt_time_passes,
/** reply arrives from the network */
repevt_back_reply,
/** test fails if query to the network does not match */
@@ -162,6 +166,9 @@ struct replay_moment {
/** The sent packet must match this. Incoming events, the data. */
struct entry* match;
/** the amount of time that passes */
struct timeval elapse;
/** address that must be matched, or packet remote host address. */
struct sockaddr_storage addr;
/** length of addr, if 0, then any address will do */
+4 -4
View File
@@ -62,7 +62,7 @@ void usage(char* argv[])
/** open TCP socket to svr */
static int
open_svr(char* svr, int udp)
open_svr(const char* svr, int udp)
{
struct sockaddr_storage addr;
socklen_t addrlen;
@@ -96,7 +96,7 @@ open_svr(char* svr, int udp)
/** write a query over the TCP fd */
static void
write_q(int fd, int udp, ldns_buffer* buf, int id,
char* strname, char* strtype, char* strclass)
const char* strname, const char* strtype, const char* strclass)
{
struct query_info qinfo;
ldns_rdf* rdf;
@@ -210,7 +210,7 @@ recv_one(int fd, int udp, ldns_buffer* buf)
/** send the TCP queries and print answers */
static void
send_em(char* svr, int udp, int noanswer, int num, char** qs)
send_em(const char* svr, int udp, int noanswer, int num, char** qs)
{
ldns_buffer* buf = ldns_buffer_new(65553);
int fd = open_svr(svr, udp);
@@ -251,7 +251,7 @@ extern char* optarg;
int main(int argc, char** argv)
{
int c;
char* svr = "127.0.0.1";
const char* svr = "127.0.0.1";
int udp = 0;
int noanswer = 0;
+54 -3
View File
@@ -42,6 +42,7 @@
#include "testcode/ldns-testpkts.h"
#include "testcode/replay.h"
#include "testcode/fake_event.h"
#include "daemon/remote.h"
/**
* include the main program from the unbound daemon.
@@ -64,6 +65,7 @@ testbound_usage()
printf("\ttest the unbound daemon.\n");
printf("-h this help\n");
printf("-p file playback text file\n");
printf("-2 detect SHA256 support (exit code 0 or 1)\n");
printf("-o str unbound commandline options separated by spaces.\n");
printf("Version %s\n", PACKAGE_VERSION);
printf("BSD licensed, see LICENSE file in source package.\n");
@@ -80,9 +82,9 @@ testbound_usage()
* @param pass_argv: the argv to pass to unbound. Modified.
*/
static void
add_opts(char* optarg, int* pass_argc, char* pass_argv[])
add_opts(const char* optarg, int* pass_argc, char* pass_argv[])
{
char *p = optarg, *np;
const char *p = optarg, *np;
size_t len;
while(p && isspace((int)*p))
p++;
@@ -222,8 +224,17 @@ main(int argc, char* argv[])
pass_argc = 1;
pass_argv[0] = "unbound";
add_opts("-d", &pass_argc, pass_argv);
while( (c=getopt(argc, argv, "ho:p:")) != -1) {
while( (c=getopt(argc, argv, "2ho:p:")) != -1) {
switch(c) {
case '2':
#ifdef HAVE_EVP_SHA256
printf("SHA256 supported\n");
exit(0);
#else
printf("SHA256 not supported\n");
exit(1);
#endif
break;
case 'p':
playback_file = optarg;
break;
@@ -268,3 +279,43 @@ main(int argc, char* argv[])
log_info("Testbound Exit Success");
return res;
}
/* fake remote control */
struct listen_port* daemon_remote_open_ports(struct config_file*
ATTR_UNUSED(cfg))
{
return NULL;
}
struct daemon_remote* daemon_remote_create(struct worker* ATTR_UNUSED(worker))
{
return (struct daemon_remote*)calloc(1,1);
}
void daemon_remote_delete(struct daemon_remote* rc)
{
free(rc);
}
int daemon_remote_open_accept(struct daemon_remote* ATTR_UNUSED(rc),
struct listen_port* ATTR_UNUSED(ports))
{
return 1;
}
int remote_accept_callback(struct comm_point* ATTR_UNUSED(c),
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
struct comm_reply* ATTR_UNUSED(repinfo))
{
log_assert(0);
return 0;
}
int remote_control_callback(struct comm_point* ATTR_UNUSED(c),
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
struct comm_reply* ATTR_UNUSED(repinfo))
{
log_assert(0);
return 0;
}
+25 -23
View File
@@ -89,7 +89,7 @@ alloc_test() {
static void
net_test()
{
char* t4[] = {"\000\000\000\000",
const char* t4[] = {"\000\000\000\000",
"\200\000\000\000",
"\300\000\000\000",
"\340\000\000\000",
@@ -289,15 +289,15 @@ rtt_test()
rtt_init(&r);
/* initial value sensible */
unit_assert( rtt_timeout(&r) == init );
rtt_lost(&r);
rtt_lost(&r, init);
unit_assert( rtt_timeout(&r) == init*2 );
rtt_lost(&r);
rtt_lost(&r, init*2);
unit_assert( rtt_timeout(&r) == init*4 );
rtt_update(&r, 4000);
unit_assert( rtt_timeout(&r) >= 2000 );
rtt_lost(&r);
rtt_lost(&r, rtt_timeout(&r) );
for(i=0; i<100; i++) {
rtt_lost(&r);
rtt_lost(&r, rtt_timeout(&r) );
unit_assert( rtt_timeout(&r) > RTT_MIN_TIMEOUT-1);
unit_assert( rtt_timeout(&r) < RTT_MAX_TIMEOUT+1);
}
@@ -315,59 +315,60 @@ infra_test()
struct infra_cache* slab;
struct config_file* cfg = config_create();
uint32_t now = 0;
uint8_t edns_lame;
int vs, to;
struct infra_host_key* k;
struct infra_host_data* d;
int init = 376;
int dlame, alame, olame;
int dlame, rlame, alame, olame;
slab = infra_create(cfg);
unit_assert( infra_host(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), now, &vs, &to) );
unit_assert( vs == 0 && to == init );
(socklen_t)sizeof(int), now, &vs, &edns_lame, &to) );
unit_assert( vs == 0 && to == init && edns_lame == 0 );
unit_assert( infra_rtt_update(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), -1, now) );
(socklen_t)sizeof(int), -1, init, now) );
unit_assert( infra_host(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), now, &vs, &to) );
unit_assert( vs == 0 && to == init*2 );
(socklen_t)sizeof(int), now, &vs, &edns_lame, &to) );
unit_assert( vs == 0 && to == init*2 && edns_lame == 0 );
unit_assert( infra_edns_update(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), -1, now) );
unit_assert( infra_host(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), now, &vs, &to) );
unit_assert( vs == -1 && to == init*2 );
(socklen_t)sizeof(int), now, &vs, &edns_lame, &to) );
unit_assert( vs == -1 && to == init*2 && edns_lame == 1);
now += cfg->host_ttl + 10;
unit_assert( infra_host(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), now, &vs, &to) );
unit_assert( vs == 0 && to == init );
(socklen_t)sizeof(int), now, &vs, &edns_lame, &to) );
unit_assert( vs == 0 && to == init && edns_lame == 0 );
unit_assert( infra_set_lame(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), zone, zonelen, now, 0,
(socklen_t)sizeof(int), zone, zonelen, now, 0, 0,
LDNS_RR_TYPE_A) );
unit_assert( (d=infra_lookup_host(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), 0, now, &k)) );
unit_assert( d->ttl == now+cfg->host_ttl );
unit_assert( d->edns_version == 0 );
unit_assert( infra_lookup_lame(d, zone, zonelen, now,
&dlame, &alame, &olame) );
unit_assert(!dlame && alame && !olame);
&dlame, &rlame, &alame, &olame) );
unit_assert(!dlame && !rlame && alame && !olame);
unit_assert( !infra_lookup_lame(d, zone, zonelen,
now+cfg->lame_ttl+10, &dlame, &alame, &olame) );
now+cfg->lame_ttl+10, &dlame, &rlame, &alame, &olame) );
unit_assert( !infra_lookup_lame(d, (uint8_t*)"\000", 1, now,
&dlame, &alame, &olame) );
&dlame, &rlame, &alame, &olame) );
lock_rw_unlock(&k->entry.lock);
/* test merge of data */
unit_assert( infra_set_lame(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), zone, zonelen, now, 0,
(socklen_t)sizeof(int), zone, zonelen, now, 0, 0,
LDNS_RR_TYPE_AAAA) );
unit_assert( (d=infra_lookup_host(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), 0, now, &k)) );
unit_assert( infra_lookup_lame(d, zone, zonelen, now,
&dlame, &alame, &olame) );
unit_assert(!dlame && alame && olame);
&dlame, &rlame, &alame, &olame) );
unit_assert(!dlame && !rlame && alame && olame);
lock_rw_unlock(&k->entry.lock);
infra_delete(slab);
@@ -412,6 +413,7 @@ main(int argc, char* argv[])
printf("Start of %s unit test.\n", PACKAGE_STRING);
ERR_load_crypto_strings();
checklock_start();
neg_test();
rnd_test();
verify_test();
net_test();
+2
View File
@@ -63,5 +63,7 @@ void dname_test();
void anchors_test();
/** unit test for verification functions */
void verify_test();
/** unit test for negative cache functions */
void neg_test();
#endif /* TESTCODE_UNITMAIN_H */
+527
View File
@@ -0,0 +1,527 @@
/*
* testcode/unitneg.c - unit test for negative cache routines.
*
* Copyright (c) 2008, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* \file
* Calls negative cache unit tests. Exits with code 1 on a failure.
*/
#include "config.h"
#include "util/log.h"
#include "util/net_help.h"
#include "util/data/packed_rrset.h"
#include "util/data/dname.h"
#include "testcode/unitmain.h"
#include "validator/val_neg.h"
/** verbose unit test for negative cache */
static int negverbose = 0;
/** debug printout of neg cache */
static void print_neg_cache(struct val_neg_cache* neg)
{
char buf[1024];
struct val_neg_zone* z;
struct val_neg_data* d;
printf("neg_cache print\n");
printf("memuse %d of %d\n", (int)neg->use, (int)neg->max);
printf("maxiter %d\n", (int)neg->nsec3_max_iter);
printf("first=%x last=%x\n", (unsigned)neg->first, (unsigned)neg->last);
printf("%d zones\n", (int)neg->tree.count);
RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) {
dname_str(z->name, buf);
printf("%24s", buf);
printf(" len=%2.2d labs=%d inuse=%d count=%d tree.count=%d\n",
(int)z->len, z->labs, (int)z->in_use, z->count,
(int)z->tree.count);
}
RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) {
printf("\n");
dname_print(stdout, NULL, z->name);
printf(" zone details\n");
printf("len=%2.2d labs=%d inuse=%d count=%d tree.count=%d\n",
(int)z->len, z->labs, (int)z->in_use, z->count,
(int)z->tree.count);
if(z->parent) {
printf("parent=");
dname_print(stdout, NULL, z->parent->name);
printf("\n");
} else {
printf("parent=NULL\n");
}
RBTREE_FOR(d, struct val_neg_data*, &z->tree) {
dname_str(d->name, buf);
printf("%24s", buf);
printf(" len=%2.2d labs=%d inuse=%d count=%d\n",
(int)d->len, d->labs, (int)d->in_use, d->count);
}
}
}
/** get static pointer to random zone name */
static char* get_random_zone()
{
static char zname[256];
int labels = random() % 3;
int i;
char* p = zname;
int labnum;
for(i=0; i<labels; i++) {
labnum = random()%10;
snprintf(p, 256-(p-zname), "\003%3.3d", labnum);
p+=4;
}
snprintf(p, 256-(p-zname), "\007example\003com");
return zname;
}
/** get static pointer to random data names from and to */
static void get_random_data(char** fromp, char** top, char* zname)
{
static char buf1[256], buf2[256];
int type;
int lab1, lab2;
int labnum1[10], labnum2[10];
int i;
char* p;
*fromp = buf1;
*top = buf2;
type = random()%10;
if(type == 0) {
/* ENT */
lab1 = random() %3 + 1;
lab2 = lab1 + random()%3 + 1;
for(i=0; i<lab1; i++) {
labnum1[i] = random()%100;
labnum2[i] = labnum1[i];
}
for(i=lab1; i<lab2; i++) {
labnum2[i] = random()%100;
}
} else if(type == 1) {
/* end of zone */
lab2 = 0;
lab1 = random()%3 + 1;
for(i=0; i<lab1; i++) {
labnum1[i] = random()%100;
}
} else if(type == 2) {
/* start of zone */
lab1 = 0;
lab2 = random()%3 + 1;
for(i=0; i<lab2; i++) {
labnum2[i] = random()%100;
}
} else {
/* normal item */
int common = random()%3;
lab1 = random() %3 + 1;
lab2 = random() %3 + 1;
for(i=0; i<common; i++) {
labnum1[i] = random()%100;
labnum2[i] = labnum1[i];
}
labnum1[common] = random()%100;
labnum2[common] = labnum1[common] + random()%20;
for(i=common; i<lab1; i++)
labnum1[i] = random()%100;
for(i=common; i<lab2; i++)
labnum2[i] = random()%100;
}
/* construct first */
p = buf1;
for(i=0; i<lab1; i++) {
snprintf(p, 256-(p-buf1), "\003%3.3d", labnum1[i]);
p+=4;
}
snprintf(p, 256-(p-buf1), "%s", zname);
/* construct 2nd */
p = buf2+2;
for(i=0; i<lab2; i++) {
snprintf(p, 256-(p-buf2)-3, "\003%3.3d", labnum2[i]);
p+=4;
}
snprintf(p, 256-(p-buf2)-3, "%s", zname);
buf2[0] = (char)(strlen(buf2+2)+1);
buf2[1] = 0;
if(negverbose) {
log_nametypeclass(0, "add from", (uint8_t*)buf1, 0, 0);
log_nametypeclass(0, "add to ", (uint8_t*)buf2+2, 0, 0);
}
}
/** add a random item */
static void add_item(struct val_neg_cache* neg)
{
struct val_neg_zone* z;
struct packed_rrset_data rd;
struct ub_packed_rrset_key nsec;
size_t rr_len;
uint32_t rr_ttl;
uint8_t* rr_data;
char* zname = get_random_zone();
char* from, *to;
if(negverbose)
log_nametypeclass(0, "add to zone", (uint8_t*)zname, 0, 0);
z = neg_find_zone(neg, (uint8_t*)zname, strlen(zname)+1,
LDNS_RR_CLASS_IN);
if(!z) {
z = neg_create_zone(neg, (uint8_t*)zname, strlen(zname)+1,
LDNS_RR_CLASS_IN);
}
unit_assert(z);
val_neg_zone_take_inuse(z);
/* construct random NSEC item */
get_random_data(&from, &to, zname);
/* create nsec and insert it */
memset(&rd, 0, sizeof(rd));
memset(&nsec, 0, sizeof(nsec));
nsec.rk.dname = (uint8_t*)from;
nsec.rk.dname_len = strlen(from)+1;
nsec.rk.type = htons(LDNS_RR_TYPE_NSEC);
nsec.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
nsec.entry.data = &rd;
rd.security = sec_status_secure;
rd.count = 1;
rd.rr_len = &rr_len;
rr_len = 19;
rd.rr_ttl = &rr_ttl;
rr_ttl = 0;
rd.rr_data = &rr_data;
rr_data = (uint8_t*)to;
neg_insert_data(neg, z, &nsec);
}
/** remove a random item */
static void remove_item(struct val_neg_cache* neg)
{
int n, i;
struct val_neg_data* d;
rbnode_t* walk;
struct val_neg_zone* z;
if(neg->tree.count == 0)
return; /* nothing to delete */
/* pick a random zone */
walk = rbtree_first(&neg->tree); /* first highest parent, big count */
z = (struct val_neg_zone*)walk;
n = random() % (int)(z->count);
if(negverbose)
printf("neg stress delete zone %d\n", n);
i=0;
walk = rbtree_first(&neg->tree);
z = (struct val_neg_zone*)walk;
while(i!=n+1 && walk && walk != RBTREE_NULL && !z->in_use) {
walk = rbtree_next(walk);
z = (struct val_neg_zone*)walk;
if(z->in_use)
i++;
}
if(!walk || walk == RBTREE_NULL)
return;
if(!z->in_use)
return;
if(negverbose)
log_nametypeclass(0, "delete zone", z->name, 0, 0);
/* pick a random nsec item. - that is in use */
walk = rbtree_first(&z->tree); /* first is highest parent */
d = (struct val_neg_data*)walk;
n = random() % (int)(d->count);
if(negverbose)
printf("neg stress delete item %d\n", n);
i=0;
walk = rbtree_first(&z->tree);
d = (struct val_neg_data*)walk;
while(i!=n+1 && walk && walk != RBTREE_NULL && !d->in_use) {
walk = rbtree_next(walk);
d = (struct val_neg_data*)walk;
if(d->in_use)
i++;
}
if(!walk || walk == RBTREE_NULL)
return;
if(d->in_use) {
if(negverbose)
log_nametypeclass(0, "neg delete item:", d->name, 0, 0);
neg_delete_data(neg, d);
}
}
/** sum up the zone trees */
static size_t sumtrees_all(struct val_neg_cache* neg)
{
size_t res = 0;
struct val_neg_zone* z;
RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) {
res += z->tree.count;
}
return res;
}
/** sum up the zone trees, in_use only */
static size_t sumtrees_inuse(struct val_neg_cache* neg)
{
size_t res = 0;
struct val_neg_zone* z;
struct val_neg_data* d;
RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) {
/* get count of highest parent for num in use */
d = (struct val_neg_data*)rbtree_first(&z->tree);
if(d && (rbnode_t*)d!=RBTREE_NULL)
res += d->count;
}
return res;
}
/** check if lru is still valid */
static void check_lru(struct val_neg_cache* neg)
{
struct val_neg_data* p, *np;
size_t num = 0;
size_t inuse;
p = neg->first;
while(p) {
if(!p->prev) {
unit_assert(neg->first == p);
}
np = p->next;
if(np) {
unit_assert(np->prev == p);
} else {
unit_assert(neg->last == p);
}
num++;
p = np;
}
inuse = sumtrees_inuse(neg);
if(negverbose)
printf("num lru %d, inuse %d, all %d\n",
(int)num, (int)sumtrees_inuse(neg),
(int)sumtrees_all(neg));
unit_assert( num == inuse);
unit_assert( inuse <= sumtrees_all(neg));
}
/** sum up number of items inuse in subtree */
static int sum_subtree_inuse(struct val_neg_zone* zone,
struct val_neg_data* data)
{
struct val_neg_data* d;
int num = 0;
RBTREE_FOR(d, struct val_neg_data*, &zone->tree) {
if(dname_subdomain_c(d->name, data->name)) {
if(d->in_use)
num++;
}
}
return num;
}
/** sum up number of items inuse in subtree */
static int sum_zone_subtree_inuse(struct val_neg_cache* neg,
struct val_neg_zone* zone)
{
struct val_neg_zone* z;
int num = 0;
RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) {
if(dname_subdomain_c(z->name, zone->name)) {
if(z->in_use)
num++;
}
}
return num;
}
/** check point in data tree */
static void check_data(struct val_neg_zone* zone, struct val_neg_data* data)
{
unit_assert(data->count > 0);
if(data->parent) {
unit_assert(data->parent->count >= data->count);
if(data->parent->in_use) {
unit_assert(data->parent->count > data->count);
}
unit_assert(data->parent->labs == data->labs-1);
/* and parent must be one label shorter */
unit_assert(data->name[0] == (data->len-data->parent->len-1));
unit_assert(query_dname_compare(data->name + data->name[0]+1,
data->parent->name) == 0);
} else {
/* must be apex */
unit_assert(dname_is_root(data->name));
}
/* tree property: */
unit_assert(data->count == sum_subtree_inuse(zone, data));
}
/** check if tree of data in zone is valid */
static void checkzonetree(struct val_neg_zone* zone)
{
struct val_neg_data* d;
/* check all data in tree */
RBTREE_FOR(d, struct val_neg_data*, &zone->tree) {
check_data(zone, d);
}
}
/** check if negative cache is still valid */
static void check_zone_invariants(struct val_neg_cache* neg,
struct val_neg_zone* zone)
{
unit_assert(zone->nsec3_hash == 0);
unit_assert(zone->tree.cmp == &val_neg_data_compare);
unit_assert(zone->count != 0);
if(zone->tree.count == 0)
unit_assert(!zone->in_use);
else {
if(!zone->in_use) {
/* details on error */
log_nametypeclass(0, "zone", zone->name, 0, 0);
log_err("inuse %d count=%d tree.count=%d",
zone->in_use, zone->count,
(int)zone->tree.count);
if(negverbose)
print_neg_cache(neg);
}
unit_assert(zone->in_use);
}
if(zone->parent) {
unit_assert(zone->parent->count >= zone->count);
if(zone->parent->in_use) {
unit_assert(zone->parent->count > zone->count);
}
unit_assert(zone->parent->labs == zone->labs-1);
/* and parent must be one label shorter */
unit_assert(zone->name[0] == (zone->len-zone->parent->len-1));
unit_assert(query_dname_compare(zone->name + zone->name[0]+1,
zone->parent->name) == 0);
} else {
/* must be apex */
unit_assert(dname_is_root(zone->name));
}
/* tree property: */
unit_assert(zone->count == sum_zone_subtree_inuse(neg, zone));
/* check structure of zone data tree */
checkzonetree(zone);
}
/** check if negative cache is still valid */
static void check_neg_invariants(struct val_neg_cache* neg)
{
struct val_neg_zone* z;
/* check structure of LRU list */
check_lru(neg);
unit_assert(neg->max == 1024*1024);
unit_assert(neg->nsec3_max_iter == 1500);
unit_assert(neg->tree.cmp == &val_neg_zone_compare);
if(neg->tree.count == 0) {
/* empty */
unit_assert(neg->tree.count == 0);
unit_assert(neg->first == NULL);
unit_assert(neg->last == NULL);
unit_assert(neg->use == 0);
return;
}
unit_assert(neg->first != NULL);
unit_assert(neg->last != NULL);
RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) {
check_zone_invariants(neg, z);
}
}
/** perform stress test on insert and delete in neg cache */
static void stress_test(struct val_neg_cache* neg)
{
int i;
if(negverbose)
printf("negcache test\n");
for(i=0; i<100; i++) {
if(random() % 10 < 8)
add_item(neg);
else remove_item(neg);
check_neg_invariants(neg);
}
/* empty it */
if(negverbose)
printf("neg stress empty\n");
while(neg->first) {
remove_item(neg);
check_neg_invariants(neg);
}
if(negverbose)
printf("neg stress emptied\n");
unit_assert(neg->first == NULL);
/* insert again */
for(i=0; i<100; i++) {
if(random() % 10 < 8)
add_item(neg);
else remove_item(neg);
check_neg_invariants(neg);
}
}
void neg_test()
{
struct val_neg_cache* neg;
srandom(48);
/* create with defaults */
neg = val_neg_create(NULL, 1500);
unit_assert(neg);
stress_test(neg);
neg_cache_delete(neg);
}
+10
View File
@@ -140,6 +140,9 @@ should_be_bogus(struct ub_packed_rrset_key* rrset)
entry.data;
if(d->rrsig_count == 0)
return 1;
/* name 'bogus' as first label signals bogus */
if(rrset->rk.dname_len > 6 && memcmp(rrset->rk.dname+1, "bogus", 5)==0)
return 1;
return 0;
}
@@ -468,6 +471,13 @@ verify_test()
verifytest_file("testdata/test_signatures.6", "20080416005004");
verifytest_file("testdata/test_signatures.7", "20070829144150");
verifytest_file("testdata/test_signatures.8", "20070829144150");
#ifdef HAVE_EVP_SHA256
verifytest_file("testdata/test_signatures.9", "20070829144150");
verifytest_file("testdata/test_signatures.11", "20070829144150");
#endif
#ifdef HAVE_EVP_SHA512
verifytest_file("testdata/test_signatures.10", "20070829144150");
#endif
dstest_file("testdata/test_ds_sig.1");
nsectest();
nsec3_hash_test("testdata/test_nsec3_hash.1");
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
example.com. 3600 IN DS 1443 8 1 54f8ccd08089fd8b7c1b51d487eadf1c527dece4 ; xihaz-mufit-bybem-nezam-ryzuc-rugyt-gucyv-pulec-sygyl-tiriv-goxox
+1
View File
@@ -0,0 +1 @@
example.com. 3600 IN DNSKEY 256 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1443 (zsk), size = 1024b}
+10
View File
@@ -0,0 +1,10 @@
Private-key-format: v1.2
Algorithm: 8 (RSASHA256)
Modulus: t31aqPMTY/KfPbU4bl2hJ/2EXMyvl2HPPbBpne9Nr7SjmvsCNMCqYDXIf8Hf5oAyKFSbm5xlJ9Wqjv6Q5pETzIWP1qK86YDWfX4kt68mr+jK9DKPFA3ZBvz0vJo1RPmgpkiIv67LKE1bcoNHdJJtD8YHBA0MdVxmL4kNHdELSvs=
PublicExponent: AQAB
PrivateExponent: azCanqnpgPDCX90Wyzp9I4xxH3kfdrLXyzTcbjvWyTcggC/0WPbYUP36U8/hSZlIM9FBWgVh/oROb9x8r4S+6DT5k3tdhI303AL6bC8x1PBCzHjXBmYa9JvPKx/7a1hpSVOw9iJJh0Y4IclrfA8Ssdqxkj5QdNvR1CqDYTvIH/E=
Prime1: 4yIEKoY9ew1mX7+MUA8T1sGp64VzTiFpnn/8eomwdYVEsX6Sg563qLEn6IuORxrqCz8Ae3qfgVkT0J96ArURsw==
Prime2: zs9dU2j2jlToxIXtKu+YeO7QCKd1gVP6beI9IxjMYm21opsVvJ/xMlHu9aocGuCgvfmFyu/ShhsF/IPlFkvtmQ==
Exponent1: EAy8TKD1wTc+L6/iY1ndZgSDVFA2yKOVygxzM9l87aEALKasBb72bWYvUsBhymZ9eVP3XcJZeRNpUgmi3oQa/w==
Exponent2: nukr9wmyWo/YBBo8sT9F07b9V4kFe4jB52luPOezNPbEGNw+CaCEv3vBuDcsPWLZYOC488Tv6WgeY3gdsdJKEQ==
Coefficient: Fr7ARq2yRTv8+1ZAAwv2gbDa92RZxdZzj9hpC+/64kjCxq5//2haIhU/wtgDbBlr99Uk90cXf6F8AeaqCYgjLQ==
+1
View File
@@ -0,0 +1 @@
example.com. 3600 IN DS 18320 10 1 c75d2cba6104e3962f93f326b1cbbee877e22f2d ; xucoh-torir-pamyb-gomon-kyrun-fased-kuses-rizuv-motov-dered-texyx
+1
View File
@@ -0,0 +1 @@
example.com. 3600 IN DNSKEY 256 3 10 AwEAAb3HJP1WF0wWvk9VqqZ2+xTpURPSwyiZcNRlO/hAXJisMA4/ZN2Kf0aNGewVDa6IhT8ehww5FBvVJm3R1KW/hqO+H3WzvCBpVDv1JdDqZvHMGiqEd2lCfKz4+fxuJ+HeUJBZlTz6pm9Rlqevry5uB7sKpgddDe2fK9CFCr7M1BzX ;{id = 18320 (zsk), size = 1024b}

Some files were not shown because too many files have changed in this diff Show More