Index: vendor/bind/dist/contrib/bind/CHANGES =================================================================== --- vendor/bind/dist/contrib/bind/CHANGES (revision 109982) +++ vendor/bind/dist/contrib/bind/CHANGES (revision 109983) @@ -1,3904 +1,3904 @@ + --- 8.3.4-REL released --- (Thu Nov 14 05:45:26 PST 2002) + 1469. [bug] buffer length calculation for PX was wrong. 1468. [bug] ns_name_ntol() could overwite a zero length buffer. -1467. [bug] off by one bug in ns_makecannon(). - 1466. [bug] large ENDS UDP buffer size could trigger a assertion. 1465. [bug] possible NULL pointer dereference in db_sec.c -1464. [bug] the buffer used to construct the -ve record was not +1464. [bug] the buffer used to construct the -ve record was not big enough for all possible SOA records. use pointer arithmetic to calculate the remaining size in this buffer. 1463. [bug] use serial space arithmetic to determine if a SIG is too old, in the future or has internally constistant times. 1462. [bug] write buffer overflow in make_rr(). --- 8.3.3-REL released --- (Wed Jun 26 21:15:43 PDT 2002) 1301. [func] log attempts to exploit #1300. 1300. [bug] Remote buffer overrun. 1299. [func] Log to xfer-in when a named-xfer fails and one of the masters returned REFUSED. 1298. [bug] named could leak a OPT record when returning a negative response. 1297. [func] 'ndc restart' will now attempt to preserve the arguments named was started with. Use 'ndc restart --' to clear the arguements. Use 'ndc restart ' to restart named with a alternate set of arguements. 1296. [bug] delay setting need_restart until the response to ndc exec has been sent. 1295. [func] new ndc command 'args'. returns the arguements that named was started with %xx escaped. 1294. [bug] #1272 broke linkage for those OS's using -lfl (flex). Move -ll/-lfl to LIBL for all platforms. --- 8.3.2-REL released --- (Mon Jun 17 20:24:32 PDT 2002) 1293. [doc] update man pages for 'dig', 'dnsquery' and 'host' to reflect IPv6 capabilities (nslookup and nsupdate were already IPv4/IPv6 agnostic). 1292. [func] host: the default lookups now also include AAAA records. 1291. [func] 'dig -x ' now works. 1290. [bug] 'dig @server' fail to report the IPv6 address of the server in error messages. 1289. [contrib] normalize_zone now handles $TTL. 1288. [bug] named: -t and -w could not be used together. 1287. [func] report serial(s) in out going transfer operation. --- 8.3.2-RC1 released --- (Thu May 30 23:06:11 PDT 2002) 1286. [func] libbind: no longer attempts bit string labels for IPv6 reverse resolution. Try IP6.ARPA then IP6.INT for nibble style resolution. 1285. [port] linux: ss_family vs __ss_family in sockaddr_storage. 1284. [port] freebsd: 5.0 uses gid_t rather that int for GETGROUPLIST_ARGS 1283. [port] bsdi: 4.2 also has struct sockaddr_storage. 1282. [bug] nslookup was using inet_ntoa() to print out a IPv6 address. 1281. [bug] escape '(' and ')' when coverting to presentation form. 1280. [func] server { edns yes_or_no; } is now supported. 1279. [bug] nslookup: partial coversion to similar style outputs for both -type=aaaa and -type=a. 1278. [bug] free() of non-malloced memory in nslookup. 1277. [port] cast all instances of yytext in commands.l to (char*) to silence compilers on OS's where lex declares it as (unsigned char *). 1276. [port] hpux 11.22: ansify GetAnswer in getinfo.c to silence compiler. 1275. [bug] bad declaration of si in tsig_key_from_addr(). 1274. [port] hpux 11.22: ansify hexstring() and display() in addr.c to silence compiler. 1273. [bug] const pointer conficts in res_debug.c. 1272. [port] hpux 11.22: don't link against -ll unless required. 1272. [bug] main_need_num was not last entry in enum. main_need_tick nolonger required. 1271. [port] hpux: treat all hpux systems as BIG_ENDIAN, don't include . 1270. [port] hpux 11.22 namespace clash DATASIZE -> BIND_DATASIZE. 1269. [port] hpux 11.11 interface scaning. 1268. [port] solaris: 64 bit binary compatability. 1267. [bug] aix4: missing IN6_IS_ADDR_V4COMPAT macro. 1266. [bug] If you are using TSIG #1261 introduced the potential of a infinite loop. 1265. [bug] nslookup failed on platforms that don't have BSD 43 style sockets. 1264. [bug] LINK_INIT and UNLINK were not compatible with C++, use LINK_INIT_TYPE and UNLINK_TYPE instead. --- 8.3.2-T1B released --- (Tue May 7 18:49:58 PDT 2002) 1263. [bug] gethostans() could get out of sync parsing the response if there was a very long CNAME chain. 1262. [bug] winnt: dumpdb and stats should now work reliably. 1261. [bug] using a valid TSIG with a compressed ownername could result a INSIST() failure. 1260. [func] "notify explicit;" from BIND 9. 1259. [misc] leave the verification of the OPT options to the caller. 1258. [func] accept SOA MNAME field as legitimate additional data. 1257. [bug] malformed response to query w/ tsig + edns. 1256. [port] darwin: probe for IPv6 support. 1255. [bug] xfers_running could become out of sync if a zone was removed while it was being transfered. 1254. [func] nsupdate can now update IPv6 servers. 1253. [func] host now accepts IPv6 addresses. 1253. [bug] reserve space for the signature when performing a zone transfer. 1252. [func] dnsquery now accepts IPv6 addresses. 1251. [bug] win32: it was possible to call RegCloseKey() on a invalid key. 1250 [func] nslookup now accepts IPv6 addresses. 1249. [func] dig now accepts IPv6 addresses. 1248. [doc] correct some typos in named.conf.5 and corresponding html. 1247. [bug] get_salen() IPv6 support was broken for OSs w/o sa_len. 1246. [support] add highly dangerous compile time option NXDOMAIN_ON_DENIAL. it should not be used except in testing. 1245. [bug] if we don't have enough file descriptors to open a socket attempt to close a idle tcp client. 1244. [port] bsdi: 4.3 has struct sockaddr_storage. 1243. [bug] SERVFAIL can have too many other causes to be used say whether a server supports EDNS or not. 1242. [port] 64k answer buffers were causing stack space to be exceeded for certian OS. Use heap space instead. 1241. [bug] getnameinfo() failed to lookup IPv4 mapped / compatible addresses. 1340. [bug] reference after free for included conf file name. 1339. [bug] doaddinfo would not always attempt to fetch missing glue when it should have. 1338. [bug] an IPv6 only nameserver could generate spurious sysquery errors. 1337. [port] linux: IN6ADDR_LOOPBACK_INIT, IN6ADDR_ANY_INIT and sockaddr_storage not declared by early kernels. 1336. [bug] getaddrinfo() could call freeaddrinfo() with an invalid pointer. 1335. [bug] res_nupdate() failed to update the name servers addresses before sending the update. 1334. [bug] A6 is expected in the additional section. --- 8.3.1-REL released --- (Thu Jan 31 21:28:59 PST 2002) 1333. [bug] cached NXDOMAIN/NODATA responses were being ignored when when fetching missing additional data. 1332. [func] "allow-query" is now supported for forward zones. #define FORWARD_ALLOWS in bin/named/named.h to enable. 1331. [bug] rrsetadd() should explictly attach to the databuf rather than inheriting the reference count. 1330. [bug] potential reference after free. 1329. [port] linux: ensure that CC is correctly propgated to probe_ipv6. 1328. [port] linux: res_init.c failed to compile on certian older machines. 1327. [contrib] add mysqlBind reference. 1326. [bug] named-xfer could incorrectly report a fopen() failure as a fdopen() failure. 1325. [bug] if fdopen() failed empty files could be left behind. 1324. [bug] certian bad delegations could result in a DNS storm. --- 8.3.0-REL released --- (Fri Jan 11 04:00:00 PST 2002) 1323. [bug] don't assume statp->_u._ext.ext is valid unless RES_INIT is set when calling res_*init(). 1322. [bug] call res_ndestroy() if RES_INIT is set when res_*init() is called. 1321. [cleanup] YPKLUDGE in no longer default. 1320. [port] winnt: namespace collision #undef the system's EV_ERR. 1319. [port] winnt: make __res_nopt() visible externally. 1318. [port] Tru64 UNIX V5.1 can return spurious EINVAL on close() after connect() failure. 1317. [bug] NULL used where zero was required. --- 8.3.0-RC2 released --- (Wed Jan 2 17:14:23 PST 2002) 1316. [bug] memory leak when a ixfr update or a re-applied update was rejected. 1315. [bug] the wrong options level check-names value was used when merging ixfr updates. 1314. [bug] corrupt update / ixfr updates should result in merge errors being reported. 1313. [bug] set current_serial in db_ixfr.c:ixfr_getdelta(). 1312. [bug] use serial space arithmetic when selecting deltas for IXFR. 1311. [contrib] mdnkit update to 2.2.3 1310. [bug] TSIG signed IXFR's wern't correctly verified. 1309. [port] winnt: re-order fclose/unlink so that the unlink succeeds. 1308. [doc] miscellaneous nroff fixes. 1307. [func] preferred-glue can now be used to partially order the additional section. 1306. [bug] It was possible to trigger an INSIST failure with certian EDNS responses. 1305. [bug] named-xfer could return a false up-to-date status. 1304. [bug] "named-xfer -x" didn't attempt to use the specified address for all possible masters if earlier connects failed. 1303. [contrib] nslint upgraded from 2.0.2 to 2.1a3 (by author). 1302. [bug] res_nametotype() and res_nametoclass() were broken. 1301. [bug] "ndc reload zone" without class was broken. 1300. [port] Tru64 UNIX 5.1 does not like __align as a element name. 1299. [bug] host failed to handle "." in search list correctly. 1298. [bug] max-ixfr-log-size default was unreasonable. 1297. [bug] read buffer overflows. 1296. [protocol] NAPTR additional section processing. --- 8.3.0-RC1 released --- (Wed Nov 21 20:41:32 PST 2001) 1295. [bug] be more aggressive at dropping messages from certian well known ports. 1294. [bug] hint zones and root stub zones were not being removed correctly. 1293. [port] MPE/iX workaround recvfrom() not supporting larger address buffers required for IPv6. 1292. [bug] memory leak: free_flushset(). 1291. [func] accept and generate EDNS0 queries. 1290. [func] allow initial notifies on startup to be suppressed. [Kenneth Karoliussen, kenneth@activeisp.com] 1289. [func] allow keys to be specified in the masters clause. 1288. [func] named-xfer report if response was signed. 1287. [bug] named-xfer could report false TSIG failures under certian conditions. 1286. [bug] don't allow rtt estimates to drop to zero. 1285. [bug] non-answering servers rtt estimates were not always penalised. 1284. [bug] struct __res_state was still broken after #1265. 1283. [port] addition platform support for _r functions. 1282. [port] pw->pw_class is platform dependant. 1281. [port] namespace collision: dprintf -> res_dprintf, ERR -> EV_ERR, OK -> EV_OK. 1280. [cleanup] gai_strerror() re-written. 1279. [bug] non-glue was not being reported on reload. 1278. [bug] Remove the INSIST at the end if zone_maint(). 1277. [func] hostname.bind/txt/chaos now returns the name of the machine hosting the nameserver. This is useful in diagnosing problems with anycast servers. 1276. [bug] dns_ho.c:add_hostent() was not returning the amount of memory consumed resulting in garbage address being returned. Alignment calculations were wasting space. We wern't suppressing duplicate addresses. 1275. [port] sunos: old sprintf. 1274. [port] MPE/iX C.70 1273. [bug] host was sorting multiple RRs into the wrong order prior to verifying. --- 8.3.0-T2A released --- (Thu Sep 27 18:15:00 PDT 2001) 1272. [bug] "ndc trace 0" should behave like "ndc notrace". 1271. [func] inet_{cidr,net}_{pton,ntop}() now have IPv6 support. 1270. [bug] AXFR style IXFR responses were not handled properly, transfer-format single-answer. 1269. [bug] misc: more string format fixes, open va_end(), call exit() with positive values, include . 1268. [func] Resolver, dig: "DNSSEC OK" (DO) support. 1267. [port] HP e3000 MPE is big-endian. 1266. [func] dig +[no]tr: use relative names when printing out a zone transfer ([NO]TRuncate). 1265. [bug] struct __res_state to large on 64 bit arch. 1264. [port] winnt: pass the root zone as "." to named-xfer rather than "". 1263. [port] #1227 broke sunos. 1262. [func] log type as well as class for denied queries. 1261. [bug] get*by*() failed to check if res_init() had been called. 1260. [func] resolver option: no-tld-query. disables trying unqualified as a tld. no_tld_query is also supported for FreeBSD compatability. 1259. [func] enable NOADDITIONAL code by default. 1258. [func] treat class ANY as class IN for access control for non-xfr queries. 1257. [func] increase nameserver chaining distance from 1 to 3 (NS_MAX_DISTANCE). 1256. [bug] increased loop avoidance with well known ports. 1255. [bug] cached NXDOMAIN responses were being ignored when selecting servers to query. 1254. [support] improved support for parallel make. 1253. [port] winnt: support for change #1218 1252. [port] winnt: the stat structure does not have st_blksize. 1251. [bug] AXFR style IXFR responses were not handled properly. 1250. [doc] document support-ixfr. 1249. [func] add support gcc's format string checking. 1248. [bug] string formats. 1247. [bug] dig -t axfr attempted to use UDP not TCP. 1246. [doc] miscellaneous nroff fixes. 1245. [port] winnt: named-xfer failures. improved recvfrom() emulation. 1244. [port] winnt: bug in tracking "file" file descriptors extend "file" file descriptors support to 2048. 1243. [cleanup] defining REPORT_ERRORS in lib/dst caused compile time errors. 1242. [bug] inet_pton() failed to reject octal input. 1241. [bug] memory leaks: zone forwarder table, server key list, global forwarder table, query tsig info, unused channels, key names, xfr tsig info. 1240. [bug] restore message if ns_forw() fails. 1239. [bug] call res_ndestroy() in net_data_destroy(). 1238. [func] named-bootconf now supports HP's "no-round-robin". 1237. [bug] buffer overrun, access mode read. 1236. [bug] ignore white space after address of nameserver. 1235. [port] solaris 2.4: use ioctl(FIONBIO) rather than fcntl(). --- 8.3.0-T1A released --- (Wed Jun 20 19:05:01 PDT 2001) 1234. [bug] memory leak with "use-id-pool no;". 1233. [func] res_setservers(), res_getservers(). 1232. [bug] don't assume the forwarder has dropped bogus records. 1231. [bug] always restart a query if we dropped records when parsing. 1230. [func] report the address the server learnt the record from in lame server messages. 1229. [func] opaque rdata support for unknown types. 1228. [protocol] IXFR don't test for AA, don't check that the question is returned. 1227. [port] solaris: sys_nerr and sys_errlist do not exist when compiling in 64 bit mode. 1226. [placeholder] 1225. [bug] don't send cross class additional records. 1224. [bug] use after realloc(), non portable pointer arithmetic in grmerge(). 1223. [bug] allow all KEY records in parent zone at bottom of zone cut. 1222. [bug] HMAC-MD5 key files are now mode 0600. 1221. [port] aix: 4.3.3.0 (4.3.2.0?) and later have strndup(). 1220. [port] winnt: isc_movefile() and syslog() updated. 1219. [bug] winnt: zone transfers could fail. 1218. [func] add IPv6 transport support to the resolver from the KAME project. Includes initial bitstring support. 1217. [bug] #1186 broke the command-line programs that relied on the fact that HMAC-MD5 keys have keyid 0. 1216. [bug] #1180 completely broke inet_nsap_addr(), inet_nsap_ntoa() still didn't emit the leading 0x. 1215. [bug] long UNIX domain control socket names were not being printed in full. 1214. [bug] getrgnam()/getgrgid() leaked memory. 1213. [bug] #1199 introduced a reference after free bug. 1212. [bug] some function declarations wern't protected by __BEGIN_DECL/__END_DECL in resolv.h. 1211. [port] next: openstep is now supported as well as nextstep. 1210. [port] add: SCO Unix 5.0.6. 1209. [port] winnt: issues. 1208. [func] close "dynamic" file channels when debug is set to zero allowing them to be removed and re-opened. 1207. [contrib] new h2n from author. 1206. [bug] ixfr_getdelta() uninitialised variable used. 1205. [bug] parse_cert_rr() passes wrong buffer size to b64_pton(). 1204. [bug] memory leak: pathname leaked specifing controls unix. 1203. [bug] detect corrupted ixfr logs. 1202. [bug] memory leak: dynamic update was leaking. 1201. [bug] ISO/IEC 9945-1 versions of getpwuid_r(), getpwnam_r(), getgrgid_r() and getgrnam_r() were not ISO/IEC 9945-1 compliant. 1200. [bug] memory leak: when following CNAMES from of req_query(). 1199. [bug] memory leak: when defining keys. 1198. [func] reference count all databuf activity. 1197. [func] deallocate-on-exit yes; will call abort() if there is still active memory. 1196. [func] memactive(): report if there is still active memory. 1195. [bug] memory leak: include in named.conf leaked file name. 1194. [port] MPE/IX port updated by Mark Bixby of the HP CSY MPE/iX Internet & Interoperability Team. 1193. [port] winnt: path separator. 1192. [bug] winnt: fix accept failures. 1191. [port] winnt: a CLI tool for controling named 'BINDcmd' now exists. 1190. [contrib] nslint upgraded from 1.5.1 to 2.0.2 (by author). 1189. [port] redo #1146 to cope w/ differing gettimeofday() function signatures. 1188. [bug] memory leak when removing multiple records via dynamic updates. --- 8.2.4-T1B released --- (Thu Apr 19 14:38:30 PDT 2001) 1187. [support] Don't accept in a query names which would be rejected in responses. 1186. [bug] DNSSEC key ids were computed incorrectly. 1185. [bug] remember if a notify came in while a zone transfer is in progress and perform a refresh check after the transfer completes. --- 8.2.4-T1A released --- (Sun Apr 1 12:15:48 PDT 2001) 1184. [support] notify delay limit now "nzones" rather than "nzones/5". 1183. [port] new port/cygwin contributed by s_c_biggs@bigfoot.com. 1182. [contrib] new contrib/mdnkit (V1.3) from author. 1181. [bug] dig -T was only delaying after the first batched query. 1180. [bug] NSAP processing did not support leading 0x as required by RFC 1706. 1179. [contrib] new contrib/adm from official ftp site. 1178. [contrib] new contrib/host from author. 1177. [contrib] new contrib/dnsp from author. 1176. [bug] fix memory and file descriptor leaks. 1175. [bug] statp->nsort could fail to be re-initialised if resolv.conf goes away. 1174. [port] winnt: missing call to sockout() in close(). 1173. [bug] suppress repeated notifies when a nameserver is a CNAME. 1172. [bug] allow res_{n}update to take a single unlinked element. 1171. [doc] rfc2308-type1 applies to answers from the cache. 1170. [port] winnt: does not have unix domain sockets. 1171. [bug] xfers_deferred could become out of sync. 1170. [bug] check the family before using a cached result from gethostbyname*(). 1169. [cleanup] namespace cleanup of prand_conf. 1168. [port] fix ctk ORD_32 problem on some HPUX 10.20 systems. 1167. [support] note possible HAVE_STRNDUP need for AIX4. 1166. [bug] bad $TTL could kill the contributed dns_signer. 1165. [func] INITIALZONES tuning for large servers (> 1000 zones). 1164. [bug] the resolver could leak a file descriptors under certain conditions. 1163. [func] ns_critical() is now available. 1162. [port] winnt: add strerror. 1161. [support] log out of memory during zone transfers. 1160. [support] extend "Response from unexpected source" message. 1159. [doc] query-source is used for TCP and that the port is ignored. 1158. [func] add A6, DNAME, SINK and OPT to list of known RR types in res_debug. 1157. [perf] add more ns_wouldlog() calls on mainline. 1156. [bug] don't use a known bogus key name. 1155. [support] log possible "TSIG BUG" exploit attempts. Requires LOG_TSIG_BUG to be defined in bin/named/named.h. 1154. [bug] RFC2317 support was broken in bin/host command again. 1153. [support] be more consist with the use of slave vs secondary. 1152. [bug] ixfr processing could leave Z_XFER_RUNNING set. 1151. [bug] failed to correctly parse the orginal ttl in SIG records. 1150. [bug] forwarders: it was possible to use freed memory. 1149. [support] zone rejected message to error level. 1148. [bug] non-glue now logged to category load. 1147. [bug] handle notify w/ SOA records better. 1146. [support] be more gentle in handling bad system clocks. 1145. [port] solaris: 2.4 does not have pthreads. 1144. [support] log class w/ denied messages. 1143. [bug] only use the query-source address, not port, for TCP connections. 1142. [doc] document change #924 better (doc/html/controls.html). 1141. [bug] DESTDIR is not part of the nslookup help file path. 1140. [bug] only reset interval timers if the value has changed. --- 8.2.3-REL released --- 1139. [bug] inet_{net_,}ntop() had an off-by-one error. 1138. [bug] purge_nonglue() should only be fatal on master servers. 1138. [port] add include/errs.h to various ports. winnt: #1130 caused linkage failures. --- 8.2.3-RC5 released --- 1137. [bug] rfc1034 escape sequences not processed when replaying updates. 1136. [port] winnt: named nolonger creates resolv.conf. 1135. [bug] fixup from #1130/1132. 1134. [port] winnt: SIOCGIFADDR, SIOCGIFFLAGS, SIOCGIFDSTADDR and mkstemp() fixes. 1133. [bug] sorting of SIG/non-SIG records prior to rrset ordering of was broken. --- 8.2.3-RC4 released --- 1132. [lint] more #1130. 1131. [support] TTL 0 is now allowed in zone files. 1130. [lint] massive, massive delinting from "gcc -Wall". 1129. [support] "max_log_size_ixfr" is now a scaled number (4m, etc). 1128. [contrib] updated mdnkit. 1127. [port] winnt: support for more interfaces, dnskeygen. 1126. [bug] resolver: close cached file descriptors when socket() fails. 1125. [bug] when ns_addr_list is rotated, rotate cached file descriptors. 1124. [bug] the select() timeout was not always being correctly computed. 1123. [bug] changes to ns_addr_list were not being reflected into our private copy. 1122. [port] sco: DESTRUN and DESTSBIN can't be the same. 1121. [cleanup] re-word "server is ??? priming" status message. 1120. [bug] more #1108 fine tuning. 1119. [bug] "delete all" RRs were not being printed correctly. 1118. [port] winnt: always install the named executable 1117. [port] linux: turn off returning ICMP port unreachables. 1116. [bug] minor tweak to #1108 1115. [bug] fail if tsig transfers are requested but we can't communicate the keys to named-xfer. 1114. [bug] remove extraneous semi-colon from ns_parser.y --- 8.2.3-T9B released --- 1113. [support] show config file name and age in "ndc status" 1112. [support] "ndc status" no longer mentions loading of config. 1111. [port] some versions of sunos don't have _POSIX_PATH_MAX 1110. [bug] zones with Null keys at delegation incorreclty rejected. 1109. [support] named-xfer was bombing on non-TSIG'd zones 1108. [support] ignore queries that come in during long synch ops 1107. [func] allow the default syslog facility to be set by adding -DISC_FACILITY= to CDEBUG in Makefile.set. 1106. [func] host statistics can now be cleared after they are dumped. Use "ndc stats clear". 1105. [func] host-statistics-max can be used to set a upper bound on the number hosts we collect statistics against. 1104. [func] the source of a record is no longer dependent on setting "host-statistics yes;" 1103. [doc] winnt: updated port specific notes. 1102. [port] winnt: BINDctrl fixes 1101. [port] winnt: install fixes 1100. [bug] named-xfer some memory allocations were not checked. 1099. [bug] more missing INIT_LINK's. 1098. [support] force gmake to fail if the sub-shell fails. 1097. [port] winnt: lower the logging level so that BINDCtrl status checks do not cause the eventlog to fillup. 1096. [bug] don't pass '-i' to named-xfer unless we are going to attempt a IXFR. 1095. [bug] dig: report missing arguements. 1094. [port] winnt: more cylink fixes, updated install. 1093. [bug] winnt: build lib cylink correctly 1092. [cleanup] winnt: snmpmib.c is nolonger required 1091. [support] winnt: workout the install directory. 1090. [bug] winnt: install was copying old over new. 1089. [bug] winnt: fix copyright for nameserver.c winnt: snmpmib.c not needed in libbind.dsp 1088. [bug] #1053 still contained NAPTR problems. --- 8.2.3-T8B released --- 1087. [port] sunos/gcc _POSIX_PATH_MAX isn't defined when it should be. 1086. [doc] malformed man page for heap. 1085. [bug] ixfr responses to zones we don't server were malformed. 1084. [bug] INIT_LINK before APPEND in four more places. 1083. [support] only log "no options before zone" config error before FIRST zone [kjd]. 1082. [bug] have client-side IXFR work in single answer mode [kjd]. 1081. [bug] have server-side IXFR work in single answer mode [kjd]. 1080. [support] still do IXFR's even when a file name is not specified for zone [kjd]. 1079. [support] need to have a file name for a hints zone [kjd]. 1078. [port] WinNT interface enumeration fixes from Danny Mayer. 1077. [support] format string audit. 1076. [port] now recognize RH7.0's "strndup()" 1075. [contrib] add contrib/resparse-1.3 [Henning Schulzrinne @CU] 1074. [support] INSIST that lists are correctly managed. 1073. [port] Win/NT port work from Danny Mayer. Dig, host and nslookup have been added. 1072. [port] work around a gcc bug on solaris. 1071. [bug] memory leak in res_nsendsigned(). 1070. [bug] We were accepting non syntactically valis SOA records. 1069. [port] movefile() is now part of libbind as isc_movefile(), remaining rename() calls converted to isc_movefile(). 1068. [bug] purge the zone from memory if an error is detected on loading. 1067. [bug] reload the parent zone if loading the child zone fails, the parent zone may otherwise be corrupted. 1066. [bug] refresh/retry timer need to be reset after IXFR 1065. [bug] IXFR change list could be freed to early. 1064. [bug] unchecked memget in sx_send_ixfr(). 1063. [bug] fix #1041 was incomplete. 1062. [bug] host printed out address records multiple times if they were at the end of a CNAME chain. 1061. [bug] host failed to look for A records for the second an subsequent entries in the search list when using the default lookup. 1060. [bug] $GENERATE did not reject a out of zone LHS. 1059. [bug] res_findzonecut() contained a bad debugging printf. 1058. [bug] possible NULL pointer de-reference in dst_key_to_buffer(). 1057. [doc] document that bogus causes anti-alias processing. 1056. [bug] ns_sprintrrf() could incorrectly print "." as "@". 1055. [bug] aa was being cleared on notify "queries" prior to testing. 1054. [bug] NAPTR records were using name compression. 1053. [bug] NAPTR records were not being printed correctly. 1052. [bug] UPDATES w/ NAPTR records were failing. 1051. [contrib] YADDAS: Yet another DNS database awk script. 1050. [bug] named-bootconf did not handle cacheless secondary/stub zones. NOTE cacheless secondary/stub zones are not recommended. 1049. [bug] buffer overruns by 1 in getnameinfo(). 1048. [bug] ns_ctl_install() was corrupting the server_controls list. 1047. [bug] req_iquery() wasn't doing a final update on buflenp. 1046. [port] Win/NT port improved by its author. --- 8.2.3-T7B released --- 1045. [bug] forwarded and initiated TCP queries weren't affected by the "query-source" config option, and weren't being set nonblocking. 1044. [support] add HITCOUNTS compile-time option (from lamont@hp.com). 1043. [bug] dnsquery's command line args could overflow buffers. 1042. [doc] maintain-ixfr-base had wrong description in named.conf(5). 1041. [bug] host assumed axfr returned "one-answer" responses. 1040. [bug] add d_rcnt processing to update processing. 1039. [bug] qcomp wasn't stable. 1038. [port] solaris needs a strerror that does not return NULL, call isc_strerror instead. 1037. [support] soften #1025 -- continue to accept !AA notify req's. 1036. [debug] add TKEY debugging support. 1035. [bug] ndc's "help" command worked in signal but not channel mode. 1034. [bug] loc_ntoa() failed to correctly print altitudes in the range [-0.99 .. -0.01]. 1033. [port] Win/NT portability infusion from Larry @NortelNetworks. 1032. [bug] fix minor signal buglet introduced in #1029. 1031. [bug] nslookup now correctly refuses to accept qtypes AXFR or IXFR. (use nslookup "ls", not queries, for this.) 1030. [protocol] nslookup "ls" command now uses writev() rather than two write()'s, to get msglen and query into same tcp seg. --- 8.2.3-T6B released --- 1029. [bug] incredibly busy systems could starve handle_needs(). 1028. [protocol] unrecognized TSIG was returning NOERROR (now NOTAUTH). 1027. [support] INSIST(), ENSURE(), et al, now always have sideeffects. 1026. [port] some kernels bogusly return tv_usec>1000000 from gettimeofday(). panic and dump core when this happens. 1025. [proto] NOTIFY messages should have AA. 1024. [bug] we were unwilling to use the last 10 octets of a response buffer in certain transaction types. 1023. [port] HP-UX 10.20 was looping inside contrib/dnssigner. 1022. [port] ensure that all handled signals are unblocked. 1021. [bug] the "host" command wasn't properly printing SRV RR's. 1020. [contrib] new "updatehosts" (V1.1.0) contributed by author. 1019. [port] separate CFLAGS and CPPFLAGS for unusual builds. 1018. [bug] When maintain_ixfr_base is set to "no" a zones IXFR file was still being written too. 1017. [doc] resolver(3) was out of date with respect to recent API changes. 1016. [bug] nslookup wasn't properly printing SIG RR's. 1015. [bug] when merging group information gr_name and gr_passwd could be left pointing at freed memory. 1014. [bug] iquery: DoS (potential), information leak. 1013. [bug] mangled hostent structures returned by gethostbyname_r() and friends. 1012. [doc] add named-bootconf example to INSTALL. 1011. [bug] if spawnxfer() fails we should return immediately. 1010. [bug] bad responses to the initial IXFR/SOA query could result in using an uninitalised variable. 1009. [port] Add support for darwin / Mac OS X 1008. [doc] specify allow-query default in named.conf. 1007. [bug] only set STREAM_AXFRIXFR if the original query is an IXFR. --- 8.2.3-T5B (RC3) released --- 1006. [port] Windows/NT does not have fchown(). 1005. [bug] RD was sometimes left set, inappropriately. 1004. [bug] cached NXT's were corrupted. 1003. [bug] correction to #997. 1002. [bug] file descriptor leak in res_nclose(). 1001. [port] some builds were too fast. --- 8.2.3-T4B (RC2) released --- 1000. [bug] #996 was wrongly implemented; replacement fix. --- 8.2.3-T3B released --- 999. [support] named now makes an effort to create its files with ownership as specified by -u and -g command options. 998. [support] show version number in NOTIFY log messages. 997. [support] forwarders are now used in order by measured RTT. 996. [protocol] if answering ixfr with full zone, used qtype axfr. 995. [bug] "dig -b" was broken due to missing switch "break;" 994. [bug] named-xfer did not handle empty question sections. 993. [bug] TSIG AXFR was completely broken in DiG. 992. [bug] OPTION_USE_IXFR and OPTION_MAINTAIN_IXFR_BASE had non-single-bit flag values in src/bin/named/ns_defs.h. 991. [protocol] send A6 glue records in xfr. 990. [bug] we could loose track of a bottom of zone cut if the write buffer filled up at just the correct moment. 989. [bug] apply to "fetch-glue no;" to notify processing. need to add A records that would be found this way w/ also-notify. 988. [support] report expired zones when detected in maintainence pass. 987. [feature] "ndc reconfig -noexpired" skip attempts to load expired zoned when reconfiguring. 986. [bug] pushlev only needs to be called for axfr/zxfr not ixfr. --- 8.2.3-T2B released --- 985. [support] remove "view" command from nslookup (it used mktemp()). 984. [bug] always restart processing query from scratch if we have chased a CNAME as we might still have the answer in the cache once the CNAME has been resolved. 983. [support] "notify from non-master server" is now debug, not info. 982. [bug] rollback the compression pointers array when a RRset/RR does not fit. 981. [port] decunix: typedef (u_)int#m_t 980. [bug] mishandled memget failure w/ TCP connections. 979. [bug] we were failing to call ns_stopxfrs() before calling purge_zone() in some cases. 978. [port] sco50: setsockopt(SO_REUSEADDR) fails on unix domain sockets 977. [bug] we should be returning notimpl for update forwarding rather than refused. a client receiving refused should terminate the update attempt. notimpl should just cause the client to skip to the next server. 976. [bug] some stats weren't getting incremented, & added a few. 975. [support] SLAVE_FORWARD is now redundant and has been removed. 974. [port] ultrix with vendor's y2k patch explicitly desupported. 973. [bug] some field names added in #935 conflicted with macros. 972. [support] restore heartbeat notifies. 971. [bug] out of order updates in log. 970. [port] solaris: add ipv6 interface scanning support. 969. [bug] post process a zone load to remove any non-glue at or below bottom of zone. 968. [bug] TSIGs failed to verify if the key name was compressed. 967. [bug] zones signed by the BIND 9 signer failed to load. --- 8.2.3-T1A released --- 966. [bug] nslookup and dig misprinted root zone in $ORIGIN. 965. [feature] dig's command line input buffer was rather small. 964. [bug] make res_nsearch() behave like res_search() of olde. 963. [bug] res_debug::do_section() can no longer spin all VM. 962. [bug] another almost-complete rewrite of IXFR from kjd (462) 961. [bug] acl "none" now fails to match but doesn't end search. 960. [bug] more hesiod library fixes from danny. 959. [doc] christos fixed several man page typos and brainos. 958. [bug] getnameinfo() should accept experimental/multicast. 957. [port] ultrix again. "cd" now presumed to be silent again. 956. [bug] multiline was not being cleared correctly. 955. [bug] explicit TTL on SOA records were being replaced with soa minimum. 954. [bug] cannot load a signed root zone. 953. [bug] memory overrun in set_zone_ixfr_file(). 952. [bug] errs was not being correctly adjusted if the included master file did not exist in db_load(). 951. [bug] contrib/dns_signer/signer: write_trim_name array bounds write error. 950. [bug] hesiod: ctx->res was not being initalised. 949. [port] aix32: add prand_conf.h and define WCOREDUMP 948. [bug] fixed logic error in a number of expressions causing res_ninit() not to be called when it should be. 947. [bug] sanity check in dst_read_key() wasn't. 946. [port] freebsd: threaded library support. 945. [bug] wrong file name logged in ixfr_have_log(). 944. [doc] add forwarders to zone types master/slave/stub in named.conf man page. 943. [bug] raise CNAME and OTHER / multiple CNAME logging to warning. 942. [bug] bad referrals logged for forwarders. 941. [bug] lame server detection wasn't checking for SOA record. 940. [clarity] unapproved -> denied in log messages. 939. [bug] reload_master and purgeandload should write the zone if it has been updated. 938. [bug] update and ixfr logs could get corrupted. fseek() before ftell() on fopen(, "a+") file. 937. [support] allow parallel makes to work. 936. [protocol] add preliminary A6 glue recognition in ns_req. 935. [cleanup] res_nsend() segmented into multiple functions for readability. also fixed two file descriptor leaks. CAN_RECONNECT is gone, keep one socket per nameserver. 934. [bug] Perror and Aerror where incorrect if DEBUG is not defined. 933. [port] cygwin port added 932. [port] sco42 does not have unix domain sockets or gethostid. 931. [bug] eventlib was not handling unix domain sockets correctly. 930. [bug] we wern't using all the potential compression pointers in the question section. 929. [bug] we were accepting updates (adds) with illegal ttls. 928. [bug] if we manage to get a illegal ttl stored, print it unsigened. 927. [port] hpux: (11.* 10.30) Makefile.set.gcc 926. [port] hpux10: gcc needs -D_HPUX_SOURCE and -fPIC 925. [protocol] when a slave loads it should notify others (RFC 1996). 924. [port] sunos solaris: #define NEED_SECURE_DIRECTORY to secure the directory containing unix domain socket rather than the socket itself. 923. [support] shutup "make clean" about missing threaded directories. 922. [bug] removing an cached zone file then performing a "ndc reload zone" should force a zone transfer. 921. [bug] nsupdate: listuprec was not being initalised. 920. [port] aix4: Makefile.set.gcc aix4: __P was being defined by 919 [port] linux: remove one level of symbolic linkage when performing make links on port/linux/include 918. [bug] update prerequisite could match w/ wildcard. 917. [port] irix: make the current IRIX release (6.5) work by not patching res_debug.c. see INSTALL if you have problems with 6.3. 916. [bug] removing / changing a zone type could result in Z_NOTIFY being cleared / tested against the wrong zone. 915. [bug] evNewWaitList() was not maintaining the prev chain. 914. [bug] signal EWOULDBLOCK if EV_POLL'ing with no timers. 913. [bug] input could get lost on the server side of a ctl sock. 912. [bug] nsupdate now allows explicit 0 TTL's on added RR's. 911. [bug] gethostbyname() should not return duplicate addresses. 910. [bug] address-sorting logic was exiting early. 909. [bug] dig wasn't respecting the +ti and +ret arguments. 908. [contrib] Tony Stoneley sent us an updated misc/makezones. 907. [port] winnt fixes from Larry at Nortel. 906. [bug] res_findzonecut() failed if the NS referred to a CNAME. 905. [doc] Minor fix to doc/man/Makefile for getnameinfo 904. [bug] bin/host wasn't looking up MX records if no -t flags were passed to it. --- 8.2.2-P6 released --- 903. [bug] divide by zero bug when querying for SIG records from a secure zone. 902. [support] don't attempt to set q_fzone if we won't be using it. 901. [support] delay notify timer setting until all zones have been loaded. 900. [port] hpux10 fix call to bison; sco call bison consistenly. 899. [bug] dynamically allocate buffer used to display RR rather than uses a fixed sized one. grow as needed. 898. [bug] if truncation caused no RR's to appear in the answer we mis-classified the answer on a NODATA. 897. [support] descriptors used by named should not be inherited by named-xfer. 896. [contrib] add contrib/adm/adm-nxt, an exploit for the NXT bug in 8.2 and 8.2.1. as before, we do not recommend its use, and we do recommend that you run the latest BIND. --- 8.2.2-P5 released --- 895. [port] minor NT build and documentation improvements. 894. [bug] incorrect "key" statements in named.conf weren't handled properly. --- 8.2.2-P4 released --- 893. [bug] DNSSEC logic in bin/host broke -t any 892. [bug] multiple SOA on AXFR bug --- 8.2.2-P3 released --- 891. [bug] options { also-notify { ... }; }; resulted in wrong pointer being memput with the wrong size on reload. 890. [port] A/UX portability improved. 889. [port] added IPv6 portability for OpenBSD, NetBSD, FreeBSD. --- 8.2.2-P2 released (internal release) --- 888. [support] add default: all tag to top src/Makefile so that "make" will work properly in some OS'. 887. [bug] "dig ... axfr" was printing spurious "TSIG ok" msgs. 886. [support] top-level Makefile now included in all tarballs. 885. [support] IXFR improvements. 884. [bug] some deprecated NXT RR forms weren't ignored properly. 883. [support] "host" command can now try to verify dnssec signatures. 882. [contrib] dns_signer/ had some last minute problems (by author). 881. [bug] possible sprintf() overflow prevented. 880. [support] minor tweak to bin/dig/dig.c TSIG code to clarify whether res_nsend or res_nsendsigned is being used. 879. [support] add "noesw" target to top-level Makefile (for PL1). 878. [port] aix4 HAS_INET6_STRUCTS was not being set based on the existance of _IN6_ADDR_STRUCT. 877. [port] freebsd + KAME need a different Makefile.set see INSTALL notes. 876. [port] IPv6 probe for MPE/IX, NetBSD. 875. [bug] bad NAPTR RRs could be loaded from zone files. 874. [port] update irix_patch in irix port. 873. [port] add SRC/tools to sco's make [std]links. --- 8.2.2-REL released --- 872. [bug] named-xfer could free() a string twice. 871. [port] linux support for broken IPv6. 870. [port] more NT fixes and improvements from larry at bay. 869. [bug] disable client side IXFR (in named-xfer) for now. 868. [bug] updated named-bootconf to handle case insensitive parts of named.boot. added stubs support. class was not being reset. 867. [support] updated INSTALL notes. 866. [port] More NT fixes from larry at bay. 865. [port] add #include to next's port_before.h 864. [port] change solaris' Makefile.set files to use yacc and lex. also clean up install and binary paths. 863. [bug] lib/isc/ctl_srvr.c needed fcntl.h #included --- 8.2.2-T8B (RC2) released --- 862. [port] another NT infusion from larry over at bay. 861. [support] improve support for tsig'd updates. 860. [port] add IPv6 probing to: decunix hpux irix lynxos mpe netbsd qnx rhapsody sco50 859. [bug] set control sockets to close-on-exec; potential file descriptor leaks in ctl_srvr. 858. [bug] make ns_samename() and use it instead of strcasecmp(). 857. [bug] unset update-log can lead to debugging msg mishaps. --- 8.2.2-T7B (RC1) released --- 856. [bug] IXFR finally works and is reenabled. 855. [port] more win/nt changes from bay. 854. [bug] /etc/hosts lines longer than 8K can crash gethostent(). 853. [bug] another linked list bug shaken out of ns_update. 852. [bug] compiled in pathname for nslookup help file was wrong. 851. [bug] ns_update had an off by 2 bug when checking names in SRV records causing unexpected failures. 850. [bug] empty updates triggered an overambitious INSIST(). --- 8.2.2-T6B released --- 849. [support] print rcode on failed UPDATE messages. 848. [port] paths.h and port_before.h tweaks from SCO for unixware7. 847. [port] add SRC/irix_patch to make links in IRIX 846. [support] restore some diagnotics lost when #634 was done. 845. [support] WATSQ patch from Ted Rule of Flextech Television. 844. [support] added src/DNSSEC with a note about BIND-8.1.2 interop. 843. [bug] IXFR fixes. 842. [bug] pointer arithmetic on (void *) not ANSI C. 841. [port] sco50: make install: libport.a not longer exists. 840. [bug] turning on touch_timer() in ctl_clnt.c found a bug. 839. [contrib] new version of contrib/host (from author). 838. [support] improve error reporting; remove lint. 837. [bug] bin/host/host.c was not RFC2317 compliant. 836. [port] hpux portability and speed improvements. 835. [port] some shell's "cd" produce output - fix in port/systype. --- 8.2.2-T5A released --- 834. [support] massive changes to dynupd API. 833. [port] more Win/NT. 832. [feature] boolean: treat-cr-as-space. If yes, BIND will treat '\r' the same as it treats ' ' and '\t' in zone files. 831. [bugs] DNSSEC/CAIRN workshop results (in addition to #826): - invalid size passed into b64_ntop in SIG parser - Invalid TSIG keys are now logged and ignored instead of panicing. - trusted-keys didn't work if a trailing dot was present - a DST problem that occurs when one of the multiprecision integers begins with a 0 byte. - TSIG signed truncated responses were mishandled. - minor RFC2535 changes. 830. [doc] Minor updates to INSTALL 829. [support] we need to cache SOA NXDOMAIN queries if only for a clock tick. 828. [support] multiple zone warning clearer. 827. [bug] the ctl interface was clearing already-cleared timers. 826. [contrib] various improvements to contrib/dns_signer (from TIS). 825. [support] change __NAMESER and __RES to 19991006. 824. [port] sco50 needed #define __BIND_RES_TEXT in port_after.h 823. [bug] named-xfer missed a SIG text format change 822. [bug] TSIG signed truncated responses crashed the server 821. [bug] potential reference after free bugs. 820. [port] ultrix finally works again. 819. [bug] removed test for missing glue from nslookup() as it got false matches. There is no simple test for missing glue. 818. [bug] back out #790, there was no memory leak. 817. [port] Solaris needed #define BSD_COMP in port_before.h. --- 8.2.2-T4B released --- 816. [bug] you could not raise the number of available file descriptors after the first call to res_send() and make use of them. 815. [feature] report version via command line option (-v). 814. [feature] getipnodebyname, getipnodebyaddr and freehostent added. These are RFC 2553 newcomers to the RFC 2133 set. 813. [support] better diagnostics when trying to clean up old unix control socket. 812. [bug] uninitalised variable. 811. [port] sco50 make links was not linking resolv.h.diffs 810. [bug] zone transfer did not transfer all DNSSEC records at delegation points. 809. [support] res_[n]sendupdate has died before it could be used. 808. [bug] res_send() wasn't checking for EINTR after select(). 807. [support] it's now possible to send TSIG'd updates. 806. [support] ns_parserr() was uncompressing from the wrong base in a certain corner case trod on by res_findzonecut(). 805. [bug] only set SO_LINGER if required by the OS, #define DO_SO_LINGER to do so. 804. [bug] another swath of IXFR fixes. 803. [port] Compaq Tru64 UNIX 4.0B with ZK3's experimental IPv6 kit installed will at least build, but hasn't been tested. 802. [support] we no longer cache NXDOMAIN if the QTYPE was SOA. 801. [bug] our negative caching logic would log spurious errors if the response had an empty question section. 800. [bug] #764 was too aggressive in one case. 799. [port] ultrix is a still-moving target. 798. [support] QRYLOG now logs the QCLASS 797. [bug] closing a thread which had called get*by*() would leak memory. 796. [support] deallocate_on_exit now frees memory allocated by irs. 795. [port] solaris 2.4 SO_REUSEADDR generates errors on unix domain sockets. 794. [bug] ixfr_have_log() was logging wrong file name. 793. [bug] clean_cache() was not alway removing complete RRsets. 792. [bug] deallocate-on-exit caused references to freed memory. 791. [support] MEMCLUSTER_DEBUG had an array size error. 790. [bug] fix minor memory leak in ixfr code. 789. [bug] #669 was too aggressive. more than cached data was removed. 788. [bugs] improvements to tsig and dnssec. 787. [port] win/nt lint. 786. [port] IRIX and emul_ioctl(). 785. [bug] #780 broke A record update support. 784. [bugs] still trying to get IXFR working again. --- 8.2.2-T3B released --- 783. [support] make res_send() more friendly to the java scheduler. 782. [support] dangling cnames aren't errors, stop logging them. 781. [support] add -n option to ndc command, to run nonstandard named. 780. [bug] UPDATE did not support the AAAA RR. 779. [bug] miscellaneous IXFR fixes. 778. [support] don't complain to syslog about negative caching RRs. --- 8.2.2-T2B released --- 777. [bug] getword() didn't increment lineno at EOF. 776. [bug] the NOERROR_NODATA cookie overlapped a valid rcode. 775. [protocol] we weren't sending properly formated FORMERR responses. 774. [bug] UPDATE did not support the SRV RR. 773. [bug] named-xfer was calling inet_ntoa in one printf. 772. [typo] Typo in ns_parser.y on maybe_zero_port: line. 771. [lint] UNLINK now performs a INIT_LINK so explicit INIT_LINK's are nolonger needed after UNLINK. 770. [protocol] dynamic update prerequisites were inappropiately matching wildcards, at variance with RFC 2136. 769. [bug] ordering of CNAMES was driven by original query type. 768. [support] MINROOTS is now a configuration option "min-roots". 767. [clarity] adjust XFR log messages to be more clear about cause. 766. [support] add "serial-queries" option to dynamify MAXQSERIAL. 765. [feature] added evInitID() and evTestID() for NOTIFY work. 764. [bug] DNSSEC changed the semantics of match() without changing all the call sites that cared about it. 763. [bug] NOTIFY events caused by dynamic update weren't being deferred, and multiple NOTIFY events weren't being coalesced. 762. [support] don't rotate log file versions on server startup. 761. [port] named-xfer's openlog() was unconditionally using the LOG_CONS option. now it does what named does. --- 8.2.2-T1A released --- 760. [port] preliminary win/nt from baynetworks (thanks!) 759. [support] new compile time option BIND_IXFR, defaults to "off", since our testing has shown up some problems with it. 758. [feature] new "ndc reconfig" command only finds new/gone zones, doesn't stat() master files or qserial() slave SOA's. 757. [support] FORCED_RELOAD is no longer optional. 756. [support] fixed output format of hmac keys; removed DST chaff. 755. [feature] "also-notify" is now a global option. 754. [bug] the control socket was not checked for event lib compatability. 753. [feature] "ndc help" now returns one line command summaries. 752. [feature] "ndc trace" now takes an optional "level" argument. 751. [support] debugging output could segfault in ns_print.c::addstr. 750. [port] A/UX 3.1.1. 749. [port] #9 has now been done for all Makefiles. 748. [feature] "transfer-source" is now a global option. 747. [support] SORT_RESPONSE is no longer a compile time option, since the behaviour can be turned off at runtime with the "rrset_order fixed;" option. 746. [bug] don't bother rescanning the interfaces if setuid!=root. 745. [protocol] IXFR transmission was just plain wrong in some cases. 744. [support] allow the calling location of strings to be recorded. 743. [feature] $GENERATE now supports more record types, and options. 742. [port] port/sco50 was using /usr/local/etc for its ndc socket. 741. [port] HPUX needed __BIND_RES_TEXT. 740. [bug] #634 had the unfortunate side effect of disabling IXFR. 739. [port] probe for IPv6 structures, solaris openbsd freebsd 738. [bug] invalidate pointers back into linked list when element is removed. 737. [port] solaris: expr is sensitive to LC_COLLATE 736. [bug] potential single file descriptor leak opening /dev/random. 735. [bug] memory leak: having rrset-order set and reconfiguring the server results in a memory leak. 734. [port] linux only fills in as many entries as will fill the buffer with SIOCGIFCONF. 733. [bug] RD is not being set on first message to first forwarder resulting in false "Lame Server" reports and degraded service. 732. [bug] errors reading keys from master files could cause the the server to drop core. 731. [bug] highestFD was not reflecting the highest value the library could cope with. 730. [port] rand() does not modify the LSB on BSD based systems. 729. [bug] allow-query responses were dependent upon cache contents. 728. [bug] it wasn't possible to specify the flags of trusted keys in hex, which was inconvenient since dig prints hex. 727. [bug] TSIG keys weren't properly shared with named-xfer if the zone named contained a slash (/). 726. [bug] TSIG keys weren't reloaded correctly with 'ndc reload'. 725. [bug] only the first key in an acl was matched correctly. 724. [bug] "ndc restart" needed a short delay before checking for the health of a newly started name server. 723. [bug] TSIG signed zone transfer failed on especially large zones. 722. [doc] the example named.conf file had invalid TSIG usage. 721. [bug] duplicate records were tripping the cname-and-otherdata test, which wasn't necessary since they'll be ignored. 720. [port] solaris doesn't have gethostid() the way we build. 719. [lint] lots of lint fixed by bob and paul. 718. [bug] multiple CNAME support was not cycling the cnames in an RRset properly. 717. [bug] wrong /bin/ps flags in solaris prand_conf.h. minor tweak to ports/prand_conf/prand_conf.c to ensure proper flags in future ports. 716. [bug] log files are now closed/reopened on a size basis. 715. [clarity] root servers don't need to be primed. 714. [typo] extra "q" in a message in ns_maint.c. --- 8.2.1 released --- 713. [bug] don't loop on untimely eof within config file. 712. [port] hp-ux signals; aix bit types. 711. [perf] don't call find_zone() four times from within qnew(). --- 8.2.1-t7b released --- 710. [bug] can fetch zone from own address if port is different. 709. [bug] make sure zones are properly reinited when they die. 708. [bug] end marker or sizeof, but not both please. --- 8.2.1-t7a released --- 707. [port] AIX, HPUX, SunOS. 706. [feature] zone forwarding can now be applied to master, slave and stub zones as well as forward zones. 705. [bug] some zone options were not being copied. 704. [bug] very obscure problem fixed in res_update(). 703. [bug] single-zone reload was stomping freed memory. --- 8.2.1-t6b released --- 702. [port] solaris vs. enum; linux vs. IPv6. 701. [bug] NOTIFY rejection logic still wasn't correct. 700. [bug] complete #697 --- 8.2.1-t5b (rc2) released --- 699. [bug] if getting the ixfr change log fails send a axfr style response. 698. [bug] res_notify() was rejecting valid NOTIFY messages. re-organise code so that logged messages are more appropriate. 697. [port] linux. some versions define _GNU_SOURCE in features.h some version require the compiler to set the byte order when probing for IPv6 structures. 696. [bug] don't use NULL file pointer if IXFR transaction log cannot be opened due to permission errors. 695. [lint] another considerable amount of lint was removed. 694. [bug] only the last two forwarders would be used. 693. [bug] nsfwdadd() needed to continue outer loop. 692. [bug] RD was not being cleared by ns_forw(). this could cause DNS storms between lame servers. 691. [bug] We still had some leftover named-xfer ixfr tmp files. 690. [bug] return IXFR in question section of AXFR style IXFR response. 689. [bug] we now return "up to date" response to IXFR queries when required. 688. [bug] UDP IXFR now tells the client to use TCP. 687. [bug] IXFR was incorrectly reporting errors on DNSSEC RRs. 686. [port] hpux Makefile.set improvement (+O2 -> +ESlit). 685. [feature] mark recursive queries in query log. 684. [bug] named-xfer now ignores out-of-class glue. --- 8.2.1-t4b (RC1) released --- 683. [lint] considerable lint was removed. 682. [perf] another round of performance tweaks from HP (thanks!). 681. [bug] SIG wasn't being ignored when generating NOTIFY msgs. 680. [feature] delay parent reload as long as we can after removing child zone to save multiple parent reloads. 679. [port] port probe now recognizes SCO 5.0.5. 678. [doc] not all man pages were being installed. 677. [feature] lost feature "allow-recursion" added back in. 676. [bug] "100" was too small for ndc message sizes. 675. [bug] we weren't storing a (needed) extra copy of the zname. 674. [bug] SIGTERM wasn't working the first time it was sent. --- 8.2.1-t3b released --- 673. [bug] nslookup wasn't accepting _ at the beginning of names. 672. [bug] ndc was only passing the verb across the command channel and not the arguements. Reload of a single zone "really" works now. 671. [feature] you can reload multiple zones with a single ndc reload command. e.g. ndc reload zone1 zone2 ... 670. [bug] db_load did not work unless a RR had the class defined. 669. [bug] the cache is now purged when a forwarder is {re}loaded. 668. [bug] complete #652. 667. [bug] allow-query wasn't being allowed for stub zones. 666. [usability] only try to chown()/chmod() a control socket when the owner or permissions _change_ between reloads. 665. [bug] "options topology" is now possible to set. 664. [security] add important solaris-related security note to README. 663. [bug] "ndc -q" now turns off initial header and EOF printing. --- 8.2.1-t2b released --- 662. [usability] src/conf/ added, containing some of ISC's config files. 661. [protocol] we weren't sending AAAA RR's as AXFR glue. 660. [port] IRIX. 659. [contrib] author-submitted changes to dnssigner, new cider2named. 658. [protocol] print better messages wrt TSIG. add p_rcode(). remove _res_resultcodes[]. improve key handling. 657. [port] apply cpp to /usr/include/netinet/in.h to work out if struct sockaddr_in6 and struct in6_addr/inaddr6 are defined. 656. [bug] Classless IN-ADDR support was broken. 655. [bug] major overhaul of IXFR code. 654. [bug] dynamic update of non top of zone SOA now ZONEERR. 653. [feature] check-names now applied dynamic updates as if the zone was being loaded. REFUSED returned. 652. [port/bug] many operating systems allow more descriptors than their default FD_SETSIZE has room for. we catch this now, both by asking the operating system not to do this and by treating as invalid any out-of-range descriptor. 651. [protocol] any soft failures in res_send() will now cause the final return value to be TRY_AGAIN. previously the last server response received was the one returned. 650. [doc] resolver.5 man page clarified and corrected; res_init() made to do what the man page now says it does. 649. [port] make header files c++ compatible. 648. [bug] multiple options definitions of allow-query / allow-transfer / sortlist / blackist / topology are not allowed. warn rather than silently applying the last definition. 647. [bug] options max-ixfr-log-size was not being applied. 646. [feature] memcluster debugging support improved. -DRECORD_MEMCLUSTER to enable. 645. [bug] memory leaks 644. [bug] res_update() could not delete the first CNAME in a chain. 643. [bug] res_update() did not correctly handle labels with periods. 642. [port] SCO 5.0 portability improved. 641. [feature] $TTL now takes TTLs of the form 1w6d7h32m20s. 640. [bug] was returning NODATA rather than NXDOMAIN after a dynamic update removed the last RR from a childless node. 639. [bug] another fix for "rrset_order fixed". --- 8.2.1-t1a released --- 638. [bug] ixfr was still creating the wrong file names sometimes. 637. [bug] bin/dnsquery/dnsquery.c wasn't init'ing the resolver correctly befloew calling gethostbyname(). 636. [port] inet_ntoa() had to go back to being non-const for now. 635. [bug] AXFR wasn't forcing an autoincrement of SOA.SERIAL following a batch of UPDATE requests. 634. [feature] check all master soa's and use best serial, rather than trying them in order and grabbing the first one who answers with one better than the local one. 633. [port] SunOS 4.1.4 has a broken recvfrom() with non-blocking sockets. 632. [bug] res_mkupdate() signed/unsigned stupidity. 631. [bug] HMAC-MD5 fixes 630. [bug] NSTATS output was spaceless. 629. [misc] improvements to TSIG error logging. 628. [bug] "rrset_order fixed" was LIFO rather than FIFO. 627. [bug] TSIG signed zone transfers broken. 626. [bug] multiple CNAME support was broken. 625. [bug] key names are really domains so they need to be made canonical. 624. [bug] ns_name_pton() accepted domains of the form "example.." when it should have rejected them. 623. [feature] it is occasionally useful to know the local address used to perform a zone transfer. this is now logged. 622. [bug] missing check for malloc() failures in strndup(). 621. [bug] various things were wrong with nslookup's "ls -d" cmd. 620. [feature] forwarders are now retried like queries to the delegated nameservers. forward only should be more robust as a result. 619. [protocol] don't refresh TTL's from delegation information. 618. [feature] ndc is now quiet and verbose when it should be. 617. [bug] SOA counters now have minima as well as maxima. 616. [bug] needs were not always processed in a timely fashion. 615. [bug] ns_shutdown() memput() the wrong amount of memory when freeing the zones array. 614. [feature] ndc can now reload single zones including the root zone. 613. [bug] check for old unix domain socket / fifo prior to attempting to establish control channel. error message no longer just noise. 612. [port] Solaris UNIX domain sockets return different error codes and also may use FIFOs. 611. [bug] extend control timeout to 10 minutes. reloads can take a long time. 610. [bug] when reloading via the control channel we were reporting that we were about to reload after the reload was performed. Ensure message is set prior to reloading. 609. [bug] zoneTypeString() could be called with NULL pointer. 608. [bug] set various pointers to NULL after associated memory has been released to prevent accidental use. 607. [bug] finddata() was returning SIG's inappropriately. 606. [bug] fix two memory leaks in db_sec.c. 605. [feature] better error reporting from named-xfer. 604. [bug] fix a bug in the handling of $TTL's absence. 603. [port] add contributed/untested rhapsody port. 602. [bug] multiple "type hint" zones are now supported. 601. [bug] z_ftime wasn't being reset when fopen() failed. 600. [bug] gen_res_get() was initializing the wrong variable. 599. [bug] "ndc reload" exercised an uninitialized variable. 598. [bug] "nslookup reports danger" was reported ambiguously. 597. [bug] we weren't priming the cache in forward-only mode. 596. [bugs] many small bugs in DNSSEC handling were fixed. 595. [bug] nsupdate failed to support quite a few rr types: sig,key,nxt,eid,numloc,srv,atma,naptr,kx,cert 594. [proto] BADID removed per I-D. 593. [bug] mk_update() didn't support SIG. 592. [bug] lcl_pr and lcl_ho were using uninitialized bufsizes. 591. [port] linux. 590. [port] irix. 589. [doc] hesiod(3) man page contrib'd in 1996 finally put in. 588. [bug] too many lame servers at once was fatal. --- 8.2 released --- 587. [perf] uses about 5% less memory than 8.1.2 now. 586. [perf] faster at tcp, therefore less blocking on udp. 585. [misc] various releng lint. 584. [bug] IXFR wasn't doing DNSSEC RRtypes. 583. [bug] dnskeygen now fully qualifies its names; better usage. 582. [port] irix needed some patches applied during the build. 581. [bug] match_order() could dump core after "ndc reload". 580. [bug] ip_match_is_none() could dump core. 579. [bug] state names were off by one in src/lib/isc/ctl_srvr.c. 578. [misc] try without "transfer-source" if axfr connect() fails. 577. [contrib] sqlbind-8. 576. [bug] insecure updates weren't supported. 575. [doc] better documentation of key, trusted-key, zone pubkey. 574. [bug] was freeing freed memory on exit. 573. [port] nextstep. 572. [misc] centralize the name hashing logic (widen in some cases) 571. [perf] the new db_marshal() code was taking too much memory. 570. [perf] the lame server storage was taking too much memory. 569. [bug] src/lib/isc/ctl_srvr.c had an incomplete assertion. 568. [doc] Brent Baccala contributed an nsupdate man page. 567. [port] mpe, nextstep. 566. [protocol] upgrade to tsig draft 08. 565. [lint] use right relative paths for dnssafe includes in dst. 564. [bug] default security level for update rr's wasn't set. 563. [bug] debugging output in dprint_key_info() could panic us. 562. [perf] 8.2-t6b used 30% more memory on root name servers than 8.1.2 did. most of that was db_marshal hash tables. --- 8.2-T6B released --- 561. [bug] DST more graceful in handling unsupported algorithms. 560. [feature] lame server ttl now a configuration option. Re-enable lame server negative caching. 559. [bug] sysquery() was still using the child's name when it switched to using the parent's NS list causing false lame server reports. 558. [bug] disable lame server negative caching for the present. 557. [bug] undersized tcp messages are now detected early. 556. [bug] DNSSEC fine tuning. 555. [bug] the named.conf lexer was depending on two characters worth of putback buffer, ansi c guarantees one char. 554. [port] port to "next" contributed by jack bryans. 553. [contrib] added "snoof", another script kiddie toy. 552. [bug] allow-query didn't interact well with external cnames. 551. [bug] validate_zone could crash the server. 550. [lint] ns_maint was using ns_log_default, not ns_log_in_xfer. 549. [port] netbsd and openbsd improved. prand_conf improved. 548. [bug] ns_resp was using the wrong logging category. 547. [bug] dig was reinit'ing its resolver flags incorrectly. 546. [bug] nsupdate didn't handle HINFO,ISDN,TXT,X25 correctly. 545. [feature] added dnssafe back in. 544. [feature] removed DES encryption support. 543. [port] cleaned cylink of non used definitons in headerfiles. 542. [bug] include/dst no longer needed 541. [bug] CERT records are allowed to have alg == 0. 540. [doc] Removed outdated doc/secure, updated dnssigner documentation, updated dnskeygen.1 539. [bug] db_dump() was misparsing CERT records. 538. [feature] The KEY set is along with SOA, NS, A, AAAA records. 537. [bug] Multiple signatures are handled correctly. 536. [bug] SIG record expiration should be checked when the SIG is verified. 535. [bug] Queries for SIG records of non-authoritative names should not look in the cache or cache the results. 534. [bug] DNSSEC SIG records are dropped when they don't sign any data correctly. 533. [bug] SIG and NXT records are correctly handled when received in responses by named 532. [bug] dynamic update data is now always considered insecure, rather than having no security status. 531. [bug] dynamic update can again remove all data associated with a name (type ANY, class ANY). 530. [lint] downgraded "ctl: unexpected eof" from error to debug. 529. [port] unixware 7 port received. 528. [bug] timeouts could make ctl_srvr dump core. 527. [bug] we were not reliably reaping our children. 526. [bug] Cached CNAMES pointing to servers returning Type 3/4 NXDOMAIN are translated to Type 3 NODATA responses. 525. [bug] nscount could be short if we had to recurse after following a cname and we got a negative response. NS rrset got split between AU and AD sections. 524. [protocol] RFC 2308 support added. 523. [feature] mark lame servers as such and don't use them for NTTL. 522. [port] solaris 7 is now known to work. 521. [port] sunos4 should be supported now. 520. [bug] inet_pton() was allowing some bad ipv6 addresses in. 519. [bug] refuse duplicate also-notify's; optimize logging. 518. [port] hpux portability fixes. 517. [contrib] dnswalk wasn't copying with 8.* "dig" output. 516. [port] MPE portability fix. --- 8.2-T5B released --- 515. [security] lib/dnssafe code removed; now a separate patch. 514. [port] freebsd patches. 513. [bug] memory leak in res_mkupdate(). 512. [bug] $GENERATE could use an unset ttl. 511. [bug] $TTL warning test was wrong. 510. [port] bugs and things found by the netbsd folks. 509. [bug] The labels field in the SIG record may be less than the number of labels in the domain name if the owner of the SIG is a wildcard. 508. [bug] rrset ordering contained an off-by-one error 507. [bug] NXT set processing was not distinguishing between the upper and lower sets at delegation points. 506. [contrib] more script-kiddie toys, this time contrib/adm. 505. [bug] the ixfr changes to named-xfer destabilized stubs. 504. [port] some IRIX problems fixed. 503. [bug] ixfr wasn't correctly setting up its qsp. --- 8.2-T4A released --- 502. [bug] some config file parsing was still using malloc(). 501. [feature] named sets the AD bit in the header when returning authenticated data 500. [bug] dst_verify_data returns the documented error codes 499. [bug] verify_set now verifies the correct data 498. [bug] ixfr was not completely finished. 497. [bug] don't put zone 0 on the free list. 496. [bug] Losing all but last RR of RRset. 495. [port] random portability noise. 494. [bug] sysquery() should not let nlookup() change its data. 493. [feature] add "options ... rrset_order ... cyclic|random|etc". this allows round robin to be turned off selectively, or replaced with pseudorandom ordering, or whatever. 492. [bug] src/bin/named/db_sec.c was memputting objects twice. 491. [feature] add IRP (Information Retrieval Protocol) and daemon. this is functionally similar to solaris "nscd". 490. [bug] lib/isc/ctl_srvr.c couldn't overlap read and write. (also: add session context set/get.) 489. [bug] "cname and other data" was more complex than thought. 488. [port] some netbsd portability stuff. (still not working?) 487. [port] digital unix 3.2 wasn't working (4.0d was though). 486. [feature] add "sortlist", which may yet be merged/renamed into the "topology" verb. 485. [bug] do not complain about default TTLs unless a master. 484. [contrib] add contrib/z0ne, a useful tool for crackers. 483. [contrib] add contrib/query-loc[-*] to look up LOC RR's. 482. [bug] all RR's must now be of the same class as the zone. 481. [bug] outbound zone transfers are killed on any UPDATE. --- 8.2-T3A released --- 480. [bug] ns_update was corrupting TXT records 479. [bug] res_mkupdate was not handling WKS, HINFO, TXT, X25, ISDN, NSAP and LOC records. 478. [bug] name_pack could leave a bad compression pointer. 477. [port] improved support for FreeBSD 3.0. 476. [bug] BSDI contributed some fixes to the /etc/group parsing. 475. [bug] another memory leak in hesiod_resolve(). 474. [bug] SRV RR names were being compressed on output. 473. [feature] IXFR is no longer optional and has been cleaned up. 472. [bug] IXFR was disabling USE_PID_FILE. 471. [feature] add support for CERT records. 470. [bug] rrset_db_upgrade was updating the wrong cache. 469. [performance] use a free list for unused zones. 468. [feature] add getaddrinfo, courtesy of WIDE. 467. [lint] include/dst/dst.h moved to include/isc/dst.h. 466. [bug] fix core dump introduced with tsig glue. --- 8.2-T2A released --- 465. [bug] ref counting bug in ns_xfr. 464. [bug] correct cut&pasteo in IXFR config syntax. 463. [lint] clean psf files after top level "make tar". --- 8.2-T1A released --- 462. [feature] we now use randomized query id's. 461. [feature] new option "version" added. 460. [feature] add initial IXFR support from Check Point Technologies. 459. [bug] res_update() was putting debugging info on stderr. 458. [doc] add named.conf(5), improve doc/html. 457. [feature] named-bootconf is now written in /bin/sh and it is now installed in ${DESTSBIN}. 456. [bug] res->defdname[] wasn't always properly \0 terminated. 455. [bug] _PATH_MEMSTATS was never being used. 454. [doc] the html docs weren't clear about logging having to be specified first in the named.conf file. 453. [feature] add zone type "forward" for selective forwarding (sometimes called "split horizon" or "fake root"). 452. [bug] lib/irs/* was generally not coping with oversized lines and files not ending in \n. 451. [port] BSD/OS 2.* is now a separate port. 450. [Feature] added DNS key generator in bin/dnskeygen. 449. [contrib] added DNS zone signer in contrib/dns_signer. 448. [doc] sample named.conf and html documentation include examples of DNSSEC / TSIG configurations. 447. [feature] named verifies TSIG records on incoming messages, and generates TSIG records on outgoing messages. 446. [feature] res_nsendsigned, res_nfindprimary, res_nsendupdate provide TSIG aware resolver functions. 445. [feature] ns_sign and ns_verify generate/authenticate TSIG signatures on DNS messages. ns_sign_tcp, ns_sign_tcp_init, ns_verify_tcp, and ns_verify_tcp_init are used for tcp transfers. 444. [feature] acls can now include shared key names. 443. [feature] added DNSSEC verification of zone data on load and partial verification of signed data received over the wire. 442. [feature] lib/dst (TIS digital signature toolkit), lib/dnssafe, and lib/cylink added to provide functionality needed for DNSSEC and transaction signatures. 441. [bug] fixed memory leak in hesoid support. 440. [bug] support for res in lib irs was a mess. _res now controls the behaviour of get*by*() again. 439. [bug] fix *END_RESULT macros in port/solaris/port_before.h. 438. [feature] permit the install user and group to be overridden. 437. [feature] TCP truncation now reports IP address of the server. 436. [bug] memory leaks in nsupdate. 435. [doc] updated resolver.3 434. [bug] named.run was not always being created when ndc trace was run. 433. [bug] req_notify required the slave zone to have been loaded. this may not be the case when a zone has expired or is being established over a dial on demand link. 432. [feature] blackhole queries from these nets. do not use these nets to resolve queries. 431. [feature] loop breaking with UDP based well known services. 430. [bug] memory leaks in dispatch_message. 429. [feature] fast retries on host/net unreachable. 428. [bug] CNAME and other data is now a hard error. 427. [feature] support very large numbers of virtual interfaces. 426. [bug] bring named closer into line with the data ranking in RFC 2181, Section 5.4.1. 425. [bug] removed spurious debug statment that generated a lot false bug reports. 424. [bug] closed file descriptor leaks in ns_update. 423. [feature] loc_ntoa() can now accept NULL like other _ntoa's. 422. [feature] you can now specify a port on the master statement to allow transfers from a non standard port. 421. [feature] warn when the root hints do not match reality. 420. [misc] added support for bcc (bounds checking compiler). 419. [feature] bring negative caching into RFC 2308 compliance. 418. [bug] expire now behaviour now as per RFC 1034/1035. 417. [bug] updates and zone transfers weren't locking eachother. 416. [port] support added for HPUX B.11.* 415. [feature] ndc is a C program now, uses new "controls" subsystem. 414. [feature] "controls" element of named.conf now live and working. 413. [feature] octal and hexadecimal numbers now parsed in named.conf. 412. [bug] we now support 2**24-1 (16M) zones. (need namespaces!) 411. [bug] fix *END_RESULT macros in port/bsdos/port_before.h 410. [feature] added support for dial on demand links between servers. 409. [port] remove aggregious use of snprintf(). 408. [feature] add -b option to dig to set srcaddr of tcp connects. 407. [feature] added $GENERATE to generate sets of RR's that only differ by an interator. 406. [doc] added manpage for inet_cidr_ntop() inet_cidr_pton(). 405. [bug] res_nsend() closed sockets unnecessarily on timeout. handle change NS list and RES_STAYOPEN generically. 404. [bug] inet_addr/inet_aton/inet_network accepted illegal inputs as legal. Also enforce octal input. 403. [bug] inet_cidr_ntop() was not producing correct output for all possible inputs. 402. [bug] fix retry/retransmit logic in face of network errors. 401. [doc] the "transfer-source" zone option wasn't documented. 400. [bug] bin/host was dumping core - converted to use getopt. 399. [port] use time() rather than gettimeofday() in dig. 398. [bug] named could exit silently on assertion failures, now assertion failures are logged using INSIST. 397. [port] add an AIX 3.2 port (requires GNU utilities). 396. [bug] dig and nslookup allowed sscanf/sprintf overflows. 395. [bug] dig and nslookup were unable to deal with 64KB answers. 394. [feature] add RES_NOCHECKNAME and "options no-check-names" (in resolv.conf) to turn off modern host/mail name checks. 393. [bug] lib/isc/tree.c was missing a critical \ (#if DEBUG). 392. [bug] inet_aton() wasn't requiring nonterminal octets to be in the range of octets, i.e., 1.300.1.1. 391. [bug] fix bug in MAX_XFERS_RUNNING logic. 390. [bug] ns_update() was capable of renaming an open file. 389. [feature] libbind.a now has a "ctl" subsystem, which is planned to replace signals as a the communication path between "ndc" and "named". preliminary support is in "named". 388. [feature] preliminary/nonfunctional/nonstandard ZXFR support. 387. [feature] inet_cidr_pton() and inet_cidr_ntop() added. 386. [bug] inet_net_pton() was not parsing hex correctly. 385. [feature] three new options for the RES_OPTIONS environment var or for the "options" directive in /etc/resolv.conf: attempts:NN default res.retry timeout:NN default res.retrans rotate use ALL listed nameservers 384. [feature] there is now a nearly-thread-safe resolver API, with the old non-thread-safe API being a set of stubs on top of this. it is possible to program without _res. note: the documentation has not been updated. also note: IRS is a thread-ready API, get*by*() is not. (see ../contrib/manyhosts for an example application.) 383. [contrib] bsdi contributed an /etc/services.db hack, which is currently conditionalized for bsd/os but would work on any modern BSD-derived system (DB, snprintf, etc). 382. [port] bsd/os 4.0 defines its own pselect(), which differs from the one we simulated. we now simulate the right one, and use the right one. 381. [contrib] added contrib/srv, the beginnings of SRV client side. --- 8.1.2 released --- 380. [bug] Replaying the dynamic update log could trigger an INSIST. 379. [port] Updated IRIX port. 378. [bug] The declaration for res_freeupdrec() in resolv.h didn't use __P(). 377. [func] The server now sets SO_SNDBUF on UDP sockets. 376. [port] The malloc() implementation on many systems didn't like memcluster.c's 4KB block allocations, sometimes causing huge amounts of memory to be wasted. memcluster.c now allocates bigger chunks and makes its own 4KB blocks. 375. [bug] If more than (sizeof u_long) gets occurred for a particular memory bucket, an INSIST about puts < gets might have been erroneously trigged. Now total gets and outstanding gets are counted. 374. [port] SCO 3.2v4.2 doesn't have initgroups(), so we do not want to define CAN_CHANGE_ID. 373. [port] Updated LynxOS port. 372. [port] Updated SCO 3.2v5.0.x port. 371. [bug] "make install" could fail on some Linux systems because src/port/linux/include/net/Makefile didn't cope with an empty HFILES variable. 370. [bug] Trying to update an expired slave zone would cause the server to panic. 369. [bug] The Makefile for named-xfer didn't try to create ${DESTDIR}${DESTEXEC} if it didn't exist. 368. [bug] Interface scanning could get confused on BSD-like systems if the sa_len of the address was less than sizeof (struct sockaddr). 367. [func] The default value for the host-statistics option has been changed to "no". --- 8.1.2-T3B released --- 366. [bug] Z_AUTH was set on the cache zone do_reload(). 365. [security] Missing bounds checking in inverse query handling allowed an attacker to overwrite the server's stack. 364. [port] Added support for HP MPE. 363. [bug] named-xfer automatically restarts the transfer if the SOA changes during the transfer. There was no limit on the number of restarts, resulting in a lot of wasted effort if the SOA was constantly changing. The number of restarts is now limited. 362. [security] Requesting a zone transfer for a domain name which had a resource record of a certain format would cause the server to abort(). 361. [bug] named-xfer tries to close files named might have had open. On Solaris, sysconf(_SC_OPEN_MAX) can return RLIM_INFINITY, and if it did named-xfer would try to close all those files. named-xfer now applies an upper limit of FD_SETSIZE. 360. [port] Solaris 2.5 systems needed to be included in port_after.h to get rlim_t. --- 8.1.2-T3A released --- 359. [func] IRS group support is now controlled by the WANT_IRS_GR define in port_before.h. 358. [port] Updated IRIX port. 357. [port] Added support for QNX. 356. [func] Added -u (set user id), -g (set group id), and -t (chroot) command line options to 'named'. 355. [func] If getnetconf() fails because it can't create the socket used to get the interface list, the server will log an error if it is doing a periodic interface scan, and panic otherwise. Previous versions of the server always panicked. 354. [security] Bounds checking in named-xfer, dig, host, and nslookup had problems similar to those in item 293. Added a few more bounds checks to the server. 353. [port] Paths are no longer overridden in port_after.h, and are now generated from the various DEST paths in Makefile.set. 352. [bug] Because of problems with setting an infinite rlim_max for RLIMIT_NOFILE on some systems, previous versions of the server implemented "limit files unlimited" by setting the limit to the value returned by sysconf(_SC_OPEN_MAX). The server will now use RLIM_INFINITY on systems which allow it. 351. [port] Updated HP/UX 10.x port. 350. [bug] errno could be changed by certain signal handlers. These signal handlers now save errno on entry and restore it on exit. This changes eliminates the need for the SPURIOUS_ECHILD #define. 349. [bug] hesiod.h wasn't installed. 348. [port] Added support for LynxOS. 347. [bug] res_update() leaked the zone section it allocated. This leak no longer occurs on normal returns, but still occurs when there is an abnormal return. This will be addressed in a future fix. 346. [bug] Fix 303 fixed one thing and broke another, resulting in a nonfunctional grscan(). 345. [bug] Fix 328 was bad, causing the root zone to be purged every time a toplevel domain was reloaded. 344. [bug] The priming fix in change 330 erroneously called unsched() twice, causing a core dump if priming failed. The priming fix could also erroneously query [0.0.0.0].0. 343. [bug] The REQUIRE() in free_rrecp() was wrong, and was triggered by an unapproved update. 342. [port] Added support for SCO UNIX 3.2v5.0.4. --- 8.1.2-T2A released --- 341. [port] The LOG_CONS option to openlog() does not work as documented on some systems. The server will now use LOG_CONS only if USE_LOG_CONS is defined by the port. Currently the bsdos, decunix, freebsd, linux, and netbsd ports define USE_LOG_CONS. 340. [bug] The pid file was updated before the configuration file had been read. 339. [port] #define HAVE_GETRUSAGE for Solaris >= 2.5. 338. [func] 'host' can now print AAAA records. 337. [bug] rm_datum() erroneously set dp->d_next to NULL when savedpp wasn't NULL. Given a dynamic update operation that deleted more than one RR, this bug would cause all but one of the RRs to be leaked, and would prevent correct rollback if the update failed. 336. [bug] Make sure 's' isn't negative in res_send(). This shouldn't happen, but there have been some reports suggesting it can happen. 335. [lint] Cleaned up more gcc warnings. 334. [port] Added support for HP-UX 9.x. 333. [bug] db_glue.c didn't compile if DEBUG wasn't defined. 332. [bug] named-bootconf.pl didn't convert secondary lines that didn't contain a filename correctly. 331. [bug] If the server was configured with forwarders (but not in forward-only mode), and a query ran out of forwarders and had no nameservers, then the server would erroneously forward the request to [0.0.0.0].0. 330. [bug] If priming of the root servers failed, recovery could take a long time. If using forwarders to prime and the query expired, the first forwarder would always be skipped on subsequent attempts. The server complained about priming problems in forward-only mode, even though it doesn't matter. 329. [port] Some versions of Linux apparently need SPURIOUS_ECHILD. 328. [bug] purge_zone() didn't recurse if given the root zone, causing old data and new data for the root zone to be merged. 327. [func] Add log_check() and log_check_channel(). 326. [func] Add r_prev field to ns_updrec in . 325. [bug] Rollback of a failed dynamic update was done in FIFO order instead of LIFO order. 324. [bug] evTryAccept() closed the wrong fd if getsockname() failed. 323. [bug] eventlib didn't clear bits that had been serviced or deselected out of ctx->{rd,wr,ex}Last. 322. [bug] evDestroy() destroyed the files list before destroying the streams list. If there were any active streams, this would cause a double destroy of the streams' file objects, very likely triggering an 'insist'. 321. [bug] The correct error code for a failed asynchronous connect was not reported. It now is, at least on systems that have the SO_ERROR socket option. 320. [func] Allow multiple pending accepts. evTryAccept() now reports the errno if an error was queued. 319. [bug] The toplevel Makefile passed MARGS before $settings, which prevented overriding a port's Makefile.set from the command line. 318. [bug] The Solaris port_after.h checked for SUNOS_2_5_1 instead of SUNOS_5_5_1. 317. [unused] [This change number was allocated but not used.] 316. [bug] evTryAccept() didn't append to the done list correctly if connLast wasn't NULL. 315. [bug] The dynamic update code was incorrectly converted to clean up ns_updrec structures using the new clustered memory allocator, and this would cause an 'insist' to be triggered some time after a dynamic update had been processed. Instead of freeing the ns_updrec fields directly in ns_update.c, res_freeupdrec() was added to the resolver. 314. [bug] Adding and then deleting an RR in a single dynamic update request would crash the server. 313. [bug] The nameserver would only try zone transfers from the master that answered its SOA query. If a master for some reason can answer the SOA but not the AXFR, the other masters (if any) should be tried. 312. [security] Bounds checking in the resolver and dynamic update code had problems similar to those in item 293. Added more checks to ns_resp.c. 311. [bug] The s_wbuf in the qstream structure was leaked in certain zone transfer failures. 310. [bug] If the server ran out of memory in ns_xfr(), the subsequent connection cleanup could modify the z_numxfrs field of zone 0 instead of the zone being transferred, causing an 'insist' to be triggered later. 309. [bug] NAMELEN() could return a negative length. 308. [func] Don't log ECONNRESET in stream_getlen(). 307. [bug] include/isc/assertions.h and include/isc/list.h weren't installed. 306. [bug] Timewarping into the future would cause repeating timers to generate an event for every interval between the previous time and the new time. Repeating timers are now rescheduled based on the last event time, not their due time. Idle timers now use the last event time to compute the idle interval instead of the due time. 305. [bug] The BOUNDS_CHECK() for the 5 32-bit integers in the SOA RR was wrong. 304. [bug] lib/isc/assertions.c and lib/isc/memcluster.c did not follow the port_{before/after}.h convention. memcluster.c #included eventlib.h but did not need it. --- 8.1.2-T1A released --- 303. [bug] 'bp' in grscan() in lib/irs/lcl_gr.c was incorrectly validated, potentially causing corrupt data to be read. 302. [port] #define HAVE_GETRUSAGE for Solaris >= 2.5.1. 301. [port] Added support for Solaris 2.6. 300. [bug] The space for the pathname of named-xfer in the options block leaked. 299. [bug] wasn't in the include directory, and wasn't included before "port_after.h". 298. [func] Added "deallocate-on-exit" and "memstatistics-file" options. If deallocate-on-exit is "yes", the server will painstakingly deallocate every object it allocated. This is slower than letting the OS clean things up, but is helpful in detecting memory leaks. 297. [port] GNU libc 2.0 doesn't have so in the Linux port we now provide a stub nlist.h that includes the real nlist.h if GNU libc < 2.0 and does nothing if >= 2.0. 296. [bug] "make stdlinks" didn't "mkdir /var/obj" if /var/obj didn't exist. 295. [bug] Specifying a query-source with and address and port that the server was listening to didn't work. 294. [security] The server was willing to answer queries on its forwarding sockets. 293. [security] rrextract() did insufficient bounds checking which could cause it to crash the server by reading from an invalid memory location. 292. [bug] The server sometimes leaked the flushset (ns_resp.c). 291. [bug] The server did not detect oversized UDP packets, causing useless retries. 290. [bug] free_listen_info_list() leaked the IP matching lists; the leak occurred when the config file was reloaded. 289. [bug] [This bug number was allocated for something that turned out not to be a bug.] 288. [func] Add new list and assertion code to the ISC library. 287. [bug] "dig +sort" doesn't do anything, but was mentioned in dig's usage message, as well as in the man page. 286. [bug] Some systems have a default FD_SETSIZE much smaller than the number of files that can be opened. This could cause problems in the resolver and eventlib. FD_SETSIZE may now be set in port/*/include/fd_setsize.h. 285. [bug] If OS probing failed to match any of the supported ports, the build would try to continue with BSD 4.4 settings, with poor results in most situations. An error message is now printed if probing fails. 284. [func] The interface list is now doubly-linked. 283. [bug] The server would panic if binding to an interface that it had discovered failed. Simply not listening to the interface is a better solution. 282. [bug] The nslookup Makefile didn't prefix DESTHELP with DESTDIR when setting DEFS. 281. [bug] A socket() called in ns_main.c used PF_INET instead of AF_INET. 280. [bug] The sample named.conf used "clean-interval" instead of "cleaning-interval". 279. [bug] Some panic() messages in the IP matching code in ns_config.c were wrong. 278. [bug] Setting an interval to zero (e.g. interface-interval) eventually caused random timer destruction. 277. [bug] ns_panic() used "args" twice, but only called va_start() and va_end() once. 276. [bug] nslookup's "ls" command always listed all records instead of behaving the way its man page describes. 275. [bug] add_related_additional() leaked memory if the name was already in the related array. 274. [bug] If a timer was cleared while in executing its callback, and a new non-repeating timer was created afterwards (but still in the callback), the new timer was erroneously destroyed when the callback completed. 273. [func] Added transfer-source and host-statistics options. 272. [func] The zone number is now unsigned, allowing up to 65536 zones instead of the previous limit of 32768. 271. [func] Added evDefer(). 270. [bug] The meaning of the count returned by select() varies somewhat by operating system. Under certain circumstances, this confused eventlib's accounting and caused the server to spin. 269. [func] Added evLastEventTime(). 268. [bug] Connections weren't cleaned up when the eventlib context was destroyed. 267. [func] Added evTimeRW() and evUntimeRW() to control idle timer usage in the eventlib streams module. 266. [func] Added file descriptor table to ev_files.c to improve performance of evSelect() and evDeselect(). 265. [func] Added evHold(), evUnhold(), and evTryAccept(). 264. [func] Double-link many eventlib lists to allow faster removal of list elements. 263. [bug] Remember the previous non-blocking status of sockets given to evListen(). 262. [func] Added idle timers to eventlib. 261. [func] Added clustered memory allocator to eventlib; eventlib and named now use this allocator. 260. [func] The value of FD_SETSIZE that eventlib uses can be set by changing include/fd_setsize.h. 259. [bug] Notification of hosts on the also-notify list stopped after the first successful notification. --- 8.1.1 released --- 258. [bug] Setting SO_SNDLOWAT to 0 in ns_xfr() wasn't doing what it was intended to do, and could trigger a kernel bug on various systems derived from BSD 4.4. 257. [bug] In lib/irs/dns_ho.c, variable needsort was used in addrsort() before it was initialized. 256. [func] Ignore ECHILD from select() if SPURIOUS_ECHILD is defined. 255. [bug] The contents of libport.a needed to be in libbind.a. libport.a has been removed. 254. [install] Install library and .h files under /usr/local/bind instead of /usr/local. When the include files were in /usr/local/include, some compilers would automatically use them. The clients would typically not link with -lbind, causing unresolved symbols at link time. 253. [port] Removed change 216. 252. [port] Added port for UnixWare 2.0.x. 251. [doc] Added a documentation on installing to non-default locations. 250. [bug] The Makefiles for the binaries didn't create the installation target directories if they didn't exist. 249. [bug] Change HAS_SA_LEN to HAVE_SA_LEN in the AIX 4 port. 248. [security] The server now caches only those response records that are within the current query domain. 247. [bug] Forwarding of dynamic update requests sent to a slave for the zone is broken. This will be fixed in a future release, but in the meantime the server will simply refuse the request. Cleaned up the way some update code indicated that the request should be refused. --- 8.1.1-T2B released --- 246. [bug] process_prereq() could core dump if the name being processed wasn't known. 245. [bug] It was possible to evSelectFD the same event bits on the same fd more than once. 244. [bug] eventlib didn't decrement fdCount correctly if the eventmask matched in multiple descriptor sets. 243. [lint] Improved comment in stale(). 242. [port] Added port for OpenBSD. 241. [bug] evConnect() didn't evDeselect() the fd if connect() failed, which would cause us to call select() with a mask that included a closed file. select() would then return EBADF and trigger an 'insist'. 240. [bug] evCancelConn() closed the fd. 239. [port] SunOS doesn't supply RAND_MAX. 238. [bug] fakeaddr() called inet_aton() which wasn't strict enough. inet_pton() is now used. 237. [port] Added UnixWare 2.1.2 port. 236. [bug] The buffer in res_querydomain could overflow. 235. [bug] Fixed memory allocation problems in lib/irs/nis_gr.c. 234. [bug] evDeselectFD didn't restore the fd's previous nonblocking status correctly. 233. [func] Define SPURIOUS_ECHILD in Solaris port. Don't complain about getting ECHILD from recvfrom() if SPURIOUS_ECHILD is defined. 232. [func] named-bootconf.pl now supplies a commented out query-source directive and instructions to use it if there's a firewall involved. 231. [bug] Changed a few strdup() calls in rrextract() into savestr() calls. This prevents "related" checking from being turned off if the server runs out of memory. 230. [bug] If the query control structure was reset in ns_resp.c, we leaked the memory used for the previous qp->q_domain. 229. [func] Added the "dump-file" and "statistics-file" options. 228. [bug] named.conf called "statistics-interval" "stats-interval". 227. [func] demoted "zones changed" and "zones shrunk" messages in tryxfer() to debug level 3. --- 8.1.1-T1A released --- 226. [bug] evCancelConn trashed the connections list if the first element was removed. This could cause a seg fault or trigger an 'insist'. 225. [bug] In the "cannot redefine listen-on for port ..." error message, the port was not converted to host byte order before being printed. 224. [port] Added port for AIX 4. 223. [bug] The dynamic update routine findzone() didn't match class, so if you had two zones with the same name but different classes (e.g. IN and HS), then the wrong allow-update ACL could be used, and the wrong zone could be updated. 222. [bug] If a dynamic master zone was updated and then was made non-dynamic by removing the allow-update ACL or changing it to "none" before the zone had been dumped, then the master file would not reflect the update. 221. [func] added 'also-notify'. 220. [func] revised HAVE_GETRUSAGE ifdefs in ns_config.c. The "cannot set resource limits on this system" message on systems without HAVE_GETRUSAGE will now be logged once per options block, and the message severity is now "info" instead of "warning". 219. [bug] If the root name was encoded in a message using a compression pointer, dn_expand() would erroneously return "." as the name instead of "". 218. [bug] when gethostans() in dns_ho.c encountered a CNAME while processing a PTR query, it erroneously required that the CNAME target pass the res_hnok() test (i.e. that it be an RFC 952 hostname). 217. [bug] dnsquery didn't work because it tried to use the obsolete and broken p_query() call instead of fp_nquery(). 216. [port] set SH=bash in port/freebsd/Makefile.set. 215. [port] #define ts_sec and ts_nsec to tv_sec and tv_nsec respectively in port/freebsd/include/port_before.h. 214. [bug] the clarification TTL changes (see change 145 below) set the SOA minimum field to zero if the MSB was set. The server now leaves the SOA RR alone, but sets z_minimum to zero if the MSB is set. 213. [bug] if the SOA refresh or retry fields of a slave zone were 0, an 'insist' would be triggered when zone maintenance was performed. The server still leaves the SOA RR alone, but now imposes a minimum value for z_refresh and z_retry. 212. [func] added the clean-interval, interface-interval, and statistics-interval options. 211. [func] scan for new or deleted interfaces periodically. 210. [func] the _PATH_DUMPFILE default is now "named_dump.db". 209. [bug] and were #included after port_after.h. They are now #included before it, since they #include system header files. ns_lexer.h was #including and ns_parseutil.h. Now it #includes neither one. These changes required that the definition of struct timespec be moved from port_after.h to port_before.h in the ULTRIX, SunOS, and A/UX ports. 208. [port] removed HAVE_GETRUSAGE from the Solaris port, since Solaris only has it if a Berkeley compatibility package is installed. 207. [bug] abortxfer() always used SIGKILL, which didn't give named-xfer a chance to clean up after itself. Now abortxfer() does a SIGTERM first. If the SIGTERM isn't successful, it will use SIGKILL. 206. [bug] If two zones with the same name but different classes (e.g. IN and HS) were defined, then a zone transfer of whichever zone loaded first would work normally, but a zone transfer of the second would give only the NS and SOA RRs. 205. [bug] certain operating systems (notably Solaris) return error codes the server didn't expect, and thus treated as fatal to the interface. More error codes are now recognized. The server will now log unrecognized errors, but will not delete the interface. Certain error results from recvfrom() and accept() now panic the server. 204. [bug] stub zone transfers would fail if there were no NS records in the SOA response. The stub logic now works as intended and has more error checking. 203. [bug] we logged a failure of bind() in opensocket_d() twice. 202. [port] Linux defines AF_INET6 as 10, so we use that value in port/linux/include/port_after.h. 201. [bug] library Makefiles want to press on if linking of an individual module fails. The 'ld' rule was set up to do this, but the subsequent 'mv' rule was not, causing the make to stop if the 'ld' failed. Now the 'mv' is done only if the 'ld' succeeds. 200. [bug] the value of timeout.tv_sec was printed in SendRequest (bin/nslookup/send.c). select() on some systems (such as Linux) modifies the value of the timeout, so printing it is useless since it will always be 0. 199. [func] if s is too big for FD_SETSIZE in res_send, complain and try another nameserver. 198. [bug] sysnotify() was too strict in requiring an NS RR for the server named in the SOA MNAME field. RFCs 1996 and 2136 say the NS RR is optional. 197. [bug] The parser erroneously freed zone_name if a zone redefinition was attempted. This would cause the server to dump core if a zone appeared more than once in a configuration file. 196. [bug] Makefiles below port/*/include had "fi \" followed by "done" on the next line. This made bash 2.0 unhappy. The "fi" is now followed by a ";". 195. [port] ULTRIX's sh doesn't like an empty "for x in ..." list, and that was causing "make install" to fail in the src/port/ultrix/include/rpc directory. 194. [port] add SH variable to toplevel Makefile, document the need to use SH=bash on systems where /bin/sh is derived from "ash". 193. [bug] named-bootconf.pl could repeat end-of-line comments 192. [bug] ndc was being installed in DESTBIN instead of DESTSBIN. 191. [bug] block delivery of all other signals when in SIGTERM handler in named-xfer. 190. [bug] named-bootconf.pl didn't handle non-masked xfrnets correctly if the network was class B or class C. --- 8.1-REL released --- 189. [port] update to the port/sco50 directory rcvd from author. 188. [func] to avoid potentially confusing log messages, don't set Z_DYNAMIC if "allow-update { none; };" is specified in the config file. 187. [bug] a panic() in new_ip_match_mask() erroneously referred to the function as "new_ip_match_pattern". 186. [bug] transfers-in couldn't be set higher than the default. It may now be set as high as 20. 185. [doc] add a stub example to named.conf. 184. [bug] the usage message was out-of-date. 183. [port] some systems don't define AF_INET6, so we define it if necessary in all port_after.h --- 8.1-T5B released --- 182. [bug] fix the way bindname is allocated in hesiod_to_bind(). 181. [bug] MAXHOSTNAMELEN wasn't defined on Solaris. 180. [bug] a check for zptr != NULL in res_update was wrong. It should have been zptr == NULL. 179. [bug] sq_remove() and sq_done() were calling ns_freexfr() when any stream was removed, resulting in a panic when the server was reloaded. ns_freexfr() is now only called when a zone transfer stream is removed. --- 8.1-T4B released --- 178. [bug] if the server was reloaded and then a zone was deleted and the server reloaded again, all within a short period of time, then pending NOTIFY messages would cause the server to panic when they ran. 177. [lint] replaced BUFSIZ with a more appropriate size in several places. 176. [func] change MAXDATA to 2*MAXDNAME + 5*INT32SZ. 175. [security] libirs now limits hostnames to MAXHOSTNAMELEN characters. 174. [bug] we called ns_refreshtime() instead of ns_retrytime() in the Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL case in zone_maint(). 173. [bug] the server didn't clear the Z_NEED_RELOAD flag in zoneinit(). 172. [bug] if a server was a slave for a zone, and an outbound transfer ever hung or terminated unusually, regular zone maintenance would cease for the zone. 171. [port] work around a bug in the Digital UNIX 4.0B SIOCGIFCONF ioctl. 170. [func] the message logged when a zone is loaded now indicates the class of the zone. 169. [func] the message logged when a zone is removed now indicates both the type and class of the zone. 168. [bug] if a zone's type changed from master to slave on a server reload, the server erroneously deleted the new zone data as part of cleaning up the old zone data. 167. [func] when converting from wire format to printable format, represent special characters ".;\@$ by escaping them with \ instead of converting them to \DDD. 166. [bug] when a slave zone expired, it was not scheduled for immedidate maintenance. 165. [port] added port for SCO OSE 5.0.2, renamed port for SCO UNIX 3.2v4.2. 164. [func] created the "response-checks" logging category. 163. [port] don't define AF_INET6 in nameser_compat.h. 162. [bug] the server panicked if a dynamic update request was sent for a dynamic zone which had not loaded because of syntax errors in the master file. The server now returns NOTAUTH. 161. [bug] debugging messages in process_prereq() referred to process_updates() instead of process_prereq(). 160. [bug] hp was not reset after a realloc() in named-xfer.c 159. [bug] named-bootconf.pl didn't translate stub zones. 158. [lint] cast a number of "no effect" statements to void so that gcc doesn't complain when invoked with -Wall -W -Wno-unused 157. [lint] a number of uses of the %lu printf() format were converted to %u; the corresponding casts to u_long were removed. 156. [lint] converted z_deferupdcnt and z_updatecnt from int to u_int32_t. 155. [func] maint_interval is now gone; SOA sanity checking related to it is gone too. 154. [bug] in named-xfer, unsigned 32-bit integers were sometimes stored in signed 32-bit variables and then printed using a cast to u_long and printf() format %lu. This would cause problems on 64-bit systems if the MSB of the 32-bit integer was set. The variable declarations have been changed to u_int32_t, and the printf format is now %u. 153. [bug] log_open_stream() had two syslogs that said the failing function was log_vwrite() instead of log_open_stream(). 152. [lint] made class, type, and dlen in rrextract() and named-xfer.c/print_output() u_int16_t. 151. [bug] the server was incrementing nssSentFErr in the formerr: code in ns_resp.c even though it wasn't sending FORMERR to anyone. 150. [func] in "check-names response fail" mode, instead of just dropping a failing response, we now send REFUSED to the client and drop the query. 149. [bug] if there wasn't a space between the SOA minimum value and a following ')' in a master file, the server would generate an error when it tried to parse the minimum value, causing the zone load to fail. 148. [func] the list of supported syslog facilities has been increased; the following facilities may now be used, provided they're available on the system 'named' is being built on: kern, user, mail, daemon, auth, syslog, lpr, news, uucp, cron, authpriv, ftp, local[0-7]. 147. [bug] the maybe_syslog_facility, logging_opt, channel_severity, address_name, key_ref, key_stmt, acl_stmt, zone_stmt, optional_class, and size_spec rules in the parser either leaked memory or could leak memory. 146. [func] if an RR set in a reply differed from an RR set in the cache only in the TTL, we would not update the TTL of the RR set in the cache. We now update this TTL to that of the reply RR set if the reply RR set's TTL is greater. 145. [func] follow the direction of the clarification draft and treat TTLs as unsigned 32-bit integers, with a maximum value of 2^31 - 1. TTLs greater than the maximum will be converted to 0. A warning will be issued if this conversion occurs while loading a master zone or during inbound zone transfer. 144. [func] "dig version.bind. txt chaos" now returns only the version number (e.g. "8.1-T4B"). 143. [lint] fixed various mismatches between printf() format string components and their corresponding arguments. 142. [lint] SendRequest_close() in nslookup/send.c had a return type of int instead of void. 141. [port] converted bcopy() to memcpy() or memmove() as appropriate. 140. [bug] certain buffer size checking comparisons in rdata_expand() weren't working because they were checking to see if an unsigned value was < 0. 139. [func] convert a few address comparisons from == to using ina_equal(). 138. [bug] an address comparison used in marking a server as bad was done incorrectly in ns_resp.c because the comparison used = instead of ==. 137. [lint] cleaned up warnings caused by assignment used as truth-value in various source files. 136. [func] changed eventlib-related INSIST statements into INSIST_ERR, so that we can print out strerror(errno). 135. [lint] replaced _getshort() with ns_get16() and _getlong() with ns_get32() in various source files. 134. [lint] findzone() and rdata_expand() were used before they were declared in ns_update.c, and were not declared static. 133. [lint] merge_logs() was not declared in ns_func.h. 132. [lint] Linux port_after.h didn't declare daemon(). We now do so, but only if GNU libc < 2.0. 131. [lint] set_boolean_option() was not declared in ns_func.h. 130. [lint] yyparse() was not declared in ns_parser.y. 129. [lint] ns_lexer.h didn't declare lexer_end_file(). 128. [lint] db_dump.c, db_lookup.c, db_update.c, db_glue.c, db_save.c, ns_ncache.c, ns_req.c, ns_stats.c, and ns_xfr.c didn't #include 127. [lint] logging.c, ev_connects.c, ns_maint.c, ns_glue.c, ns_update.c, dig/dig.c, nslookup/list.c, nslookup/send.c, host/host.c, and dnsquery/dnsquery.c didn't #include . 126. [lint] res_update.c, heap.c, db_load.c, db_save.c, db_glue.c, ns_lexer.c, ns_forw.c, ns_maint.c, ns_req.c, ns_stats.c, ns_xfr.c, ns_glue.c, ns_config.c, ns_update.c, host/host.c, nslookup/list.c, and nslookup/getinfo.c didn't #include . 125. [lint] res_mkupdate.c, ns_update.c, nsupdate.c, ns_print.c, didn't #include . 124. [port] replaced bcmp() with memcmp(). 123. [func] while not required, it's nice to preserve the order of RRs as received when ROUND_ROBIN isn't on, so we now do so. 122. [bug] under certain improbable conditions, the server could erroneously set a maintenance timer for a master zone. When the timer went off, it would trigger the INSIST() in zone_maint(). 121. [port] replaced bzero() with memset(). 120. [func] added multiple-cnames option. 119. [bug] the timeout: code in ns_resp.c didn't clean up TCP connections. 118. [port] added port for IRIX 5.3, 6.2, 6.4 117. [bug] removed declaration of getnum_error from db_load.c, since it is now declared in ns_glob.h. 116. [bug] GNU libc 2.0 doesn't have a , so in the Linux port we now provide a stub net/route.h that includes the real if GNU libc < 2.0 and does nothing if >= 2.0. 115. [func] on Linux systems, avoid an often unnecessary 'ranlib' and the subsequent relinking of all binaries by using the 's' flag of 'ar'. 114. [bug] 'make install' didn't work on HP/UX because the path to the install script was wrong in many cases. 113. [bug] named-xfer didn't clean up properly when sent SIGTERM. 112. [bug] named-xfer didn't clean up properly if an error occured in print_output(). 111. [func] added "max-transfer-time-in" option. The server used to allow a maximum of 2 hours for an inbound zone transfer to complete. This time can now be set globally or on a per-zone basis. The parameter is the number of minutes a transfer can take. 110. [func] moved declaration of d_ns in struct databuf to improve structure alignment. 109. [bug] addname() in ns_print.c didn't write an "@" for RRs that contained a domain name which was the same as the zone origin (it wrote nothing). 108. [bug] the server didn't check for EINTR in readable() and writable() in ev_streams.c. 107. [bug] check for both EWOULDBLOCK and EAGAIN after certain system calls instead of using PORT_WOULDBLK. This fixes partial zone transfer problems reported on Sun systems. 106. [bug] db_load() couldn't read SOAs with ( ) that were only one line. 105. [bug] fixed typo in Linux Makefile.set MANROFF definition. 104. [func] move various rrset debugging messages, rm_datum, and nsfree messages to debug level 3. Moved a few rrset debugging messages to debug level 2. 103. [bug] d_rcnt could overflow; to prevent this it has been increased to 32 bits. d_mark was made unsigned and decreased to 12 bits. 102. [func] added macro DRCNTDEC to go along with DRCNTINC. 101. [bug] clean_cache() didn't count deleted RRs, so it always reported "Cleaned cache of 0 RRs". 100. [bug] heap_for_each() didn't return a status, and didn't check for a NULL context or a NULL action. heap_element() didn't set errno to EINVAL when given invalid arguments. 99. [bug] the category rule in the parser leaked memory. 98. [bug] "notify" was not recognized as a valid category name. 97. [security] zone access control wasn't applied correctly to names that didn't exist, allowing an attacker to determine whether or not a given name exists in a zone. 96. [bug] we didn't recognize certain non-fatal errno values when recvfrom() failed; this would result in us dropping an interface unnecessarily. --- 8.1-T3B released --- 95. [bug] named-bootconf.pl didn't process xfrnets correctly (if no netmask was specifed, it assumed a mask of 255.255.255.255 instead of the natural netmask for the class of the address). 94. [bug] named-bootconf.pl didn't handle lines ending in a comment. 93. [bug] if rename() failed in merge_logs(), we would return garbage instead of -1. 92. [bug] writemsg() in named-xfer.c was returning a random value instead of the number of bytes written. 91. [bug] schedretry() could set retry times in the past because it was relying on 'tt' which hadn't been updated. It now calls gettime(&tt). 90. [bug] 'tt' might not have been current when clean_cache() was called. 89. [bug] ns_lexer.h didn't #include 88. [cleanup] removed some relics of the early days of BIND 8's new logging system from the parser and ns_config.c. 87. [bug] when writing to a TCP socket, the server didn't handle errors from the write() correctly. Under the right circumstances, this will cause the server to spin. The most common trigger would be a large outbound zone transfer where the far end died. 86. [cleanup] fixed comment in dig.c that messed up font-lock mode in emacs. 85. [bug] inet_lnaof, inet_makeaddr, inet_netof, and inet_network were missing from lib/inet. 84. [func] improved log_channel creation and use by making the type more opaque. The logging API provides a more complete set of services. Added the LOG_CHANNEL_OFF flag. 83. [func] removed statistics_channel; it wasn't being used. 82. [lint] a few handler functions were declared as void (*)() instead of void (*)(void). All now have the latter declaration. 81. [port] added port for A/UX 3.1.1. 80. [port] added port for SCO UNIX 3.2v4.2. 79. [bug] when processsing slave zones during a config file reload, in the "backup file changed" (or missing) case we were calling purge_zone() and do_reload() even if we had never successfully transferred and loaded the zone. 78. [cleanup] moved writemsg() to named-xfer.c. 77. [cleanup] removed doupdate() from ns_resp.c. 76. [bug] writev() in lib/bsd would keep going if there was a partial write; this could cause incorrect output. 75. [func] added readv() to lib/bsd. 74. [bug] if evConnect() failed in tcp_send() we were aborting the server instead of just returning an error. 73. [port] automatically fix getgrgid() declaration in ULTRIX 4.5 grp.h. 72. [func] make port/*/Makefile invoke SUBDIR make in include. Add/modify include and include/sys Makefiles. 71. [port] added utimes() to lib/bsd. 70. [doc] README broken up into INSTALL, TODO, port/README. Added more info about many topics. 69. [bug] NOTIFY didn't handle an unknown NS target. E.g. if we had "test.domain NS unknown.name" and "unknown.name" was not known, NOTIFY wasn't doing an "A" query for "unknown.name". 68. [lint] tweaks to ERR() and OK() in eventlib_p.h. 67. [bug] 'ch' in main() was a char instead of an int. 66. [bug] in bin/named/Makefile, pathnames wasn't getting linked with ${LIBBIND}, ${LIBPORT}, and ${SYSLIBS}. 65. [port] automatically fix timespec in BSD/OS 2.1 includes. 64. [func] lib/isc/heap.c now includes port_before.h and port_after.h. Fix 58 (below) has been undone; with port_after.h we'll now use __ansi_realloc() from Fix 59. 63. [bug] STRIP and PS were missing from MARGS in bin/Makefile. 62. [func] RRs in the additional data section must relate to RRs in the answer and authority sections. Only certain RR types are allowed in the authority and additional data sections. 61. [bug] Dynamic update didn't understand SRV records. 60. [bug] SRV records weren't decoded properly. --- 8.1-T3A released --- 59. [bug] The IRS library also wanted an ANSI C realloc(). port/sunos now provides __ansi_realloc(). 58. [bug] SunOS didn't like heap.c doing realloc() on a NULL pointer (in ANSI C that is equivalent to malloc()), so we malloc() instead. 57. [bug] interface discovery complained about bogus interfaces on ULTRIX, SunOS, and HP/UX because SIOCGIFCONF_ADDR wasn't defined in their port_after.h. 56. [API] created lib/nameser/ns_name.c and moved a lot of the functionality from lib/resolv/res_comp.c into it. functions older than 8.1 were stubbed out, but new functions from 8.1 were just renamed/removed. 55. [bug] findzone in ns_update wasn't ignoring z_nil zones. 54. [bug] if the named-xfer exec() failed, a misleading message was printed. 53. [bug] interface discovery didn't work on NetBSD because HAVE_SA_LEN wasn't defined in port_after.h. 52. [func] log the host we got a NOTIFY message from 51. [bug] we weren't sending out NOTIFY messages if the SOA was changed as the result of a dynamic update. 50. [bug] req_notify() wasn't calling sched_zone_maint() after it called qserial_query(). 49. [bug] initial_{data,stack,core}_size and initial_num_files weren't in an #ifdef HAVE_GETRUSAGE block. 48. [func] use sysconf(_SC_OPEN_MAX) instead of getdtablesize() in all cases when USE_POSIX is defined. 47. [bug] printupdatelog() was printing the post-update serial number in the zone section instead of the pre-update serial number. 46. [bug] zp->z_serial wasn't being updated if a dynamic update changed the zone serial number. 45. [bug] the SEQ_GT test in db_update was backwards. 44. [func] merge_logs() didn't work because a 'break' wasn't removed when class and type lookups were converted to sym_ston. 43. [func] evResetTimer() added to eventlib. 42. [bug] incr_serial() doesn't need to call schedule_dump(). 41. [bug] reset_retrytimer() could clear a timer that had already been cleared. 40. [bug] some zone data structures weren't freed if the zone was removed. 39. [func] The eventlib timers module now uses a heap to implement the timer queue. 38. [bug] dynamic zones weren't dumped if they were removed from the configuration file. 37. [func] created the "load" logging category. 36. [func] find_zone now uses a hash table instead of a linear search. 35. [bug] we weren't scheduling a retry for dumps or soa serial increments that failed. 34. [func] instead of doing all NOTIFY messages five seconds after loading completes, we now spread them out over up to fifteen minutes (the maximum delay depends on how many zones there are). 33. [func] if there are too many qserials running, we'll try again in five to thirty seconds. 32. [bug] z_dumptime wasn't getting set to zero after a zone dump. 31. [func] Each zone now has a maintenance timer. sched_maint() is gone. The new programming rule: if you change zp->z_time, it's your reponsibility to ensure sched_zone_maint(zp) gets called. 30. [func] short circuit PrintTimers evPrintfs if not debugging at a level where PrintTimers would print something. 29. [bug] if a log message with a non-default category was logged to a default category channel which had print-category on, "default" was printed instead of the category name. 28. [func] the performance of the main loop has been improved. 27. [bug] NOTIFY messages weren't being delayed after a zone load. 26. [bug] the eventlib category wasn't working if the channel wasn't the default debugging channel. 25. [func] added the "maintenance" logging category. 24. [func] periodic statistics dumps are now done using an eventlib timer instead of in ns_maint(). 23. [bug] names which have multiple CNAME records are illegal, but the server was allowing them. 22. [func] convert to POSIX signals from eventlib signal handling; the eventlib API no longer provides signal support. 21. [func] converted assert() to INSIST() so that the logging system (category "insist") will be used if a consistency check fails. 20. [bug] the server could exit when it shouldn't, and without leaving a message or a core file, because it wasn't handling SIGPIPE. 19. [port] Solaris has trouble if the size of the buffer used for IP_OPTIONS processing isn't 40 bytes. 18. [bug] library Makefiles we were using 'ld' instead of ${LD}. Added LD_LIBFLAGS. 17. [bug] on at least one OS, ctime() can return NULL and this can cause problems. We now call checked_ctime() in ns_glue.c, which returns "\n" if ctime() fails. 16. [bug] some signal handlers were calling library routines which POSIX does not designate as safe for use by signal handlers. 15. [func] finished conversion to new options scheme of name checking and inbound zone transfer parameters. 14. [func] added os_change_directory(). 13. [bug] write_open() in ns_config.c wasn't checking if the file was regular before unlinking. 12. [func] added "os" logging category. 11. [bug] named-bootconf.pl used the deprecated channel name "default" instead of "default_syslog". 10. [bug] named-bootconf.pl didn't understand continuation lines. 9. [bug] remove -p from mkdep command in Makefiles for bin/named and bin/nslookup. 8. [bug] add CDEBUG to Makefiles that link using ${CC}. 7. [bug] timestamp and level were printed twice for file channels in lib/isc/logging.c. 6. [bug] off by one with on level_text subscript in lib/isc/logging.c. 5. [bug] broken channels sometimes weren't marked as broken in lib/isc/logging.c. 4. [bug] didn't set foundname=0 after try_again: in ns_resp.c. 3. [bug] update_pid_file() didn't put a newline after the pid. 2. [func] minor log message tweaks in ns_config.c. 1. [bug] zone names needed to be canonicalized in the parser. --- 8.1-T2B released --- Index: vendor/bind/dist/contrib/bind/README =================================================================== --- vendor/bind/dist/contrib/bind/README (revision 109982) +++ vendor/bind/dist/contrib/bind/README (revision 109983) @@ -1,247 +1,250 @@ This is the source portion of BIND version 8. Its companions are "doc" and "contrib" so you are probably not missing anything. See the CHANGES file for a detailed listing of all changes. See the INSTALL file for information on building and installing BIND. See the SUPPORT file for information on obtaining commercial support for ISC artifacts including BIND, INN, and DHCP. Note that BIND 8 is in "end-of-life", having been replaced by BIND 9. See http://www.isc.org/ for more details. +BIND 8.3.4 Highlights + Security Fix DoS and buffer overrun. + BIND 8.3.3 Highlights Security Fix libbind. All applications linked against libbind need to relinked. 'rndc restart' now preserves named's arguements BIND 8.3.2 Highlights dig, nslookup, host and nsupdate have improved IPv6 support. BIND 8.3.1 Highlights Critical bug fix to prevent DNS storms. If you have BIND 8.3.0 you need to upgrade. BIND 8.3.0 Highlights IPv6 transport support in resolver (from KAME). Opaque rdata support. EDNS0 support. Glue ordering to help non-ENDS0 aware clients (servers) cope with larger responses as a result of IPv6 by allowing A records to be added first to the additional section. IPv6 capable clients are expected to use EDNS0 to allow larger responses to be sent. Bug Fixes, includes BIND 8.2.5 changes. BIND 8.2.4 Highlights NSAP processing was not RFC 1706 compliant. NOTE: OLD MASTER FILES NEED TO BE CORRECTED AND CACHE FILES REMOVED. Fixes long-standing protocol incompatibility in DNSSEC support. Avoids fwd'ing to root name servers if response will be rejected. new port/cygwin contributed by s_c_biggs@bigfoot.com. new contrib/mdnkit (V1.3) from author. new contrib/adm from official ftp site. new contrib/host from author. new contrib/dnsp from author. fixed file descriptor leak in resolver. fixed a major memory leak in the processing of dynamic updates. numerous portability improvements. numerous bug fixes. BIND 8.2.3 Highlights Improved support for Windows NT and Windows 2000. Host stats are no longer required to track the source of a record. IXFR improvements. Forwarders track and use RTT to select fastest. Unix domain sockets implementions that require the directory to be secure, are now secured. Many minor problems fixed. Linux DoS removed. BIND 8.2.2 patchlevel 5 Highlights Bug in named-xfer (from patchlevel 4). Portability to IPv6 versions of FreeBSD, OpenBSD, NetBSD. Portability improvements (A/UX, AIX, IRIX, NetBSD, SCO, MPE/IX, NT). "also-notify" option could cause memory allocation errors. IXFR improvements (though client-side is still disabled). Contributed software upgraded (including TIS's "dns_signer"). Several latent denial-of-service bugs fixed (from audits, not abuse). New "make noesw" top-level target for removing encumbered components. BIND 8.2.2 Highlights Interoperability with MS-Win2K has been improved. Server-side IXFR is now known to work even under high load. Support for Windows/NT (thanks to BayNetworks). More fixes, especially to DNSSEC, TSIG, IXFR, and selective forwarding. More portability improvements and lint removal (A/UX 3.1.1, SCO 5.0). Better NOTIFY behaviour, especially with large update volume. Better UPDATE handling, including SRV RR support and RFC compliance. Fix for "ndc reload ZONENAME" (specific zone reload) problems. Fix for round robin when multiple CNAMEs are in use. New "min-roots" (MINROOTS) and "serial-queries" (MAXQSERIAL) options. Log files are no longer auto-rotated every time the server starts up. New "ndc reconfig" command only finds new/deleted zones, no stat()ing. New global options for "transfer-source" and "also-notify". $GENERATE now supports more record types, and options. BIND 8.2.1 Highlights Bug fixes, especially to DNSSEC, TSIG, IXFR, and selective forwarding. Portability improvements and lint removal. Use best SOA rather than first-better when selecting an AXFR master. $TTL now accepts symbolic time values (such as "$TTL 1h30m"). "ndc reload" now accepts a zone argument, for single-zone reloads. ndc is better behaved; is verbose or quiet when appropriate. event and error reporting improvements. BIND 8.2 Highlights RFC 2308 (Negative Caching) RFC 2181 (DNS Clarifications) RFC 2065 (DNS Security) TSIG (Transaction SIGnatures) support for multiple virtual name servers NDC uses a "control channel" now (no more signals) "Split DNS" via zone type "forward". Many bug fixes Documentation improvements Performance enhancements BIND 8.1.2 Highlights Security fixes for a number of problems including: An attacker could overwrite the stack if inverse query support was enabled. A number of denial of service attacks where malformed packets could cause the server to crash. The server was willing to answer queries on its forwarding sockets. Several memory leaks have been plugged. The server no longer panics if a periodic interface scan fails due to no file descriptors being available. Updates to a number of ports. New ports for QNX, LynxOS, HP-UX 9.x, and HP MPE. "files unlimited" now works as expected on systems where setting an infinite rlim_max for RLIMIT_NOFILE works. Adding and deleting the same record in the same dynamic update no longer crashes the server. If a dynamic update fails, rollback is now done in LIFO order instead of FIFO order. Better behavior when priming of the root servers fails. purge_zone() didn't work correctly for the root zone, allowing old data to persist after loading the zone. Improved handling of oversized UDP packets. All hosts on the also-notify list are now notified. The meaning of the count returned by select() varies somewhat by operating system, and this could cause previous releases of the server to spin. Per-host statistics may be disabled by specifying 'host-statistics no' in named.conf. The maximum number of zones has been increased from 32768 to 65536. query-source may specify an address and port that the server is already listening on. BIND 8.1.1 required that either the address or port be wild. E.g., you can now say: listen-on port 53 { 10.0.0.1; }; query-source address 10.0.0.1 port 53; The value of FD_SETSIZE to use may be specified. Experimental -u (set user id), -g (set group id), and -t (chroot) command line options. See the INSTALL file for details. BIND 8 Features -> DNS Dynamic Updates (RFC 2136) -> DNS Change Notification (RFC 1996) -> Completely new configuration syntax -> Flexible, categorized logging system -> IP-address-based access control for queries, zone transfers, and updates that may be specified on a zone-by-zone basis -> More efficient zone transfers -> Improved performance for servers with thousands of zones -> The server no longer forks for outbound zone transfers -> Many bug fixes File and Directory Overview CHANGES history of added features and fixed bugs INSTALL how to build and install README this file TODO features planned but not yet written Version the version number of this release bin/* source for executables, including the nameserver include/* public .h files lib/* the resolver and various BIND support libraries port/* ports to various operating systems Kits, Questions, Comments, and Bug Reports current non-test release latest public test kit using BIND DNS operations in general DNS standards in general gw'd to u:c.p.d.bind gw'd to u:c.p.d.std code warriors only please the BIND home page bug reports To Support the Effort Note that BIND is supported by the Internet Software Consortium, and although it is free for use and redistribution and incorporation into vendor products and export and anything else you can think of, it costs money to produce. That money comes from ISPs, hardware and software vendors, companies who make extensive use of the software, and generally kind hearted folk such as yourself. The Internet Software Consortium has also commissioned a DHCP server implementation, has taken over official support/release of the INN system, and has supported the Kerberos Version 5 effort at MIT. You can learn more about the ISC's goals and accomplishments from the web page at . Index: vendor/bind/dist/contrib/bind/Version =================================================================== --- vendor/bind/dist/contrib/bind/Version (revision 109982) +++ vendor/bind/dist/contrib/bind/Version (revision 109983) @@ -1 +1 @@ -8.3.3-REL +8.3.4-REL Index: vendor/bind/dist/contrib/bind/bin/named/db_defs.h =================================================================== --- vendor/bind/dist/contrib/bind/bin/named/db_defs.h (revision 109982) +++ vendor/bind/dist/contrib/bind/bin/named/db_defs.h (revision 109983) @@ -1,341 +1,341 @@ /* * from db.h 4.16 (Berkeley) 6/1/90 - * $Id: db_defs.h,v 8.47 2002/05/18 01:02:53 marka Exp $ + * $Id: db_defs.h,v 8.47.4.1 2002/11/14 13:22:24 marka Exp $ */ /* * Copyright (c) 1985, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University 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 REGENTS 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. */ /* * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1996-2000 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Global definitions for data base routines. */ /* max length of data in RR data field */ #define MAXDATA (3*MAXDNAME + 5*INT32SZ) /* max length of data in a TXT RR segment */ #define MAXCHARSTRING 255 #define DB_ROOT_TIMBUF 3600 #define TIMBUF 300 #define DICT_INDEXBITS 24 #define DICT_MAXLENGTH 127 #define DICT_INSERT_P 0x0001 /* Average hash chain depths. */ #define AVGCH_MARSHAL 5 #define AVGCH_NLOOKUP 3 /* Nonstandard maximum class to force better packing. */ #define ZONE_BITS 24 #define CLASS_BITS 8 #define ZONE_MAX ((1<> ((sizeof(v) * 8) - HASHSHIFT))) #define HASHLOWER(c) ((isascii(c) && isupper(c)) ? tolower(c) : (c)) #define HASHIMILATE(v,c) ((v) = (HASHROTATE(v)) + (HASHLOWER(c) & HASHMASK)) #define TSIG_BUF_SIZE 640 #define TSIG_SIG_SIZE 20 struct tsig_record { u_int8_t sig[TSIG_SIG_SIZE]; struct dst_key *key; int siglen; int tsig_size; }; struct sig_record { u_int16_t sig_type_n; u_int8_t sig_alg_n, sig_labels_n; u_int32_t sig_ottl_n, sig_exp_n, sig_time_n; u_int16_t sig_keyid_n; }; /* This is the wire format size of "struct sig_record", i.e., no padding. */ #define SIG_HDR_SIZE 18 struct dnode { struct databuf *dp; struct dnode *dn_next; int line; const char *file; }; typedef struct dnode * dlist; struct db_rrset { dlist rr_list; dlist rr_sigs; char *rr_name; int16_t rr_class; int16_t rr_type; struct db_rrset *rr_next; }; #define DBHASHSIZE(s) (sizeof(struct hashbuf) + \ (s-1) * sizeof(struct db_rrset *)) #define SIG_COVERS(dp) (ns_get16(dp->d_data)) /* * Flags to updatedb */ #define DB_NODATA 0x01 /* data should not exist */ #define DB_MEXIST 0x02 /* data must exist */ #define DB_DELETE 0x04 /* delete data if it exists */ #define DB_NOTAUTH 0x08 /* must not update authoritative data */ #define DB_NOHINTS 0x10 /* don't reflect update in fcachetab */ #define DB_PRIMING 0x20 /* is this update the result of priming? */ #define DB_MERGE 0x40 /* make no control on rr in db_update (for ixfr) */ #define DB_REPLACE 0x80 /* replace data if it exists */ #define DB_Z_CACHE 0 /* cache-zone-only db_dump() */ #define DB_Z_ALL 65535 /* normal db_dump() */ #define DB_Z_SPECIAL(z) ((z) == DB_Z_CACHE || (z) == DB_Z_ALL) /* * Error return codes */ #define OK 0 #define NONAME (-1) #define NOCLASS (-2) #define NOTYPE (-3) #define NODATA (-4) #define DATAEXISTS (-5) #define NODBFILE (-6) #define TOOMANYZONES (-7) #define GOODDB (-8) #define NEWDB (-9) #define AUTH (-10) #ifdef BIND_UPDATE #define SERIAL (-11) #endif #define CNAMEANDOTHER (-12) #define DNSSECFAIL (-13) /* db_set_update */ #define NONGLUE (-14) /* * getnum() options */ #define GETNUM_NONE 0x00 /* placeholder */ #define GETNUM_SERIAL 0x01 /* treat as serial number */ #define GETNUM_SCALED 0x02 /* permit "k", "m" suffixes, scale result */ /* * db_load() options */ #define ISNOTIXFR 0 #define ISIXFR 1 #define ISAXFRIXFR 2 /* * Database access abstractions. */ #define foreach_rr(dp, np, ty, cl, zn) \ for ((dp) = (np)->n_data; (dp) != NULL; (dp) = (dp)->d_next) \ if (!match(dp, (cl), (ty))) \ continue; \ else if (((zn) == DB_Z_CACHE) \ ? stale(dp) \ : (zn) != (dp)->d_zone) \ continue; \ else if ((dp)->d_rcode) \ continue; \ else \ /* Caller code follows in sequence. */ #define DRCNTINC(x) \ do { \ if (++((x)->d_rcnt) == 0) \ ns_panic(ns_log_db, 1, "++d_rcnt == 0"); \ } while (0) #define DRCNTDEC(x) \ do { \ if (((x)->d_rcnt)-- == 0) \ ns_panic(ns_log_db, 1, "d_rcnt-- == 0"); \ } while (0) #define ISVALIDGLUE(xdp) ((xdp)->d_type == T_NS || (xdp)->d_type == T_A \ || (xdp)->d_type == T_AAAA || (xdp)->d_type == ns_t_a6) Index: vendor/bind/dist/contrib/bind/bin/named/db_sec.c =================================================================== --- vendor/bind/dist/contrib/bind/bin/named/db_sec.c (revision 109982) +++ vendor/bind/dist/contrib/bind/bin/named/db_sec.c (revision 109983) @@ -1,1081 +1,1081 @@ #if !defined(lint) && !defined(SABER) -static const char rcsid[] = "$Id: db_sec.c,v 8.35 2001/06/18 14:42:57 marka Exp $"; +static const char rcsid[] = "$Id: db_sec.c,v 8.35.4.2 2002/11/14 13:24:44 marka Exp $"; #endif /* not lint */ /* * Copyright (c) 1986, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University 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 REGENTS 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. */ /* * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1996-2000 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include "port_before.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "port_after.h" #include "named.h" struct zpubkey { struct dst_key *zpk_key; /* Should be DST_KEY */ char *zpk_name; struct zpubkey *zpk_next; }; typedef struct zpubkey *zpubkey_list; static int nxt_match_rrset(struct databuf *dp, struct db_rrset *rrset); /* * A converted databuf is a stripped down databuf after converting the * data to wire format. */ struct converted_databuf { struct converted_databuf *cd_next; u_char *cd_data; int cd_size, cd_alloc; }; /* All of the trusted keys and zone keys */ static tree *trusted_keys = NULL; static int compare_pubkey (struct zpubkey *zpk1, struct zpubkey *zpk2) { char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; if (ns_makecanon(zpk1->zpk_name, ta, sizeof ta) < 0 || ns_makecanon(zpk2->zpk_name, tb, sizeof tb) < 0) return (-1); return (strcasecmp(ta, tb)); } static struct zpubkey * tree_srch_pubkey (const char *name) { struct zpubkey tkey, *key; DE_CONST(name, tkey.zpk_name); if (trusted_keys == NULL) { tree_init(&trusted_keys); return (NULL); } key = (struct zpubkey *)tree_srch(&trusted_keys, compare_pubkey, &tkey); return (key); } static DST_KEY * find_public_key (const char *name, u_int16_t key_id) { struct namebuf *knp; struct hashbuf *htp; struct databuf *dp; const char *fname; DST_KEY *key; ns_debug(ns_log_default, 5, "find_public_key(%s, %d)", name, key_id); htp = hashtab; knp = nlookup (name, &htp, &fname, 0); if (fname != name) /* The name doesn't exist, so there's no key */ return (NULL); for (dp = knp->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_type != ns_t_key || dp->d_secure < DB_S_SECURE) continue; key = dst_dnskey_to_key(name, dp->d_data, dp->d_size); /* XXX what about multiple keys with same footprint? */ if (key) { if (key->dk_id == ntohs(key_id)) return (key); else dst_free_key(key); } } return (NULL); } static DST_KEY * find_trusted_key (const char *name, u_int16_t key_id) { struct zpubkey *zpk; zpubkey_list keylist = tree_srch_pubkey (name); ns_debug(ns_log_default, 5, "find_trusted_key(%s, %d)", name, key_id); for (zpk = keylist; zpk; zpk = zpk->zpk_next) if (zpk->zpk_key->dk_id == ntohs(key_id)) return (zpk->zpk_key); return (NULL); } int add_trusted_key (const char *name, const int flags, const int proto, const int alg, const char *str) { zpubkey_list keylist; struct zpubkey *zpk; u_char buf[1024]; int n; keylist = tree_srch_pubkey (name); zpk = (struct zpubkey *) memget (sizeof (struct zpubkey)); if (zpk == NULL) ns_panic(ns_log_default, 1, "add_trusted_key: memget failed(%s)", name); n = b64_pton(str, buf, sizeof(buf)); if (n < 0) goto failure; zpk->zpk_key = dst_buffer_to_key(name, alg, flags, proto, buf, n); if (zpk->zpk_key == NULL) { ns_warning(ns_log_default, "add_trusted_key: dst_buffer_to_key(%s) failed", name); goto failure; } zpk->zpk_name = zpk->zpk_key->dk_key_name; zpk->zpk_next = NULL; if (keylist == NULL) { if (tree_add (&trusted_keys, compare_pubkey, zpk, NULL) == NULL) goto failure; } else { struct zpubkey *tkey = keylist; while (tkey->zpk_next) tkey = tkey->zpk_next; tkey->zpk_next = zpk; } return (1); failure: memput(zpk, sizeof (struct zpubkey)); return (0); } /* Can the signer sign records for this name? This is a heuristic. */ static int can_sign(const char *name, const char *signer) { return (ns_samedomain(name, signer) && dn_count_labels(name) - dn_count_labels(signer) <= 2); } static int rrset_set_security(struct db_rrset *rrset, int slev) { struct dnode *dnp; for (dnp = rrset->rr_list; dnp != NULL; dnp = dnp->dn_next) dnp->dp->d_secure = slev; for (dnp = rrset->rr_sigs; dnp != NULL; dnp = dnp->dn_next) dnp->dp->d_secure = slev; return (slev); } static int convert_databuf(struct databuf *dp, struct converted_databuf *cdp) { u_char *bp = cdp->cd_data; u_char *cp = dp->d_data; u_char *eob = cdp->cd_data + cdp->cd_alloc; int len; u_char buf[MAXDNAME]; switch (dp->d_type) { case ns_t_soa: case ns_t_minfo: case ns_t_rp: if (eob - bp < (int)strlen((char *)cp) + 1) return (-1); if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) return (-1); len = ns_name_ntol(buf, bp, eob - bp); if (len < 0) return (-1); bp += len; cp += strlen((char *)cp) + 1; if (eob - bp < (int)strlen((char *)cp) + 1) return (-1); if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) return (-1); len = ns_name_ntol(buf, bp, eob - bp); if (len < 0) return (-1); bp += len; cp += strlen((char *)cp) + 1; if (dp->d_type == ns_t_soa) { if (eob - bp < 5 * INT32SZ) return (-1); memcpy(bp, cp, 5 * INT32SZ); bp += (5 * INT32SZ); cp += (5 * INT32SZ); } break; case ns_t_ns: case ns_t_cname: case ns_t_mb: case ns_t_mg: case ns_t_mr: case ns_t_ptr: case ns_t_nxt: if (eob - bp < (int)strlen((char *)cp) + 1) return (-1); if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) return (-1); len = ns_name_ntol(buf, bp, eob - bp); if (len < 0) return (-1); bp += len; cp += (len = strlen((char *)cp) + 1); if (dp->d_type == ns_t_nxt) { if (eob - bp < dp->d_size - len) return (-1); memcpy(bp, cp, dp->d_size - len); bp += (dp->d_size - len); cp += (dp->d_size - len); } break; case ns_t_srv: if (eob - bp < 2 * INT16SZ) return (-1); memcpy(bp, cp, 2 * INT16SZ); bp += (2 * INT16SZ); cp += (2 * INT16SZ); /* no break */ case ns_t_rt: case ns_t_mx: case ns_t_afsdb: case ns_t_px: if (eob - bp < INT16SZ) return (-1); memcpy (bp, cp, INT16SZ); bp += INT16SZ; cp += INT16SZ; if (eob - bp < (int)strlen((char *)cp) + 1) return (-1); if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) return (-1); len = ns_name_ntol(buf, bp, eob - bp); if (len < 0) return (-1); bp += len; cp += strlen((char *)cp) + 1; if (dp->d_type == ns_t_px) { if (eob - bp < (int)strlen((char *)cp) + 1) return (-1); if (ns_name_pton((char *)cp, buf, sizeof buf) < 0) return (-1); len = ns_name_ntol(buf, bp, eob - bp); if (len < 0) return (-1); bp += len; cp += strlen((char *)cp) + 1; } break; default: if (eob - bp < dp->d_size) return (-1); memcpy(bp, cp, dp->d_size); bp += dp->d_size; } cdp->cd_size = bp - cdp->cd_data; return (cdp->cd_size); } static int digest_rr(char *envelope, int elen, struct converted_databuf *cdp, char *buffer, int blen) { char *bp = buffer, *eob = buffer + blen; if (eob - bp < elen) return (-1); memcpy (bp, envelope, elen); bp += elen; if (eob - bp < INT16SZ) return (-1); PUTSHORT(cdp->cd_size, bp); if (eob - bp < cdp->cd_size) return (-1); memcpy (bp, cdp->cd_data, cdp->cd_size); bp += cdp->cd_size; return (bp - buffer); } /* Sorts the converted databuf in the list */ static void insert_converted_databuf(struct converted_databuf *cdp, struct converted_databuf **clist) { struct converted_databuf *tcdp, *next; int t; #define compare_cdatabuf(c1, c2, t) \ (t = memcmp(c1->cd_data, c2->cd_data, MIN(c1->cd_size, c2->cd_size)), \ t == 0 ? c1->cd_size - c2->cd_size : t) if (*clist == NULL) { *clist = cdp; return; } tcdp = *clist; if (compare_cdatabuf(cdp, tcdp, t) < 0) { cdp->cd_next = tcdp; *clist = cdp; return; } next = tcdp->cd_next; while (next) { if (compare_cdatabuf(cdp, next, t) < 0) { cdp->cd_next = next; tcdp->cd_next = cdp; return; } tcdp = next; next = next->cd_next; } tcdp->cd_next = cdp; #undef compare_cdatabuf } static void free_clist(struct converted_databuf *clist) { struct converted_databuf *cdp; while (clist != NULL) { cdp = clist; clist = clist->cd_next; memput(cdp->cd_data, cdp->cd_alloc); memput(cdp, sizeof(struct converted_databuf)); } } /* Removes all empty nodes from an rrset's SIG list. */ static void rrset_trim_sigs(struct db_rrset *rrset) { struct dnode *dnp, *odnp, *ndnp; odnp = NULL; dnp = rrset->rr_sigs; while (dnp != NULL) { if (dnp->dp != NULL) { odnp = dnp; dnp = dnp->dn_next; } else { if (odnp != NULL) odnp->dn_next = dnp->dn_next; else rrset->rr_sigs = dnp->dn_next; ndnp = dnp->dn_next; memput(dnp, sizeof(struct dnode)); dnp = ndnp; } } } static int verify_set(struct db_rrset *rrset) { DST_KEY *key = NULL; struct sig_record *sigdata; struct dnode *sigdn; struct databuf *sigdp; u_int32_t now; u_int32_t exptime; u_int32_t signtime; char *signer; u_char name_n[MAXDNAME]; u_char *sig, *eom; int trustedkey = 0, siglen, labels, len = 0, ret; u_char *buffer = NULL, *bp; u_char envelope[MAXDNAME+32], *ep; struct dnode *dnp; int bufsize = 2048; /* Large enough for MAXDNAME + SIG_HDR_SIZE */ struct converted_databuf *clist = NULL, *cdp; int dnssec_failed = 0, dnssec_succeeded = 0; int return_value; int i; int expired = 0; if (rrset == NULL || rrset->rr_name == NULL) { ns_warning (ns_log_default, "verify_set: missing rrset/name"); return (rrset_set_security(rrset, DB_S_FAILED)); } if (rrset->rr_sigs == NULL) return (rrset_set_security(rrset, DB_S_INSECURE)); ns_debug(ns_log_default, 5, "verify_set(%s, %s, %s)", rrset->rr_name, p_type(rrset->rr_type), p_class(rrset->rr_class)); now = time(NULL); for (sigdn = rrset->rr_sigs; sigdn != NULL; sigdn = sigdn->dn_next) { u_int32_t namefield; struct sig_record sigrec; sigdp = sigdn->dp; eom = sigdp->d_data + sigdp->d_size; if (sigdp->d_size < SIG_HDR_SIZE) { return_value = DB_S_FAILED; goto end; } memcpy(&sigrec, sigdp->d_data, SIG_HDR_SIZE); sigdata = &sigrec; signer = (char *)sigdp->d_data + SIG_HDR_SIZE; sig = (u_char *)signer + strlen(signer) + 1; siglen = eom - sig; /* * Don't verify a set if the SIG inception time is in * the future. This should be fixed before 2038 (BEW) */ signtime = ntohl(sigdata->sig_time_n); if (SEQ_GT(signtime, now)) continue; /* An expired set is dropped, but the data is not. */ exptime = ntohl(sigdata->sig_exp_n); if (SEQ_GT(now, exptime)) { expired++; db_detach(&sigdn->dp); sigdp = NULL; continue; } /* Cleanup from the last iteration if we continue'd */ if (trustedkey == 0 && key != NULL) dst_free_key(key); key = find_trusted_key(signer, sigdata->sig_keyid_n); if (key == NULL) { trustedkey = 0; key = find_public_key(signer, sigdata->sig_keyid_n); } else trustedkey = 1; /* if we don't have the key, either * - the data should be considered insecure * - the sig is not a dnssec signature */ if (key == NULL) continue; /* Can a key with this name sign the data? */ if (!can_sign(rrset->rr_name, signer)) continue; /* Check the protocol and flags of the key */ if (key->dk_proto != NS_KEY_PROT_DNSSEC && key->dk_proto != NS_KEY_PROT_ANY) continue; if (key->dk_flags & NS_KEY_NO_AUTH) continue; namefield = key->dk_flags & NS_KEY_NAME_TYPE; if (namefield == NS_KEY_NAME_USER || namefield == NS_KEY_NAME_RESERVED) continue; if (namefield == NS_KEY_NAME_ENTITY && (key->dk_flags & NS_KEY_SIGNATORYMASK) == 0) continue; /* * If we're still here, we have a non-null key that's either * a zone key or an entity key with signing authority. */ if (buffer == NULL) { bp = buffer = memget(bufsize); if (bp == NULL) { return_value = DB_S_FAILED; goto end; } } else bp = buffer; /* Digest the fixed portion of the SIG record */ memcpy(bp, (char *) sigdata, SIG_HDR_SIZE); bp += SIG_HDR_SIZE; /* Digest the signer's name, canonicalized */ if (ns_name_pton(signer, name_n, sizeof name_n) < 0) { return_value = DB_S_FAILED; goto end; } i = ns_name_ntol(name_n, (u_char *)bp, bufsize - SIG_HDR_SIZE); if (i < 0) { return_value = DB_S_FAILED; goto end; } bp += i; /* create the dns record envelope: * */ if (ns_name_pton(rrset->rr_name, name_n, sizeof name_n) < 0 || ns_name_ntol(name_n, (u_char *)envelope, sizeof envelope) < 0) { return_value = DB_S_FAILED; goto end; } labels = dn_count_labels(rrset->rr_name); if (labels > sigdata->sig_labels_n) { ep = envelope; for (i=0; i < (labels - 1 - sigdata->sig_labels_n); i++) ep += (*ep+1); i = dn_skipname(ep, envelope + sizeof envelope); if (i < 0) { return_value = DB_S_FAILED; goto end; } envelope[0] = '\001'; envelope[1] = '*'; memmove(envelope + 2, ep, i); } i = dn_skipname(envelope, envelope + sizeof envelope); if (i < 0) { return_value = DB_S_FAILED; goto end; } ep = envelope + i; PUTSHORT (rrset->rr_type, ep); PUTSHORT (rrset->rr_class, ep); if (envelope + sizeof(envelope) - ep < INT32SZ) { return_value = DB_S_FAILED; goto end; } memcpy (ep, &sigdata->sig_ottl_n, INT32SZ); ep += INT32SZ; if (clist == NULL) { for (dnp = rrset->rr_list; dnp != NULL; dnp = dnp->dn_next) { struct databuf *dp = dnp->dp; cdp = memget(sizeof(struct converted_databuf)); if (cdp == NULL) { return_value = DB_S_FAILED; goto end; } memset(cdp, 0, sizeof(*cdp)); /* Should be large enough... */ cdp->cd_alloc = dp->d_size + 8; cdp->cd_data = memget(cdp->cd_alloc); if (cdp->cd_data == NULL) { memput(cdp, sizeof(*cdp)); return_value = DB_S_FAILED; goto end; } while (convert_databuf(dp, cdp) < 0) { memput(cdp->cd_data, cdp->cd_alloc); cdp->cd_alloc *= 2; cdp->cd_data = memget(cdp->cd_alloc); if (cdp->cd_data == NULL) { memput(cdp, sizeof(*cdp)); return_value = DB_S_FAILED; goto end; } } insert_converted_databuf(cdp, &clist); } } for (cdp = clist; cdp != NULL; cdp = cdp->cd_next) { len = digest_rr((char *)envelope, ep-envelope, cdp, (char *)bp, bufsize - (bp - buffer)); while (len < 0) { u_char *newbuf; /* Double the buffer size */ newbuf = memget(bufsize*2); if (newbuf == NULL) { return_value = DB_S_FAILED; goto end; } memcpy(newbuf, buffer, bp - buffer); bp = (bp - buffer) + newbuf; memput(buffer, bufsize); buffer = newbuf; bufsize *= 2; len = digest_rr((char *)envelope, ep-envelope, cdp, (char *)bp, bufsize - (bp - buffer)); } bp += len; } if (len < 0) { return_value = DB_S_FAILED; goto end; } ret = dst_verify_data(SIG_MODE_ALL, key, NULL, buffer, bp - buffer, sig, siglen); if (ret < 0) { dnssec_failed++; db_detach(&sigdn->dp); sigdp = NULL; } else dnssec_succeeded++; } end: if (dnssec_failed > 0 || expired > 0) rrset_trim_sigs(rrset); if (trustedkey == 0 && key != NULL) dst_free_key(key); if (dnssec_failed > 0 && dnssec_succeeded == 0) { ns_warning (ns_log_default, "verify_set(%s, %s, %s) failed", rrset->rr_name, p_type(rrset->rr_type), p_class(rrset->rr_class)); return_value = DB_S_FAILED; } else if (dnssec_succeeded > 0) return_value = DB_S_SECURE; else return_value = DB_S_INSECURE; free_clist(clist); if (buffer != NULL) memput(buffer, bufsize); return (rrset_set_security(rrset, return_value)); } static void rrset_free(struct db_rrset *rrset) { struct dnode *dnp; ns_debug(ns_log_default, 5, "rrset_free(%s)", rrset->rr_name); while (rrset->rr_list) { dnp = rrset->rr_list; rrset->rr_list = rrset->rr_list->dn_next; if (dnp->dp != NULL) db_detach(&dnp->dp); memput(dnp, sizeof(struct dnode)); } while (rrset->rr_sigs) { dnp = rrset->rr_sigs; rrset->rr_sigs = rrset->rr_sigs->dn_next; if (dnp->dp != NULL) db_detach(&dnp->dp); memput(dnp, sizeof(struct dnode)); } } /* * This is called when we have an rrset with SIGs and no other data. * Returns 1 if we either found the necessary data or if the SIG can be added * with no other data. 0 indicates that the SIG cannot be added. */ static int attach_data(struct db_rrset *rrset) { int type, class; struct databuf *dp, *newdp, *sigdp; struct dnode *dnp; struct namebuf *np; struct hashbuf *htp; char *signer; const char *fname; char *name = rrset->rr_name; sigdp = rrset->rr_sigs->dp; type = SIG_COVERS(sigdp); class = sigdp->d_class; signer = (char *)(sigdp + SIG_HDR_SIZE); /* First, see if the signer can sign data for the name. If not, * it's not a DNSSEC signature, so we can insert it with no * corresponding data. */ if (!can_sign(name, signer)) return (1); htp = hashtab; np = nlookup (name, &htp, &fname, 0); if (fname != name) return (0); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_type == type && dp->d_class == class) { newdp = savedata(class, type, dp->d_ttl, dp->d_data, dp->d_size); dnp = (struct dnode *) memget (sizeof (struct dnode)); if (dnp == NULL) ns_panic(ns_log_default, 1, "attach_data: memget failed"); dnp->dp = newdp; dnp->dn_next = rrset->rr_list; rrset->rr_list = dnp; } } if (rrset->rr_list != NULL) return (1); else return (0); } static int rrset_db_update(struct db_rrset *rrset, int flags, struct hashbuf **htpp, struct sockaddr_in from, int *rrcount) { struct dnode *dnp; int ret; /* If we have any unattached SIG records that are DNSSEC signatures, * don't cache them unless we already have the corresponding data. * If we do cache unattached SIGs, we run into problems later if we * have a SIG X and get a query for type X. */ if (rrset->rr_list == NULL) { if (attach_data(rrset) == 0) { rrset_free(rrset); return (OK); } if (rrset->rr_list != NULL && verify_set(rrset) == DB_S_FAILED) { rrset_free(rrset); return (OK); } } for (dnp = rrset->rr_list; dnp != NULL; dnp = dnp->dn_next) { ret = db_update(rrset->rr_name, dnp->dp, dnp->dp, NULL, flags, (*htpp), from); if (ret != OK) { /* XXX Probably should do rollback. */ db_err(ret, rrset->rr_name, dnp->dp->d_type, dnp->file, dnp->line); if (ret != DATAEXISTS) { rrset_free(rrset); return (ret); } } if (rrcount != NULL) (*rrcount)++; } for (dnp = rrset->rr_sigs; dnp != NULL; dnp = dnp->dn_next) { if (dnp->dp == NULL) /* verifyset() can remove sigs */ continue; ret = db_update(rrset->rr_name, dnp->dp, dnp->dp, NULL, flags, (*htpp), from); if (ret != OK) { /* XXX Probably should do rollback. */ db_err(ret, rrset->rr_name, dnp->dp->d_type, dnp->file, dnp->line); if (ret != DATAEXISTS) { rrset_free(rrset); return (ret); } } if (rrcount != NULL) (*rrcount)++; } rrset_free(rrset); return (OK); } static int rr_in_set(struct databuf *rr, struct dnode *set) { struct dnode *dnp; if (set == NULL) return (0); for(dnp = set; dnp != NULL; dnp = dnp->dn_next) { if (dnp->dp->d_size == rr->d_size && memcmp(dnp->dp->d_data, rr->d_data, dnp->dp->d_size) == 0) return (1); } return (0); } static int add_to_rrset_list(struct db_rrset **rrsets, char *name, struct databuf *dp, int line, const char *file) { struct db_rrset *rrset = *rrsets; struct dnode *dnp; while (rrset != NULL) { if (rrset->rr_type != ns_t_nxt || dp->d_type != ns_t_nxt) { if (dp->d_type == ns_t_sig) { if ((int)SIG_COVERS(dp) == rrset->rr_type) break; } else { if (dp->d_type == rrset->rr_type) break; } } else if (nxt_match_rrset(dp, rrset)) break; rrset = rrset->rr_next; } if (rrset != NULL) { if ((dp->d_type == ns_t_sig && rr_in_set(dp, rrset->rr_sigs)) || (dp->d_type != ns_t_sig && rr_in_set(dp, rrset->rr_list))) return (DATAEXISTS); } else { rrset = (struct db_rrset *) memget(sizeof(struct db_rrset)); if (rrset == NULL) ns_panic(ns_log_default, 1, "add_to_rrset_list: memget failed(%s)", name); memset(rrset, 0, sizeof(struct db_rrset)); rrset->rr_name = savestr(name, 1); rrset->rr_class = dp->d_class; if (dp->d_type == ns_t_sig) rrset->rr_type = SIG_COVERS(dp); else rrset->rr_type = dp->d_type; rrset->rr_next = *rrsets; *rrsets = rrset; } dnp = (struct dnode *) memget(sizeof(struct dnode)); if (dnp == NULL) ns_panic(ns_log_default, 1, "add_to_rrset_list: memget failed(%s)", name); memset(dnp, 0, sizeof(struct dnode)); dnp->dp = dp; DRCNTINC(dnp->dp); if (dp->d_type == ns_t_sig) { if (rrset->rr_sigs != NULL) { struct dnode *fdnp; /* Preserve the order of the RRs */ /* Add this one to the end of the list */ for (fdnp = rrset->rr_sigs; fdnp->dn_next != NULL; fdnp = fdnp->dn_next) /* NULL */ ; fdnp->dn_next = dnp; } else rrset->rr_sigs = dnp; } else { if (rrset->rr_list != NULL) { struct dnode *fdnp; /* Preserve the order of the RRs */ /* Add this one to the end of the list */ for (fdnp = rrset->rr_list; fdnp->dn_next != NULL; fdnp = fdnp->dn_next) /* NULL */ ; fdnp->dn_next = dnp; } else rrset->rr_list = dnp; } dnp->file = file; dnp->line = line; return (0); } static int update_rrset_list(struct db_rrset **rrsets, int flags, struct hashbuf **htpp, struct sockaddr_in from, int *rrcount) { struct db_rrset *rrset = *rrsets, *next = NULL, *last = NULL; int result = 0, tresult, cnameandother = 0; while (rrset != NULL) { if (rrset->rr_type == ns_t_key) break; last = rrset; rrset = rrset->rr_next; } if (rrset != NULL && last != NULL) { last->rr_next = rrset->rr_next; rrset->rr_next = *rrsets; *rrsets = rrset; } rrset = *rrsets; while (rrset != NULL) { if (verify_set(rrset) > DB_S_FAILED) { ns_debug(ns_log_default, 10, "update_rrset_list(%s, %s): set verified", rrset->rr_name, p_type(rrset->rr_type)); tresult = rrset_db_update(rrset, flags, htpp, from, rrcount); if (tresult == CNAMEANDOTHER) cnameandother++; if (tresult != OK) result = tresult; } else { rrset_free(rrset); result = DNSSECFAIL; } rrset->rr_name = freestr(rrset->rr_name); next = rrset->rr_next; memput(rrset, sizeof(struct db_rrset)); rrset = next; } *rrsets = NULL; if (cnameandother != 0) return (CNAMEANDOTHER); return (result); } int db_set_update(char *name, struct databuf *dp, void **state, int flags, struct hashbuf **htpp, struct sockaddr_in from, int *rrcount, int line, const char *file) { struct db_rrset **rrsets; struct db_rrset *rrset; int result = 0; ns_debug(ns_log_default, 5, "db_set_update(%s)", (name == NULL) ? "" : (*name == 0) ? "." : name); if (state == NULL) ns_panic(ns_log_default, 1, "Called db_set_update with state == NULL"); rrsets = (struct db_rrset **) state; if (*rrsets != NULL) { rrset = *rrsets; if (rrset->rr_name != NULL && dp != NULL && name != NULL && ns_samename(name, rrset->rr_name) == 1 && dp->d_class == rrset->rr_class) return (add_to_rrset_list(rrsets, name, dp, line, file)); } if (*rrsets != NULL) result = update_rrset_list(rrsets, flags, htpp, from, rrcount); if (dp != NULL) { ns_debug(ns_log_default, 10, "db_set_update(%s), creating new list", name); (void) add_to_rrset_list(rrsets, name, dp, line, file); } return (result); } static int nxt_match_rrset(struct databuf *dp, struct db_rrset *rrset) { if (rrset->rr_list != NULL) return (nxtmatch(rrset->rr_name, dp, rrset->rr_list->dp)); else return (nxtmatch(rrset->rr_name, dp, rrset->rr_sigs->dp)); } Index: vendor/bind/dist/contrib/bind/bin/named/ns_defs.h =================================================================== --- vendor/bind/dist/contrib/bind/bin/named/ns_defs.h (revision 109982) +++ vendor/bind/dist/contrib/bind/bin/named/ns_defs.h (revision 109983) @@ -1,932 +1,932 @@ /* * from ns.h 4.33 (Berkeley) 8/23/90 - * $Id: ns_defs.h,v 8.121 2002/06/26 03:27:19 marka Exp $ + * $Id: ns_defs.h,v 8.121.2.1 2002/11/14 13:28:12 marka Exp $ */ /* * Copyright (c) 1986 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University 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 REGENTS 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. */ /* * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1996-2000 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Check Point Software Technologies Incorporated not be used * in advertising or publicity pertaining to distribution of the document * or software without specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Global definitions for the name server. */ /* * Effort has been expended here to make all structure members 32 bits or * larger land on 32-bit boundaries; smaller structure members have been * deliberately shuffled and smaller integer sizes chosen where possible * to make sure this happens. This is all meant to avoid structure member * padding which can cost a _lot_ of memory when you have hundreds of * thousands of entries in your cache. */ /* * Timeout time should be around 1 minute or so. Using the * the current simplistic backoff strategy, the sequence * retrys after 4, 8, and 16 seconds. With 3 servers, this * dies out in a little more than a minute. * (sequence RETRYBASE, 2*RETRYBASE, 4*RETRYBASE... for MAXRETRY) */ #define NEWZONES 64 /* how many zones to grow the zone table by */ #define INITIALZONES NEWZONES /* how many zones are allocated initially */ #define MINROOTS 2 /* min number of root hints */ #define NSMAX 16 /* max number of NS addrs to try ([0..255]) */ #define RETRYBASE 4 /* base time between retries */ #define MAXCLASS 255 /* XXX - may belong elsewhere */ #define MAXRETRY 3 /* max number of retries per addr */ #define MAXCNAMES 8 /* max # of CNAMES tried per addr */ #define MAXQUERIES 20 /* max # of queries to be made */ #define MAXQSERIAL 4 /* max # of outstanding QSERIAL's */ /* (prevent "recursive" loops) */ #define INIT_REFRESH 600 /* retry time for initial slave */ /* contact (10 minutes) */ #define MIN_REFRESH 2 /* never refresh more frequently than once */ /* every MIN_REFRESH seconds */ #define MIN_RETRY 1 /* never retry more frequently than once */ /* every MIN_RETRY seconds */ #define MAX_REFRESH 2419200 /* perform a refresh query at least */ /* every 4 weeks*/ #define MAX_RETRY 1209600 /* perform a retry after no more than 2 weeks */ #define MAX_EXPIRE 31536000 /* expire a zone if we have not talked to */ /* the primary in 1 year */ #define NADDRECS 20 /* max addt'l rr's per resp */ #define XFER_TIMER 120 /* named-xfer's connect timeout */ #define MAX_XFER_TIME 60*60*2 /* default max seconds for an xfer */ #define XFER_TIME_FUDGE 10 /* MAX_XFER_TIME fudge */ #define MAX_XFERS_RUNNING 20 /* max value of transfers_in */ #define DEFAULT_XFERS_RUNNING 10 /* default value of transfers_in */ #define DEFAULT_XFERS_PER_NS 2 /* default # of xfers per peer nameserver */ #define XFER_BUFSIZE (16*1024) /* arbitrary but bigger than most MTU's */ #define MAX_SYNCDELAY 3 /* Presumed timeout in use by our clients. */ #define MAX_SYNCDRAIN 100000 /* How long we'll spin in drain_all_rcvbuf. */ #define MAX_SYNCSTORE 500 #define NS_MAX_DISTANCE 3 /* maximum nameserver chaining before failure */ /* maximum time to cache negative answers */ #define DEFAULT_MAX_NCACHE_TTL (3*60*60) #define ALPHA 0.7 /* How much to preserve of old response time */ #define BETA 1.2 /* How much to penalize response time on failure */ #define GAMMA 0.98 /* How much to decay unused response times */ /* What maintainance operations need to be performed sometime soon? */ typedef enum need { main_need_zreload = 0, /* ns_zreload() needed. */ main_need_reload, /* ns_reload() needed. */ main_need_reconfig, /* ns_reconfig() needed. */ main_need_endxfer, /* endxfer() needed. */ main_need_zoneload, /* loadxfer() needed. */ main_need_dump, /* doadump() needed. */ main_need_statsdump, /* ns_stats() needed. */ main_need_statsdumpandclear, /* ns_stats() needed. */ main_need_exit, /* exit() needed. */ main_need_qrylog, /* toggle_qrylog() needed. */ main_need_debug, /* use_desired_debug() needed. */ main_need_restart, /* exec() needed. */ main_need_reap, /* need to reap dead children. */ main_need_noexpired, /* ns_reconfig() needed w/ noexpired set. */ main_need_tryxfer, /* attemt to start a zone transfer. */ main_need_num /* MUST BE LAST. */ } main_need; /* What global options are set? */ #define OPTION_NORECURSE 0x00000001 /* Don't recurse even if asked. */ #define OPTION_NOFETCHGLUE 0x00000002 /* Don't fetch missing glue. */ #define OPTION_FORWARD_ONLY 0x00000004 /* Don't use NS RR's, just forward. */ #define OPTION_FAKE_IQUERY 0x00000008 /* Fake up bogus response to IQUERY. */ #ifdef BIND_NOTIFY /* #define OPTION_NONOTIFY 0x00000010 */ /* Turn off notify */ #define OPTION_SUPNOTIFY_INITIAL 0x00000020 /* Supress initial notify */ #endif #define OPTION_NONAUTH_NXDOMAIN 0x00000040 /* Generate non-auth NXDOMAINs? */ #define OPTION_MULTIPLE_CNAMES 0x00000080 /* Allow a name to have multiple * CNAME RRs */ #define OPTION_HOSTSTATS 0x00000100 /* Maintain per-host statistics? */ #define OPTION_DEALLOC_ON_EXIT 0x00000200 /* Deallocate everything on exit? */ #define OPTION_NODIALUP 0x00000400 /* Turn off dialup support */ #define OPTION_NORFC2308_TYPE1 0x00000800 /* Prevent type1 respones (RFC 2308) * to cached negative respones */ #define OPTION_USE_ID_POOL 0x00001000 /* Use the memory hogging query ID */ #define OPTION_TREAT_CR_AS_SPACE 0x00002000 /* Treat CR in zone files as * space */ #define OPTION_USE_IXFR 0x00004000 /* Use by default ixfr in zone * transfer */ #define OPTION_MAINTAIN_IXFR_BASE 0x00008000 /* Part of IXFR file name logic. */ #define OPTION_HITCOUNT 0x00010000 /* Keep track of each time an * RR gets hit in the database */ #define DEFAULT_OPTION_FLAGS (OPTION_NODIALUP|OPTION_NONAUTH_NXDOMAIN|\ OPTION_USE_ID_POOL|OPTION_NORFC2308_TYPE1) #ifdef BIND_UPDATE #define SOAINCRINTVL 300 /* default value for the time after which * the zone serial number must be incremented * after a successful update has occurred */ #define DUMPINTVL 3600 /* default interval at which to dump changed zones * randomized, not exact */ #define DEFERUPDCNT 100 /* default number of updates that can happen * before the zone serial number will be * incremented */ #define UPDATE_TIMER XFER_TIMER #endif /* BIND_UPDATE */ #define USE_MINIMUM 0xffffffff #define MAXIMUM_TTL 0x7fffffff #define CLEAN_TIMER 0x01 #define INTERFACE_TIMER 0x02 #define STATS_TIMER 0x04 #define HEARTBEAT_TIMER 0x08 /* IP address accessor, network byte order. */ #define ina_ulong(ina) (ina.s_addr) /* IP address accessor, host byte order, read only. */ #define ina_hlong(ina) ntohl(ina.s_addr) /* IP address equality. */ /* XXX: assumes that network byte order won't affect equality. */ #define ina_equal(a, b) (ina_ulong(a) == ina_ulong(b)) /* IP address equality with a mask. */ #define ina_onnet(h, n, m) ((ina_ulong(h) & ina_ulong(m)) == ina_ulong(n)) /* Sequence space arithmetic. */ #define SEQ_GT(a,b) ((int32_t)((a)-(b)) > 0) #define SEQ_LT(a,b) ((int32_t)((a)-(b)) < 0) #define NS_OPTION_P(option) ((server_options == NULL) ? \ (panic(panic_msg_no_options, NULL), 0) : \ ((server_options->flags & option) != 0)) #define NS_ZOPTION_P(zp, option) \ (((zp) != NULL && (((zp)->z_optset & option) != 0)) ? \ (((zp)->z_options & option) != 0) : NS_OPTION_P(option)) #define NS_ZFWDTAB(zp) (((zp) == NULL) ? \ server_options->fwdtab : (zp)->z_fwdtab) #define NS_INCRSTAT(addr, which) \ do { \ if ((int)which >= (int)nssLast) \ ns_panic(ns_log_insist, 1, panic_msg_bad_which, \ __FILE__, __LINE__, #which); \ else { \ if (NS_OPTION_P(OPTION_HOSTSTATS)) { \ struct nameser *ns = \ nameserFind(addr, NS_F_INSERT); \ if (ns != NULL) \ ns->stats[(int)which]++; \ } \ globalStats[(int)which]++; \ } \ } while (0) enum severity { ignore, warn, fail, not_set }; #ifdef BIND_NOTIFY enum notify { notify_use_default=0, notify_yes, notify_no, notify_explicit }; #endif enum zdialup { zdialup_use_default=0, zdialup_yes, zdialup_no }; enum axfr_format { axfr_use_default=0, axfr_one_answer, axfr_many_answers }; struct ip_match_direct { struct in_addr address; struct in_addr mask; }; struct ip_match_indirect { struct ip_match_list *list; }; struct ip_match_key { struct dst_key *key; }; typedef enum { ip_match_pattern, ip_match_indirect, ip_match_localhost, ip_match_localnets, ip_match_key } ip_match_type; typedef struct ip_match_element { ip_match_type type; u_int flags; union { struct ip_match_direct direct; struct ip_match_indirect indirect; struct ip_match_key key; } u; struct ip_match_element *next; } *ip_match_element; /* Flags for ip_match_element */ #define IP_MATCH_NEGATE 0x01 /* match means deny access */ typedef struct ip_match_list { ip_match_element first; ip_match_element last; } *ip_match_list; typedef struct ztimer_info { char *name; int class; int type; } *ztimer_info; /* * These fields are ordered to maintain word-alignment; * be careful about changing them. */ struct zoneinfo { char *z_origin; /* root domain name of zone */ time_t z_time; /* time for next refresh */ time_t z_lastupdate; /* time of last soa serial increment */ u_int32_t z_refresh; /* refresh interval */ u_int32_t z_retry; /* refresh retry interval */ u_int32_t z_expire; /* expiration time for cached info */ u_int32_t z_minimum; /* minimum TTL value */ u_int32_t z_serial; /* changes if zone modified */ char *z_source; /* source location of data */ time_t z_ftime; /* modification time of source file */ struct in_addr z_axfr_src; /* bind() the axfr socket to this */ struct in_addr z_addr[NSMAX]; /* list of master servers for zone */ struct dst_key * z_keys[NSMAX]; /* tsig key associated with master */ u_char z_addrcnt; /* number of entries in z_addr[] */ struct in_addr z_xaddr[NSMAX]; /* list of master servers for xfer */ u_char z_xaddrcnt; /* number of entries in z_xaddr[] */ u_char z_type; /* type of zone; see below */ u_int32_t z_flags; /* state bits; see below */ pid_t z_xferpid; /* xfer child pid */ u_int z_options; /* options set specific to this zone */ u_int z_optset; /* which opts override global opts */ int z_class; /* class of zone */ int z_numxfrs; /* Ref count of concurrent xfrs. */ enum severity z_checknames; /* How to handle non-RFC-compliant names */ #ifdef BIND_UPDATE time_t z_dumptime; /* randomized time for next zone dump * if Z_NEED_DUMP is set */ u_int32_t z_dumpintvl; /* time interval between zone dumps */ time_t z_soaincrintvl; /* interval for updating soa serial */ time_t z_soaincrtime; /* time for soa increment */ u_int32_t z_deferupdcnt; /* max number of updates before SOA * serial number incremented */ u_int32_t z_updatecnt; /* number of update requests processed * since the last SOA serial update */ char *z_updatelog; /* log file for updates */ #endif ip_match_list z_update_acl; /* list of who can issue dynamic updates */ ip_match_list z_query_acl; /* sites we'll answer questions for */ ip_match_list z_transfer_acl; /* sites that may get a zone transfer from us */ long z_max_transfer_time_in; /* max num seconds for AXFR */ #ifdef BIND_NOTIFY enum notify z_notify; /* Notify mode */ struct in_addr *z_also_notify; /* More nameservers to notify */ int z_notify_count; #endif enum zdialup z_dialup; /* secondaries over a dialup link */ char *z_ixfr_base; /* where to find the history of the zone */ char *z_ixfr_tmp; /* tmp file for the ixfr */ int z_maintain_ixfr_base; long z_max_log_size_ixfr; u_int32_t z_serial_ixfr_start; evTimerID z_timer; /* maintenance timer */ ztimer_info z_timerinfo; /* UAP associated with timer */ time_t z_nextmaint; /* time of next maintenance */ u_int16_t z_port; /* perform AXFR to this port */ struct fwdinfo *z_fwdtab; /* zone-specific forwarders */ LINK(struct zoneinfo) z_freelink; /* if it's on the free list. */ LINK(struct zoneinfo) z_reloadlink; /* if it's on the reload list. */ }; /* zone types (z_type) */ enum zonetype { z_nil, z_master, z_slave, z_hint, z_stub, z_forward, z_cache, z_any }; #define Z_NIL z_nil /* XXX */ #define Z_MASTER z_master /* XXX */ #define Z_PRIMARY z_master /* XXX */ #define Z_SLAVE z_slave /* XXX */ #define Z_SECONDARY z_slave /* XXX */ #define Z_HINT z_hint /* XXX */ #define Z_CACHE z_cache /* XXX */ #define Z_STUB z_stub /* XXX */ #define Z_FORWARD z_forward /* XXX */ #define Z_ANY z_any /* XXX*2 */ /* zone state bits (32 bits) */ #define Z_AUTH 0x00000001 /* zone is authoritative */ #define Z_NEED_XFER 0x00000002 /* waiting to do xfer */ #define Z_XFER_RUNNING 0x00000004 /* asynch. xfer is running */ #define Z_NEED_RELOAD 0x00000008 /* waiting to do reload */ #define Z_SYSLOGGED 0x00000010 /* have logged timeout */ #define Z_QSERIAL 0x00000020 /* sysquery()'ing for serial number */ #define Z_FOUND 0x00000040 /* found in boot file when reloading */ #define Z_INCLUDE 0x00000080 /* set if include used in file */ #define Z_DB_BAD 0x00000100 /* errors when loading file */ #define Z_TMP_FILE 0x00000200 /* backup file for xfer is temporary */ #ifdef BIND_UPDATE #define Z_DYNAMIC 0x00000400 /* allow dynamic updates */ #define Z_NEED_DUMP 0x00000800 /* zone has changed, needs a dump */ #define Z_NEED_SOAUPDATE 0x00001000 /* soa serial number needs increment */ #endif /* BIND_UPDATE */ #define Z_XFER_ABORTED 0x00002000 /* zone transfer has been aborted */ #define Z_XFER_GONE 0x00004000 /* zone transfer process is gone */ #define Z_TIMER_SET 0x00008000 /* z_timer contains a valid id */ #ifdef BIND_NOTIFY #define Z_NOTIFY 0x00010000 /* has an outbound notify executing */ #endif #define Z_NEED_QSERIAL 0x00020000 /* we need to re-call qserial() */ #define Z_PARENT_RELOAD 0x00040000 /* we need to reload this as parent */ #define Z_FORWARD_SET 0x00080000 /* has forwarders been set */ #define Z_EXPIRED 0x00100000 /* expire timer has gone off */ #define Z_NEEDREFRESH 0x00200000 /* need to perform a refresh check */ /* named_xfer exit codes */ #define XFER_UPTODATE 0 /* zone is up-to-date */ #define XFER_SUCCESS 1 /* performed transfer successfully */ #define XFER_TIMEOUT 2 /* no server reachable/xfer timeout */ #define XFER_FAIL 3 /* other failure, has been logged */ #define XFER_SUCCESSAXFR 4 /* named-xfr recived a xfr */ #define XFER_SUCCESSIXFR 5 /* named-xfr recived a ixfr */ #define XFER_SUCCESSAXFRIXFRFILE 6 /* named-xfr received AXFR for IXFR */ #define XFER_REFUSED 7 /* one master returned REFUSED */ #define XFER_ISAXFR -1 /* the last XFR is AXFR */ #define XFER_ISIXFR -2 /* the last XFR is IXFR */ #define XFER_ISAXFRIXFR -3 /* the last XFR is AXFR but we must create IXFR base */ struct qserv { struct sockaddr_in ns_addr; /* address of NS */ struct databuf *ns; /* databuf for NS record */ struct databuf *nsdata; /* databuf for server address */ struct timeval stime; /* time first query started */ unsigned int forwarder:1; /* this entry is for a forwarder */ unsigned int noedns:1; /* don't try edns */ unsigned int nretry:30; /* # of times addr retried */ u_int32_t serial; /* valid if Q_ZSERIAL */ }; /* * Structure for recording info on forwarded or generated queries. */ struct qinfo { u_int16_t q_id; /* id of query */ u_int16_t q_nsid; /* id of forwarded query */ struct sockaddr_in q_from; /* requestor's address */ u_char *q_msg, /* the message */ *q_cmsg; /* the cname message */ int16_t q_msglen, /* len of message */ q_msgsize, /* allocated size of message */ q_cmsglen, /* len of cname message */ q_cmsgsize; /* allocated size of cname message */ int16_t q_dfd; /* UDP file descriptor */ u_int16_t q_udpsize; /* UDP message size */ int q_distance; /* distance this query is from the * original query that the server * received. */ time_t q_time; /* time to retry */ time_t q_expire; /* time to expire */ struct qinfo *q_next; /* rexmit list (sorted by time) */ struct qinfo *q_link; /* storage list (random order) */ struct databuf *q_usedns[NSMAX]; /* databuf for NS that we've tried */ struct qserv q_addr[NSMAX]; /* addresses of NS's */ #ifdef notyet struct nameser *q_ns[NSMAX]; /* name servers */ #endif struct dst_key *q_keys[NSMAX]; /* keys to use with this address */ u_char q_naddr; /* number of addr's in q_addr */ u_char q_curaddr; /* last addr sent to */ u_char q_nusedns; /* number of elements in q_usedns[] */ u_int8_t q_flags; /* see below */ int16_t q_cname; /* # of cnames found */ int16_t q_nqueries; /* # of queries required */ struct qstream *q_stream; /* TCP stream, null if UDP */ struct zoneinfo *q_zquery; /* Zone query is about (Q_ZSERIAL) */ struct zoneinfo *q_fzone; /* Forwarding zone, if any */ char *q_domain; /* domain of most enclosing zone cut */ char *q_name; /* domain of query */ u_int16_t q_class; /* class of query */ u_int16_t q_type; /* type of query */ #ifdef BIND_NOTIFY int q_notifyzone; /* zone which needs another notify() * when the reply to this comes in. */ #endif struct tsig_record *q_tsig; /* forwarded query's TSIG record */ struct tsig_record *q_nstsig; /* forwarded query's TSIG record */ }; /* q_flags bits (8 bits) */ #define Q_SYSTEM 0x01 /* is a system query */ #define Q_PRIMING 0x02 /* generated during priming phase */ #define Q_ZSERIAL 0x04 /* getting zone serial for xfer test */ #define Q_USEVC 0x08 /* forward using tcp not udp */ #define Q_EDNS 0x10 /* add edns opt record to answer */ #define Q_NEXTADDR(qp,n) (&(qp)->q_addr[n].ns_addr) #define RETRY_TIMEOUT 45 /* * Return codes from ns_forw: */ #define FW_OK 0 #define FW_DUP 1 #define FW_NOSERVER 2 #define FW_SERVFAIL 3 typedef void (*sq_closure)(struct qstream *qs); #ifdef BIND_UPDATE struct fdlist { int fd; struct fdlist *next; }; #endif typedef struct ns_delta { LINK(struct ns_delta) d_link; ns_updque d_changes; } ns_delta; typedef LIST(ns_delta) ns_deltalist; typedef struct _interface { int dfd, /* Datagram file descriptor */ sfd; /* Stream file descriptor. */ time_t gen; /* Generation number. */ struct in_addr addr; /* Interface address. */ u_int16_t port; /* Interface port. */ u_int16_t flags; /* Valid bits for evXXXXID. */ evFileID evID_d; /* Datagram read-event. */ evConnID evID_s; /* Stream listen-event. */ LINK(struct _interface) link; } interface; #define INTERFACE_FILE_VALID 0x01 #define INTERFACE_CONN_VALID 0x02 #define INTERFACE_FORWARDING 0x04 struct qstream { int s_rfd; /* stream file descriptor */ int s_size; /* expected amount of data to rcv */ int s_bufsize; /* amount of data received in s_buf */ u_char *s_buf; /* buffer of received data */ u_char *s_wbuf; /* send buffer */ u_char *s_wbuf_send; /* next sendable byte of send buffer */ u_char *s_wbuf_free; /* next free byte of send buffer */ u_char *s_wbuf_end; /* byte after end of send buffer */ sq_closure s_wbuf_closure; /* callback for writable descriptor */ struct qstream *s_next; /* next stream */ struct sockaddr_in s_from; /* address query came from */ interface *s_ifp; /* interface query came from */ time_t s_time; /* time stamp of last transaction */ int s_refcnt; /* number of outstanding queries */ u_char s_temp[HFIXEDSZ]; #ifdef BIND_UPDATE int s_opcode; /* type of request */ int s_linkcnt; /* number of client connections using * this connection to forward updates * to the primary */ struct fdlist *s_fds; /* linked list of connections to the * primaries that have been used by * the server to forward this client's * update requests */ #endif evStreamID evID_r; /* read event. */ evFileID evID_w; /* writable event handle. */ evConnID evID_c; /* connect event handle */ u_int flags; /* see below */ struct qstream_xfr { enum { s_x_base, s_x_firstsoa, s_x_zone, s_x_lastsoa, s_x_done, s_x_adding, s_x_deleting, s_x_addsoa, s_x_deletesoa } state; /* state of transfer. */ u_char *msg, /* current assembly message. */ *cp, /* where are we in msg? */ *eom, /* end of msg. */ *ptrs[128]; /* ptrs for dn_comp(). */ int class, /* class of an XFR. */ type, /* type of XFR. */ id, /* id of an XFR. */ opcode; /* opcode of an XFR. */ u_int zone; /* zone being XFR'd. */ union { struct namebuf *axfr; /* top np of an AXFR. */ ns_deltalist *ixfr; /* top udp of an IXFR. */ } top; int ixfr_zone; u_int32_t serial; /* serial number requested in IXFR */ ns_tcp_tsig_state *tsig_state; /* used by ns_sign_tcp */ int tsig_skip; /* skip calling ns_sign_tcp * during the next flush */ int tsig_size; /* need to reserve this space * for the tsig. */ struct qs_x_lev { /* decompose the recursion. */ enum {sxl_ns, sxl_all, sxl_sub} state; /* what's this level doing? */ int flags; /* see below (SXL_*). */ char dname[MAXDNAME]; struct namebuf *np, /* this node. */ *nnp, /* next node to process. */ **npp, /* subs. */ **npe; /* end of subs. */ struct databuf *dp; /* current rr. */ struct qs_x_lev *next; /* link. */ } *lev; /* LIFO. */ enum axfr_format transfer_format; } xfr; }; #define SXL_GLUING 0x01 #define SXL_ZONECUT 0x02 /* flags */ #define STREAM_MALLOC 0x01 #define STREAM_WRITE_EV 0x02 #define STREAM_READ_EV 0x04 #define STREAM_CONNECT_EV 0x08 #define STREAM_DONE_CLOSE 0x10 #define STREAM_AXFR 0x20 #define STREAM_AXFRIXFR 0x40 #define ALLOW_NETS 0x0001 #define ALLOW_HOSTS 0x0002 #define ALLOW_ALL (ALLOW_NETS | ALLOW_HOSTS) struct fwddata { struct sockaddr_in fwdaddr; /* address of NS */ struct databuf *ns; /* databuf for NS record */ struct databuf *nsdata; /* databuf for server address */ int ref_count; /* how many users of this */ }; struct fwdinfo { struct fwdinfo *next; struct fwddata *fwddata; }; enum nameserStats { nssRcvdR, /* sent us an answer */ nssRcvdNXD, /* sent us a negative response */ nssRcvdFwdR, /* sent us a response we had to fwd */ nssRcvdDupR, /* sent us an extra answer */ nssRcvdFail, /* sent us a SERVFAIL */ nssRcvdFErr, /* sent us a FORMERR */ nssRcvdErr, /* sent us some other error */ nssRcvdAXFR, /* sent us an AXFR */ nssRcvdLDel, /* sent us a lame delegation */ nssRcvdOpts, /* sent us some IP options */ nssSentSysQ, /* sent them a sysquery */ nssSentAns, /* sent them an answer */ nssSentFwdQ, /* fwdd a query to them */ nssSentDupQ, /* sent them a retry */ nssSendtoErr, /* error in sendto */ nssRcvdQ, /* sent us a query */ nssRcvdIQ, /* sent us an inverse query */ nssRcvdFwdQ, /* sent us a query we had to fwd */ nssRcvdDupQ, /* sent us a retry */ nssRcvdTCP, /* sent us a query using TCP */ nssSentFwdR, /* fwdd a response to them */ nssSentFail, /* sent them a SERVFAIL */ nssSentFErr, /* sent them a FORMERR */ nssSentNaAns, /* sent them a non autoritative answer */ nssSentNXD, /* sent them a negative response */ nssRcvdUQ, /* sent us an unapproved query */ nssRcvdURQ, /* sent us an unapproved recursive query */ nssRcvdUXFR, /* sent us an unapproved AXFR or IXFR */ nssRcvdUUpd, /* sent us an unapproved update */ nssLast }; struct nameser { struct in_addr addr; /* key */ u_long stats[nssLast]; /* statistics */ #ifdef notyet u_int32_t rtt; /* round trip time */ /* XXX - need to add more stuff from "struct qserv", and use our rtt */ u_int16_t flags; /* see below */ u_int8_t xfers; /* #/xfers running right now */ #endif }; enum transport { primary_trans, secondary_trans, response_trans, update_trans, num_trans }; /* types used by the parser or config routines */ typedef struct zone_config { void *opaque; } zone_config; typedef struct listen_info { u_short port; ip_match_list list; struct listen_info *next; } *listen_info; typedef struct listen_info_list { listen_info first; listen_info last; } *listen_info_list; #ifndef RLIMIT_TYPE #define RLIMIT_TYPE u_long #endif typedef RLIMIT_TYPE rlimit_type; struct control; typedef struct control *control; typedef LIST(struct control) controls; enum ordering { unknown_order, fixed_order, cyclic_order, random_order }; #define DEFAULT_ORDERING cyclic_order typedef struct rrset_order_element { int class; int type; char *name; enum ordering order; struct rrset_order_element *next; } *rrset_order_element ; typedef struct rrset_order_list { rrset_order_element first; rrset_order_element last; } *rrset_order_list; typedef struct options { u_int32_t flags; char *hostname; char *version; char *directory; char *dump_filename; char *pid_filename; char *stats_filename; char *memstats_filename; char *named_xfer; int transfers_in; int transfers_per_ns; int transfers_out; int serial_queries; int max_log_size_ixfr; enum axfr_format transfer_format; long max_transfer_time_in; struct sockaddr_in query_source; struct in_addr axfr_src; #ifdef BIND_NOTIFY int notify_count; struct in_addr *also_notify; #endif ip_match_list query_acl; ip_match_list recursion_acl; ip_match_list transfer_acl; ip_match_list blackhole_acl; ip_match_list topology; ip_match_list sortlist; enum severity check_names[num_trans]; u_long data_size; u_long stack_size; u_long core_size; u_long files; listen_info_list listen_list; struct fwdinfo *fwdtab; /* XXX need to add forward option */ int clean_interval; int interface_interval; int stats_interval; rrset_order_list ordering; int heartbeat_interval; u_int max_ncache_ttl; u_int max_host_stats; u_int lame_ttl; int minroots; u_int16_t preferred_glue; enum notify notify; } *options; typedef struct key_list_element { struct dst_key *key; struct key_list_element *next; } *key_list_element; typedef struct key_info_list { key_list_element first; key_list_element last; } *key_info_list; typedef struct topology_config { void *opaque; } topology_config; #define UNKNOWN_TOPOLOGY_DISTANCE 9998 #define MAX_TOPOLOGY_DISTANCE 9999 typedef struct topology_distance { ip_match_list patterns; struct topology_distance *next; } *topology_distance; typedef struct topology_context { topology_distance first; topology_distance last; } *topology_context; typedef struct acl_table_entry { char *name; ip_match_list list; struct acl_table_entry *next; } *acl_table_entry; typedef struct server_config { void *opaque; } server_config; #define SERVER_INFO_BOGUS 0x01 #define SERVER_INFO_SUPPORT_IXFR 0x02 #define SERVER_INFO_EDNS 0x04 typedef struct server_info { struct in_addr address; u_int flags; int transfers; enum axfr_format transfer_format; key_info_list key_list; /* could move statistics to here, too */ struct server_info *next; } *server_info; /* * enum <--> name translation */ struct ns_sym { int number; /* Identifying number, like ns_log_default */ const char * name; /* Its symbolic name, like "default" */ }; /* * Logging options */ typedef enum ns_logging_categories { ns_log_default = 0, ns_log_config, ns_log_parser, ns_log_queries, ns_log_lame_servers, ns_log_statistics, ns_log_panic, ns_log_update, ns_log_ncache, ns_log_xfer_in, ns_log_xfer_out, ns_log_db, ns_log_eventlib, ns_log_packet, #ifdef BIND_NOTIFY ns_log_notify, #endif ns_log_cname, ns_log_security, ns_log_os, ns_log_insist, ns_log_maint, ns_log_load, ns_log_resp_checks, ns_log_control, ns_log_max_category } ns_logging_categories; typedef struct log_config { log_context log_ctx; log_channel eventlib_channel; log_channel packet_channel; int default_debug_active; } *log_config; struct map { const char * token; int val; }; #define NOERROR_NODATA 15 /* only used internally by the server, used for * -ve $ing non-existence of records. 15 is not * a code used as yet anyway. */ #define NTTL 600 /* ttl for negative data: 10 minutes? */ #define VQEXPIRY 900 /* a VQ entry expires in 15*60 = 900 seconds */ #ifdef BIND_UPDATE enum req_action { Finish, Refuse, Return }; #endif #ifdef INIT error "INIT already defined, check system include files" #endif #ifdef DECL error "DECL already defined, check system include files" #endif #ifdef MAIN_PROGRAM #define INIT(x) = x #define DECL #else #define INIT(x) #define DECL extern #endif #define EDNS_MESSAGE_SZ 4096 Index: vendor/bind/dist/contrib/bind/bin/named/ns_ncache.c =================================================================== --- vendor/bind/dist/contrib/bind/bin/named/ns_ncache.c (revision 109982) +++ vendor/bind/dist/contrib/bind/bin/named/ns_ncache.c (revision 109983) @@ -1,269 +1,269 @@ #if !defined(lint) && !defined(SABER) -static const char rcsid[] = "$Id: ns_ncache.c,v 8.29 2001/06/18 14:43:16 marka Exp $"; +static const char rcsid[] = "$Id: ns_ncache.c,v 8.29.4.1 2002/11/14 13:41:31 marka Exp $"; #endif /* not lint */ /* * Copyright (c) 1996-2000 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include "port_before.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "port_after.h" #include "named.h" #define BOUNDS_CHECK(ptr, count) \ do { \ if ((ptr) + (count) > eom) { \ return; \ } \ } while (0) void cache_n_resp(u_char *msg, int msglen, struct sockaddr_in from, const char *qname, int qclass, int qtype) { struct databuf *dp; HEADER *hp; u_char *cp, *eom, *rdatap; char dname[MAXDNAME]; int n, type, class, flags; u_int ancount, nscount, dlen; #ifdef RETURNSOA u_int32_t ttl; u_int16_t atype; u_char *sp, *cp1; u_char data[MAXDATA]; u_char *eod = data + sizeof(data); #endif nameserIncr(from.sin_addr, nssRcvdNXD); hp = (HEADER *)msg; cp = msg + HFIXEDSZ; eom = msg + msglen; switch (ntohs(hp->qdcount)) { case 0: dname[sizeof dname - 1] = '\0'; strncpy(dname, qname, sizeof dname); if (dname[sizeof dname - 1] != '\0') { ns_debug(ns_log_ncache, 1, "qp->qname too long (%d)", strlen(qname)); hp->rcode = FORMERR; return; } class = qclass; type = qtype; break; case 1: n = dn_expand(msg, eom, cp, dname, sizeof dname); if (n < 0) { ns_debug(ns_log_ncache, 1, "Query expand name failed: cache_n_resp"); hp->rcode = FORMERR; return; } cp += n; BOUNDS_CHECK(cp, 2 * INT16SZ); GETSHORT(type, cp); GETSHORT(class, cp); if (class > CLASS_MAX) { ns_debug(ns_log_ncache, 1, "bad class in cache_n_resp"); hp->rcode = FORMERR; return; } break; default: ns_debug(ns_log_ncache, 1, "QDCOUNT>1 (%d) in cache_n_resp", ntohs(hp->qdcount)); hp->rcode = FORMERR; return; } ns_debug(ns_log_ncache, 1, "ncache: dname %s, type %d, class %d", dname, type, class); ancount = ntohs(hp->ancount); nscount = ntohs(hp->nscount); while (ancount--) { u_int32_t ttl; int atype, aclass; n = dn_skipname(cp, eom); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: form error"); return; } cp += n; BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); GETSHORT(atype, cp); GETSHORT(aclass, cp); if (atype != T_CNAME || aclass != class) { ns_debug(ns_log_ncache, 3, "ncache: not CNAME (%s) or wrong class (%s)", p_type(atype), p_class(aclass)); return; } GETLONG(ttl, cp); GETSHORT(dlen, cp); BOUNDS_CHECK(cp, dlen); rdatap = cp; n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: bad cname target"); return; } cp += n; if (cp != rdatap + dlen) { ns_debug(ns_log_ncache, 3, "ncache: bad cname rdata"); return; } } dp = NULL; #ifdef RETURNSOA while (nscount--) { sp = cp; /* we store NXDOMAIN as T_SOA regardless of the query type */ if (hp->rcode == NXDOMAIN) type = T_SOA; /* store ther SOA record */ n = dn_skipname(cp, msg + msglen); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: form error"); return; } cp += n; BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); GETSHORT(atype, cp); /* type */ cp += INT16SZ; /* class */ GETLONG(ttl, cp); /* ttl */ GETSHORT(dlen, cp); /* dlen */ BOUNDS_CHECK(cp, dlen); if (atype != T_SOA) { ns_debug(ns_log_ncache, 3, "ncache: type (%d) != T_SOA", atype); cp += dlen; continue; } rdatap = cp; /* origin */ n = dn_expand(msg, msg + msglen, cp, (char*)data, eod - data); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: origin form error"); return; } cp += n; n = strlen((char*)data) + 1; cp1 = data + n; /* mail */ n = dn_expand(msg, msg + msglen, cp, (char*)cp1, eod - cp1); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: mail form error"); return; } cp += n; n = strlen((char*)cp1) + 1; cp1 += n; n = 5 * INT32SZ; if (n > (eod - cp1)) /* Can't happen. See MAXDATA. */ return; BOUNDS_CHECK(cp, n); memcpy(cp1, cp, n); /* serial, refresh, retry, expire, min */ cp1 += n; cp += n; if (cp != rdatap + dlen) { ns_debug(ns_log_ncache, 3, "ncache: form error"); return; } /* store the zone of the soa record */ n = dn_expand(msg, msg + msglen, sp, (char*)cp1, eod - cp1); if (n < 0) { ns_debug(ns_log_ncache, 3, "ncache: form error 2"); return; } n = strlen((char*)cp1) + 1; cp1 += n; /* * we only want to store these long enough so that * ns_resp can find it. */ if (qtype == T_SOA && hp->rcode == NXDOMAIN) ttl = 0; dp = savedata(class, type, MIN(ttl, server_options->max_ncache_ttl) + tt.tv_sec, data, cp1 - data); break; } #endif if (dp == NULL) #ifdef STRICT_RFC2308 dp = savedata(class, type, tt.tv_sec, NULL, 0); #else dp = savedata(class, type, NTTL + tt.tv_sec, NULL, 0); #endif dp->d_zone = DB_Z_CACHE; dp->d_cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER; dp->d_secure = DB_S_INSECURE; /* BEW - should be UNCHECKED */ dp->d_clev = 0; if(hp->rcode == NXDOMAIN) { dp->d_rcode = NXDOMAIN; flags = DB_NODATA|DB_NOTAUTH|DB_NOHINTS; } else { dp->d_rcode = NOERROR_NODATA; flags = DB_NOTAUTH|DB_NOHINTS; } n = db_update(dname, dp, dp, NULL, flags, hashtab, from); if (n != OK) ns_debug(ns_log_ncache, 1, "db_update failed (%d), cache_n_resp()", n); else ns_debug(ns_log_ncache, 4, "ncache succeeded: [%s %s %s] rcode:%d ttl:%ld", dname, p_type(type), p_class(class), dp->d_rcode, (long)(dp->d_ttl - tt.tv_sec)); db_detach(&dp); } Index: vendor/bind/dist/contrib/bind/bin/named/ns_req.c =================================================================== --- vendor/bind/dist/contrib/bind/bin/named/ns_req.c (revision 109982) +++ vendor/bind/dist/contrib/bind/bin/named/ns_req.c (revision 109983) @@ -1,2545 +1,2545 @@ #if !defined(lint) && !defined(SABER) static const char sccsid[] = "@(#)ns_req.c 4.47 (Berkeley) 7/1/91"; -static const char rcsid[] = "$Id: ns_req.c,v 8.169 2002/05/12 23:41:52 marka Exp $"; +static const char rcsid[] = "$Id: ns_req.c,v 8.169.2.1 2002/11/14 13:02:48 marka Exp $"; #endif /* not lint */ /* * Copyright (c) 1986, 1988, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University 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 REGENTS 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. */ /* * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ /* * Portions Copyright (c) 1996-2000 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include "port_before.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "port_after.h" #include "named.h" struct addinfo { char *a_dname; /* domain name */ char *a_rname; /* referred by */ u_int16_t a_rtype; /* referred by */ u_int16_t a_type; /* type for data */ u_int16_t a_class; /* class for data */ }; #ifndef BIND_UPDATE enum req_action { Finish, Refuse, Return }; #endif static struct addinfo addinfo[NADDRECS]; static void addname(const char *, const char *, u_int16_t, u_int16_t, u_int16_t); static void copyCharString(u_char **, const char *); static enum req_action req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, int *buflenp, int *msglenp, u_char *msg, int dfd, int *ra, struct sockaddr_in from, struct tsig_record *in_tsig, u_int16_t udpsize); static enum req_action req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, struct sockaddr_in from); #ifdef BIND_NOTIFY static enum req_action req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg,struct sockaddr_in from); #endif /* * See if there is a OPT record at the end of the message. * * Results: * -1 FORMERR * 0 last RR is not a OPT record * n>0 lenght of OPT record */ int ns_get_opt(u_char *msg, u_char *eom, u_int8_t *versionp, u_int16_t *rcodep, u_int16_t *flagp, u_int16_t *bufsizep, u_char **optionsp, size_t *optsizep) { HEADER *hp = (HEADER *) msg; u_char *start, *options, *cp; u_int8_t version; u_int16_t rdlen, type, bufsize, flags, optsize, rcode; int i, n, root; if (msg == NULL || eom == NULL || (msg + HFIXEDSZ) > eom) return (-1); if (ntohs(hp->arcount) == 0) return (0); cp = msg + HFIXEDSZ; n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount)); if (n < 0) return (-1); cp += n; n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount)); if (n < 0) return (-1); cp += n; n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount)); if (n < 0) return (-1); cp += n; i = ntohs(hp->arcount); while (i-- > 0) { start = cp; if (cp >= eom) return (-1); root = (*cp == 0); n = dn_skipname(cp, eom); if (n < 0) return (-1); cp += n; if (cp + (2 + 2 + 4 + 2) > eom) return (-1); GETSHORT(type, cp); if (type != ns_t_opt) { cp += INT16SZ + INT32SZ; /* class, ttl */ GETSHORT(rdlen, cp); if (cp + rdlen > eom) return (-1); cp += rdlen; continue; } /* We have the OPT record. Check it out in detail. */ if (!root) return (-1); GETSHORT(bufsize, cp); rcode = (*cp++ <<4) + hp->rcode ; version = *cp++; GETSHORT(flags, cp); GETSHORT(rdlen, cp); if (cp + rdlen > eom) return (-1); options = cp; optsize = rdlen; if (versionp != NULL) *versionp = version; if (rcodep != NULL) *rcodep = rcode; if (flagp != NULL) *flagp = flags; if (bufsizep != NULL) *bufsizep = bufsize; if (optionsp != NULL) *optionsp = options; if (optsizep != NULL) *optsizep = optsize; return (cp - start); } /* OPT not found */ return (0); } int ns_add_opt(u_char *msg, u_char *cp, size_t buflen, u_int8_t version, u_int16_t rcode, u_int16_t size, u_int16_t flags, u_char *options, size_t optlen) { HEADER *hp = (HEADER *) msg; if ((cp + 1 + 2 + 2 + 4 + 2 + optlen) > (msg + buflen)) return (-1); *cp++ = 0; /* "." */ PUTSHORT(ns_t_opt, cp); /* type */ PUTSHORT(size, cp); /* class (udp size) */ *cp++ = (rcode >> 4) & 0xff; /* ttl (rcode + version + flags) */ hp->rcode = rcode & 0xf; *cp++ = version; PUTSHORT(flags, cp); PUTSHORT(optlen, cp); /* rdlen */ memcpy(cp, options, optlen); /* options */ hp->arcount = htons(ntohs(hp->arcount) + 1); return (1 + 2 + 2 + 4 + 2 + optlen); } /* * Process request using database; assemble and send response. */ void ns_req(u_char *msg, int msglen, int buflen, struct qstream *qsp, struct sockaddr_in from, int dfd) { HEADER *hp = (HEADER *) msg; u_char *cp, *eom; enum req_action action = Return; int n, ra, has_tsig, tsig_size = 0, opt_size = 0, sig2len; u_char *tsigstart; u_char sig[TSIG_SIG_SIZE], sig2[TSIG_SIG_SIZE]; struct tsig_record *in_tsig = NULL; int error = NOERROR; int msglen_orig = msglen; int buflen_orig = buflen; int siglen = sizeof sig; DST_KEY *key = NULL; time_t tsig_time; int opt = 0; u_int8_t version = 0; u_int16_t rcode = ns_r_noerror; u_int16_t udpsize = 0; int drop; int tsig_adjust = 0; #ifdef DEBUG if (debug > 3) { ns_debug(ns_log_packet, 3, "ns_req(from %s)", sin_ntoa(from)); fp_nquery(msg, msglen, log_get_stream(packet_channel)); } #endif drop = drop_port(ntohs(from.sin_port)); if (qsp == NULL && drop == 1) return; tsigstart = ns_find_tsig(msg, msg + msglen); if (tsigstart == NULL) has_tsig = 0; else { char buf[MAXDNAME]; u_char tmp[NS_MAXCDNAME]; has_tsig = 1; n = ns_name_unpack(msg, msg + msglen, tsigstart, tmp, sizeof tmp); if (n > 0) { tsig_adjust = dn_skipname(tmp, tmp + sizeof(tmp)) - n; if (ns_name_ntop(tmp, buf, sizeof buf) == -1) n = -1; else if (buf[0] == '.') buf[0] = '\0'; } if (n < 0) { ns_debug(ns_log_default, 1, "ns_req: bad TSIG key name"); error = ns_r_formerr; hp->rcode = ns_r_formerr; key = NULL; } else if ((key = find_key(buf, NULL)) == NULL) { error = ns_r_badkey; hp->rcode = ns_r_notauth; ns_debug(ns_log_default, 1, "ns_req: TSIG verify failed - unknown key %s", buf); } #ifdef LOG_TSIG_BUG if (n < 0 || key == NULL) ns_error(ns_log_security, "SECURITY: POSSIBLE ATTEMPT TO EXERCISE \"TSIG BUG\" FROM %s: %s%s%s", sin_ntoa(from), (n < 0) ? "bad key (formerr)" : "unknown key (", (n < 0) ? "" : (buf[0] != '\0' ? buf : "."), (n < 0) ? "" : ")"); #endif } if (has_tsig && key != NULL) { n = ns_verify(msg, &msglen, key, NULL, 0, sig, &siglen, &tsig_time, 0); if (n != 0) { hp->rcode = ns_r_notauth; /* A query should never have an error code set */ if (n == ns_r_badsig || n == ns_r_badkey || n == ns_r_badtime) { ns_debug(ns_log_default, 1, "ns_req: TSIG verify failed - query had error %s (%d) set", p_rcode(n), n); error = n; action = Return; } /* If there's a processing error just respond */ else if (n == -ns_r_badsig || n == -ns_r_badkey || n == -ns_r_badtime) { n = -n; ns_debug(ns_log_default, 1, "ns_req: TSIG verify failed - %s (%d)", p_rcode(n), n); error = n; } else { ns_debug(ns_log_default, 1, "ns_req: TSIG verify failed - FORMERR"); error = ns_r_formerr; } action = Finish; } in_tsig = memget(sizeof(struct tsig_record)); if (in_tsig == NULL) ns_panic(ns_log_default, 1, "memget failed"); in_tsig->key = key; in_tsig->siglen = siglen; memcpy(in_tsig->sig, sig, siglen); tsig_size = msglen_orig - msglen; /* AXFR/IXFR need the uncompressed tsig size. */ in_tsig->tsig_size = tsig_size + tsig_adjust; } else if (has_tsig) { action = Finish; in_tsig = memget(sizeof(struct tsig_record)); if (in_tsig == NULL) ns_panic(ns_log_default, 1, "memget failed"); in_tsig->key = NULL; in_tsig->siglen = 0; tsig_size = msg + msglen - tsigstart; in_tsig->tsig_size = tsig_size; msglen = tsigstart - msg; } /* Hash some stuff so it's nice and random */ nsid_hash((u_char *)&tt, sizeof(tt)); nsid_hash(msg, (msglen > 512) ? 512 : msglen); if (error == NOERROR) { opt = ns_get_opt(msg, msg + msglen, &version, NULL, NULL, &udpsize, NULL, NULL); if (opt < 0) { rcode = ns_r_formerr; action = Finish; } else if (opt == 0) { if (qsp == NULL && buflen > PACKETSZ) buflen_orig = buflen = PACKETSZ; } else if (opt > 0) { if (version != 0) { rcode = ns_r_badvers; action = Finish; } opt_size = 11; if (udpsize < 512) udpsize = 512; if (qsp == NULL && buflen > udpsize) buflen_orig = buflen = udpsize; } } else if (qsp == NULL && buflen > PACKETSZ) buflen_orig = buflen = PACKETSZ; /* * It's not a response so these bits have no business * being set. will later simplify work if we can * safely assume these are always 0 when a query * comes in. */ #ifdef BIND_NOTIFY if (hp->opcode != ns_o_notify) #endif hp->aa = 0; hp->ra = 0; ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); if (error == NOERROR) hp->rcode = ns_r_noerror; if (rcode == ns_r_noerror) rcode = hp->rcode; cp = msg + HFIXEDSZ; eom = msg + msglen; buflen -= HFIXEDSZ; free_addinfo(); /* sets addcount to zero */ dnptrs[0] = NULL; if (error == NOERROR && rcode == ns_r_noerror) { switch (hp->opcode) { case ns_o_query: action = req_query(hp, &cp, eom, qsp, &buflen, &msglen, msg, dfd, &ra, from, in_tsig, udpsize); break; case ns_o_iquery: action = req_iquery(hp, &cp, eom, &buflen, from); break; #ifdef BIND_NOTIFY case ns_o_notify: action = req_notify(hp, &cp, eom, msg, from); break; #endif #ifdef BIND_UPDATE case ns_o_update: action = req_update(hp, cp, eom, msg, from, in_tsig); break; #endif /* BIND_UPDATE */ default: ns_debug(ns_log_default, 1, "ns_req: Opcode %d not implemented", hp->opcode); /* XXX - should syslog, limited by haveComplained */ hp->qdcount = htons(0); hp->ancount = htons(0); hp->nscount = htons(0); hp->arcount = htons(0); hp->rcode = ns_r_notimpl; action = Finish; } rcode = hp->rcode; } if (in_tsig != NULL) { memput(in_tsig, sizeof(struct tsig_record)); in_tsig = NULL; } /* * Loop advoidance. */ if (qsp == NULL && drop == 2 && (hp->rcode == FORMERR || hp->rcode == NOTIMP)) action = Return; /* * Vector via internal opcode. */ switch (action) { case Return: return; case Refuse: rcode = hp->rcode = ns_r_refused; cp = eom; /*FALLTHROUGH*/ case Finish: /* rest of the function handles this case */ break; default: panic("ns_req: bad action variable", NULL); /*NOTREACHED*/ } /* * Apply final polish. */ hp->qr = 1; /* set Response flag */ hp->ra = ra; /* init above, may be modified by req_query */ if (!hp->tc && (has_tsig > 0 || opt > 0) && buflen < (tsig_size + opt_size)) hp->tc = 1; /* * If there was a format error, then we don't know what the msg has. */ if (hp->rcode == ns_r_formerr || rcode == ns_r_badvers) { hp->qdcount = htons(0); hp->ancount = htons(0); hp->nscount = htons(0); hp->arcount = htons(0); cp = msg + HFIXEDSZ; } /* * If the query had a TSIG / OPT and the message is truncated or * there was a TSIG error, build a new message with no data and a * TSIG / OPT. */ if ((hp->tc || error != NOERROR) && (has_tsig > 0 || opt > 0)) { sign_again: hp->ancount = htons(0); hp->nscount = htons(0); hp->arcount = htons(0); cp = msg + HFIXEDSZ; cp += ns_skiprr(cp, msg + msglen, ns_s_qd, ntohs(hp->qdcount)); ns_name_rollback(cp, (const u_char **)dnptrs, (const u_char **)dnptrs_end); if (opt > 0) { n = ns_add_opt(msg, cp, buflen_orig, 0, rcode, EDNS_MESSAGE_SZ, 0, NULL, 0); if (n < 0) { hp->qdcount = htons(0); goto sign_again; } cp += n; } if (has_tsig > 0) { sig2len = sizeof sig2; msglen = cp - msg; buflen = buflen_orig - msglen; n = ns_sign2(msg, &msglen, msglen + buflen, error, key, sig, siglen, sig2, &sig2len, tsig_time, dnptrs, dnptrs_end); if (n == NS_TSIG_ERROR_NO_SPACE && ntohs(hp->qdcount) != 0) { hp->qdcount = htons(0); goto sign_again; } if (n != 0) ns_info(ns_log_default, "ns_req: unable to sign response"); cp = msg + msglen; } } /* Either the message is not truncated or there was no TSIG & OPT */ else { /* * Reserve space for tsig if required. */ if (has_tsig > 0 || opt_size != 0) buflen -= tsig_size + opt_size; INSIST(buflen >= 0); msglen = cp - msg; n = doaddinfo(hp, cp, buflen); cp += n; buflen -= n; msglen += n; if (opt > 0) { buflen += opt_size; n = ns_add_opt(msg, cp, msglen + buflen, 0, rcode, EDNS_MESSAGE_SZ, 0, NULL, 0); INSIST(n > 0); cp += n; buflen -= n; msglen += n; } if (has_tsig > 0) { buflen += tsig_size; sig2len = sizeof sig2; n = ns_sign2(msg, &msglen, msglen + buflen, error, key, sig, siglen, sig2, &sig2len, tsig_time, dnptrs, dnptrs_end); if (n != 0) { INSIST(0); } cp = msg + msglen; } } #ifdef DEBUG if (ns_wouldlog(ns_log_default, 1)) { ns_debug(ns_log_default, 1, "ns_req: answer -> %s fd=%d id=%d size=%d rc=%d", sin_ntoa(from), (qsp == NULL) ? dfd : qsp->s_rfd, ntohs(hp->id), cp - msg, hp->rcode); } if (debug >= 10) res_pquery(&res, msg, cp - msg, log_get_stream(packet_channel)); #endif /*DEBUG*/ if (qsp == NULL) { if (sendto(dfd, (char*)msg, cp - msg, 0, (struct sockaddr *)&from, sizeof from) < 0) { if (!haveComplained(ina_ulong(from.sin_addr), (u_long)sendtoStr)) ns_info(ns_log_default, "ns_req: sendto(%s): %s", sin_ntoa(from), strerror(errno)); nameserIncr(from.sin_addr, nssSendtoErr); } nameserIncr(from.sin_addr, nssSentAns); if (hp->rcode == ns_r_nxdomain) nameserIncr(from.sin_addr, nssSentNXD); if (!hp->aa) nameserIncr(from.sin_addr, nssSentNaAns); } else writestream(qsp, msg, cp - msg); /* Is now a safe time? */ if (needs_prime_cache) prime_cache(); } #ifdef BIND_NOTIFY int findZonePri(const struct zoneinfo *zp, const struct sockaddr_in from) { struct in_addr ina; int i; ina = from.sin_addr; for (i = 0; (u_int)i < zp->z_addrcnt; i++) if (ina_equal(zp->z_addr[i], ina)) return (i); return (-1); } static enum req_action req_notify(HEADER *hp, u_char **cpp, u_char *eom, u_char *msg, struct sockaddr_in from) { int n, type, class; char dnbuf[MAXDNAME]; struct zoneinfo *zp; /* valid notify's are authoritative */ if (!hp->aa) { ns_debug(ns_log_notify, 1, "FORMERR Notify request without AA"); #ifdef not_yet hp->rcode = ns_r_formerr; return (Finish); #endif } hp->aa = 0; /* valid notify's have one question */ if (ntohs(hp->qdcount) != 1) { ns_debug(ns_log_notify, 1, "FORMERR Notify header counts wrong"); hp->rcode = ns_r_formerr; return (Finish); } n = dn_expand(msg, eom, *cpp, dnbuf, sizeof dnbuf); if (n < 0) { ns_debug(ns_log_notify, 1, "FORMERR Query expand name failed"); hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; if (*cpp + 2 * INT16SZ > eom) { ns_debug(ns_log_notify, 1, "FORMERR notify too short"); hp->rcode = ns_r_formerr; return (Finish); } GETSHORT(type, *cpp); GETSHORT(class, *cpp); ns_info(ns_log_notify, "rcvd NOTIFY(%s, %s, %s) from %s", dnbuf, p_class(class), p_type(type), sin_ntoa(from)); /* XXX - when answers are allowed, we'll need to do compression * correctly here, and we will need to check for packet underflow. */ /* * We are ignoring the other field, make sure the header reflects * *cpp. */ hp->ancount = htons(0); hp->nscount = htons(0); hp->arcount = htons(0); /* Find the zone this NOTIFY refers to. */ zp = find_auth_zone(dnbuf, class); if (zp == NULL) { ns_info(ns_log_notify, "rcvd NOTIFY for \"%s\", name not one of our zones", dnbuf); hp->rcode = ns_r_servfail; return (Finish); } /* Access control. */ switch (type) { case T_SOA: if (zp->z_type != z_slave) { /* * This can come if a user did an AXFR of some zone * somewhere and that zone's server now wants to * tell us that the SOA has changed. AXFR's always * come from nonpriv ports so it isn't possible to * know whether it was the server or just "dig". * This condition can be avoided by using secure * zones since that way only real secondaries can * AXFR from you. */ ns_info(ns_log_notify, "NOTIFY(SOA) for non-slave zone (%s), from %s", dnbuf, sin_ntoa(from)); goto refuse; } if (ns_samename(dnbuf, zp->z_origin) != 1) { ns_info(ns_log_notify, "NOTIFY(SOA) for non-origin (%s), from %s", dnbuf, sin_ntoa(from)); goto refuse; } if (findZonePri(zp, from) == -1) { ns_debug(ns_log_notify, 1, "NOTIFY(SOA) from non-master server (zone %s), from %s", zp->z_origin, sin_ntoa(from)); goto refuse; } break; default: /* No access requirements defined for other types. */ break; } /* The work occurs here. */ switch (type) { case T_SOA: if (zp->z_flags & (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL|Z_XFER_RUNNING)) { ns_info(ns_log_notify, "NOTIFY(SOA) for zone already xferring (%s)", dnbuf); zp->z_flags |= Z_NEEDREFRESH; goto noerror; } zp->z_time = tt.tv_sec; qserial_query(zp); sched_zone_maint(zp); break; default: /* * Unimplemented, but it's not a protocol error, just * something to be ignored. */ hp->rcode = ns_r_notimpl; return (Finish); } noerror: hp->rcode = ns_r_noerror; hp->aa = 1; return (Finish); refuse: hp->rcode = ns_r_refused; return (Finish); } #endif /*BIND_NOTIFY*/ static int add_bind(HEADER *hp, u_char **cpp, u_char *msg, int *msglenp, const char *label, const char *data) { u_char *tp; hp->ancount = htons(1); hp->nscount = htons(0); hp->arcount = htons(0); hp->rcode = ns_r_noerror; hp->aa = 1; hp->ra = 0; copyCharString(cpp, label); /* Name */ copyCharString(cpp, "BIND"); *(*cpp)++ = 0x00; PUTSHORT(T_TXT, *cpp); /* Type */ PUTSHORT(C_CHAOS, *cpp); /* Class */ PUTLONG(0, *cpp); /* TTL */ tp = *cpp; /* Temp RdLength */ PUTSHORT(0, *cpp); copyCharString(cpp, data); PUTSHORT((*cpp) - (tp + INT16SZ), tp); /* Real RdLength */ *msglenp = *cpp - msg; /* Total message length */ return (Finish); } static enum req_action req_query(HEADER *hp, u_char **cpp, u_char *eom, struct qstream *qsp, int *buflenp, int *msglenp, u_char *msg, int dfd, int *ra, struct sockaddr_in from, struct tsig_record *in_tsig, u_int16_t udpsize) { int n, class, type, count, zone, foundname, founddata, omsglen, cname; int recursion_blocked_by_acl; u_int16_t id; u_int32_t serial_ixfr = 0; int ixfr_found; int ixfr_error = 0; char dnbuf2[MAXDNAME]; u_char **dpp, *omsg, *answers, *afterq; char dnbuf[MAXDNAME], *dname; const char *fname; struct hashbuf *htp; struct databuf *nsp[NSMAX]; struct namebuf *np, *anp; struct qinfo *qp; struct zoneinfo *zp; struct databuf *dp; DST_KEY *in_key = (in_tsig != NULL) ? in_tsig->key : NULL; int access_class; int adjustlen = 0; nameserIncr(from.sin_addr, nssRcvdQ); nsp[0] = NULL; dpp = dnptrs; *dpp++ = msg; *dpp = NULL; /* * Make gcc happy. */ omsglen = 0; omsg = NULL; id = 0; recursion_blocked_by_acl = 0; /* valid queries have one question and zero answers */ if ((ntohs(hp->qdcount) != 1) || ntohs(hp->ancount) != 0) { ns_debug(ns_log_default, 1, "FORMERR Query header counts wrong"); hp->rcode = ns_r_formerr; return (Finish); } if (ntohs(hp->arcount) != 0) { ns_debug(ns_log_default, 1, "Ignoring addition section"); hp->arcount = htons(0); adjustlen = 1; } /* * Get domain name, class, and type. */ if ((**cpp & INDIR_MASK) == 0) *dpp++ = *cpp; /* remember name for compression */ *dpp = NULL; n = dn_expand(msg, eom, *cpp, dnbuf, sizeof dnbuf); if (n < 0) { ns_debug(ns_log_default, 1, "FORMERR Query expand name failed"); hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; answers = *cpp; if (*cpp + 2 * INT16SZ > eom) { ns_debug(ns_log_default, 1, "FORMERR Query message length short"); hp->rcode = ns_r_formerr; return (Finish); } GETSHORT(type, *cpp); GETSHORT(class, *cpp); if (*cpp < eom && type != ns_t_ixfr) { if (!adjustlen) ns_debug(ns_log_default, 6, "message length > received message"); *msglenp = *cpp - msg; } if (((ntohs(hp->nscount) != 0) && (type != ns_t_ixfr)) || ((ntohs(hp->nscount) != 1) && (type == ns_t_ixfr))) { ns_debug(ns_log_default, 1, "FORMERR Query nscount wrong"); hp->rcode = ns_r_formerr; return (Finish); } afterq = *cpp; qtypeIncr(type); /* * Process query. */ if (type == ns_t_ixfr) { ns_info(ns_log_security, "Request %s from %s", p_type(type), sin_ntoa(from)); hp->nscount = htons(0); hp->rd = 0; /* Force IXFR queries to be non recursive. */ n = dn_expand(msg, eom, *cpp, dnbuf2, sizeof dnbuf2); if (n < 0) { ns_debug(ns_log_default, 1, "FORMERR Query expand name failed"); hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; if (*cpp + 3 * INT16SZ + INT32SZ > eom) { ns_debug(ns_log_default, 1, "ran out of data in IXFR query"); hp->rcode = ns_r_formerr; return (Finish); } GETSHORT(n, *cpp); if (n != ns_t_soa || ns_samename(dnbuf, dnbuf2) != 1) { ns_debug(ns_log_default, 1, "FORMERR SOA record expected"); hp->rcode = ns_r_formerr; return (Finish); } *cpp += INT32SZ + INT16SZ * 2; /* skip class, ttl, dlen */ if (0 >= (n = dn_skipname(*cpp, eom))) { ns_debug(ns_log_default, 1, "FORMERR Query expand name failed"); hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; /* mname */ if (0 >= (n = dn_skipname(*cpp, eom))) { ns_debug(ns_log_default, 1, "FORMERR Query expand name failed"); hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; /* rname */ if (*cpp + 5 * INT32SZ > eom) { ns_debug(ns_log_default, 1, "ran out of data in IXFR query"); hp->rcode = ns_r_formerr; return (Finish); } GETLONG(serial_ixfr, *cpp); /* ignore other soa counters */ if ((*cpp + (4 * INT32SZ)) < eom && !adjustlen) ns_debug(ns_log_default, 6, "ixfr: message length > received message"); /* Reset msglenp to cover just the question. */ *msglenp = afterq - msg; } *cpp = afterq; if (!ns_t_udp_p(type)) { /* Refuse request if not a TCP connection. */ if (qsp == NULL) { ns_info(ns_log_default, "rejected UDP %s from %s for \"%s\"", p_type(type), sin_ntoa(from), *dnbuf ? dnbuf : "."); return (Refuse); } /* The position of this is subtle. */ nameserIncr(from.sin_addr, nssRcvdAXFR); hp->rd = 0; /* Recursion not possible. */ } *buflenp -= (*msglenp - HFIXEDSZ); count = 0; founddata = 0; dname = dnbuf; cname = 0; #ifdef QRYLOG if (qrylog) { ns_info(ns_log_queries, "%s/%s/%s/%s/%s", (hp->rd) ? "XX+" : "XX ", inet_ntoa(from.sin_addr), (dname[0] == '\0') ? "." : dname, p_type(type), p_class(class)); } #endif /*QRYLOG*/ try_again: foundname = 0; ns_debug(ns_log_default, 1, "req: nlookup(%s) id %d type=%d class=%d", dname, ntohs(hp->id), type, class); htp = hashtab; /* lookup relative to root */ if ((anp = np = nlookup(dname, &htp, &fname, 0)) == NULL) fname = ""; ns_debug(ns_log_default, 1, "req: %s '%s' as '%s' (cname=%d)", np == NULL ? "missed" : "found", dname, fname, cname); #ifdef YPKLUDGE /* Some braindamaged resolver software will not recognize internet addresses in dot notation and send out address queries for "names" such as 128.93.8.1. This kludge will prevent those from flooding higher level servers. We simply claim to be authoritative and that the domain doesn't exist. Note that we could return the address but we don't do that in order to encourage that broken software is fixed. */ if (!np && type == T_A && class == C_IN && dname) { struct in_addr ina; if (inet_aton(dname, &ina)) { hp->rcode = ns_r_nxdomain; hp->aa = 1; ns_debug(ns_log_default, 3, "ypkludge: hit as '%s'", dname); return (Finish); } } #endif /*YPKLUDGE*/ /* * Don't accept in a query names which would be rejected in responses. * (This is primarily in case we have to forward it, but it's also a * matter of architectural symmetry.) */ if (!ns_nameok(NULL, dname, class, NULL, response_trans, ns_ownercontext(type, response_trans), dname, from.sin_addr)) { ns_debug(ns_log_default, 1, "bad name in query"); hp->rcode = ns_r_formerr; return (Refuse); } /* * Begin Access Control Point */ zone = DB_Z_CACHE; /* * Map class ANY to to class IN for the purpose of access control. */ access_class = (class == C_ANY && !ns_t_xfr_p(type)) ? C_IN : class; if (np) { #ifndef FORWARD_ALLOWS struct namebuf *access_np; /* * Find out which zone this will be answered from. Note * that we look for a zone with the same class as ours. * The np that we found in the database might not be the * one we asked for (i.e. dname might not equal fname). This * is OK, since if a name doesn't exist, we need to go up * the tree until we find the closest enclosing zone that * is of the same class. */ for (access_np = np; access_np != NULL; access_np = np_parent(access_np)) { dp = access_np->n_data; while (dp && dp->d_class != access_class) dp = dp->d_next; if (dp != NULL) { zone = dp->d_zone; break; } } #else /* * Try looking for forward zone. It can be deeper than * any entry in the cache. */ if (zone == DB_Z_CACHE) { char *s = dname; int escape = 0; while ((zp = find_zone(s, access_class)) == NULL) { if (*s == '\0') break; while (*s != '\0' && (escape || *s != '.')) { escape = escape ? 0 : (*s == '\\'); s++; } if (*s == '.') s++; } if (zp != NULL) zone = zp - zones; } #endif } zp = &zones[zone]; ixfr_found = 0; if (type == ns_t_ixfr && zone != DB_Z_CACHE) { if (SEQ_GT(serial_ixfr, zp->z_serial)) ixfr_found = 0; else { ixfr_error = ixfr_have_log(zp, serial_ixfr, zp->z_serial); if (ixfr_error < 0) { ns_info(ns_log_security, "No %s log from %d for \"%s\"", p_type(type), serial_ixfr, *dname ? dname : "."); ns_debug(ns_log_default, 1, "ixfr_have_log(%d %d) failed %d", serial_ixfr, zp->z_serial, ixfr_error); ixfr_found = 0; /* Refuse IXFR and send AXFR */ } else if (ixfr_error == 1) { ixfr_found = 1; } } ns_debug(ns_log_default, 1, "IXFR log lowest serial: %d", zp->z_serial_ixfr_start); } /* * If recursion is turned on, we need to check recursion ACL * if it exists - and return result to caller. */ { ip_match_list recursion_acl; recursion_acl = server_options->recursion_acl; if (!NS_OPTION_P(OPTION_NORECURSE) && recursion_acl != NULL && !ip_address_allowed(recursion_acl, from.sin_addr)) { recursion_blocked_by_acl = 1; *ra = 0; } } /* * Are queries allowed from this host? */ if (!ns_t_xfr_p(type)) { ip_match_list query_acl; if (zp->z_query_acl != NULL) query_acl = zp->z_query_acl; else query_acl = server_options->query_acl; if (query_acl != NULL && !ip_addr_or_key_allowed(query_acl, from.sin_addr, in_key)) { /* * If this is *not* a zone acl and we would not * have recursed and we have some answer return * what we have with a referral. */ if ((zp->z_query_acl == NULL) && (!hp->rd || NS_OPTION_P(OPTION_NORECURSE) || recursion_blocked_by_acl) && (ntohs(hp->ancount) != 0)) { goto fetchns; } /* * See if we would have made a referral from * an enclosing zone if we are actually in the * cache. */ if (zp->z_type == z_cache && np != NULL) { struct namebuf *access_np; zone = DB_Z_CACHE; for (access_np = np; access_np != NULL; access_np = np_parent(access_np)) { dp = access_np->n_data; while (dp && (dp->d_class != access_class || dp->d_zone == DB_Z_CACHE)) dp = dp->d_next; if (dp != NULL) { zone = dp->d_zone; np = access_np; break; } } zp = &zones[zone]; if (zp->z_type != z_cache && zp->z_query_acl != NULL && ip_addr_or_key_allowed(zp->z_query_acl, from.sin_addr, in_key) && (!hp->rd || recursion_blocked_by_acl || NS_OPTION_P(OPTION_NORECURSE))) { goto fetchns; } } #ifdef NXDOMAIN_ON_DENIAL hp->rcode = ns_r_nxdomain; return (Finish); #else ns_notice(ns_log_security, "denied query from %s for \"%s\" %s/%s", sin_ntoa(from), *dname ? dname : ".", p_type(type), p_class(class)); nameserIncr(from.sin_addr, nssRcvdUQ); return (Refuse); #endif } } else { ip_match_list transfer_acl; /* Do they have permission to do a zone transfer? */ if (zp->z_transfer_acl != NULL) transfer_acl = zp->z_transfer_acl; else transfer_acl = server_options->transfer_acl; if (transfer_acl != NULL && !ip_addr_or_key_allowed(transfer_acl, from.sin_addr, in_key)) { ns_notice(ns_log_security, "denied %s from %s for \"%s\" %s (acl)", p_type(type), sin_ntoa(from), *dname ? dname : ".", p_class(class)); nameserIncr(from.sin_addr, nssRcvdUXFR); if (type == ns_t_ixfr) { hp->rcode = ns_r_refused; return (Finish); } return (Refuse); } /* Are we master or slave? */ if (zp->z_type != z_master && zp->z_type != z_slave) { ns_notice(ns_log_security, "denied %s from %s for \"%s\" (not master/slave)", p_type(type), sin_ntoa(from), *dname ? dname : "."); nameserIncr(from.sin_addr, nssRcvdUXFR); if (type == ns_t_ixfr) { hp->rcode = ns_r_refused; return (Finish); } return (Refuse); } /* Are we authoritative? */ if ((zp->z_flags & Z_AUTH) == 0) { ns_notice(ns_log_security, "denied %s from %s for \"%s\" %s (not authoritative)", p_type(type), sin_ntoa(from), *dname ? dname : ".", p_class(class)); nameserIncr(from.sin_addr, nssRcvdUXFR); if (type == ns_t_ixfr) { hp->rcode = ns_r_refused; return (Finish); } return (Refuse); } /* Is the name at a zone cut? */ if (ns_samename(zp->z_origin, dname) != 1) { ns_notice(ns_log_security, "denied %s from %s for \"%s\" %s (not zone top)", p_type(type), sin_ntoa(from), *dname ? dname : ".", p_class(class)); nameserIncr(from.sin_addr, nssRcvdUXFR); if (type == ns_t_ixfr) { hp->rcode = ns_r_refused; return (Finish); } return (Refuse); } if (type == ns_t_ixfr) { ns_info(ns_log_security, "approved %s from %s for \"%s\"", (ixfr_found) ? p_type(type) : "IXFR/AXFR", sin_ntoa(from), *dname ? dname : "."); } else ns_info(ns_log_security, "approved %s from %s for \"%s\"", p_type(type), sin_ntoa(from), *dname ? dname : "."); } /* * End Access Control Point */ /* * Yow! */ if (class == ns_c_chaos && type == ns_t_txt && ns_samename(dnbuf, "VERSION.BIND") == 1 && server_options->version != NULL && server_options->version[0] != '\0') return (add_bind(hp, cpp, msg, msglenp, "VERSION", server_options->version)); if (class == ns_c_chaos && type == ns_t_txt && ns_samename(dnbuf, "HOSTNAME.BIND") == 1 && server_options->hostname != NULL && server_options->hostname[0] != '\0') return (add_bind(hp, cpp, msg, msglenp, "HOSTNAME", server_options->hostname)); /* * If we don't know anything about the requested name, * go look for nameservers. */ if (!np || fname != dname) goto fetchns; foundname++; answers = *cpp; count = *cpp - msg; /* The response is authoritative until we add insecure data */ hp->ad = 1; /* Look for NXDOMAIN record with appropriate class * if found return immediately */ for (dp = np->n_data; dp; dp = dp->d_next) { if (!stale(dp) && (dp->d_rcode == ns_r_nxdomain) && (dp->d_class == class)) { #ifdef RETURNSOA n = finddata(np, class, T_SOA, hp, &dname, buflenp, &count); if (n != 0) { if (count) { *cpp += n; *buflenp -= n; *msglenp += n; hp->nscount = htons((u_int16_t)count); } if (hp->rcode == NOERROR_NODATA) { /* this should not occur */ hp->rcode = ns_r_noerror; return (Finish); } } #else count = 0; #endif hp->rcode = ns_r_nxdomain; /* * XXX forcing AA all the time isn't right, but * we have to work that way by default * for compatibility with older servers. */ if (!NS_OPTION_P(OPTION_NONAUTH_NXDOMAIN)) hp->aa = 1; ns_debug(ns_log_default, 3, "NXDOMAIN aa = %d", hp->aa); if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) return (Finish); founddata = 1; goto fetchns; } } /* * If not NXDOMAIN, the NOERROR_NODATA record might be * anywhere in the chain. Have to go through the grind. */ n = finddata(np, class, type, hp, &dname, buflenp, &count); if (n == 0) { /* * NO data available. Refuse transfer requests, or * look for better servers for other requests. */ if (ns_t_xfr_p(type)) { ns_debug(ns_log_default, 1, "transfer refused: no data"); return (Refuse); } goto fetchns; } if (hp->rcode == NOERROR_NODATA) { hp->rcode = ns_r_noerror; #ifdef RETURNSOA if (count) { *cpp += n; *buflenp -= n; *msglenp += n; hp->nscount = htons(count); } #endif founddata = 1; ns_debug(ns_log_default, 1, "count = %d", count); if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) return (Finish); goto fetchns; } *cpp += n; *buflenp -= n; *msglenp += n; hp->ancount = htons(ntohs(hp->ancount) + (u_int16_t)count); if (fname != dname && type != T_CNAME && type != T_ANY) { if (cname++ >= MAXCNAMES) { ns_debug(ns_log_default, 3, "resp: leaving, MAXCNAMES exceeded"); hp->rcode = ns_r_servfail; return (Finish); } goto try_again; } founddata = 1; ns_debug(ns_log_default, 3, "req: foundname=%d, count=%d, founddata=%d, cname=%d", foundname, count, founddata, cname); if (ns_t_xfr_p(type)) { #ifdef BIND_UPDATE if ((zp->z_flags & Z_NEED_SOAUPDATE) != 0) if (incr_serial(zp) < 0) ns_error(ns_log_default, "error updating serial number for %s from %d", zp->z_origin, zp->z_serial); #endif /* * Just return SOA if "up to date". */ if (type == ns_t_ixfr) { hp->aa = 1; if ((SEQ_GT(serial_ixfr, zp->z_serial) || serial_ixfr == zp->z_serial)) { return (Finish); } } /* * We don't handle UDP based IXFR queries (yet). * Tell client to retry with TCP by returning SOA. */ if (qsp == NULL) return (Finish); else { if (!ixfr_found && type == ns_t_ixfr) { qsp->flags |= STREAM_AXFRIXFR; hp->qdcount = htons(1); } ns_xfr(qsp, np, zone, class, type, hp->opcode, ntohs(hp->id), serial_ixfr, in_tsig); } return (Return); } if (count > 1 && type == T_A && !NS_OPTION_P(OPTION_NORECURSE) && hp->rd) sort_response(answers, *cpp, count, &from); fetchns: /* * If we're already out of room in the response, we're done. */ if (hp->tc) return (Finish); if (hp->ancount == 0) hp->ad = 0; /* * Look for name servers to refer to and fill in the authority * section or record the address for forwarding the query * (recursion desired). */ free_nsp(nsp); nsp[0] = NULL; count = 0; switch (findns(&np, class, nsp, &count, 0)) { case NXDOMAIN: /* We are authoritative for this np. */ if (!foundname) hp->rcode = ns_r_nxdomain; ns_debug(ns_log_default, 3, "req: leaving (%s, rcode %d)", dname, hp->rcode); if (class != C_ANY) { hp->aa = 1; if (np && (!foundname || !founddata)) { n = doaddauth(hp, *cpp, *buflenp, np, nsp[0]); *cpp += n; *buflenp -= n; #ifdef ADDAUTH } else if (ntohs(hp->ancount) != 0) { /* don't add NS records for NOERROR NODATA as some servers can get confused */ free_nsp(nsp); switch (findns(&np, class, nsp, &count, 1)) { case NXDOMAIN: case SERVFAIL: break; default: if (np && (type != T_NS || np != anp) ) { n = add_data(np, nsp, *cpp, *buflenp, &count); if (n < 0) { hp->tc = 1; n = (-n); } *cpp += n; *buflenp -= n; hp->nscount = htons((u_int16_t) count); } } #endif /*ADDAUTH*/ } } free_nsp(nsp); return (Finish); case SERVFAIL: /* We're authoritative but the zone isn't loaded. */ if (!founddata && !(NS_ZOPTION_P(zp, OPTION_FORWARD_ONLY) && NS_ZFWDTAB(zp))) { hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } } if (!founddata && hp->rd && recursion_blocked_by_acl) { ns_notice(ns_log_security, "denied recursion for query from %s for %s %s", sin_ntoa(from), *dname ? dname : ".", p_class(class)); nameserIncr(from.sin_addr, nssRcvdURQ); } /* * If we successfully found the answer in the cache, * or this is not a recursive query, or we are purposely * never recursing, or recursion is prohibited by ACL, then * add the nameserver references("authority section") here * and we're done. */ if (founddata || !hp->rd || NS_OPTION_P(OPTION_NORECURSE) || recursion_blocked_by_acl) { /* * If the qtype was NS, and the np of the authority is * the same as the np of the data, we don't need to add * another copy of the answer here in the authority * section. */ if (!founddata || type != T_NS || anp != np) { n = add_data(np, nsp, *cpp, *buflenp, &count); if (n < 0) { hp->tc = 1; n = (-n); } *cpp += n; *buflenp -= n; hp->nscount = htons(ntohs(hp->nscount) + (u_int16_t)count); } free_nsp(nsp); /* Our caller will handle the Additional section. */ return (Finish); } /* * At this point, we don't have the answer, but we do * have some NS's to try. If the user would like us * to recurse, create the initial query. If a cname * is involved, we need to build a new query and save * the old one in cmsg/cmsglen. */ if (cname) { omsg = (u_char *)memget((unsigned) *msglenp); if (omsg == NULL) { ns_info(ns_log_default, "ns_req: Out Of Memory"); hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } id = hp->id; omsglen = *msglenp; memcpy(omsg, msg, omsglen); n = res_nmkquery(&res, QUERY, dname, class, type, NULL, 0, NULL, msg, *msglenp + *buflenp); if (n < 0) { ns_info(ns_log_default, "res_mkquery(%s) failed", dname); memcpy(msg, omsg, omsglen); memput(omsg, omsglen); hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } *msglenp = n; } n = ns_forw(nsp, msg, *msglenp, from, qsp, dfd, &qp, dname, class, type, np, 0, in_tsig); if (n != FW_OK && cname) { memcpy(msg, omsg, omsglen); memput(omsg, omsglen); *msglenp = omsglen; omsg = NULL; } switch (n) { case FW_OK: if (cname) { qp->q_cname = cname; qp->q_cmsg = omsg; qp->q_cmsglen = omsglen; qp->q_cmsgsize = omsglen; qp->q_id = id; } if (udpsize != 0) { qp->q_flags |= Q_EDNS; qp->q_udpsize = udpsize; } else qp->q_udpsize = PACKETSZ; break; case FW_DUP: break; /* Duplicate request dropped */ case FW_NOSERVER: /* * Don't go into an infinite loop if * the admin gave root NS records in the cache * file without giving address records * for the root servers. */ if (np) { if (NAME(*np)[0] == '\0') { ns_notice(ns_log_default, "ns_req: no address for root server"); hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } for (dp = np->n_data; dp ; dp = dp->d_next) if (dp->d_zone && match(dp, class, T_NS)) break; if (dp) { /* * we know the child zone exists but are * missing glue. * * nslookup has called sysquery() to get the * missing glue. * * for UDP, drop the response and let the * client retry. for TCP, we should probably * (XXX) hold open the TCP connection for a * while in case the sysquery() comes back * soon. meanwhile we SERVFAIL. */ if (qsp) goto do_servfail; break; } np = np_parent(np); } goto fetchns; /* Try again. */ case FW_SERVFAIL: do_servfail: hp->rcode = ns_r_servfail; free_nsp(nsp); return (Finish); } free_nsp(nsp); return (Return); } static enum req_action req_iquery(HEADER *hp, u_char **cpp, u_char *eom, int *buflenp, struct sockaddr_in from) { u_int rdata_offset; size_t alen; int dlen, n; ns_type type; ns_class class; u_char anbuf[PACKETSZ], *anptr; char dnbuf[MAXDNAME]; nameserIncr(from.sin_addr, nssRcvdIQ); if (ntohs(hp->ancount) != 1 || ntohs(hp->qdcount) != 0 || ntohs(hp->nscount) != 0 || ntohs(hp->arcount) != 0) { ns_debug(ns_log_default, 1, "FORMERR IQuery header counts wrong"); hp->rcode = ns_r_formerr; return (Finish); } /* * Skip domain name, get class, and type. */ anptr = *cpp; n = dn_skipname(*cpp, eom); if (n < 0) { ns_debug(ns_log_default, 1, "FORMERR IQuery packet name problem"); hp->rcode = ns_r_formerr; return (Finish); } *cpp += n; if (*cpp + 3 * INT16SZ + INT32SZ > eom) { ns_debug(ns_log_default, 1, "FORMERR IQuery message too short"); hp->rcode = ns_r_formerr; return (Finish); } GETSHORT(type, *cpp); GETSHORT(class, *cpp); *cpp += INT32SZ; /* ttl */ GETSHORT(dlen, *cpp); if (*cpp + dlen != eom) { ns_debug(ns_log_default, 1, "FORMERR IQuery message length off"); hp->rcode = ns_r_formerr; return (Finish); } rdata_offset = *cpp - anptr; *cpp += dlen; INSIST(*cpp == eom); /* * Not all inverse queries are handled. */ if (type != ns_t_a) { ns_warning(ns_log_security, "unsupported iquery type from %s", inet_ntoa(from.sin_addr)); return (Refuse); } if (dlen != INT32SZ) { ns_warning(ns_log_security, "bad iquery from %s", inet_ntoa(from.sin_addr)); return (Refuse); } if (!NS_OPTION_P(OPTION_FAKE_IQUERY)) return (Refuse); ns_debug(ns_log_default, 1, "req: IQuery class %d type %d", class, type); alen = eom - anptr; if (alen > sizeof anbuf) { ns_warning(ns_log_security, "bad iquery from %s", inet_ntoa(from.sin_addr)); return (Refuse); } memcpy(anbuf, anptr, alen); *cpp = anptr; *buflenp -= HFIXEDSZ; #ifdef QRYLOG if (qrylog) { char tmp[sizeof "255.255.255.255"]; strcpy(tmp, inet_ntoa(from.sin_addr)); ns_info(ns_log_queries, "XX /%s/%s/-%s", tmp, inet_ntoa(ina_get(&anbuf[rdata_offset])), p_type(type)); } #endif /*QRYLOG*/ /* * We can only get here if the option "fake-iquery" is on in the boot * file. * * What we do here is send back a bogus response of "[dottedquad]". * A better strategy would be to turn this into a PTR query, but that * would legitimize inverse queries in a way they do not deserve. */ sprintf(dnbuf, "[%s]", inet_ntoa(ina_get(&anbuf[rdata_offset]))); *buflenp -= QFIXEDSZ; n = dn_comp(dnbuf, *cpp, *buflenp, NULL, NULL); if (n < 0) { hp->tc = 1; return (Finish); } *cpp += n; *buflenp -= n; PUTSHORT((u_int16_t)type, *cpp); *buflenp -= INT16SZ; PUTSHORT((u_int16_t)class, *cpp); *buflenp -= INT16SZ; hp->qdcount = htons(1); if ((int)alen > *buflenp) { hp->tc = 1; return (Finish); } memcpy(*cpp, anbuf, alen); *cpp += alen; *buflenp -= alen; return (Finish); } /* * Test a datum for validity and return non-zero if it is out of date. */ int stale(struct databuf *dp) { struct zoneinfo *zp = &zones[dp->d_zone]; #ifdef CHECK_MAGIC INSIST(dp->d_magic == DATABUF_MAGIC); #endif switch (zp->z_type) { case z_master: return (0); #ifdef STUBS case z_stub: /* root stub zones have DB_F_HINT set */ if (dp->d_flags & DB_F_HINT) return (0); /* FALLTROUGH */ #endif case z_slave: /* * Check to see whether a slave zone has expired or * time warped; if so clear authority flag for zone, * schedule the zone for immediate maintenance, and * return true. */ if ((int32_t)(tt.tv_sec - zp->z_lastupdate) > (int32_t)zp->z_expire) { ns_debug(ns_log_default, 1, "stale: slave zone %s expired", zp->z_origin); if (!haveComplained((u_long)zp, (u_long)stale)) { ns_notice(ns_log_default, "slave zone \"%s\" expired", zp->z_origin); } zp->z_flags &= ~Z_AUTH; if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0) { zp->z_time = tt.tv_sec; sched_zone_maint(zp); } return (1); } if (zp->z_lastupdate > tt.tv_sec) { if (!haveComplained((u_long)zp, (u_long)stale)) { ns_notice(ns_log_default, "slave zone \"%s\" time warp", zp->z_origin); } zp->z_flags &= ~Z_AUTH; if ((zp->z_flags & (Z_QSERIAL|Z_XFER_RUNNING)) == 0) { zp->z_time = tt.tv_sec; sched_zone_maint(zp); } return (1); } return (0); case z_hint: case z_cache: if (dp->d_flags & DB_F_HINT || dp->d_ttl >= (u_int32_t)tt.tv_sec) return (0); ns_debug(ns_log_default, 3, "stale: ttl %d %ld (x%lx)", dp->d_ttl, (long)(dp->d_ttl - tt.tv_sec), (u_long)dp->d_flags); return (1); default: /* FALLTHROUGH */ ; } panic("stale: impossible condition", NULL); /* NOTREACHED */ return (0); /* Make gcc happy. */ } /* * Copy databuf into a resource record for replies. * Return size of RR if OK, -1 if buffer is full. */ int make_rr(const char *name, struct databuf *dp, u_char *buf, int buflen, int doadd, u_char **comp_ptrs, u_char **edp, int use_minimum) { u_char *cp; u_char *cp1, *sp; struct zoneinfo *zp; int32_t n; int16_t type = dp->d_type; u_int32_t ttl; u_char naptr_flag; ns_debug(ns_log_default, 5, "make_rr(%s, %lx, %lx, %d, %d) %d zone %d ttl %lu", name, (u_long)dp, (u_long)buf, buflen, doadd, dp->d_size, dp->d_zone, (u_long)dp->d_ttl); if (dp->d_rcode && dp->d_size == 0) panic("make_rr: impossible d_rcode value", NULL); zp = &zones[dp->d_zone]; /* check for outdated RR before updating comp_ptrs[] by dn_comp() */ if (zp->z_type == Z_CACHE) { if ((dp->d_flags & DB_F_HINT) != 0 || dp->d_ttl < (u_int32_t)tt.tv_sec) { ttl = 0; } else ttl = dp->d_ttl - (u_int32_t) tt.tv_sec; } else { if (dp->d_ttl != USE_MINIMUM && !use_minimum) ttl = dp->d_ttl; else ttl = zp->z_minimum; /* really default */ } buflen -= RRFIXEDSZ; if (buflen < 0) return (-1); #ifdef RETURNSOA if (dp->d_rcode) { name = (char *)dp->d_data; name += strlen(name) +1; name += strlen(name) +1; name += 5 * INT32SZ; type = T_SOA; } #endif if ((n = dn_comp(name, buf, buflen, comp_ptrs, edp)) < 0) goto cleanup; cp = buf + n; buflen -= n; if (buflen < 0) goto cleanup; PUTSHORT((u_int16_t)type, cp); PUTSHORT((u_int16_t)dp->d_class, cp); PUTLONG(ttl, cp); sp = cp; cp += INT16SZ; switch (type) { case T_CNAME: case T_MG: case T_MR: case T_PTR: n = dn_comp((char *)dp->d_data, cp, buflen, comp_ptrs, edp); if (n < 0) goto cleanup; PUTSHORT((u_int16_t)n, sp); cp += n; break; case T_MB: case T_NS: /* Store domain name in answer */ n = dn_comp((char *)dp->d_data, cp, buflen, comp_ptrs, edp); if (n < 0) goto cleanup; PUTSHORT((u_int16_t)n, sp); cp += n; if (doadd) { addname((char*)dp->d_data, name, type, T_A, dp->d_class); addname(name, name, type, T_KEY, dp->d_class); } break; case T_SOA: case T_MINFO: case T_RP: cp1 = dp->d_data; n = dn_comp((char *)cp1, cp, buflen, comp_ptrs, edp); if (n < 0) goto cleanup; cp += n; buflen -= type == T_SOA ? n + 5 * INT32SZ : n; if (buflen < 0) goto cleanup; cp1 += strlen((char *)cp1) + 1; n = dn_comp((char *)cp1, cp, buflen, comp_ptrs, edp); if (n < 0) goto cleanup; cp += n; if (type == T_SOA) { cp1 += strlen((char *)cp1) + 1; #ifdef BIND_UPDATE if (zp->z_flags & Z_NEED_SOAUPDATE) if (incr_serial(zp) < 0) ns_error(ns_log_default, "error updating serial number for %s from %d", zp->z_origin, zp->z_serial); #endif n = 5 * INT32SZ; memcpy(cp, cp1, n); cp += n; if (doadd) addname(name, name, type, T_KEY, dp->d_class); } n = (u_int16_t)((cp - sp) - INT16SZ); PUTSHORT((u_int16_t)n, sp); break; case T_NAPTR: /* cp1 == our data/ cp == data of RR */ cp1 = dp->d_data; /* copy order */ buflen -= INT16SZ; if (buflen < 0) goto cleanup; memcpy(cp, cp1, INT16SZ); cp += INT16SZ; cp1 += INT16SZ; n = (u_int16_t)((cp - sp) - INT16SZ); ns_debug(ns_log_default, 1, "current size n = %u", n); /* copy preference */ buflen -= INT16SZ; if (buflen < 0) goto cleanup; memcpy(cp, cp1, INT16SZ); cp += INT16SZ; cp1 += INT16SZ; n = (u_int16_t)((cp - sp) - INT16SZ); ns_debug(ns_log_default, 1, "current size n = %u", n); /* Flags */ n = *cp1++; ns_debug(ns_log_default, 1, "size of n at flags = %d", n); buflen -= n + 1; if (buflen < 0) goto cleanup; naptr_flag = (n == 1) ? *cp1 : 0; *cp++ = n; memcpy(cp, cp1, n); cp += n; cp1 += n; n = (u_int16_t)((cp - sp) - INT16SZ); ns_debug(ns_log_default, 1, "current size n = %u", n); /* Service */ n = *cp1++; buflen -= n + 1; if (buflen < 0) goto cleanup; *cp++ = n; memcpy(cp, cp1, n); cp += n; cp1 += n; n = (u_int16_t)((cp - sp) - INT16SZ); ns_debug(ns_log_default, 1, "current size n = %u", n); /* Regexp */ n = *cp1++; buflen -= n + 1; if (buflen < 0) goto cleanup; *cp++ = n; memcpy(cp, cp1, n); cp += n; cp1 += n; n = (u_int16_t)((cp - sp) - INT16SZ); ns_debug(ns_log_default, 1, "current size n = %u", n); /* Replacement */ ns_debug(ns_log_default, 1, "Replacement = %s", cp1); n = dn_comp((char *)cp1, cp, buflen, NULL, NULL); ns_debug(ns_log_default, 1, "dn_comp's n = %u", n); if (n < 0) goto cleanup; cp += n; if (doadd && *cp1 != 0) { if (naptr_flag == 's' || naptr_flag == 'S') addname((char*)cp1, name, type, T_SRV, dp->d_class); if (naptr_flag == 'a' || naptr_flag == 'A') addname((char*)cp1, name, type, T_A, dp->d_class); } /* save data length */ n = (u_int16_t)((cp - sp) - INT16SZ); ns_debug(ns_log_default, 1, "saved size n = %u", n); PUTSHORT((u_int16_t)n, sp); break; case T_MX: case T_AFSDB: case T_RT: case T_SRV: /* cp1 == our data/ cp == data of RR */ cp1 = dp->d_data; if ((buflen -= INT16SZ) < 0) goto cleanup; /* copy preference */ memcpy(cp, cp1, INT16SZ); cp += INT16SZ; cp1 += INT16SZ; if (type == T_SRV) { buflen -= INT16SZ*2; if (buflen < 0) goto cleanup; memcpy(cp, cp1, INT16SZ*2); cp += INT16SZ*2; cp1 += INT16SZ*2; } n = dn_comp((char *)cp1, cp, buflen, (type == ns_t_mx) ? comp_ptrs : NULL, (type == ns_t_mx) ? edp : NULL); if (n < 0) goto cleanup; cp += n; /* save data length */ n = (u_int16_t)((cp - sp) - INT16SZ); PUTSHORT((u_int16_t)n, sp); if (doadd) addname((char*)cp1, name, type, T_A, dp->d_class); break; case T_PX: cp1 = dp->d_data; if ((buflen -= INT16SZ) < 0) goto cleanup; /* copy preference */ memcpy(cp, cp1, INT16SZ); cp += INT16SZ; cp1 += INT16SZ; n = dn_comp((char *)cp1, cp, buflen, comp_ptrs, edp); if (n < 0) goto cleanup; cp += n; buflen -= n; cp1 += strlen((char *)cp1) + 1; n = dn_comp((char *)cp1, cp, buflen, comp_ptrs, edp); if (n < 0) goto cleanup; cp += n; /* save data length */ n = (u_int16_t)((cp - sp) - INT16SZ); PUTSHORT((u_int16_t)n, sp); break; case T_SIG: /* cp1 == our data; cp == data of target RR */ cp1 = dp->d_data; /* first just copy over the type_covered, algorithm, */ /* labels, orig ttl, two timestamps, and the footprint */ if (buflen < 18) goto cleanup; /* out of room! */ memcpy(cp, cp1, 18); cp += 18; cp1 += 18; buflen -= 18; /* then the signer's name */ n = dn_comp((char *)cp1, cp, buflen, NULL, NULL); if (n < 0) goto cleanup; cp += n; buflen -= n; cp1 += strlen((char*)cp1)+1; /* finally, we copy over the variable-length signature */ n = dp->d_size - (u_int16_t)((cp1 - dp->d_data)); if (n > buflen) goto cleanup; /* out of room! */ memcpy(cp, cp1, n); cp += n; /* save data length & return */ n = (u_int16_t)((cp - sp) - INT16SZ); PUTSHORT((u_int16_t)n, sp); break; case T_NXT: cp1 = dp->d_data; n = dn_comp((char *)cp1, cp, buflen, NULL, NULL); if (n < 0) goto cleanup; cp += n; buflen -=n; cp1 += strlen((char *)cp1) + 1; /* copy nxt bit map */ n = dp->d_size - (u_int16_t)((cp1 - dp->d_data)); if (n > buflen) goto cleanup; /* out of room! */ memcpy(cp, cp1, n); cp += n; buflen -= n; n = (u_int16_t)((cp - sp) - INT16SZ); PUTSHORT((u_int16_t)n, sp); break; default: if ((type == T_A || type == T_AAAA) && doadd) addname(name, name, type, T_KEY, dp->d_class); if (dp->d_size > buflen) goto cleanup; memcpy(cp, dp->d_data, dp->d_size); PUTSHORT((u_int16_t)dp->d_size, sp); cp += dp->d_size; } return (cp - buf); cleanup: /* Rollback RR. */ ns_name_rollback(buf, (const u_char **)comp_ptrs, (const u_char **)edp); return (-1); } static void addname(const char *dname, const char *rname, u_int16_t rtype, u_int16_t type, u_int16_t class) { struct addinfo *ap; int n; for (ap = addinfo, n = addcount; --n >= 0; ap++) if (ns_samename(ap->a_dname, dname) == 1 && ap->a_type == type) return; /* add domain name to additional section */ if (addcount < NADDRECS) { addcount++; ap->a_dname = savestr(dname, 1); ap->a_rname = savestr(rname, 1); ap->a_rtype = rtype; ap->a_type = type; ap->a_class = class; } } /* * Lookup addresses/keys for names in addinfo and put into the message's * additional section. */ int doaddinfo(HEADER *hp, u_char *msg, int msglen) { register struct namebuf *np; register struct databuf *dp; register struct addinfo *ap; register u_char *cp; struct hashbuf *htp; const char *fname; register int n, count; register int ns_logging; int pass = 0; int i, doadd; if (!addcount) return (0); ns_logging = ns_wouldlog(ns_log_default, 3); if (ns_logging) ns_debug(ns_log_default, 3, "doaddinfo() addcount = %d", addcount); if (hp->tc) { ns_debug(ns_log_default, 4, "doaddinfo(): tc already set, bailing"); return (0); } count = 0; cp = msg; loop: for (ap = addinfo, i = 0; i < addcount; ap++, i++) { int auth = 0, founda = 0, foundaaaa = 0, founda6 = 0, foundcname = 0, save_count = count, save_msglen = msglen; u_char *save_cp = cp; if ((pass != 0 && (pass != 1 || server_options->preferred_glue == 0) && ap->a_type == T_A) || (pass != 0 && ap->a_type == T_SRV) || (pass != 2 && ap->a_type == T_KEY)) continue; if (ns_logging) ns_debug(ns_log_default, 3, "do additional \"%s\" (from \"%s\")", ap->a_dname, ap->a_rname); htp = hashtab; /* because "nlookup" stomps on arg. */ np = nlookup(ap->a_dname, &htp, &fname, 0); if (np == NULL || fname != ap->a_dname) goto next_rr; if (ns_logging) ns_debug(ns_log_default, 3, "found it"); /* look for the data */ (void)delete_stale(np); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_class != ap->a_class) continue; if (dp->d_rcode == NXDOMAIN) { founda = founda6 = foundaaaa = 1; continue; } switch (dp->d_type) { case ns_t_a: founda = 1; break; case ns_t_a6: founda6 = 1; break; case ns_t_aaaa: foundaaaa = 1; break; } if (!dp->d_rcode && dp->d_type == T_CNAME) { foundcname++; break; } if (auth == 0 && ap->a_type == T_A && (dp->d_type == ns_t_a || dp->d_type == ns_t_a6 || dp->d_type == ns_t_aaaa) && (zones[dp->d_zone].z_type == z_master || zones[dp->d_zone].z_type == z_slave)) auth = 1; if (pass == 0 && ap->a_type == T_A && server_options->preferred_glue != 0 && !match(dp, (int)ap->a_class, server_options->preferred_glue)) { continue; } if (pass != 0 && ap->a_type == T_A && server_options->preferred_glue != 0 && match(dp, (int)ap->a_class, server_options->preferred_glue)) { continue; } if (ap->a_type == T_A && !match(dp, (int)ap->a_class, T_A) && !match(dp, (int)ap->a_class, T_AAAA) && !match(dp, (int)ap->a_class, ns_t_a6)) { continue; } if (ap->a_type == T_KEY && !match(dp, (int)ap->a_class, T_KEY)) continue; if (ap->a_type == T_SRV && !match(dp, (int)ap->a_class, T_SRV)) continue; if (dp->d_rcode) continue; /* * Should be smart and eliminate duplicate * data here. XXX */ doadd = 0; if (ap->a_type == T_SRV) doadd = 1; if ((n = make_rr(ap->a_dname, dp, cp, msglen, doadd, dnptrs, dnptrs_end, 0)) < 0) { /* truncation in the additional-data section * is not all that serious. we do not set TC, * since the answer and authority sections are * OK; however, since we're not setting TC we * have to make sure that none of the RR's for * this name go out (!TC implies that all * {name,type} appearances are complete -- and * since we only do A RR's here, the name is * the key). vixie, 23apr93 */ ns_debug(ns_log_default, 5, "addinfo: not enough room, remaining msglen = %d", save_msglen); /* Rollback RRset. */ ns_name_rollback(save_cp, (const u_char **)dnptrs, (const u_char **)dnptrs_end); cp = save_cp; msglen = save_msglen; count = save_count; break; } ns_debug(ns_log_default, 5, "addinfo: adding address data n = %d", n); cp += n; msglen -= n; count++; } next_rr: if (!NS_OPTION_P(OPTION_NOFETCHGLUE) && !foundcname && ap->a_type == T_A) { /* ask a real server for this info */ if (!founda && !auth) (void) sysquery(ap->a_dname, (int)ap->a_class, ns_t_a, NULL, NULL, 0, ns_port, QUERY, 0); if (!foundaaaa && !auth) (void) sysquery(ap->a_dname, (int)ap->a_class, ns_t_aaaa, NULL, NULL, 0, ns_port, QUERY, 0); if (!founda6 && !auth) (void) sysquery(ap->a_dname, (int)ap->a_class, ns_t_a6, NULL, NULL, 0, ns_port, QUERY, 0); } if (foundcname) { if (!haveComplained(nhash(ap->a_dname), nhash(ap->a_rname))) { ns_info(ns_log_cname, "\"%s %s %s\" points to a CNAME (%s)", ap->a_rname, p_class(ap->a_class), p_type(ap->a_rtype), ap->a_dname); } } } if (pass++ < 2) goto loop; /* now do the KEYs... */ hp->arcount = htons((u_int16_t)count); for (ap = addinfo, i = 0; i < addcount; ap++, i++) { ap->a_dname = freestr(ap->a_dname); ap->a_rname = freestr(ap->a_rname); } addcount = 0; return (cp - msg); } int doaddauth(HEADER *hp, u_char *cp, int buflen, struct namebuf *np, struct databuf *dp) { char dnbuf[MAXDNAME]; int n; getname(np, dnbuf, sizeof dnbuf); if (stale(dp)) { ns_debug(ns_log_default, 1, "doaddauth: can't add stale '%s' (%d)", dnbuf, buflen); return (0); } n = make_rr(dnbuf, dp, cp, buflen, 1, dnptrs, dnptrs_end, 1); if (n <= 0) { ns_debug(ns_log_default, 1, "doaddauth: can't add oversize '%s' (%d) (n=%d)", dnbuf, buflen, n); if (n < 0) { hp->tc = 1; } return (0); } if (dp->d_secure != DB_S_SECURE) hp->ad = 0; hp->nscount = htons(ntohs(hp->nscount) + 1); return (n); } void free_addinfo() { struct addinfo *ap; for (ap = addinfo; --addcount >= 0; ap++) { ap->a_dname = freestr(ap->a_dname); ap->a_rname = freestr(ap->a_rname); } addcount = 0; } void free_nsp(struct databuf **nsp) { while (*nsp) db_detach(nsp++); } static void copyCharString(u_char **dst, const char *src) { size_t len = strlen(src) & 0xff; *(*dst)++ = (u_char) len; memcpy(*dst, src, len); *dst += len; } /* * Questionable source ports for queries / responses. */ int drop_port(u_int16_t port) { switch (port) { case 7: /* echo */ case 13: /* daytime */ case 19: /* chargen */ case 37: /* time */ return (1); case 464: /* kpasswd */ return (2); } return (0); } Index: vendor/bind/dist/contrib/bind/bin/named/ns_resp.c =================================================================== --- vendor/bind/dist/contrib/bind/bin/named/ns_resp.c (revision 109982) +++ vendor/bind/dist/contrib/bind/bin/named/ns_resp.c (revision 109983) @@ -1,4136 +1,4136 @@ #if !defined(lint) && !defined(SABER) static const char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91"; -static const char rcsid[] = "$Id: ns_resp.c,v 8.178 2002/06/27 03:09:19 marka Exp $"; +static const char rcsid[] = "$Id: ns_resp.c,v 8.178.2.2 2002/11/14 13:39:13 marka Exp $"; #endif /* not lint */ /* * Copyright (c) 1986, 1988, 1990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University 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 REGENTS 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. */ /* * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ /* * Portions Copyright (c) 1996-2000 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #include "port_before.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "port_after.h" #include "named.h" static u_int8_t norootlogged[MAXCLASS]; /* XXX- should be a bitmap */ static const char skipnameFailedAnswer[] = "skipname failed in answer", skipnameFailedAuth[] = "skipname failed in authority", skipnameFailedQuery[] = "skipname failed in query", outofDataQuery[] = "ran out of data in query", outofDataAnswer[] = "ran out of data in answer", notSingleQuery[] = "not exactly one query", expandFailedQuery[] = "dn_expand failed in query", expandFailedAnswer[] = "dn_expand failed in answer", expandFailedAuth[] = "dn_expand failed in authority", outofDataAuth[] = "ran out of data in authority", dlenOverrunAnswer[] = "dlen overrun in answer", dlenOverrunAuth[] = "dlen overrun in authority", dlenUnderrunAnswer[] = "dlen underrun in answer", outofDataFinal[] = "out of data in final pass", outofDataAFinal[] = "out of data after final pass", badNameFound[] = "found an invalid domain name", wrongQuestion[] = "answer to wrong question", danglingCname[] = "dangling CNAME pointer", nonRecursiveForwarder[]= "non-recursive forwarder"; struct db_list { struct db_list *db_next; struct databuf *db_dp; }; struct flush_set { char * fs_name; int fs_type; int fs_class; u_int fs_cred; struct db_list *fs_list; struct db_list *fs_last; }; static void rrsetadd(struct flush_set *, const char *, struct databuf *), rrsetupdate(struct flush_set *, int flags, struct sockaddr_in, int), flushrrset(struct flush_set *, struct sockaddr_in), free_flushset(struct flush_set *, int), check_hints(struct flush_set *); static int rrsetcmp(char *, struct db_list *, struct hashbuf *), check_root(void), check_ns(void), wanted(const struct databuf *, int, int), wantedsig(const struct databuf *, int, int), rrextract(u_char *, int, u_char *, struct databuf **, char *, int, struct sockaddr_in, char **); static void mark_bad(struct qinfo *qp, struct sockaddr_in from); static void mark_lame(struct qinfo *qp, struct sockaddr_in from); static int mark_noedns(struct qinfo *qp, struct sockaddr_in from, int cache); static void fast_retry(struct qinfo *qp, struct sockaddr_in from, int samehost); static void add_related_additional(char *); static void free_related_additional(void); static int related_additional(char *); static void freestr_maybe(char **); static enum ordering match_order(const struct namebuf *, int, int); static int match_name(const struct namebuf *, const char *, size_t); #define MAX_RELATED 100 static int num_related = 0; static char *related[MAX_RELATED]; static char * learntFrom(struct qinfo *qp, struct sockaddr_in *server) { static char *buf = NULL; const char *a, *ns, *na; struct databuf *db; int i; char nsbuf[20]; char abuf[20]; static const char fmt[] = " '%s': learnt (A=%s,NS=%s)"; a = ns = na = ""; for (i = 0; (u_int)i < qp->q_naddr; i++) { if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, server->sin_addr)) { db = qp->q_addr[i].ns; if (db != NULL) { if (db->d_addr.s_addr != htonl(0)) { strcpy(nsbuf, inet_ntoa(db->d_addr)); ns = nsbuf; } else { ns = zones[db->d_zone].z_origin; } if (db->d_rcode == 0) na = (char*)qp->q_addr[i].ns->d_data; } db = qp->q_addr[i].nsdata; if (db != NULL) { if (db->d_addr.s_addr != htonl(0)) { strcpy(abuf, inet_ntoa(db->d_addr)); a = abuf; } else { a = zones[db->d_zone].z_origin; } } break; } } if (a == ns && ns == na) /* all "UNKNOWN" */ return (NULL); if (*a == '\0') a = "\".\""; if (*ns == '\0') ns = "\".\""; if (*na == '\0') na = "\".\""; buf = newstr(sizeof fmt + strlen(na) + strlen(a) + strlen(ns), 0); if (buf == NULL) return (NULL); sprintf(buf, fmt, na, a, ns); return (buf); } void ns_resp(u_char *msg, int msglen, struct sockaddr_in from, struct qstream *qsp) { struct qinfo *qp; HEADER *hp; struct qserv *qs = NULL; struct databuf *ns, *ns2; u_char *cp, *answers, *eom = msg + msglen; struct flush_set *flushset = NULL; int flushset_size = 0; struct sockaddr_in *nsa; struct databuf *nsp[NSMAX]; int i, c, n, qdcount, ancount, aucount, nscount, arcount, arfirst; int soacount; u_int qtype, qclass; int restart; /* flag for processing cname response */ int validanswer, dbflags; int cname, lastwascname, externalcname; int count, founddata, foundname; int buflen; int newmsglen; char name[MAXDNAME], qname[MAXDNAME], aname[MAXDNAME]; char msgbuf[MAXDNAME+100]; char *dname, tmpdomain[MAXDNAME]; const char *fname; const char *formerrmsg = "brain damage"; u_char newmsg[EDNS_MESSAGE_SZ]; u_char **dpp, *tp; time_t rtrip; struct hashbuf *htp; struct namebuf *np; struct fwdinfo *fwd; struct databuf *dp; char *tname = NULL; int sendto_errno = 0; int has_tsig, oldqlen = 0; u_char *oldqbuf = NULL; u_char *smsg = NULL; int smsglen, smsgsize = 0, siglen; u_char sig[TSIG_SIG_SIZE]; time_t tsig_time; DST_KEY *key; int expect_cname; nameserIncr(from.sin_addr, nssRcvdR); nsp[0] = NULL; hp = (HEADER *) msg; if ((qp = qfindid(hp->id)) == NULL ) { ns_debug(ns_log_default, 1, "DUP? dropped (id %d)", ntohs(hp->id)); nameserIncr(from.sin_addr, nssRcvdDupR); return; } if (ns_wouldlog(ns_log_default, 2)) { ns_debug(ns_log_default, 2, "Response (%s %s %s) nsid=%d id=%d", (qp->q_flags & Q_SYSTEM) ?"SYSTEM" :"USER", (qp->q_flags & Q_PRIMING) ?"PRIMING" :"NORMAL", (qp->q_flags & Q_ZSERIAL) ?"ZSERIAL" :"-", ntohs(qp->q_nsid), ntohs(qp->q_id)); } if (qp->q_nstsig == NULL) has_tsig = 0; else { int ret; ret = ns_verify(msg, &msglen, qp->q_nstsig->key, qp->q_nstsig->sig, qp->q_nstsig->siglen, NULL, NULL, &tsig_time, 0); if (ret == 0) has_tsig = 1; else { if (hp->rcode == NOERROR) hp->rcode = NOTAUTH; ns_debug(ns_log_default, 1, "resp: error bad tsig, record dropped"); return; } } /* * Here we handle high level formatting problems by parsing the header. */ qdcount = ntohs(hp->qdcount); ancount = ntohs(hp->ancount); aucount = ntohs(hp->nscount); arcount = ntohs(hp->arcount); free_addinfo(); /* sets addcount to zero */ cp = msg + HFIXEDSZ; dpp = dnptrs; *dpp++ = msg; if ((*cp & INDIR_MASK) == 0) *dpp++ = cp; *dpp = NULL; if (qdcount == 1) { n = dn_expand(msg, eom, cp, qname, sizeof(qname)); if (n <= 0) { formerrmsg = expandFailedQuery; goto formerr; } cp += n; if (cp + 2 * INT16SZ > eom) { formerrmsg = outofDataQuery; goto formerr; } GETSHORT(qtype, cp); GETSHORT(qclass, cp); if (!ns_nameok(qp, qname, qclass, NULL, response_trans, ns_ownercontext(qtype, response_trans), qname, from.sin_addr)) { formerrmsg = badNameFound; goto refused; } if (cp > eom) { formerrmsg = outofDataQuery; goto formerr; } if (qp->q_msg && qp->q_msglen && !res_nameinquery(qname, qtype, qclass, qp->q_msg, qp->q_msg + qp->q_msglen)) { sprintf(msgbuf, "query section mismatch (%s %s %s)", qname, p_class(qclass), p_type(qtype)); formerrmsg = msgbuf; goto formerr; } if (ns_samename(qp->q_name, qname) != 1 || qp->q_class != qclass || qp->q_type != qtype) { formerrmsg = wrongQuestion; goto formerr; } } else { strcpy(qname, qp->q_name); qclass = qp->q_class; qtype = qp->q_type; } /* cp now points after the query section. */ /* * Here we handle bad responses from servers. * Several possibilities come to mind: * The server is sick and returns SERVFAIL * The server returns some garbage opcode (it's sick) * The server can't understand our query and return FORMERR * In all these cases, we drop the packet, disable retries on * this server and immediately force a retry. */ if ((hp->rcode != NOERROR && hp->rcode != NXDOMAIN) || (hp->opcode != QUERY #ifdef BIND_NOTIFY && hp->opcode != NS_NOTIFY_OP #endif )) { int noedns = 1; ns_debug(ns_log_default, 2, "resp: error (ret %d, op %d), dropped", hp->rcode, hp->opcode); switch (hp->rcode) { case SERVFAIL: nameserIncr(from.sin_addr, nssRcvdFail); noedns = mark_noedns(qp, from, 0); break; case FORMERR: nameserIncr(from.sin_addr, nssRcvdFErr); noedns = mark_noedns(qp, from, 1); break; case NOTIMP: nameserIncr(from.sin_addr, nssRcvdErr); noedns = mark_noedns(qp, from, 1); break; default: nameserIncr(from.sin_addr, nssRcvdErr); break; } if (ns_samename(qp->q_name, qp->q_domain) == 1 && hp->rcode == SERVFAIL && hp->opcode == QUERY && noedns) mark_lame(qp, from); if (noedns) mark_bad(qp, from); fast_retry(qp, from, noedns ? 0 : 1); return; } if (qdcount != 1) { /* We don't generate or forward these (yet). */ formerrmsg = notSingleQuery; goto formerr; } /* * Determine if the response came from a forwarder. Packets from * anyplace not listed as a forwarder or as a server to whom we * might have forwarded the query will be dropped. * XXX - should put this in STATS somewhere. */ for (fwd = NS_ZFWDTAB(qp->q_fzone); fwd; fwd = fwd->next) if (ina_equal(fwd->fwddata->fwdaddr.sin_addr, from.sin_addr)) break; /* * find the qinfo pointer and update * the rtt and fact that we have called on this server before. */ { struct timeval *stp; for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++) if (ina_equal(qs->ns_addr.sin_addr, from.sin_addr)) break; if ((u_int)n >= qp->q_naddr) { if (!haveComplained(ina_ulong(from.sin_addr), (u_long)"unexpected source")) { ns_info(ns_log_default, "Response from unexpected source (%s) for query \"%s %s %s\"", sin_ntoa(from), *(qp->q_name) ? qp->q_name : ".", p_class(qp->q_class), p_type(qp->q_type)); } /* * We don't know who this response came from so it * gets dropped on the floor. */ return; } stp = &qs->stime; /* Handle response from different (untried) interface. */ if (qs->ns != NULL && stp->tv_sec == 0) { ns = qs->ns; while (qs > qp->q_addr && (qs->stime.tv_sec == 0 || qs->ns != ns)) qs--; *stp = qs->stime; /* XXX - sometimes stp still ends up pointing to * a zero timeval, in spite of the above attempt. * Why? What should we do about it? */ /* XXX - catch aliases here */ } /* compute query round trip time */ /* XXX - avoid integer overflow, which is quite likely if stp * points to a zero timeval (see above). * rtrip is of type time_t, which we assume is at least * as big as an int. */ if ((tt.tv_sec - stp->tv_sec) > (INT_MAX-999)/1000) { rtrip = INT_MAX; } else { rtrip = ((tt.tv_sec - stp->tv_sec) * 1000 + (tt.tv_usec - stp->tv_usec) / 1000); } if (ns_wouldlog(ns_log_default, 3)) { ns_debug(ns_log_default, 3, "stime %lu/%lu now %lu/%lu rtt %ld", (u_long)stp->tv_sec, (u_long)stp->tv_usec, (u_long)tt.tv_sec, (u_long)tt.tv_usec, (long)rtrip); } /* prevent floating point overflow, limit to 1000 sec */ if (rtrip > 1000000) { rtrip = 1000000; } ns = qs->nsdata; /* * Don't update nstime if this doesn't look * like an address databuf now. XXX */ if (ns && ns->d_type == T_A && ns->d_class == qs->ns->d_class) { u_long t; if (ns->d_nstime == 0) t = rtrip; else t = ns->d_nstime * ALPHA + (1 - ALPHA) * rtrip; if (t > 65535) t = 65535; else if (t == 0) t = 1; ns->d_nstime = (u_int16_t)t; } /* * Record the source so that we do not use this NS again. */ if (ns && qs->ns && (qp->q_nusedns < NSMAX)) { qp->q_usedns[qp->q_nusedns++] = qs->ns; if (ns_wouldlog(ns_log_default, 2)) { ns_debug(ns_log_default, 2, "NS #%d addr %s used, rtt %d", n, sin_ntoa(qs->ns_addr), ns->d_nstime); } } /* * Penalize those who had earlier chances but failed * by multiplying round-trip times by BETA (>1). * Improve nstime for unused addresses by applying GAMMA. * The GAMMA factor makes unused entries slowly * improve, so they eventually get tried again. * GAMMA should be slightly less than 1. * Watch out for records that may have timed out * and are no longer the correct type. XXX */ for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++) { u_long t; ns2 = qs->nsdata; if (!ns2 || ns2 == ns) continue; if (ns2->d_type != T_A || ns2->d_class != qs->ns->d_class) /* XXX */ continue; if (qs->stime.tv_sec) { if (ns2->d_nstime == 0) t = (rtrip * BETA) + 1; else t = ns2->d_nstime * BETA + (1 - ALPHA) * rtrip + 1; } else t = ns2->d_nstime * GAMMA; if (t > 65535) t = 65535; else if (t == 0) t = 1; ns2->d_nstime = (u_int16_t)t; if (ns_wouldlog(ns_log_default, 2)) { ns_debug(ns_log_default, 2, "NS #%d %s rtt now %d", n, sin_ntoa(qs->ns_addr), ns2->d_nstime); } } } #ifdef BIND_NOTIFY /* * For now, NOTIFY isn't defined for ANCOUNT!=0, AUCOUNT!=0, * or ADCOUNT!=0. Therefore the only real work to be done for * a NOTIFY-QR is to remove it from the query queue. */ if (hp->opcode == NS_NOTIFY_OP) { ns_info(ns_log_notify, "Received NOTIFY answer (%sAA) from %s for \"%s %s %s\"", hp->aa ? "" : "!", inet_ntoa(from.sin_addr), *(qp->q_name) ? qp->q_name : ".", p_class(qp->q_class), p_type(qp->q_type)); qremove(qp); return; } #endif if ((qp->q_flags & Q_ZSERIAL) != 0) { if (hp->aa && ancount > 0 && hp->rcode == NOERROR && qtype == T_SOA && (qclass == C_IN || qclass == C_HS)) { int n; u_int type, class, dlen; u_int32_t serial; u_char *tp = cp; u_char *rdatap; n = dn_expand(msg, eom, tp, name, sizeof name); if (n < 0) { formerrmsg = expandFailedAnswer; goto formerr; } tp += n; /* name */ if (tp + 3 * INT16SZ + INT32SZ > eom) { formerrmsg = outofDataAnswer; goto formerr; } GETSHORT(type, tp); /* type */ GETSHORT(class, tp); /* class */ tp += INT32SZ; /* ttl */ GETSHORT(dlen, tp); /* dlen */ rdatap = tp; /* start of rdata */ if (!ns_nameok(qp, name, class, NULL, response_trans, ns_ownercontext(type, response_trans), name, from.sin_addr)) { formerrmsg = badNameFound; goto refused; } if (ns_samename(qname, name) != 1 || qtype != type || qclass != class) { sprintf(msgbuf, "qserial answer mismatch (%s %s %s)", name, p_class(class), p_type(type)); formerrmsg = msgbuf; goto formerr; } if (0 >= (n = dn_skipname(tp, eom))) { formerrmsg = skipnameFailedAnswer; goto formerr; } tp += n; /* mname */ if (0 >= (n = dn_skipname(tp, eom))) { formerrmsg = skipnameFailedAnswer; goto formerr; } tp += n; /* rname */ if (tp + 5 * INT32SZ > eom) { formerrmsg = dlenUnderrunAnswer; goto formerr; } GETLONG(serial, tp); tp += 4 * INT32SZ; /* Skip rest of SOA. */ if ((u_int)(tp - rdatap) != dlen) { formerrmsg = dlenOverrunAnswer; goto formerr; } for (n = 0, qs = qp->q_addr; (u_int)n < qp->q_naddr; n++, qs++) if (ina_equal(qs->ns_addr.sin_addr, from.sin_addr)) break; if (n == qp->q_naddr) { qserial_answer(qp); qremove(qp); return; } qs->serial = serial; } retry(qp, 0); return; } /* * Non-authoritative, no answer, no error, with referral. */ if (hp->rcode == NOERROR && !hp->tc && !hp->aa && ancount == 0 && aucount > 0 #ifdef BIND_NOTIFY && hp->opcode != NS_NOTIFY_OP #endif ) { u_char *tp; int type, class = 0, dlen; int foundns, foundsoa; #ifdef DEBUG if (debug > 0) res_pquery(&res, msg, msglen, log_get_stream(packet_channel)); #endif /* * Since there is no answer section (ancount == 0), * we must be pointing at the authority section (aucount > 0). */ tp = cp; foundns = foundsoa = 0; for (i = 0 ; i < aucount ; i++) { n = dn_expand(msg, eom, tp, name, sizeof name); if (n < 0) { formerrmsg = expandFailedAuth; goto formerr; } tp += n; if (tp + 3 * INT16SZ + INT32SZ > eom) { formerrmsg = outofDataAuth; goto formerr; } GETSHORT(type, tp); GETSHORT(class, tp); tp += INT32SZ; /* ttl */ GETSHORT(dlen, tp); if (!ns_nameok(qp, name, class, NULL, response_trans, ns_ownercontext(type, response_trans), name, from.sin_addr)) { formerrmsg = badNameFound; goto refused; } /* skip rest of record */ if (tp + dlen > eom) { formerrmsg = outofDataAuth; goto formerr; } tp += dlen; if (type == T_NS) { strcpy(aname, name); foundns = 1; } if (type == T_SOA) foundsoa = 1; } /* * If the answer delegates us either to the same level in * the hierarchy or closer to the root, we consider this * server lame. Note that for now we only log the message * if the T_NS was C_IN, which is technically wrong (NS is * visible in all classes) but necessary anyway (non-IN * classes tend to not have good strong delegation graphs). */ if (foundns && !foundsoa && ns_samedomain(qp->q_domain, aname)) { if (fwd == NULL) { nameserIncr(from.sin_addr, nssRcvdLDel); mark_lame(qp, from); } mark_bad(qp, from); if (class == C_IN && fwd == NULL && !haveComplained(ina_ulong(from.sin_addr), nhash(qp->q_domain))) { char *learnt_from = learntFrom(qp, &from); ns_info(ns_log_lame_servers, "Lame server on '%s' (in '%s'?): %s%s", qname, qp->q_domain, sin_ntoa(from), (learnt_from == NULL) ? "" : learnt_from); if (learnt_from != NULL) learnt_from = freestr(learnt_from); } else if (fwd != NULL) { if (!haveComplained(ina_ulong(from.sin_addr), (u_long)nonRecursiveForwarder)) ns_warning(ns_log_default, "%s: %s", nonRecursiveForwarder, sin_ntoa(from)); } fast_retry(qp, from, 0); return; } } /* * Add the info received in the response to the data base. */ arfirst = ancount + aucount; c = arfirst + arcount; /* Don't return if it's a TSIG signed truncated message */ if (has_tsig > 0 && hp->tc) goto tcp_retry; /* -ve $ing non-existence of record, must handle non-authoritative * NOERRORs with c == 0. */ if (!hp->aa && !hp->tc && hp->rcode == NOERROR && c == 0) goto return_msg; if (qp->q_flags & Q_SYSTEM) dbflags = DB_NOTAUTH | DB_NODATA; else dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS; count = c; if (qp->q_flags & Q_PRIMING) dbflags |= DB_PRIMING; if (hp->tc) { count -= arcount; /* truncation had to affect this */ if (!arcount) { count -= aucount; /* guess it got this too */ } if (!(arcount || aucount)) { count -= ancount; /* things are pretty grim */ } tcp_retry: /* retry using tcp provided this was not a tcp query */ if (!(qp->q_flags & Q_USEVC)) { qp->q_flags |= Q_USEVC; unsched(qp); schedretry(qp, 60); nsa = Q_NEXTADDR(qp, 0); key = qp->q_keys[0]; if (key != NULL) key = qp->q_keys[0] = tsig_key_from_addr(nsa->sin_addr); if (key != NULL) { smsgsize = qp->q_msglen + TSIG_BUF_SIZE; smsg = memget(smsgsize); smsglen = qp->q_msglen; siglen = sizeof(sig); memcpy(smsg, qp->q_msg, qp->q_msglen); n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0, sig, &siglen, 0); if (n == 0) { oldqbuf = qp->q_msg; oldqlen = qp->q_msglen; qp->q_msglen = smsglen; qp->q_msg = smsg; has_tsig = 1; free_tsig(qp->q_nstsig); qp->q_nstsig = new_tsig(key, sig, siglen); } else { has_tsig = 0; free_tsig(qp->q_nstsig); qp->q_nstsig = NULL; INSIST(0); } } else { has_tsig = 0; free_tsig(qp->q_nstsig); qp->q_nstsig = NULL; } if (tcp_send(qp) != NOERROR) /* * We're probably in trouble if tcp_send * failed, but we'll try to press on because * there isn't anything else to do. */ retry(qp, 0); if (has_tsig == 1) { memput(qp->q_msg, smsgsize); qp->q_msg = oldqbuf; qp->q_msglen = oldqlen; } return; } else if (!qsp) { /* outstanding udp response */ return; } /* XXX truncated tcp response */ ns_error(ns_log_default, "ns_resp: TCP truncated: \"%s\" %s %s from %s", qname, p_class(qclass), p_type(qtype), sin_ntoa(from)); /* mark this server as bad */ mark_bad(qp, from); /* try another server, it may have a bigger write buffer */ retry(qp, 0); return; } tp = cp; restart = 0; validanswer = -1; nscount = 0; soacount = 0; cname = 0; lastwascname = 0; externalcname = 0; strcpy(aname, qname); if (count) { /* allocate 1 extra record for end of set detection */ flushset_size = (count + 1) * sizeof *flushset; flushset = memget(flushset_size); if (flushset == NULL) panic("flushset: out of memory", NULL); memset(flushset, 0, flushset_size); } else flushset = NULL; expect_cname = 1; for (i = 0; i < count; i++) { struct databuf *dp; int type; freestr_maybe(&tname); if (cp >= eom) { free_related_additional(); if (flushset != NULL) free_flushset(flushset, flushset_size); formerrmsg = outofDataFinal; goto formerr; } n = rrextract(msg, msglen, cp, &dp, name, sizeof name, from, &tname); if (n < 0) { free_related_additional(); freestr_maybe(&tname); if (flushset != NULL) free_flushset(flushset, flushset_size); formerrmsg = outofDataFinal; if (hp->rcode == REFUSED) goto refused; else goto formerr; } cp += n; if (!dp) continue; type = dp->d_type; if (i < ancount) { /* Answer section. */ /* * Check for attempts to overflow the buffer in * getnameanswer. */ if (type == ns_t_cname && !expect_cname) { ns_warning(ns_log_security, "late CNAME in answer section for %s %s from %s", *qname ? qname : ".", p_type(qtype), sin_ntoa(from)); } else if (type != ns_t_cname && type != ns_t_dname && type != ns_t_sig) expect_cname = 0; if (externalcname || ns_samename(name, aname) != 1) { if (!externalcname) ns_info(ns_log_resp_checks, "wrong ans. name (%s != %s)", name[0] ? name : ".", aname[0] ? aname : "."); else ns_debug(ns_log_resp_checks, 3, "ignoring answer '%s' after external cname", name); db_detach(&dp); validanswer = 0; continue; } if (type == T_CNAME && qtype != T_CNAME && qtype != T_ANY) { strcpy(aname, (char *)dp->d_data); if (!ns_samedomain(aname, qp->q_domain)) externalcname = 1; cname++; lastwascname = 1; } else { if (validanswer) validanswer = 1; lastwascname = 0; } if (tname != NULL) { add_related_additional(tname); tname = NULL; } dp->d_cred = (hp->aa && ns_samename(name, qname) == 1) ? DB_C_AUTH : DB_C_ANSWER; } else { /* After answer section. */ if (lastwascname) { ns_debug(ns_log_resp_checks, 3, "last was cname, ignoring auth. and add."); db_detach(&dp); validanswer = 0; break; } if (i < arfirst) { /* Authority section. */ switch (type) { case T_NS: case T_SOA: if (!ns_samedomain(aname, name)) { ns_info(ns_log_resp_checks, "bad referral (%s !< %s) from %s", aname[0] ? aname : ".", name[0] ? name : ".", sin_ntoa(from)); db_detach(&dp); validanswer = 0; continue; } else if (!ns_samedomain(name, qp->q_domain)) { if (fwd == NULL && !externalcname) ns_info(ns_log_resp_checks, "bad referral (%s !< %s) from %s", name[0] ? name : ".", qp->q_domain[0] ? qp->q_domain : ".", sin_ntoa(from)); db_detach(&dp); validanswer = 0; continue; } if (type == T_NS) { nscount++; add_related_additional(tname); tname = NULL; } if (type == T_SOA) { soacount++; } break; case T_NXT: /* XXX check */ break; case T_SIG: /* XXX check that it relates to an NS or SOA or NXT */ break; default: ns_info(ns_log_resp_checks, "invalid RR type '%s' in authority section (name = '%s') from %s", p_type(type), name, sin_ntoa(from)); db_detach(&dp); validanswer = 0; continue; } dp->d_cred = (hp->aa && (cname == 0)) ? DB_C_AUTH : (qp->q_flags & Q_PRIMING) ? DB_C_ANSWER : DB_C_ADDITIONAL; } else { /* Additional section. */ switch (type) { case T_A: case ns_t_a6: case T_AAAA: case T_SRV: if (externalcname || !ns_samedomain(name, qp->q_domain)) { ns_debug(ns_log_resp_checks, 3, "ignoring additional info '%s' type %s", name, p_type(type)); db_detach(&dp); validanswer = 0; continue; } if (!related_additional(name)) { ns_info(ns_log_resp_checks, "unrelated additional info '%s' type %s from %s", name, p_type(type), sin_ntoa(from)); db_detach(&dp); validanswer = 0; continue; } if (type == T_SRV && tname != NULL) { add_related_additional(tname); tname = NULL; } break; case T_KEY: /* XXX check? */ break; case T_SIG: /* * XXX a SIG RR should relate * to some other RR in this section, * although if it's the last RR * it might be a transaction signature. */ break; case ns_t_opt: /* * OPT does not get cached. */ db_detach(&dp); validanswer = 0; continue; default: ns_info(ns_log_resp_checks, "invalid RR type '%s' in additional section (name = '%s') from %s", p_type(type), name, sin_ntoa(from)); db_detach(&dp); validanswer = 0; continue; } dp->d_cred = (qp->q_flags & Q_PRIMING) ? DB_C_ANSWER : DB_C_ADDITIONAL; } } #ifdef HITCOUNTS ++dp->d_hitcnt; ++db_total_hits; #endif /* HITCOUNTS */ rrsetadd(flushset, name, dp); db_detach(&dp); } free_related_additional(); freestr_maybe(&tname); if (flushset != NULL) { if ((qp->q_flags & Q_SYSTEM) && (qp->q_flags & Q_PRIMING)) { check_hints(flushset); /* before rrsetupdate */ rrsetupdate(flushset, dbflags, from, 1); } else rrsetupdate(flushset, dbflags, from, 0); free_flushset(flushset, flushset_size); } if (lastwascname && !externalcname) ns_debug(ns_log_cname, 3, "%s (%s) q(%s %s %s) %s qd(%s)", danglingCname, aname, (qname && *qname) ? qname : ".", p_class(qclass), p_type(qtype), sin_ntoa(from), qp->q_domain); if (cp > eom) { formerrmsg = outofDataAFinal; goto formerr; } if ((qp->q_flags & Q_SYSTEM) && ancount) { if ((qp->q_flags & Q_PRIMING) && !check_root()) { /* mark server as bad */ mark_bad(qp, from); fast_retry(qp, from, 0); return; } ns_debug(ns_log_default, 3, "resp: leaving, SYSQUERY ancount %d", ancount); #ifdef BIND_NOTIFY if (qp->q_notifyzone != DB_Z_CACHE) { struct zoneinfo *zp = &zones[qp->q_notifyzone]; qp->q_notifyzone = DB_Z_CACHE; ns_notify(zp->z_origin, zp->z_class, ns_t_soa); } #endif qremove(qp); return; } if (ancount && count && validanswer != 1) { /* * Everything passed validation but we didn't get the * final answer. The response must have contained * a dangling CNAME. Force a restart of the query. * * Don't set restart if count==0, since this means * the response was truncated in the answer section, * causing us to set count to 0 which will cause * validanswer to be 0 as well even though the answer * section probably contained valid RRs (just not * a complete set). * XXX - this works right if we can just forward this * response to the client, but not if we found a CNAME * in a prior response and restarted the query. */ restart = 1; } if (!restart && !qp->q_cmsglen && ancount > 1 && qtype == T_A) sort_response(tp, eom, ancount, &qp->q_from); /* * An answer to a T_ANY query or a successful answer to a * regular query with no indirection, then just return answer. */ if (!restart && ancount && (qtype == T_ANY || !qp->q_cmsglen)) { ns_debug(ns_log_default, 3, "resp: got as much answer as there is"); goto return_msg; } /* * We might want to cache this negative answer. * * if ancount != 0 and rcode == NOERROR we cannot determine if the * CNAME chain has been processed to completion or not, so just * restart the query. DNS needs a NODATA return code! * * As some servers incorrectly return a NODATA indication when * there is a CNAME chain instead of NXDOMAIN, we requery to get * a definitive answer. */ if ((hp->rcode == NXDOMAIN && cname == ancount) || (hp->rcode == NOERROR && ancount == 0 && (nscount == 0 || soacount != 0) ) ) { cache_n_resp(msg, msglen, from, qp->q_name, qp->q_class, qp->q_type); if (!qp->q_cmsglen && validanswer) { ns_debug(ns_log_default, 3, "resp: leaving NO: auth = %d", hp->aa); goto return_msg; } } /* * All messages in here need further processing. i.e. they * are either CNAMEs or we got referred again. */ count = 0; founddata = 0; dname = name; /* * XXX - the restart stuff doesn't work if any of the answer RRs * is not cacheable (TTL==0 or unknown RR type), since all of the * answer must pass through the cache and be re-assembled. */ if (qp->q_cmsglen != 0) { ns_debug(ns_log_default, 1, "Cname second pass"); newmsglen = MIN(EDNS_MESSAGE_SZ, qp->q_cmsglen); memcpy(newmsg, qp->q_cmsg, newmsglen); } else { newmsglen = MIN(EDNS_MESSAGE_SZ, msglen); memcpy(newmsg, msg, newmsglen); } hp = (HEADER *) newmsg; hp->ancount = htons(0); hp->nscount = htons(0); hp->arcount = htons(0); hp->rcode = NOERROR; dnptrs[0] = newmsg; dnptrs[1] = NULL; cp = newmsg + HFIXEDSZ; /* * Keep in mind that none of this code works when QDCOUNT>1. * cp ends up pointed just past the query section in both cases. */ /* * Arrange for dname to contain the query name. The query * name can be either the original query name if restart==0 * or the target of the last CNAME if we are following a * CNAME chain and were referred. */ n = dn_expand(newmsg, newmsg + newmsglen, cp, dname, sizeof name); if (n < 0) { ns_debug(ns_log_default, 1, "dn_expand failed"); goto servfail; } if (!res_dnok(dname)) { ns_debug(ns_log_default, 1, "bad name (%s)", dname); goto servfail; } cp += n + QFIXEDSZ; buflen = sizeof(newmsg) - (cp - newmsg); cname = 0; try_again: ns_debug(ns_log_default, 1, "resp: nlookup(%s) qtype=%d", dname, qtype); foundname = 0; fname = ""; htp = hashtab; /* lookup relative to root */ np = nlookup(dname, &htp, &fname, 0); ns_debug(ns_log_default, 1, "resp: %s '%s' as '%s' (cname=%d)", np == NULL ? "missed" : "found", dname, fname, cname); if (np == NULL || fname != dname) goto fetch_ns; foundname++; answers = cp; count = cp - newmsg; /* * Look for NXDOMAIN record. */ for (dp = np->n_data; dp; dp = dp->d_next) { if (!stale(dp) && (dp->d_rcode == NXDOMAIN) && (dp->d_class == (int)qclass)) { #ifdef RETURNSOA n = finddata(np, qclass, T_SOA, hp, &dname, &buflen, &count); if ( n != 0) { if (count) { cp += n; buflen -= n; newmsglen += n; hp->nscount = htons((u_int16_t)count); } if (hp->rcode == NOERROR_NODATA) { hp->rcode = NOERROR; goto return_newmsg; } } #else count = 0; #endif hp->rcode = NXDOMAIN; /* * XXX forcing AA all the time isn't right, but * we have to work that way by default * for compatibility with older servers. */ if (!NS_OPTION_P(OPTION_NONAUTH_NXDOMAIN)) hp->aa = 1; ns_debug(ns_log_default, 3, "resp: NXDOMAIN aa = %d", hp->aa); if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) goto return_newmsg; founddata = 1; goto fetch_ns; } } n = finddata(np, qclass, qtype, hp, &dname, &buflen, &count); if (n == 0) goto fetch_ns; /* NO data available */ if (hp->rcode) { if (hp->rcode == NOERROR_NODATA) hp->rcode = NOERROR; #ifdef RETURNSOA if (count) { cp += n; buflen -= n; hp->nscount = htons((u_int16_t)count); } #endif if ((count == 0) || NS_OPTION_P(OPTION_NORFC2308_TYPE1)) goto return_newmsg; founddata = 1; goto fetch_ns; } cp += n; buflen -= n; hp->ancount = htons(ntohs(hp->ancount) + (u_int16_t)count); if (fname != dname && qtype != T_CNAME && qtype != T_ANY) { cname++; goto try_again; } founddata = 1; ns_debug(ns_log_default, 3, "resp: foundname=%d, count=%d, founddata=%d, cname=%d", foundname, count, founddata, cname); if (count > 1 && qtype == T_A) sort_response(answers, cp, count, &qp->q_from); fetch_ns: if (hp->tc) goto return_newmsg; /* * Look for name servers to refer to and fill in the authority * section or record the address for forwarding the query * (recursion desired). */ free_nsp(nsp); switch (findns(&np, qclass, nsp, &count, 0)) { case NXDOMAIN: /* shouldn't happen */ ns_debug(ns_log_default, 3, "req: leaving (%s, rcode %d)", dname, hp->rcode); if (!foundname) hp->rcode = NXDOMAIN; if (qclass != C_ANY) { hp->aa = 1; if (np && (!foundname || !founddata)) { n = doaddauth(hp, cp, buflen, np, nsp[0]); cp += n; buflen -= n; } } goto return_newmsg; case SERVFAIL: goto servfail; } if (founddata) { hp = (HEADER *)newmsg; n = add_data(np, nsp, cp, buflen, &count); if (n < 0) { hp->tc = 1; n = (-n); } cp += n; buflen -= n; hp->nscount = htons((u_int16_t)count + ntohs(hp->nscount)); goto return_newmsg; } /* * If we get here, we don't have the answer yet and are about * to iterate to try and get it. First, infinite loop avoidance. */ if (qp->q_nqueries++ > MAXQUERIES) { ns_debug(ns_log_default, 1, "resp: MAXQUERIES exceeded (%s %s %s)", dname, p_class(qclass), p_type(qtype)); ns_info(ns_log_default, "MAXQUERIES exceeded, possible data loop in resolving (%s)", dname); goto servfail; } /* Reset the query control structure */ ns_freeqns(qp); qp->q_naddr = 0; qp->q_curaddr = 0; nsfwdadd(qp, NS_ZFWDTAB(qp->q_fzone)); if (qp->q_domain != NULL) (void)freestr(qp->q_domain); getname(np, tmpdomain, sizeof tmpdomain); qp->q_domain = savestr(tmpdomain, 1); if (NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) n = 0; else if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) { if (n < 0) { if (n == -1) ns_debug(ns_log_default, 3, "resp: nslookup reports danger"); if (cname) /* a remote CNAME that does not have data */ goto return_newmsg; goto servfail; } else { ns_debug(ns_log_default, 3, "resp: no addrs found for NS's"); /* * Timeout while sysquery looks up the NS addresses. * * Hopefully we'll have them when the client asks * again. * * too bad we can't just wait for the sysquery * response to restart this query (it's too hard). * * We could try to crawl back up the tree looking * for reachable servers, but we may have just * gotten delegated down here by a response with * no A RRs for the servers. If we blindly tried * this strategy, we bang on the same server forever. */ goto timeout; } } for (n = 0; (u_int)n < qp->q_naddr; n++) qp->q_addr[n].stime.tv_sec = 0; qp->q_addr[0].stime = tt; if (cname) { if (qp->q_cname++ == MAXCNAMES) { ns_debug(ns_log_default, 3, "resp: leaving, MAXCNAMES exceeded"); goto servfail; } ns_debug(ns_log_default, 1, "q_cname = %d", qp->q_cname); ns_debug(ns_log_default, 3, "resp: building recursive query; nslookup"); if (qp->q_cmsg == NULL) { qp->q_cmsg = qp->q_msg; qp->q_cmsglen = qp->q_msglen; qp->q_cmsgsize = qp->q_msgsize; } else if (qp->q_msg != NULL) memput(qp->q_msg, qp->q_msgsize); qp->q_msg = (u_char *)memget(PACKETSZ); if (qp->q_msg == NULL) { ns_notice(ns_log_default, "resp: memget error"); goto servfail; } qp->q_msgsize = PACKETSZ; n = res_nmkquery(&res, QUERY, dname, qclass, qtype, NULL, 0, NULL, qp->q_msg, PACKETSZ); if (n < 0) { ns_info(ns_log_default, "resp: res_mkquery(%s) failed", dname); goto servfail; } if (qp->q_name != NULL) (void)freestr(qp->q_name); qp->q_name = savestr(dname, 1); qp->q_msglen = n; hp = (HEADER *) qp->q_msg; hp->rd = 0; } else hp = (HEADER *) qp->q_msg; hp->id = qp->q_nsid = htons(nsid_next()); hp->rd = (qp->q_addr[0].forwarder ? 1 : 0); unsched(qp); schedretry(qp, retrytime(qp)); nsa = Q_NEXTADDR(qp, 0); if (ns_wouldlog(ns_log_default, 1)) { ns_debug(ns_log_default, 1, "resp: forw -> %s ds=%d nsid=%d id=%d %dms", sin_ntoa(*nsa), ds, ntohs(qp->q_nsid), ntohs(qp->q_id), (qp->q_addr[0].nsdata != NULL) ? qp->q_addr[0].nsdata->d_nstime : -1); } #ifdef DEBUG if (debug >= 10) res_pquery(&res, qp->q_msg, qp->q_msglen, log_get_stream(packet_channel)); #endif key = qp->q_keys[0]; if (key == NULL) key = qp->q_keys[0] = tsig_key_from_addr(nsa->sin_addr); if (key != NULL || !qp->q_addr[0].noedns) { smsgsize = qp->q_msglen + TSIG_BUF_SIZE + 11; smsg = memget(smsgsize); smsglen = qp->q_msglen; siglen = sizeof(sig); memcpy(smsg, qp->q_msg, qp->q_msglen); } if (!qp->q_addr[0].noedns) smsglen += ns_add_opt(smsg, smsg + smsglen, smsgsize, 0, 0, EDNS_MESSAGE_SZ, 0, NULL, 0); if (key != NULL) { n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0, sig, &siglen, 0); if (n == 0) { has_tsig = 1; free_tsig(qp->q_nstsig); qp->q_nstsig = new_tsig(key, sig, siglen); } else { has_tsig = 0; free_tsig(qp->q_nstsig); qp->q_nstsig = NULL; INSIST(0); } } else { has_tsig = 0; free_tsig(qp->q_nstsig); qp->q_nstsig = NULL; } if (smsg != NULL) { oldqbuf = qp->q_msg; oldqlen = qp->q_msglen; qp->q_msglen = smsglen; qp->q_msg = smsg; } if (qp->q_flags & Q_USEVC) { if (tcp_send(qp) != NOERROR) { if (!haveComplained(ina_ulong(nsa->sin_addr), (u_long)tcpsendStr)) ns_info(ns_log_default, "ns_resp: tcp_send(%s) failed: %s", sin_ntoa(*nsa), strerror(errno)); } } else if (sendto(ds, (char*)qp->q_msg, qp->q_msglen, 0, (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { sendto_errno = errno; if (!haveComplained(ina_ulong(nsa->sin_addr), (u_long)sendtoStr)) ns_info(ns_log_default, "ns_resp: sendto(%s): %s", sin_ntoa(*nsa), strerror(errno)); nameserIncr(nsa->sin_addr, nssSendtoErr); } if (smsgsize != 0) { memput(smsg, smsgsize); qp->q_msg = oldqbuf; qp->q_msglen = oldqlen; } hp->rd = 0; /* leave set to 0 for dup detection */ nameserIncr(nsa->sin_addr, nssSentFwdR); nameserIncr(qp->q_from.sin_addr, nssRcvdFwdR); ns_debug(ns_log_default, 3, "resp: Query sent."); free_nsp(nsp); switch (sendto_errno) { case ENETDOWN: case ENETUNREACH: case EHOSTDOWN: case EHOSTUNREACH: unsched(qp); schedretry(qp, (time_t) 0); } return; formerr: if (!haveComplained(ina_ulong(from.sin_addr), (u_long)formerrmsg)) ns_info(ns_log_resp_checks, "Malformed response from %s (%s)", sin_ntoa(from), formerrmsg); fast_retry(qp, from, 0); free_nsp(nsp); return; return_msg: nameserIncr(from.sin_addr, nssRcvdFwdR); nameserIncr(qp->q_from.sin_addr, nssSentFwdR); nameserIncr(qp->q_from.sin_addr, nssSentAns); if (!hp->aa) nameserIncr(qp->q_from.sin_addr, nssSentNaAns); if (hp->rcode == NXDOMAIN) nameserIncr(qp->q_from.sin_addr, nssSentNXD); /* The "standard" return code */ hp->qr = 1; hp->id = qp->q_id; hp->rd = 1; hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); (void) send_msg(msg, msglen, qp); qremove(qp); free_nsp(nsp); return; return_newmsg: nameserIncr(qp->q_from.sin_addr, nssSentAns); if (!hp->aa) nameserIncr(qp->q_from.sin_addr, nssSentNaAns); if (hp->rcode == NXDOMAIN) nameserIncr(qp->q_from.sin_addr, nssSentNXD); n = doaddinfo(hp, cp, buflen); cp += n; buflen -= n; hp->qr = 1; hp->id = qp->q_id; hp->rd = 1; hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); (void) send_msg(newmsg, cp - newmsg, qp); qremove(qp); free_nsp(nsp); return; refused: hp = (HEADER *)(qp->q_cmsglen ? qp->q_cmsg : qp->q_msg); hp->rcode = REFUSED; hp->qr = 1; hp->id = qp->q_id; hp->rd = 1; hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); (void) send_msg((u_char *)hp, (qp->q_cmsglen ? qp->q_cmsglen : qp->q_msglen), qp); qremove(qp); free_nsp(nsp); return; servfail: nameserIncr(qp->q_from.sin_addr, nssSentFail); hp = (HEADER *)(qp->q_cmsglen ? qp->q_cmsg : qp->q_msg); hp->rcode = SERVFAIL; hp->qr = 1; hp->id = qp->q_id; hp->rd = 1; hp->ra = (NS_OPTION_P(OPTION_NORECURSE) == 0); (void) send_msg((u_char *)hp, (qp->q_cmsglen ? qp->q_cmsglen : qp->q_msglen), qp); qremove(qp); free_nsp(nsp); return; timeout: if (qp->q_stream) sq_remove(qp->q_stream); qremove(qp); free_nsp(nsp); return; } #define BOUNDS_CHECK(ptr, count) \ do { \ if ((ptr) + (count) > eom) { \ hp->rcode = FORMERR; \ return (-1); \ } \ } while (0) static int rrextract(u_char *msg, int msglen, u_char *rrp, struct databuf **dpp, char *dname, int namelen, struct sockaddr_in from, char **tnamep) { u_char *cp, *eom, *rdatap; u_int class, type, dlen; int n, n1, n2; u_int32_t ttl; u_char *cp1, data[MAXDATA*2]; HEADER *hp = (HEADER *)msg; enum context context; if (tnamep != NULL) *tnamep = NULL; *dpp = NULL; cp = rrp; eom = msg + msglen; if ((n = dn_expand(msg, eom, cp, dname, namelen)) < 0) { hp->rcode = FORMERR; return (-1); } cp += n; BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); GETSHORT(type, cp); GETSHORT(class, cp); if (type != ns_t_opt && class > CLASS_MAX) { ns_debug(ns_log_default, 3, "bad class in rrextract"); hp->rcode = FORMERR; return (-1); } GETLONG(ttl, cp); if (ttl > MAXIMUM_TTL) { ns_debug(ns_log_default, 5, "%s: converted TTL > %u to 0", dname, MAXIMUM_TTL); ttl = 0; } GETSHORT(dlen, cp); BOUNDS_CHECK(cp, dlen); rdatap = cp; if (!ns_nameok(NULL, dname, class, NULL, response_trans, ns_ownercontext(type, response_trans), dname, from.sin_addr)) { hp->rcode = REFUSED; return (-1); } ns_debug(ns_log_default, 3, "rrextract: dname %s type %d class %d ttl %d", dname, type, class, ttl); /* * Convert the resource record data into the internal * database format. * * On entry to the switch: * CP points to the RDATA section of the wire-format RR. * DLEN is its length. * The memory area at DATA is available for processing. * * On exit from the switch: * CP has been incremented past the RR. * CP1 points to the RDATA section of the database-format RR. * N contains the length of the RDATA section of the dbase-format RR. * * The new data at CP1 for length N will be copied into the database, * so it need not be in any particular storage location. */ switch (type) { case T_A: if (dlen != INT32SZ) { hp->rcode = FORMERR; return (-1); } /*FALLTHROUGH*/ case T_WKS: case T_HINFO: case T_TXT: case T_X25: case T_ISDN: case T_NSAP: case T_AAAA: case T_LOC: case T_KEY: case ns_t_cert: case ns_t_opt: cp1 = cp; n = dlen; cp += n; break; case T_CNAME: case T_MB: case T_MG: case T_MR: case T_NS: case T_PTR: n = dn_expand(msg, eom, cp, (char *)data, sizeof data); if (n < 0) { hp->rcode = FORMERR; return (-1); } if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans, type == T_PTR ?ns_ptrcontext(dname) :domain_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); } cp += n; cp1 = data; n = strlen((char *)data) + 1; if (tnamep != NULL && (type == T_NS || type == T_MB)) *tnamep = savestr((char *)cp1, 1); break; case T_SOA: context = hostname_ctx; goto soa_rp_minfo; case T_RP: case T_MINFO: context = mailname_ctx; /* FALLTHROUGH */ soa_rp_minfo: n = dn_expand(msg, eom, cp, (char *)data, sizeof data); if (n < 0) { hp->rcode = FORMERR; return (-1); } if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans, context, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); } cp += n; /* * The next use of 'cp' is dn_expand(), so we don't have * to BOUNDS_CHECK() here. */ cp1 = data + (n = strlen((char *)data) + 1); n1 = sizeof(data) - n; if (type == T_SOA) n1 -= 5 * INT32SZ; n = dn_expand(msg, eom, cp, (char *)cp1, n1); if (n < 0) { hp->rcode = FORMERR; return (-1); } if (type == T_RP) context = domain_ctx; else context = mailname_ctx; if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, context, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); } cp += n; cp1 += strlen((char *)cp1) + 1; if (type == T_SOA) { n = 5 * INT32SZ; BOUNDS_CHECK(cp, n); memcpy(cp1, cp, n); cp += n; cp1 += n; } n = cp1 - data; cp1 = data; if (tnamep != NULL && type == T_SOA) *tnamep = savestr((char *)cp1, 1); break; case T_NAPTR: /* Grab weight and port. */ BOUNDS_CHECK(cp, INT16SZ*2); memcpy(data, cp, INT16SZ*2); cp1 = data + INT16SZ*2; cp += INT16SZ*2; /* Flags */ BOUNDS_CHECK(cp, 1); n = *cp++; BOUNDS_CHECK(cp, n); *cp1++ = n; memcpy(cp1, cp, n); cp += n; cp1 += n; /* Service */ BOUNDS_CHECK(cp, 1); n = *cp++; BOUNDS_CHECK(cp, n); *cp1++ = n; memcpy(cp1, cp, n); cp += n; cp1 += n; /* Regexp */ BOUNDS_CHECK(cp, 1); n = *cp++; BOUNDS_CHECK(cp, n); *cp1++ = n; memcpy(cp1, cp, n); cp += n; cp1 += n; /* Replacement */ n = dn_expand(msg, eom, cp, (char *)cp1, sizeof data - (cp1 - data)); if (n < 0) { hp->rcode = FORMERR; return (-1); } if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, hostname_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); } cp += n; if (tnamep != NULL && *cp1 != 0) *tnamep = savestr((char *)cp1, 1); /* compute end of data */ cp1 += strlen((char *)cp1) + 1; /* compute size of data */ n = cp1 - data; cp1 = data; break; case T_MX: case T_AFSDB: case T_RT: case T_SRV: /* grab preference */ BOUNDS_CHECK(cp, INT16SZ); memcpy(data, cp, INT16SZ); cp1 = data + INT16SZ; cp += INT16SZ; if (type == T_SRV) { /* Grab weight and port. */ BOUNDS_CHECK(cp, INT16SZ*2); memcpy(cp1, cp, INT16SZ*2); cp1 += INT16SZ*2; cp += INT16SZ*2; } /* get name */ n = dn_expand(msg, eom, cp, (char *)cp1, sizeof data - (cp1 - data)); if (n < 0) { hp->rcode = FORMERR; return (-1); } if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, hostname_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); } cp += n; if (tnamep != NULL) *tnamep = savestr((char *)cp1, 1); /* compute end of data */ cp1 += strlen((char *)cp1) + 1; /* compute size of data */ n = cp1 - data; cp1 = data; break; case T_PX: /* grab preference */ BOUNDS_CHECK(cp, INT16SZ); memcpy(data, cp, INT16SZ); cp1 = data + INT16SZ; cp += INT16SZ; /* get MAP822 name */ n = dn_expand(msg, eom, cp, (char *)cp1, sizeof data - INT16SZ); if (n < 0) { hp->rcode = FORMERR; return (-1); } if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, domain_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); } cp += n; /* * The next use of 'cp' is dn_expand(), so we don't have * to BOUNDS_CHECK() here. */ cp1 += (n = strlen((char *)cp1) + 1); n1 = sizeof(data) - n - INT16SZ; n = dn_expand(msg, eom, cp, (char *)cp1, n1); if (n < 0) { hp->rcode = FORMERR; return (-1); } if (!ns_nameok(NULL, (char *)cp1, class, NULL, response_trans, domain_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); } cp += n; cp1 += strlen((char *)cp1) + 1; n = cp1 - data; cp1 = data; break; case T_SIG: { u_int32_t origTTL, exptime, signtime, timetilexp, now; u_int8_t alg; /* Check signature time, expiration, and adjust TTL. */ /* This code is similar to that in db_load.c. */ /* Skip coveredType, save alg, skip labels */ BOUNDS_CHECK(cp, INT16SZ + 1 + 1 + 3*INT32SZ); cp1 = cp + INT16SZ; alg = *cp1++; cp1++; GETLONG(origTTL, cp1); GETLONG(exptime, cp1); GETLONG(signtime, cp1); now = time(NULL); /* Get current time in GMT/UTC */ /* Don't let bogus name servers increase the signed TTL */ if (ttl > origTTL) { ns_debug(ns_log_default, 3, "shrinking SIG TTL from %lu to origTTL %lu", (unsigned long)ttl, (unsigned long)origTTL); ttl = origTTL; } /* * Check that expire and signature times are internally * consistant. */ if (!SEQ_GT(exptime, signtime) && exptime != signtime) { ns_debug(ns_log_default, 3, "ignoring SIG: signature expires before it was signed"); return ((cp - rrp) + dlen); } /* Don't let bogus signers "sign" in the future. */ if (SEQ_GT(signtime, now)) { ns_debug(ns_log_default, 3, "ignoring SIG: signature date %s is in the future", p_secstodate (signtime)); return ((cp - rrp) + dlen); } /* Ignore received SIG RR's that are already expired. */ if (SEQ_GT(now, exptime)) { ns_debug(ns_log_default, 3, "ignoring SIG: expiration %s is in the past", p_secstodate (exptime)); return ((cp - rrp) + dlen); } /* Lop off the TTL at the expiration time. */ timetilexp = exptime - now; if (timetilexp < ttl) { ns_debug(ns_log_default, 3, "shrinking expiring %s SIG TTL from %d to %d", p_secstodate (exptime), ttl, timetilexp); ttl = timetilexp; } /* The following code is copied from named-xfer.c. */ cp1 = (u_char *)data; /* first just copy over the type_covered, algorithm, */ /* labels, orig ttl, two timestamps, and the footprint */ BOUNDS_CHECK(cp, 18); memcpy(cp1, cp, 18); cp += 18; cp1 += 18; /* then the signer's name */ n = dn_expand(msg, eom, cp, (char *)cp1, (sizeof data) - 18); if (n < 0 || n + NS_SIG_SIGNER > (int)dlen) { hp->rcode = FORMERR; return (-1); } cp += n; cp1 += strlen((char*)cp1)+1; /* finally, we copy over the variable-length signature. Its size is the total data length, minus what we copied. */ n = dlen - (NS_SIG_SIGNER + n); if (n > (int)(sizeof data) - (cp1 - (u_char *)data)) { hp->rcode = FORMERR; return (-1); /* out of room! */ } switch (alg) { case NS_ALG_MD5RSA: if (n < NS_MD5RSA_MIN_SIZE || n > NS_MD5RSA_MAX_SIZE) hp->rcode = FORMERR; break; case NS_ALG_DSA: if (n != NS_DSA_SIG_SIZE) hp->rcode = FORMERR; break; default: break; } if (hp->rcode == FORMERR) return (-1); memcpy(cp1, cp, n); cp += n; cp1 += n; /* compute size of data */ n = cp1 - (u_char *)data; cp1 = (u_char *)data; break; } case T_NXT: n = dn_expand(msg, eom, cp, (char *)data, sizeof data); /* * By testing if n >= dlen, we are requiring that the type * bitmap be at least one octet. This is reasonable * because we always have to look at the 0 bit to see if * this is a "different format" NXT or not. */ if (n < 0 || n >= (int)dlen) { hp->rcode = FORMERR; return (-1); } if (!ns_nameok(NULL, (char *)data, class, NULL, response_trans, domain_ctx, dname, from.sin_addr)) { hp->rcode = FORMERR; return (-1); } cp += n; n1 = strlen((char *)data) + 1; cp1 = data + n1; /* * We don't need to BOUNDS_CHECK() cp here because we've * previously checked that 'dlen' bytes are in bounds, and * we know that n < dlen. */ n2 = dlen - n; /* * The first bit of the first octet determines the format * of the NXT record. A format for types >= 128 has not * yet been defined, so if bit zero is set, we just copy * what's there because we don't understand it. */ if ((*cp & 0x80) == 0) { /* * Bit zero is not set; this is an ordinary NXT * record. The bitmap must be at least 4 octets * because the NXT bit should be set. It should be * less than or equal to 16 octets because this NXT * format is only defined for types < 128. */ if (n2 < 4 || n2 > 16) { hp->rcode = FORMERR; return (-1); } } if (n2 > (int)(sizeof data - n1)) { hp->rcode = FORMERR; return (-1); } memcpy(cp1, cp, n2); cp += n2; cp1 += n2; /* compute size of data */ n = cp1 - (u_char *)data; cp1 = (u_char *)data; break; default: /* treat as opaque data */ ns_debug(ns_log_default, 3, "unknown type %d", type); cp1 = cp; n = dlen; cp += n; } if (cp > eom) { hp->rcode = FORMERR; return (-1); } if ((u_int)(cp - rdatap) != dlen) { ns_debug(ns_log_default, 3, "encoded rdata length is %u, but actual length was %u", dlen, (u_int)(cp - rdatap)); hp->rcode = FORMERR; return (-1); } if (n > MAXDATA) { ns_debug(ns_log_default, 1, "update type %d: %d bytes is too much data", type, n); hp->rcode = FORMERR; return (-1); } ttl += tt.tv_sec; if (type == ns_t_opt) class = 0; /* Lie. */ *dpp = savedata(class, type, ttl, cp1, n); return (cp - rrp); } int send_msg(u_char *msg, int msglen, struct qinfo *qp) { HEADER *hp = (HEADER *) msg; u_char *oldmsg; int oldlen = 0; int msgsize; int ret; int trunc; int adjust = 0; if (qp->q_flags & Q_SYSTEM) return (1); trunc = (qp->q_stream != NULL) ? 65535 : qp->q_udpsize; if (qp->q_tsig != NULL) adjust += qp->q_tsig->tsig_size; if ((qp->q_flags & Q_EDNS) != 0) adjust += 11; if (msglen > trunc - adjust) msglen = trunc_adjust(msg, msglen, trunc - adjust); if (ns_wouldlog(ns_log_default, 1)) { ns_debug(ns_log_default, 1, "send_msg -> %s (%s %d) id=%d", sin_ntoa(qp->q_from), qp->q_stream == NULL ? "UDP" : "TCP", qp->q_stream == NULL ? qp->q_dfd : qp->q_stream->s_rfd, ntohs(qp->q_id)); } #ifdef DEBUG if (ns_wouldlog(ns_log_default, 4)) { struct qinfo *tqp; for (tqp = nsqhead; tqp != NULL; tqp = tqp->q_link) { ns_debug(ns_log_default, 4, "qp %#lx q_id: %d q_nsid: %d q_msglen: %d", (u_long)tqp, tqp->q_id, tqp->q_nsid, tqp->q_msglen); ns_debug(ns_log_default, 4, "\tq_naddr: %d q_curaddr: %d", tqp->q_naddr, tqp->q_curaddr); ns_debug(ns_log_default, 4, "\tq_next: %#lx q_link: %#lx", (u_long)qp->q_next, (u_long)qp->q_link); } } #endif /* DEBUG */ if (adjust != 0) { oldmsg = msg; oldlen = msglen; msgsize = msglen + adjust; msg = memget(msgsize); memcpy(msg, oldmsg, oldlen); } else msgsize = msglen; /* silence compiler */ if ((qp->q_flags & Q_EDNS) != 0) msglen += ns_add_opt(msg, msg + msglen, msgsize, 0, hp->rcode, EDNS_MESSAGE_SZ, 0, NULL, 0); if (qp->q_tsig != NULL) { u_char sig[TSIG_SIG_SIZE]; int siglen = sizeof(sig); ret = ns_sign(msg, &msglen, msgsize, NOERROR, qp->q_tsig->key, qp->q_tsig->sig, qp->q_tsig->siglen, sig, &siglen, 0); if (ret != 0) { INSIST(0); } } #ifdef DEBUG if (debug >= 6) res_pquery(&res, msg, msglen, log_get_stream(packet_channel)); #endif /* DEBUG */ if (qp->q_stream == NULL) { /* * Don't send FORMERR to certian well known ports. */ if (hp->rcode == FORMERR && drop_port(ntohs(qp->q_from.sin_port))) return (-1); if (sendto(qp->q_dfd, (char*)msg, msglen, 0, (struct sockaddr *)&qp->q_from, sizeof(qp->q_from)) < 0) { if (!haveComplained(ina_ulong(qp->q_from.sin_addr), (u_long)sendtoStr)) #if defined(SPURIOUS_ECONNREFUSED) if (errno != ECONNREFUSED) #endif ns_info(ns_log_default, "send_msg: sendto(%s): %s", sin_ntoa(qp->q_from), strerror(errno)); nameserIncr(qp->q_from.sin_addr, nssSendtoErr); return (1); } } else writestream(qp->q_stream, (u_char*)msg, msglen); if (adjust != 0) memput(msg, oldlen + adjust); return (0); } static int root_server_p(ns_class class) { struct zoneinfo *zp = find_zone("", class); return (zp != NULL && (zp->z_type == z_master || zp->z_type == z_slave)); } void prime_cache(void) { int root = root_server_p(ns_c_in); ns_debug(ns_log_default, 1, "prime_cache: priming = %d, root = %d", priming, root); if (!priming && !root) { struct qinfo *qp = sysquery("", ns_c_in, ns_t_ns, NULL, NULL, 0, ns_port, ns_o_query, 0); if (qp != NULL) { qp->q_flags |= (Q_SYSTEM | Q_PRIMING); priming++; } } needs_prime_cache = 0; } struct qinfo * sysquery(const char *dname, int class, int type, struct in_addr *nss, struct dst_key **keys, int nsc, u_int16_t port, int opcode, int distance) { struct qinfo *qp, *oqp; HEADER *hp; char tmpdomain[MAXDNAME]; struct namebuf *np = NULL; struct databuf *nsp[NSMAX]; struct hashbuf *htp1; struct hashbuf *htp2; struct hashbuf *htp3; struct sockaddr_in *nsa; const char *fname; int n, count; int sendto_errno = 0; u_char *oldqbuf = NULL; int oldqlen = 0, has_tsig; u_char *smsg = NULL; int smsglen, smsgsize = 0, siglen; u_char sig[TSIG_SIG_SIZE]; DST_KEY *key; nsp[0] = NULL; ns_debug(ns_log_default, 3, "sysquery(%s, %d, %d, %p, %p, %d, %d)", dname, class, type, nss, keys, nsc, ntohs(port)); qp = qnew(dname, class, type, (nss != NULL && nsc != 0) ? 0 : 1); qp->q_distance = distance; if (nss != NULL && nsc != 0) np = NULL; else if (!NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) { htp1 = hashtab; htp2 = hashtab; htp3 = fcachetab; if (priming && dname[0] == '\0') { np = NULL; } else if (((np = nlookup(dname, &htp1, &fname, 0)) == NULL) && ((np = nlookup("", &htp2, &fname, 0)) == NULL) && ((np = nlookup("", &htp3, &fname, 0)) == NULL)) { ns_info(ns_log_default, "sysquery: nlookup error on %s?", dname); err1: ns_freeqry(qp); return (NULL); } n = findns(&np, class, nsp, &count, 0); switch (n) { case NXDOMAIN: case SERVFAIL: ns_info(ns_log_default, "sysquery: findns error (%s) on %s?", n == NXDOMAIN ? "NXDOMAIN" : "SERVFAIL", dname); err2: free_nsp(nsp); goto err1; } } /* Build new qinfo struct. */ qp->q_cmsg = qp->q_msg = NULL; qp->q_dfd = ds; if (nss == NULL || nsc == 0) nsfwdadd(qp, NS_ZFWDTAB(qp->q_fzone)); qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2; qp->q_flags |= Q_SYSTEM; getname(np, tmpdomain, sizeof tmpdomain); qp->q_domain = savestr(tmpdomain, 1); if ((qp->q_msg = (u_char *)memget(PACKETSZ)) == NULL) { ns_notice(ns_log_default, "sysquery: memget failed"); goto err2; } qp->q_msgsize = PACKETSZ; n = res_nmkquery(&res, opcode, dname, class, type, NULL, 0, NULL, qp->q_msg, PACKETSZ); if (n < 0) { ns_info(ns_log_default, "sysquery: res_mkquery(%s) failed", dname); goto err2; } qp->q_msglen = n; hp = (HEADER *) qp->q_msg; hp->id = qp->q_nsid = htons(nsid_next()); hp->rd = (qp->q_addr[qp->q_curaddr].forwarder ? 1 : 0); hp->aa = (opcode == NS_NOTIFY_OP); /* First check for an already pending query for this data. */ for (oqp = nsqhead; oqp != NULL; oqp = oqp->q_link) { if ((oqp != qp) && (oqp->q_msglen == qp->q_msglen) && memcmp(oqp->q_msg+2, qp->q_msg + 2, qp->q_msglen - 2) == 0 ) { #ifdef BIND_NOTIFY /* XXX - need fancier test to suppress duplicate * NOTIFYs to the same server (compare nss?) */ if (opcode != NS_NOTIFY_OP) #endif /*BIND_NOTIFY*/ { ns_debug(ns_log_default, 3, "sysquery: duplicate"); goto err2; } } } if (nss != NULL && nsc != 0) { int i; struct qserv *qs; for (i = 0, qs = qp->q_addr; i < nsc; i++, qs++) { qs->ns_addr.sin_family = AF_INET; qs->ns_addr.sin_addr = nss[i]; qs->ns_addr.sin_port = port; if (keys != NULL) qp->q_keys[i] = keys[i]; qs->ns = NULL; qs->nsdata = NULL; qs->stime = tt; qs->forwarder = 0; qs->noedns = 1; /* XXXMPA */ qs->nretry = 0; } qp->q_naddr = nsc; } else if (!NS_ZOPTION_P(qp->q_fzone, OPTION_FORWARD_ONLY)) { fetch_a: count = nslookup(nsp, qp, dname, "sysquery"); if (count <= 0) { if (count < 0) { if (n == -1) ns_info(ns_log_default, "sysquery: nslookup reports danger (%s)", dname); goto err2; } else if (np && NAME(*np)[0] == '\0') { /* * It's not too serious if we don't have * the root server addresses if we have to * go through a forwarder anyway. Don't * bother to log it, since prime_cache() * won't do anything about it as currently * implemented. * * XXX - should we skip setting * needs_prime_cache as well? * * XXX - what happens when we implement * selective forwarding? */ if (!NS_OPTION_P(OPTION_FORWARD_ONLY)) ns_warning(ns_log_default, "sysquery: no addrs found for root NS (%s)", dname); if (class == C_IN && !priming) needs_prime_cache = 1; goto err2; } if (np) { free_nsp(nsp); nsp[0] = NULL; np = np_parent(np); n = findns(&np, class, nsp, &count, 0); switch (n) { case NXDOMAIN: /*FALLTHROUGH*/ case SERVFAIL: ns_info(ns_log_default, "sysquery: findns error (%d) on %s?", n, dname); goto err2; } getname(np, tmpdomain, sizeof tmpdomain); if (qp->q_domain != NULL) (void)freestr(qp->q_domain); qp->q_domain = savestr(tmpdomain, 1); goto fetch_a; } goto err2; } } schedretry(qp, retrytime(qp)); qp->q_addr[0].stime = tt; /* XXX - why not every? */ nsa = Q_NEXTADDR(qp, 0); if (ns_wouldlog(ns_log_default, 1)) { ns_debug(ns_log_default, 1, "sysquery: send -> %s dfd=%d nsid=%d id=%d retry=%ld", sin_ntoa(*nsa), qp->q_dfd, ntohs(qp->q_nsid), ntohs(qp->q_id), (long)qp->q_time); } #ifdef DEBUG if (debug >= 10) res_pquery(&res, qp->q_msg, qp->q_msglen, log_get_stream(packet_channel)); #endif key = qp->q_keys[0]; if (key == NULL) key = qp->q_keys[0] = tsig_key_from_addr(nsa->sin_addr); if (key != NULL || !qp->q_addr[0].noedns) { smsgsize = qp->q_msglen + TSIG_BUF_SIZE + 11; smsg = memget(smsgsize); smsglen = qp->q_msglen; siglen = sizeof(sig); memcpy(smsg, qp->q_msg, qp->q_msglen); } if (!qp->q_addr[0].noedns) smsglen += ns_add_opt(smsg, smsg + smsglen, smsgsize, 0, 0, EDNS_MESSAGE_SZ, 0, NULL, 0); if (key != NULL) { n = ns_sign(smsg, &smsglen, smsgsize, NOERROR, key, NULL, 0, sig, &siglen, 0); if (n == 0) { has_tsig = 1; free_tsig(qp->q_nstsig); qp->q_nstsig = new_tsig(key, sig, siglen); } else { INSIST(0); has_tsig = 0; free_tsig(qp->q_nstsig); qp->q_nstsig = NULL; } } else { has_tsig = 0; free_tsig(qp->q_nstsig); qp->q_nstsig = NULL; } if (smsgsize != 0) { oldqbuf = qp->q_msg; oldqlen = qp->q_msglen; qp->q_msglen = smsglen; qp->q_msg = smsg; } if (sendto(qp->q_dfd, (char*)qp->q_msg, qp->q_msglen, 0, (struct sockaddr *)nsa, sizeof(struct sockaddr_in)) < 0) { sendto_errno = errno; if (!haveComplained(ina_ulong(nsa->sin_addr), (u_long)sendtoStr)) ns_info(ns_log_default, "sysquery: sendto(%s): %s", sin_ntoa(*nsa), strerror(errno)); nameserIncr(nsa->sin_addr, nssSendtoErr); } if (smsgsize != 0) { memput(smsg, smsgsize); qp->q_msg = oldqbuf; qp->q_msglen = oldqlen; } nameserIncr(nsa->sin_addr, nssSentSysQ); free_nsp(nsp); switch (sendto_errno) { case ENETDOWN: case ENETUNREACH: case EHOSTDOWN: case EHOSTUNREACH: unsched(qp); schedretry(qp, (time_t) 0); } return (qp); } /* * Check the list of root servers after receiving a response * to a query for the root servers. */ static int check_root() { struct databuf *dp, *pdp; struct namebuf *np; int count = 0; priming = 0; for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) if (NAME(*np)[0] == '\0') break; if (np == NULL) { ns_notice(ns_log_default, "check_root: Can't find root!"); return (0); } for (dp = np->n_data; dp != NULL; dp = dp->d_next) if (dp->d_type == T_NS) count++; ns_debug(ns_log_default, 1, "%d root servers", count); if (count < server_options->minroots) { ns_notice(ns_log_default, "check_root: %d root servers after query to root server < min", count); return (0); } pdp = NULL; dp = np->n_data; while (dp != NULL) { if (dp->d_type == T_NS && dp->d_zone == DB_Z_CACHE && dp->d_ttl < (u_int32_t)tt.tv_sec) { ns_debug(ns_log_default, 1, "deleting old root server '%s'", dp->d_data); dp = rm_datum(dp, np, pdp, NULL); /* SHOULD DELETE FROM HINTS ALSO */ continue; } pdp = dp; dp = dp->d_next; } if (check_ns()) return (1); else { priming = 1; return (0); } } /* * Check the root to make sure that for each NS record we have a A RR */ static int check_ns() { struct databuf *dp, *tdp; struct namebuf *np, *tnp; struct hashbuf *htp; char *dname; int found_arr; const char *fname; time_t curtime; int servers = 0, rrsets = 0; ns_debug(ns_log_default, 2, "check_ns()"); curtime = (u_int32_t) tt.tv_sec; for (np = hashtab->h_tab[0]; np != NULL; np = np->n_next) { if (NAME(*np)[0] != '\0') continue; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { int cnames = 0; if (dp->d_rcode) continue; if (dp->d_type != T_NS) continue; servers++; /* look for A records */ dname = (caddr_t) dp->d_data; htp = hashtab; tnp = nlookup(dname, &htp, &fname, 0); if (tnp == NULL || fname != dname) { ns_debug(ns_log_default, 3, "check_ns: %s: not found %s %#lx", dname, fname, (u_long)tnp); sysquery(dname, dp->d_class, T_A, NULL, NULL, 0, ns_port, QUERY, 0); continue; } /* look for name server addresses */ found_arr = 0; (void)delete_stale(tnp); for (tdp = tnp->n_data; tdp != NULL; tdp = tdp->d_next) { if (tdp->d_rcode) continue; if (tdp->d_type == T_CNAME) cnames++; if (tdp->d_type != T_A || tdp->d_class != dp->d_class) continue; if ((tdp->d_zone == DB_Z_CACHE) && (tdp->d_ttl < (u_int32_t)curtime)) { ns_debug(ns_log_default, 3, "check_ns: stale entry '%s'", NAME(*tnp)); found_arr = 0; break; } found_arr++; } if (found_arr) rrsets++; else if (cnames > 0) ns_info(ns_log_default, "Root NS %s -> CNAME %s", NAME(*np), NAME(*tnp)); else sysquery(dname, dp->d_class, T_A, NULL, NULL, 0, ns_port, QUERY, 0); } } ns_debug(ns_log_default, 2, "check_ns: %d %d", servers, rrsets); return ((servers <= 2) ? (rrsets == servers) : ((rrsets * 2) >= servers) ); } /* int findns(npp, class, nsp, countp, flag) * Find NS's or an SOA * npp, class: * dname whose most enclosing NS is wanted * nsp, countp: * result array and count; array will also be NULL terminated * flag: * boolean: we're being called from ADDAUTH, bypass authority checks * return value: * NXDOMAIN: we are authoritative for this {dname,class} * *countp is bogus, but nsp[] has a single SOA returned in it. * SERVFAIL: we are auth but zone isn't loaded; or, no root servers found * *countp and nsp[] are bogus. * OK: we are not authoritative, and here are the NS records we found. * *countp and nsp[] return NS records of interest. */ int findns(struct namebuf **npp, int class, struct databuf **nsp, int *countp, int flag) { struct namebuf *np = *npp; struct databuf *dp; struct databuf **nspp; struct hashbuf *htp; nsp[0] = NULL; if (priming && (np == NULL || NAME(*np)[0] == '\0')) htp = fcachetab; else htp = hashtab; try_again: if (htp == fcachetab && class == C_IN && !priming) /* * XXX - do we want to set needs_prime_cache if * OPTION_FORWARD_ONLY? */ needs_prime_cache = 1; if (np == NULL) { /* find the root */ for (np = htp->h_tab[0]; np != NULL; np = np->n_next) if (NAME(*np)[0] == '\0') break; } while (np != NULL) { ns_debug(ns_log_default, 5, "findns: np %p '%s'", np, NAME(*np)); /* Look first for SOA records. */ #ifdef ADDAUTH if (!flag) #endif for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_zone != DB_Z_CACHE && ((zones[dp->d_zone].z_type == Z_PRIMARY) || (zones[dp->d_zone].z_type == Z_SECONDARY)) && match(dp, class, T_SOA) && dp->d_type == T_SOA) { ns_debug(ns_log_default, 3, "findns: SOA found"); if (zones[dp->d_zone].z_flags & Z_AUTH) { *npp = np; nsp[0] = dp; nsp[1] = NULL; DRCNTINC(dp); return (NXDOMAIN); } else { /* XXX: zone isn't loaded but we're * primary or slave for it. * should we fwd this? */ return (SERVFAIL); } } } /* If no SOA records, look for NS records. */ nspp = &nsp[0]; *nspp = NULL; (void)delete_stale(np); for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!match(dp, class, T_NS)) continue; if (dp->d_rcode) continue; /* * Don't use records that may become invalid to * reference later when we do the rtt computation. * Never delete our safety-belt information! * * XXX: this is horribly bogus. */ if ((dp->d_zone == DB_Z_CACHE) && (dp->d_ttl < (u_int32_t)tt.tv_sec) && !(dp->d_flags & DB_F_HINT)) { ns_debug(ns_log_default, 1, "findns: stale entry '%s'", NAME(*np)); /* * We may have already added NS databufs * and are going to throw them away. Fix * reference counts. We don't need to free * them here as we just got them from the * cache. */ while (nspp > &nsp[0]) db_detach(--nspp); nsp[0] = NULL; goto try_parent; } if (nspp < &nsp[NSMAX-1]) { *nspp++ = dp; DRCNTINC(dp); } } *countp = nspp - nsp; if (*countp > 0) { ns_debug(ns_log_default, 3, "findns: %d NS's added for '%s'", *countp, NAME(*np)); *nspp = NULL; *npp = np; return (OK); /* Success, got some NS's */ } try_parent: np = np_parent(np); } if (htp == hashtab) { htp = fcachetab; goto try_again; } ns_debug(ns_log_default, 1, "findns: No root nameservers for class %s?", p_class(class)); if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) { norootlogged[class] = 1; ns_info(ns_log_default, "No root nameservers for class %s", p_class(class)); } return (SERVFAIL); } /* * Extract RR's from the given node that match class and type. * Return number of bytes added to response. * If no matching data is found, then 0 is returned. */ int finddata(struct namebuf *np, int class, int type, HEADER *hp, char **dnamep, int *lenp, int *countp) { struct databuf *dp; char *cp; int buflen, n, count = 0; char *new_dnamep = NULL; int defer = 0, found_count = 0, choice, i; struct databuf **found = NULL; struct databuf **tmpfound = NULL; int foundcname; int stalecount; int ret = 0; stalecount = delete_stale(np); /* We don't want to return cached SIG records when asked for SIGs, * since we may have an incomplete set. */ if (type == T_SIG && findMyZone(np, class) == DB_Z_CACHE) return(0); if (type != T_ANY && type != T_PTR && type != T_NXT) { found = memget((stalecount + 1) * sizeof *found); tmpfound = memget((stalecount + 1) * sizeof *tmpfound); if (found == NULL || tmpfound == NULL) ns_panic(ns_log_default, 1, "finddata: out of memory"); defer = 1; } buflen = *lenp; #ifdef DEBUG if (buflen > PACKETSZ) ns_debug(ns_log_default, 1, "finddata(): buflen=%d", buflen); #endif cp = ((char *)hp) + *countp; foundcname = 0; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!wanted(dp, class, type)) { if (type == T_CNAME && class == dp->d_class) { /* any data means no CNAME exists */ if (dp->d_type != T_NXT && dp->d_type != T_KEY && dp->d_type != T_SIG) { ret = 0; goto done; } } continue; } if (dp->d_cred == DB_C_ADDITIONAL) { #ifdef NOADDITIONAL continue; #else /* we want to expire additional data very * quickly. current strategy is to cut 5% * off each time it is accessed. this makes * stale(dp) true earlier when this datum is * used often. */ dp->d_ttl = tt.tv_sec + 0.95 * (int) (dp->d_ttl - tt.tv_sec); #endif } /* -ve $ing stuff, anant@isi.edu * if we have a -ve $ed record, change the rcode on the * header to reflect that */ if (dp->d_rcode == NOERROR_NODATA) { if (count != 0) { /* * This should not happen, yet it does... */ ns_info(ns_log_default, "NODATA & data for \"%s\" type %d class %d", *dnamep, type, class); continue; } if (type == T_ANY) continue; hp->rcode = NOERROR_NODATA; if (dp->d_size == 0) { /* !RETURNSOA */ ret = 1; goto done; } } if (dp->d_rcode == NXDOMAIN) { if (count != 0) { /* * This should not happen, yet it might... */ ns_info(ns_log_default, "NXDOMAIN & data for \"%s\" type %d class %d", *dnamep, type, class); continue; } hp->rcode = NXDOMAIN; if (dp->d_size == 0) { /* !RETURNSOA */ ret = 1; goto done; } } #ifdef HITCOUNTS ++dp->d_hitcnt; ++db_total_hits; #endif /* HITCOUNTS */ /* Don't put anything but key or sig RR's in response to requests for key or sig */ if (((type == T_SIG) || (type == T_KEY)) && (!((dp->d_type == T_SIG) || (dp->d_type == T_KEY))) ) continue; if (!defer) { if (foundcname != 0 && dp->d_type == T_CNAME) continue; if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1, dnptrs, dnptrs_end, 0)) < 0) { hp->tc = 1; ret = *lenp - buflen; goto done; } if (dp->d_secure != DB_S_SECURE) hp->ad = 0; cp += n; buflen -= n; count++; if (dp->d_type == T_CNAME) { foundcname = 1; #define FOLLOWCNAME(type) \ (type != T_KEY) && (type != T_SIG) && (type != T_NXT) && (type != T_ANY) /* don't alias if querying for key, sig, nxt, or any */ if (FOLLOWCNAME(type)) new_dnamep = (char *)dp->d_data; } } else { if (dp->d_type == T_CNAME) foundcname = 1; found[found_count++] = dp; } } if (found_count == 0 && count == 0) { ret = 0; goto done; } /* * If the query type was SIG or ANY we will have returned the SIG * records already. */ if (type != T_SIG && type != T_ANY) { for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!wantedsig(dp, class, type)) continue; if (dp->d_cred == DB_C_ADDITIONAL) { #ifdef NOADDITIONAL continue; #else /* we want to expire additional data very * quickly. current strategy is to cut 5% * off each time it is accessed. this makes * stale(dp) true earlier when this datum is * used often. */ dp->d_ttl = tt.tv_sec + 0.95 * (int) (dp->d_ttl - tt.tv_sec); #endif } if (!defer) { if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1, dnptrs, dnptrs_end, 0)) < 0) { hp->tc = 1; ret = *lenp - buflen; goto done; } if (dp->d_secure != DB_S_SECURE) hp->ad = 0; cp += n; buflen -= n; count++; } else found[found_count++] = dp; } } if (defer && found_count > 0) { int first_sig; int non_sig_count; int sig_count; /* number of SIG records in found */ int idx, jdx; enum ordering order; order = match_order(np, class, foundcname ? T_CNAME : type); /* * shuffle the SIG records down to the bottom of the array * as we need to make sure they get packed last, no matter * what the ordering is. We're sure to maintain the * original ordering within the two sets of records (so * that fixed_order can work). * First we pack the non-SIG records into the temp array. */ for (idx = jdx = 0 ; idx < found_count ; idx++) { if (found[idx]->d_type != T_SIG) { tmpfound[jdx++] = found[idx]; } } non_sig_count = jdx; sig_count = found_count - jdx; first_sig = jdx ; /* * now shift the SIG records down to the end of the array * and copy in the non-SIG records */ for (i = idx = found_count - 1 ; i >= 0 ; idx--) { if (i < non_sig_count) { found[i] = tmpfound[i]; i--; } else if (found[idx]->d_type == T_SIG) { found[i--] = found[idx] ; } } foundcname = 0; switch (order) { case fixed_order: for (i = 0; i < found_count; i++) { dp = found[i]; if (foundcname != 0 && dp->d_type == T_CNAME) continue; if (dp->d_type == T_CNAME) { foundcname = 1; if (FOLLOWCNAME(type)) { new_dnamep = (char *)dp->d_data; } } if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1, dnptrs, dnptrs_end, 0)) < 0) { hp->tc = 1; ret = *lenp - buflen; goto done; } if (dp->d_secure != DB_S_SECURE) hp->ad = 0; cp += n; buflen -= n; count++; } break; case random_order: { /* first we shuffle the non-SIG records */ int iters = non_sig_count; for (i = 0; i < iters; i++) { choice = ((u_int)rand()>>3) % non_sig_count; non_sig_count--; dp = found[choice]; found[choice] = found[non_sig_count]; if (foundcname != 0 && dp->d_type == T_CNAME) continue; if (dp->d_type == T_CNAME) { foundcname = 1; if (FOLLOWCNAME(type)) { new_dnamep = (char *)dp->d_data; } } if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1, dnptrs, dnptrs_end, 0)) < 0) { hp->tc = 1; ret = *lenp - buflen; goto done; } if (dp->d_secure != DB_S_SECURE) hp->ad = 0; cp += n; buflen -= n; count++; } /* now shuffle the SIG records */ iters = sig_count; for (i = 0; i < iters; i++) { choice = ((u_int)rand()>>3) % sig_count; choice += first_sig; sig_count--; dp = found[choice]; found[choice] = found[sig_count + first_sig]; if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1, dnptrs, dnptrs_end, 0)) < 0) { hp->tc = 1; ret = *lenp - buflen; goto done; } if (dp->d_secure != DB_S_SECURE) hp->ad = 0; cp += n; buflen -= n; count++; } break; } case cyclic_order: /* first we do the non-SIG records */ if (non_sig_count > 0) choice = ((u_int)rand()>>3) % non_sig_count; else choice = 0; for (i = 0; i < non_sig_count ; i++) { dp = found[(i + choice) % non_sig_count]; if (foundcname != 0 && dp->d_type == T_CNAME) continue; if (dp->d_type == T_CNAME) { foundcname = 1; if (FOLLOWCNAME(type)) { new_dnamep = (char *)dp->d_data; } } if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1, dnptrs, dnptrs_end, 0)) < 0) { hp->tc = 1; ret = *lenp - buflen; goto done; } if (dp->d_secure != DB_S_SECURE) hp->ad = 0; cp += n; buflen -= n; count++; } /* now do the SIG record rotation. */ if (sig_count > 0) { choice = ((u_int)rand()>>3) % sig_count; choice += first_sig; i = choice; do { dp = found[i]; if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1, dnptrs, dnptrs_end, 0)) < 0) { hp->tc = 1; ret = *lenp - buflen; goto done; } if (dp->d_secure != DB_S_SECURE) hp->ad = 0; cp += n; buflen -= n; count++; i++; if (i >= found_count) i = first_sig; } while (i != choice); } break; default: ns_warning(ns_log_default, "finddata: unknown ordering: %d", order); break; } } if (new_dnamep != NULL) *dnamep = new_dnamep; ns_debug(ns_log_default, 3, "finddata: added %d class %d type %d RRs", count, class, type); ret = *lenp - buflen; done: if (found != NULL) memput(found, (stalecount + 1) * sizeof *found); if (tmpfound != NULL) memput(tmpfound, (stalecount + 1) * sizeof *tmpfound); *countp = count; return (ret); } /* * Do we want this data record based on the class and type? */ static int wanted(const struct databuf *dp, int class, int type) { const u_char *cp; int coveredType; time_t expiration; #ifdef DEBUG char pclass[15], ptype[15]; #endif #ifdef DEBUG strcpy(pclass, p_class(class)); strcpy(ptype, p_type(type)); ns_debug(ns_log_default, 3, "wanted(%p, %s %s) [%s %s]", dp, pclass, ptype, p_class(dp->d_class), p_type(dp->d_type)); #endif if (dp->d_class != class && class != C_ANY) return (0); /* * Must check SIG for expiration below, other matches * return OK here. */ if (type == dp->d_type && (type != T_SIG)) return (1); /* For a T_ANY query, we do not want to return -ve $ed RRs. */ if (type == T_ANY && dp->d_rcode == NOERROR_NODATA) return (0); /* First, look at the type of RR. */ switch (dp->d_type) { /* Cases to deal with: T_ANY search, return all unexpired SIGs. T_SIG search, return all unexpired SIGs. T_ search, return all unexp SIG s. */ case T_SIG: cp = dp->d_data; GETSHORT(coveredType, cp); cp += INT16SZ + INT32SZ; /* skip alg, labels, & orig TTL */ GETLONG(expiration,cp); if (type == T_ANY || type == T_SIG) { if (expiration > time(0)) return (1); /* Unexpired matching SIG */ } return (0); /* We don't return this SIG. */ case T_ANY: return (1); case T_CNAME: if (dp->d_rcode != NOERROR_NODATA) return (1); else break; } /* OK, now look at the type of query. */ if (type == ns_t_any) return (1); else if (type == ns_t_mailb) switch (dp->d_type) { case T_MR: case T_MB: case T_MG: case T_MINFO: return (1); } else if (ns_t_xfr_p(type)) { /* * This is used to validate transfer requests, not * generate transfer responses. Is there an SOA? */ if (dp->d_type == ns_t_soa && dp->d_zone != DB_Z_CACHE && (zones[dp->d_zone].z_flags & Z_AUTH)) return (1); } return (0); } static int wantedsig(const struct databuf *dp, int class, int type) { const u_char *cp; int coveredType; time_t expiration; #ifdef DEBUG char pclass[15], ptype[15]; #endif #ifdef DEBUG strcpy(pclass, p_class(class)); strcpy(ptype, p_type(type)); ns_debug(ns_log_default, 3, "wantedtsig(%p, %s %s) [%s %s]", dp, pclass, ptype, p_class(dp->d_class), p_type(dp->d_type)); #endif if (dp->d_class != class && class != C_ANY) return (0); if (dp->d_type != T_SIG || dp->d_rcode != 0) return (0); cp = dp->d_data; GETSHORT(coveredType, cp); cp += INT16SZ + INT32SZ; /* skip alg, labels, & orig TTL */ GETLONG(expiration,cp); if (expiration < time(0)) return (0); if (type == T_ANY || type == T_SIG || type == coveredType) return (1); if (type == ns_t_mailb) { switch (coveredType) { case T_MR: case T_MB: case T_MG: case T_MINFO: return (1); } } return (0); } /* * Add RR entries from dpp array to a query/response. * Return the number of bytes added or negative the amount * added if truncation occured. Typically you are * adding NS records to a response. */ int add_data(struct namebuf *np, struct databuf **dpp, u_char *cp, int buflen, int *countp) { struct databuf *dp; char dname[MAXDNAME]; int n, bytes; bytes = *countp = 0; getname(np, dname, sizeof(dname)); for (dp = *dpp++; dp != NULL; dp = *dpp++) { if (stale(dp)) continue; /* ignore old cache entry */ if (dp->d_rcode) continue; if ((n = make_rr(dname, dp, cp, buflen, 1, dnptrs, dnptrs_end, 0)) < 0) return (-bytes); /* Truncation */ cp += n; buflen -= n; bytes += n; (*countp)++; } return (bytes); } static void rrsetadd(struct flush_set *flushset, const char *name, struct databuf *dp) { struct flush_set *fs = flushset; struct db_list *dbl; while (fs->fs_name && ( ns_samename(fs->fs_name,name) != 1 || (fs->fs_class != dp->d_class) || (fs->fs_type != dp->d_type) || (fs->fs_cred != dp->d_cred))) { fs++; } if (!fs->fs_name) { fs->fs_name = savestr(name, 1); fs->fs_class = dp->d_class; fs->fs_type = dp->d_type; fs->fs_cred = dp->d_cred; fs->fs_list = NULL; fs->fs_last = NULL; } dbl = (struct db_list *)memget(sizeof(struct db_list)); if (!dbl) panic("rrsetadd: out of memory", NULL); dbl->db_next = NULL; dbl->db_dp = dp; DRCNTINC(dbl->db_dp); if (fs->fs_last == NULL) fs->fs_list = dbl; else fs->fs_last->db_next = dbl; fs->fs_last = dbl; } static int ttlcheck(const char *name, struct db_list *dbl, int update) { int type = dbl->db_dp->d_type; int class = dbl->db_dp->d_class; struct hashbuf *htp = hashtab; const char *fname; struct namebuf *np; struct db_list *dbp = dbl; struct databuf *dp; u_int32_t ttl = 0; /* Make gcc happy. */ int first; np = nlookup(name, &htp, &fname, 0); if (np == NULL || fname != name || ns_wildcard(NAME(*np))) return (1); /* check that all the ttl's we have are the same, if not return 1 */ first = 1; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!match(dp, class, type)) continue; if (first) { /* we can't update zone data so return early */ if (dp->d_zone != DB_Z_CACHE) return (0); ttl = dp->d_ttl; first = 0; } else if (ttl != dp->d_ttl) return (1); } /* there are no records of this type in the cache */ if (first) return(1); /* * the ttls of all records we have in the cache are the same * if the ttls differ in the new set we don't want it. */ /* check that all the ttl's we have are the same, if not return 0 */ first = 1; while (dbp) { if (first) { ttl = dbp->db_dp->d_ttl; first = 0; } else if (ttl != dbp->db_dp->d_ttl) { return(0); } dbp = dbp->db_next; } /* update ttl if required */ if (update) { for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!match(dp, class, type)) continue; if (dp->d_ttl > ttl) break; dp->d_ttl = ttl; fixttl(dp); } } return(1); } /* * lookup rrset in table and compare to dbl * tri state result * -1: lookup failed * 0: rrsets same * 1: rrsets differ */ static int rrsetcmp(char * name, struct db_list * dbl, struct hashbuf * table) { int type = dbl->db_dp->d_type; int class = dbl->db_dp->d_class; struct hashbuf *htp = table; const char *fname; struct namebuf *np; struct db_list *dbp = dbl; struct databuf *dp; int exists = 0; np = nlookup(name, &htp, &fname, 0); if (np == NULL || fname != name || ns_wildcard(NAME(*np))) { ns_debug(ns_log_default, 3, "rrsetcmp: name not in database"); return (-1); } /* check that all entries in dbl are in the cache */ while (dbp) { for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!match(dp, class, type)) continue; exists = 1; if (!db_cmp(dp, dbp->db_dp) #ifdef NOADDITIONAL && ((dp->d_cred == dbp->db_dp->d_cred) || (dp->d_cred != DB_C_ADDITIONAL)) #endif ) break; } if (!dp) { ns_debug(ns_log_default, 3, "rrsetcmp: %srecord%s in database", exists ? "" : "no ", exists ? " not" : "s"); return (exists ? 1 : -1); } dbp = dbp->db_next; } /* Check that all cache entries are in the list. */ for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (!match(dp, class, type)) continue; #ifdef NCACHE if (dp->d_rcode) return (1); #endif dbp = dbl; while (dbp) { if (!db_cmp(dp, dbp->db_dp)) break; dbp = dbp->db_next; } if (!dbp) { ns_debug(ns_log_default, 3, "rrsetcmp: record not in rrset"); return (1); } } ns_debug(ns_log_default, 3, "rrsetcmp: rrsets matched"); return (0); } /* * verify incoming answer against what we already have in the hints * issue warnings / errors if differences detected. */ static void check_hints(struct flush_set * flushset) { struct zoneinfo *zp; struct flush_set *fs; struct db_list *dbp; /* We don't use hints when in forward only mode */ if (NS_OPTION_P(OPTION_FORWARD_ONLY)) return; /* find "." NS rrset and hence class */ for (fs = flushset; fs->fs_name != NULL; fs++) { if ((fs->fs_name[0] != '\0') || (fs->fs_type != ns_t_ns)) continue; /* see if we are a root server */ zp = find_zone(fs->fs_name, fs->fs_class); if (zp != NULL && (zp->z_type == z_master || zp->z_type == z_slave)) return; switch (rrsetcmp(fs->fs_name, fs->fs_list, fcachetab)) { case -1: ns_error(ns_log_default, "check_hints: no NS records for class %d in hints", fs->fs_class); break; case 1: ns_warning(ns_log_default, "check_hints: root NS list in hints for class %d does not match root NS list", fs->fs_class); break; case 0: break; default: ns_error(ns_log_default, "check_hints: unexpected response from rrsetcmp"); break; } break; } if (fs->fs_name == NULL) /* no root NS records */ return; dbp = fs->fs_list; while (dbp) { /* for each NS find A rrset in answer and check */ for (fs = flushset; fs->fs_name != NULL; fs++) { if (ns_samename(fs->fs_name, (char *)dbp->db_dp->d_data) != 1 || fs->fs_type != ns_t_a) continue; switch (rrsetcmp(fs->fs_name, fs->fs_list, fcachetab)) { case -1: ns_error(ns_log_default, "check_hints: no A records for %s class %d in hints", fs->fs_name[0] ? fs->fs_name : ".", fs->fs_class); break; case 1: ns_warning(ns_log_default, "check_hints: A records for %s class %d do not match hint records", fs->fs_name[0] ? fs->fs_name : ".", fs->fs_class); break; case 0: break; default: ns_error(ns_log_default, "check_hints: unexpected response from rrsetcmp"); break; } break; } if (fs->fs_name == NULL) ns_debug(ns_log_default, 2, "check_hints: no A records for %s", dbp->db_dp->d_data); dbp = dbp->db_next; } } static void rrsetupdate(struct flush_set * flushset, int flags, struct sockaddr_in from, int updatettl) { struct flush_set *fs = flushset; struct db_list *dbp, *odbp; int n; void *state = NULL; while (fs->fs_name) { ns_debug(ns_log_default, 2, "rrsetupdate: %s", fs->fs_name[0] ? fs->fs_name : "."); if ((n = rrsetcmp(fs->fs_name, fs->fs_list, hashtab)) && ttlcheck(fs->fs_name, fs->fs_list, 0)) { if (n > 0) flushrrset(fs, from); dbp = fs->fs_list; while (dbp) { n = db_set_update(fs->fs_name, dbp->db_dp, &state, flags, &hashtab, from, NULL, 0, NULL); ns_debug(ns_log_default, 3, "rrsetupdate: %s %d", fs->fs_name[0] ? fs->fs_name : ".", n); odbp = dbp; dbp = dbp->db_next; db_detach(&odbp->db_dp); memput(odbp, sizeof *odbp); } ns_debug(ns_log_default, 3, "rrsetupdate: %s %d", fs->fs_name[0] ? fs->fs_name : ".", n); } else { if ((n == 0) && updatettl) (void)ttlcheck(fs->fs_name,fs->fs_list, 1); dbp = fs->fs_list; while (dbp) { db_detach(&dbp->db_dp); odbp = dbp; dbp = dbp->db_next; memput(odbp, sizeof *odbp); } } fs->fs_list = NULL; fs++; } n = db_set_update(NULL, NULL, &state, flags, &hashtab, from, NULL, 0, NULL); } static void flushrrset(struct flush_set * fs, struct sockaddr_in from) { struct databuf *dp; int n; ns_debug(ns_log_default, 2, "flushrrset(%s, %s, %s, %d)", fs->fs_name[0]?fs->fs_name:".", p_type(fs->fs_type), p_class(fs->fs_class), fs->fs_cred); dp = savedata(fs->fs_class, fs->fs_type, 0, NULL, 0); dp->d_zone = DB_Z_CACHE; dp->d_cred = fs->fs_cred; dp->d_clev = 0; do { n = db_update(fs->fs_name, dp, NULL, NULL, DB_DELETE, hashtab, from); ns_debug(ns_log_default, 3, "flushrrset: %d", n); } while (n == OK); db_detach(&dp); } static void free_flushset(struct flush_set *flushset, int flushset_size) { struct flush_set *fs; struct db_list *dbl; for (fs = flushset; fs->fs_name != NULL; fs++) { fs->fs_name = freestr(fs->fs_name); while ((dbl = fs->fs_list) != NULL) { fs->fs_list = dbl->db_next; dbl->db_next = NULL; db_detach(&dbl->db_dp); memput(dbl, sizeof(*dbl)); } } memput(flushset, flushset_size); } /* * This is best thought of as a "cache invalidate" function. * It is called whenever a piece of data is determined to have * become invalid either through a timeout or a validation * failure. It is better to have no information, than to * have partial information you pass off as complete. */ void delete_all(struct namebuf *np, int class, int type) { struct databuf *dp, *pdp; ns_debug(ns_log_default, 3, "delete_all(%p:\"%s\" %s %s)", np, NAME(*np), p_class(class), p_type(type)); pdp = NULL; dp = np->n_data; while (dp != NULL) { if (dp->d_zone == DB_Z_CACHE && (dp->d_flags & DB_F_HINT) == 0 && match(dp, class, type)) { dp = rm_datum(dp, np, pdp, NULL); continue; } pdp = dp; dp = dp->d_next; } } /* delete_stale(np) * for all RRs associated with this name, check for staleness (& delete) * arguments: * np = pointer to namebuf to be cleaned. * returns: * number of RRs associated with this name. * side effects: * delete_all() can be called, freeing memory and relinking chains. */ int delete_stale(np) struct namebuf *np; { struct databuf *dp; int count; again: count = 0; for (dp = np->n_data; dp != NULL; dp = dp->d_next) { if (dp->d_zone == DB_Z_CACHE && stale(dp)) { delete_all(np, dp->d_class, dp->d_type); goto again; } count++; } return (count); } /* * Adjust answer message so that it fits in outlen. Set tc if required. * * If outlen = msglen, can be used to verify qdcount, ancount, nscount * and arcount. * * return new length */ int trunc_adjust(u_char *msg, int msglen, int outlen) { register HEADER *hp; u_int qdcount, ancount, nscount, arcount, dlen; u_char *cp = msg, *cp1, *eom_in, *eom_out; int n; eom_in = msg + msglen; eom_out = msg + outlen; hp = (HEADER *)msg; qdcount = ntohs(hp->qdcount); ancount = ntohs(hp->ancount); nscount = ntohs(hp->nscount); arcount = ntohs(hp->arcount); cp += HFIXEDSZ; while ((qdcount || ancount || nscount || arcount) && cp < eom_in && cp < eom_out) { cp1 = cp; /* use temporary in case we break */ n = dn_skipname(cp1, eom_in); if (n < 0) break; cp1 += n + 2 * INT16SZ; /* type, class */ if (!qdcount) { cp1 += INT32SZ; /* ttl */ if (cp1 + INT16SZ > eom_in) break; GETSHORT(dlen, cp1); cp1 += dlen; } if (cp1 > eom_in || cp1 > eom_out) break; cp = cp1; if (qdcount) qdcount--; else if (ancount) ancount--; else if (nscount) nscount--; else arcount--; } if (qdcount || ancount || nscount || arcount) { ns_debug(ns_log_default, 1, "trunc_adjust:%s %d %d %d %d %d, %d %d %d %d %d", hp->tc?" tc":"", msglen, ntohs(hp->qdcount), ntohs(hp->ancount), ntohs(hp->nscount), ntohs(hp->arcount), cp-msg, qdcount, ancount, nscount, arcount); hp->tc = 1; hp->qdcount = htons(ntohs(hp->qdcount) - qdcount); hp->ancount = htons(ntohs(hp->ancount) - ancount); hp->nscount = htons(ntohs(hp->nscount) - nscount); hp->arcount = htons(ntohs(hp->arcount) - arcount); } ENSURE(cp <= eom_out); return (cp - msg); } /* * mark the server "from" bad in the qp structure so it won't be retried. */ static int mark_noedns(struct qinfo *qp, struct sockaddr_in from, int cache) { int i; for (i = 0; i < (int)qp->q_naddr; i++) if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, from.sin_addr)) { if (qp->q_addr[i].noedns) return (1); if (qp->q_addr[i].nsdata && cache) qp->q_addr[i].nsdata->d_noedns = 1; qp->q_addr[i].noedns = 1; break; } return (0); } static void mark_bad(struct qinfo *qp, struct sockaddr_in from) { int i; for (i = 0; i < (int)qp->q_naddr; i++) if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, from.sin_addr)) qp->q_addr[i].nretry = MAXRETRY; } static void mark_lame(struct qinfo *qp, struct sockaddr_in from) { int i; for (i = 0; i < (int)qp->q_naddr; i++) if (ina_equal(qp->q_addr[i].ns_addr.sin_addr, from.sin_addr) && qp->q_addr[i].ns != NULL) { qp->q_addr[i].ns->d_flags |= DB_F_LAME; db_lame_add(qp->q_domain, (char*)qp->q_addr[i].ns->d_data, tt.tv_sec + server_options->lame_ttl); } } /* * Retry the message if and only if from matches where the query was * last sent to. The code does not handle responses sent from the * wrong interface an a multihomed server. */ static void fast_retry(struct qinfo *qp, struct sockaddr_in from, int samehost) { if (ina_equal(qp->q_addr[qp->q_curaddr].ns_addr.sin_addr, from.sin_addr)) retry(qp, samehost); } static void add_related_additional(char *name) { int i; if (num_related >= MAX_RELATED - 1) return; for (i = 0; i < num_related; i++) if (ns_samename(name, related[i]) == 1) { (void)freestr(name); return; } related[num_related++] = name; } static void free_related_additional() { int i; for (i = 0; i < num_related; i++) related[i] = freestr(related[i]); num_related = 0; } static int related_additional(char *name) { int i; for (i = 0; i < num_related; i++) if (ns_samename(name, related[i]) == 1) return (1); return (0); } static void freestr_maybe(char **tname) { if (tname == NULL || *tname == NULL) return; *tname = freestr(*tname); } /* * Match a request namebuf against the configured rrset-order info. First * match wins. There is an implicit '*.' at the front to the ordering names. */ static enum ordering match_order(const struct namebuf *np, int class, int type) { rrset_order_list orders = server_options->ordering; rrset_order_element roe; if (orders == NULL) return (DEFAULT_ORDERING); for (roe = orders->first ; roe != NULL ; roe = roe->next) { if (roe->class != C_ANY && roe->class != class) continue; if (roe->type != T_ANY && roe->type != type) continue; if (match_name(np, roe->name, strlen(roe->name)) == 0) { return (roe->order); } } /* none matched so use default */ return (DEFAULT_ORDERING); } /* Do a simple compare of the NP data against the given NAME, recursively * looking at the NP parent if necessary. NAMELEN is the length of the NAME * that needs to be matched. Matching happen from right to left. Returns -1 * on failure, on success the index of the first character of the matched * portion of the string is returned. In the first level call a return * value of 0 is of interest. */ static int match_name(const struct namebuf *np, const char *name, size_t namelen) { int matched ; if (name[0] == '*' && name[1] == '\0') return 0; if (np->n_parent != NULL) { /* recurse to end of np list */ matched = match_name(np->n_parent,name,namelen); } else { matched = namelen; } if (matched > 0) { int labellen = NAMELEN(*np); char pch; const char *start; if (labellen > matched) { return -1; } else if (labellen < matched) { /* string is longer than this namebuf's data, so make sure there's a period before the end of the match so we don't just match a suffix. */ start = name + (matched - labellen); pch = start[-1]; if (pch != '.') { return -1; } } else { start = name ; } if (strncasecmp(start, NAME(*np), labellen) == 0) { /* looking good. tell our caller what portion of the tail of string has been matched */ if (start == name) return (0) ; else return (start - name - 1); /* matched '.' too */ } else { return (-1); } } return (matched); } Index: vendor/bind/dist/contrib/bind/doc/html/logging.html =================================================================== --- vendor/bind/dist/contrib/bind/doc/html/logging.html (revision 109982) +++ vendor/bind/dist/contrib/bind/doc/html/logging.html (revision 109983) @@ -1,369 +1,373 @@ BIND logging Statement

BIND Configuration File Guide -- logging Statement


Syntax

 logging {
   [ channel channel_name {
     ( file path_name
        [ versions ( number | unlimited ) ]
        [ size size_spec ]
      | syslog ( kern | user | mail | daemon | auth | syslog | lpr |
                 news | uucp | cron | authpriv | ftp |
                 local0 | local1 | local2 | local3 |
                 local4 | local5 | local6 | local7 )
      | null );
 
     [ severity ( critical | error | warning | notice |
                  info  | debug [ level ] | dynamic ); ]
     [ print-category yes_or_no; ]
     [ print-severity yes_or_no; ]
     [ print-time yes_or_no; ]
   }; ]
 
   [ category category_name {
     channel_name; [ channel_name; ... ]
   }; ]
   ...
 };
 

Definition and Usage

The logging statement configures a wide variety of logging options for the nameserver. Its channel phrase associates output methods, format options and severity levels with a name that can then be used with the category phrase to select how various classes of messages are logged.

Only one logging statement is used to define as many channels and categories as are wanted. If there are multiple logging statements in a configuration, the first defined determines the logging, and warnings are issued for the others. If there is no logging statement, the logging configuration will be:

     logging {
         category default { default_syslog; default_debug; };
         category panic { default_syslog; default_stderr; };
         category packet { default_debug; };
         category eventlib { default_debug; };
     };
 
The logging configuration is established as soon as the logging statement is parsed. If you want to redirect messages about processing of the entire configuration file, the loggingstatement must appear first. Even if you do not redirect configuration file parsing messages, we recommend always putting the logging statement first so that this rule need not be consciously recalled if you ever do want the parser's messages relocated.

The channel phrase

All log output goes to one or more "channels"; you can make as many of them as you want.

Every channel definition must include a clause that says whether messages selected for the channel go to a file, to a particular syslog facility, or are discarded. It can optionally also limit the message severity level that will be accepted by the channel (default is "info"), and whether to include a named-generated time stamp, the category name and/or severity level (default is not to include any).

The word null as the destination option for the channel will cause all messages sent to it to be discarded; other options for the channel are meaningless.

The file clause can include limitations both on how large the file is allowed to become, and how many versions of the file will be saved each time the file is opened.

The size option for files is simply a hard ceiling on log growth. If the file ever exceeds the size, named will just not write anything more to it until the file is reopened; exceeding the size does not automatically trigger a reopen. The default behavior is to not limit the size of the file.

If you use the version logfile option, named will retain that many backup versions of the file by renaming them when opening. For example, if you choose to keep 3 old versions of the file "lamers.log" then just before it is opened lamers.log.1 is renamed to lames.log.2, lamers.log.0 is renamed to lamers.log.1, and lamers.log is renamed to lamers.log.0. No rolled versions are kept by default; any existing log file is simply appended. The unlimited keyword is synonymous with 99 in current BIND releases.

Example usage of the size and versions options:

     channel an_example_level {
         file "lamers.log" versions 3 size 20m;
         print-time yes;
         print-category yes;
     };
 

The argument for the syslog clause is a syslog facility as described in the syslog manual page. How syslogd will handle messages sent to this facility is described in the syslog.conf manual page. If you have a system which uses a very old version of syslog that only uses two arguments to the openlog() function, this clause is silently ignored.

The severity clause works like syslog's "priorities", except that they can also be used if you are writing straight to a file rather than using syslog. Messages which are not at least of the severity level given will not be selected for the channel; messages of higher severity levels will be accepted.

If you are using syslog, the syslog.conf priorities will also determine what eventually passes through. For example, defining a channel facility and severity as daemon and debug but only logging daemon.warning via syslog.conf will cause messages of severity info and notice to be dropped. If the situation were reversed, with named writing messages of only warning or higher, syslogd would print all messages it received from the channel.

The server can supply extensive debugging information when it is in debugging mode. If the server's global debug level is greater than zero, debugging mode will be active. The global debug level is set either by starting the named server with the "-d" flag followed by a positive integer, or by sending the running server the SIGUSR1 signal (for example, by using "ndc trace"). The global debug level can be set to zero, and debugging mode turned off, by sending the server the SIGUSR2 signal ("ndc notrace"). All debugging messages in the server have a debug level, and higher debug levels give more more detailed output. Channels that specify a specific debug severity, e.g.

     channel specific_debug_level {
         file "foo";
         severity debug 3;
     };
 

will get debugging output of level 3 or less any time the server is in debugging mode, regardless of the global debugging level. Channels with dynamic severity use the server's global level to determine what messages to print.

If print-time has been turned on, the date and time will be logged. print-time may be specified for a syslog channel, but is usually pointless since syslog also prints the date and time. If print-category is requested, then the category of the message will be logged as well. Finally, if print-severity is on, the severity level of the message will be logged. The print- options may be used in any combination, and will always be printed in the following order: time, category, severity. Here is an example where all three print- options are on:

     28-Apr-1997 15:05:32.863 default: notice: Ready to answer queries.
 

There are four predefined channels that are used for default logging as follows. How they are used used is described in the next section, The category phrase.

     channel default_syslog {
         syslog daemon;        # send to syslog's daemon facility
         severity info;        # only send priority info and higher
     };
 
     channel default_debug {
         file "named.run";     # write to named.run in the working directory
                               # Note: stderr is used instead of "named.run"
                               # if the server is started with the "-f" option.
         severity dynamic;     # log at the server's current debug level
     };
 
     channel default_stderr {  # writes to stderr
         file "<stderr>";      # this is illustrative only; there's currently
                               # no way of specifying an internal file
                               # descriptor in the configuration language.
         severity info;        # only send priority info and higher
     };
 
     channel null {            
         null;                 # toss anything sent to this channel
     };
 

Once a channel is defined, it cannot be redefined. Thus you cannot alter the built-in channels directly, but you can modify the default logging by pointing categories at channels you have defined.

The category phrase

There are many categories, so you can send the logs you want to see wherever you want, without seeing logs you don't want. If you don't specify a list of channels for a category, log messages in that category will be sent to the default category instead. If you don't specify a default category, the following "default default" is used:

     category default { default_syslog; default_debug; };
 

As an example, let's say you want to log security events to a file, but you also want keep the default logging behavior. You'd specify the following:

     channel my_security_channel {
         file "my_security_file";
         severity info;
     };
     category security { my_security_channel; default_syslog; default_debug; };
 

To discard all messages in a category, specify the null channel:

     category lame-servers { null; };
     category cname { null; };
 

The following categories are available:

default
The catch-all. Many things still aren't classified into categories, and they all end up here. Also, if you don't specify any channels for a category, the default category is used instead. If you do not define the default category, the following definition is used: category default { default_syslog; default_debug; };
config
High-level configuration file processing.
parser
Low-level configuration file processing.
queries
A short log message is generated for every query the server receives.
lame-servers
Messages like "Lame server on ..."
statistics
Statistics.
panic
If the server has to shut itself down due to an internal problem, it will log the problem in this category as well as in the problem's native category. If you do not define the panic category, the following definition is used: category panic { default_syslog; default_stderr; };
update
Dynamic updates. +
update-security +
+Denied dynamic updates due to access controls. +
ncache
Negative caching.
xfer-in
Zone transfers the server is receiving.
xfer-out
Zone transfers the server is sending.
db
All database operations.
eventlib
Debugging info from the event system. Only one channel may be specified for this category, and it must be a file channel. If you do not define the eventlib category, the following definition is used: category eventlib { default_debug; };
packet
Dumps of packets received and sent. Only one channel may be specified for this category, and it must be a file channel. If you do not define the packet category, the following definition is used: category packet { default_debug; };
notify
The NOTIFY protocol.
cname
Messages like "... points to a CNAME".
security
Approved/unapproved requests.
os
Operating system problems.
insist
Internal consistency check failures.
maintenance
Periodic maintenance events.
load
Zone loading messages.
response-checks
Messages arising from response checking, such as "Malformed response ...", "wrong ans. name ...", "unrelated additional info ...", "invalid RR type ...", and "bad referral ...".

[ BIND Config. File | BIND Home | ISC ]


-Last Updated: $Id: logging.html,v 1.13 2002/04/02 00:57:48 marka Exp $ +Last Updated: $Id: logging.html,v 1.14 2002/07/19 22:44:05 marka Exp $
Index: vendor/bind/dist/contrib/bind/doc/html/options.html =================================================================== --- vendor/bind/dist/contrib/bind/doc/html/options.html (revision 109982) +++ vendor/bind/dist/contrib/bind/doc/html/options.html (revision 109983) @@ -1,853 +1,853 @@ BIND options Statement

BIND Configuration File Guide -- options Statement


Syntax

 options {
   [ hostname hostname_string; ]
   [ version version_string; ]
   [ directory path_name; ]
   [ named-xfer path_name; ]
   [ dump-file path_name; ]
   [ memstatistics-file path_name; ]
   [ pid-file path_name; ]
   [ statistics-file path_name; ]
   [ auth-nxdomain yes_or_no; ]
   [ deallocate-on-exit yes_or_no; ]
   [ dialup yes_or_no; ]
   [ fake-iquery yes_or_no; ]
   [ fetch-glue yes_or_no; ]
   [ has-old-clients yes_or_no; ]
   [ host-statistics yes_or_no; ]
   [ host-statistics-max number; ]
   [ multiple-cnames yes_or_no; ]
   [ notify ( yes_or_no | explicit ) <; ]
   [ suppress-initial-notify yes_or_no; ]
   [ recursion yes_or_no; ]
   [ rfc2308-type1 yes_or_no; ]
   [ use-id-pool yes_or_no; ]
   [ treat-cr-as-space yes_or_no; ]
   [ also-notify { ip_addr; [ ip_addr; ... ] }; ]
   [ forward ( only | first ); ]
   [ forwarders { [ in_addr ; [ in_addr ; ... ] ] }; ]
   [ check-names ( master | slave | response ) ( warn | fail | ignore); ]
   [ allow-query { address_match_list }; ]
   [ allow-transfer { address_match_list }; ]
   [ allow-recursion { address_match_list }; ]
   [ blackhole { address_match_list }; ]
   [ listen-on [ port ip_port ] { address_match_list }; ]
   [ query-source [ address ( ip_addr | * ) ] [ port ( ip_port | * ) ] ; ]
   [ lame-ttl number; ]
   [ max-transfer-time-in number; ]
   [ max-ncache-ttl number; ]
   [ min-roots number; ]
   [ serial-queries number; ]
   [ transfer-format ( one-answer | many-answers ); ]
   [ transfers-in  number; ]
   [ transfers-out number; ]
   [ transfers-per-ns number; ]
   [ transfer-source ip_addr; ]
   [ maintain-ixfr-base yes_or_no; ]
   [ max-ixfr-log-size number; ]
   [ coresize size_spec ; ]
   [ datasize size_spec ; ]
   [ files size_spec ; ]
   [ stacksize size_spec ; ]
   [ cleaning-interval number; ]
   [ heartbeat-interval number; ]
   [ interface-interval number; ]
   [ statistics-interval number; ]
   [ topology { address_match_list }; ]
   [ sortlist { address_match_list }; ]
   [ rrset-order { order_spec ; [ order_spec ; ... ] }; ]
   [ preferred-glue ( A | AAAA ); ]
 };
 

Definition and Usage

The options statement sets up global options to be used by BIND. This statement may appear at only once in a configuration file; if more than one occurrence is found, the first occurrence determines the actual options used, and a warning will be generated. If there is no options statement, an options block with each option set to its default will be used.

Server Information

hostname
This defaults to the hostname of the machine hosting the nameserver as found by gethostname(). Its prime purpose is to be able to identify which of a number of anycast servers is actually answering your queries by sending a txt query for hostname.bind in class chaos to the anycast server and getting back a unique name. Setting the hostname to a empty string ("") will disable processing of the queries.
version
The version the server should report via the ndc command or via a query of name version.bind in class chaos. The default is the real version number of the server, but some server operators prefer the string "surely you must be joking". Changing the value of this string will not prevent people from identifying what version you are running.

Pathnames

directory
The working directory of the server. Any non-absolute pathnames in the configuration file will be taken as relative to this directory. The default location for most server output files (e.g. "named.run") is this directory. If a directory is not specified, the working directory defaults to ".", the directory from which the server was started. The directory specified should be an absolute path.
named-xfer
The pathname to the named-xfer program that the server uses for inbound zone transfers. If not specified, the default is system dependent (e.g. "/usr/sbin/named-xfer").
dump-file
The pathname of the file the server dumps the database to when it receives SIGINT signal (ndc dumpdb). If not specified, the default is "named_dump.db".
memstatistics-file
The pathname of the file the server writes memory usage statistics to, on exit, if deallocate-on-exit is yes. If not specified, the default is "named.memstats".
pid-file
The pathname of the file the server writes its process ID in. If not specified, the default is operating system dependent, but is usually "/var/run/named.pid" or "/etc/named.pid". The pid-file is used by programs like "ndc" that want to send signals to the running nameserver.
statistics-file
The pathname of the file the server appends statistics to when it receives SIGILL signal (ndc stats). If not specified, the default is "named.stats".

Boolean Options

auth-nxdomain
If yes, the AA bit is always set on NXDOMAIN responses, even if the server is not actually authoritative. -The default is yes. Do not turn off -auth-nxdomain unless you are sure you know what you are -doing, as some older software won't like it. +The default is no. Turning auth-nxdomain will +allow older clients that require AA to be set to accept +NXDOMAIN responses to work.
deallocate-on-exit
If yes, the server will painstakingly deallocate every object it it allocated, when it exits, and then write a memory usage report to the memstatistics-file. The default is no, because it is faster to let the operating system clean up. deallocate-on-exit is handy for detecting memory leaks.
dialup
If yes, the server treats all zones as if they are doing zone transfers across a dial on demand dialup link, which can be brought up by traffic originating from this server. This has different effects according to zone type and concentrates the zone maintenance so that it all happens in a short interval, once every heartbeat-interval and hopefully during the one call. It also suppresses some of the normal zone maintainance traffic. The default is no. The dialup option may also be specified in the zone statement, in which case it overrides the options dialup statement.

If the zone is a master zone, the server will send out NOTIFY request to all the slaves. This will trigger the "zone up to date checking" in the slave (providing it supports NOTIFY), allowing the slave to verify the zone while the call us up.

If the zone is a slave or stub zone, the server will suppress the regular "zone up to date" queries and only perform them when the heartbeat-interval expires.

fake-iquery
If yes, the server will simulate the obsolete DNS query type IQUERY. The default is no.
fetch-glue
If yes (the default), the server will fetch "glue" resource records it doesn't have when constructing the additional data section of a response. fetch-glue no can be used in conjunction with recursion no to prevent the server's cache from growing or becoming corrupted (at the cost of requiring more work from the client).
has-old-clients
Setting the option to yes is equivalent to setting the following options: auth-nxdomain yes; and rfc2308-type1 no;. The use of has-old-clients with auth-nxdomain and rfc2308-type1 is order dependent.
host-statistics
If yes, statistics are kept for every host that the the nameserver interacts with. The default is no. Note: turning on host-statistics can consume huge amounts of memory.
host-statistics-max
The maximum number of host records that will be kept. When this limit is reached no new hosts will be added to the host statistics. If the set to zero then there is no limit set. The default value is zero.
maintain-ixfr-base
If yes, a transaction log is kept for Incremental Zone Transfer. The default is no.
multiple-cnames
If yes, multiple CNAME resource records will be allowed for a domain name. The default is no. Allowing multiple CNAME records is against standards and is not recommended. Multiple CNAME support is available because previous versions of BIND allowed multiple CNAME records, and these records have been used for load balancing by a number of sites.
notify
If yes (the default), DNS NOTIFY messages are sent when a zone the server is authoritative for changes. The use of NOTIFY speeds convergence between the master and its slaves. Slave servers that receive a NOTIFY message, and understand it, will contact the master server for the zone to see if they need to do a zone transfer. If they do, they will initiate it immediately. If explicit, the NOTIFY messages will only be sent to the addresses in the also-notify list. The notify option may also be specified in the zone statement, in which case it overrides the options notify statement.
suppress-initial-notify
If yes, suppress the initial notify messages when the server first loads. The default is no.
recursion
If yes, and a DNS query requests recursion, the server will attempt to do all the work required to answer the query. If recursion is not on, the server will return a referral to the client if it doesn't know the answer. The default is yes. See also fetch-glue above.
rfc2308-type1
If yes, the server will send NS records along with the SOA record for negative answers from the cache. You need to set this to no if you have an old BIND server using you as a forwarder that does not understand negative answers which contain both SOA and NS records or you have an old version of sendmail. The correct fix is to upgrade the broken server or sendmail. The default is no.
use-id-pool
If yes, the server will keep track of its own outstanding query ID's to avoid duplication and increase randomness. This will result in 128KB more memory being consumed by the server. The default is no.
treat-cr-as-space
If yes, the server will treat '\r' characters the same way it treats a ' ' or '\t'. This may be necessary when loading zone files on a UNIX system that were generated on an NT or DOS machine. The default is no.

Also-Notify

also-notify

Defines a global list of IP addresses that also get sent NOTIFY messages whenever a fresh copy of the zone is loaded. This helps to ensure that copies of the zones will quickly converge on ``stealth'' servers. If an also-notify list is given in a zone statement, it will override the options also-notify statement. When a zone notify statement is set to no, the IP addresses in the global also-notify list will not get sent NOTIFY messages for that zone. The default is the empty list (no global notification list).

Forwarding

The forwarding facility can be used to create a large site-wide cache on a few servers, reducing traffic over links to external nameservers. It can also be used to allow queries by servers that do not have direct access to the Internet, but wish to look up exterior names anyway. Forwarding occurs only on those queries for which the server is not authoritative and does not have the answer in its cache.

forward
This option is only meaningful if the forwarders list is not empty. A value of first, the default, causes the server to query the forwarders first, and if that doesn't answer the question the server will then look for the answer itself. If only is specified, the server will only query the forwarders.
forwarders
Specifies the IP addresses to be used for forwarding. The default is the empty list (no forwarding).

Forwarding can also be configured on a per-zone basis, allowing for the global forwarding options to be overridden in a variety of ways. You can set particular zones to use different forwarders, or have different forward only/first behavior, or to not forward at all. See the zone statement for more information.

Future versions of BIND 8 will provide a more powerful forwarding system. The syntax described above will continue to be supported.

Name Checking

The server can check domain names based upon their expected client contexts. For example, a domain name used as a hostname can be checked for compliance with the RFCs defining valid hostnames.

Three checking methods are available:

ignore
No checking is done.
warn
Names are checked against their expected client contexts. Invalid names are logged, but processing continues normally.
fail
Names are checked against their expected client contexts. Invalid names are logged, and the offending data is rejected.

The server can check names three areas: master zone files, slave zone files, and in responses to queries the server has initiated. If check-names response fail has been specified, and answering the client's question would require sending an invalid name to the client, the server will send a REFUSED response code to the client.

The defaults are:

     check-names master fail;
     check-names slave warn;
     check-names response ignore;
 

check-names may also be specified in the zone statement, in which case it overrides the options check-names statement. When used in a zone statement, the area is not specified (because it can be deduced from the zone type).

Access Control

Access to the server can be restricted based on the IP address of the requesting system. See address_match_list for details on how to specify IP address lists.

allow-query
Specifies which hosts are allowed to ask ordinary questions. allow-query may also be specified in the zone statement, in which case it overrides the options allow-query statement. If not specified, the default is to allow queries from all hosts.
allow-transfer
Specifies which hosts are allowed to receive zone transfers from the server. allow-transfer may also be specified in the zone statement, in which case it overrides the options allow-transfer statement. If not specified, the default is to allow transfers from all hosts.
allow-recursion
Specifies which hosts are allowed to make recursive queries through this server. If not specified, the default is to allow recursive queries from all hosts.
blackhole
Specifies a list of addresses that the server will not accept queries from or use to resolve a query. Queries from these addresses will not be responded to.

Interfaces

The interfaces and ports that the server will answer queries from may be specified using the listen-on option. listen-on takes an optional port, and an address_match_list. The server will listen on all interfaces allowed by the address match list. If a port is not specified, port 53 will be used.

Multiple listen-on statements are allowed. For example,

     listen-on { 5.6.7.8; };
     listen-on port 1234 { !1.2.3.4; 1.2/16; };
 
will enable the nameserver on port 53 for the IP address 5.6.7.8, and on port 1234 of an address on the machine in net 1.2 that is not 1.2.3.4.

If no listen-on is specified, the server will listen on port 53 on all interfaces.

Query Address

If the server doesn't know the answer to a question, it will query other nameservers. query-source specifies the address and port used for such queries. If address is * or is omitted, a wildcard IP address (INADDR_ANY) will be used. If port is * or is omitted, a random unprivileged port will be used. The default is

     query-source address * port *;
 

Note: query-source port applies only to UDP queries, TCP queries always use a random unprivileged port.

Zone Transfers

max-transfer-time-in
Inbound zone transfers (named-xfer processes) running longer than this many minutes will be terminated. The default is 120 minutes (2 hours).
transfer-format
The server supports two zone transfer methods. one-answer uses one DNS message per resource record transferred. many-answers packs as many resource records as possible into a message. many-answers is more efficient, but is only known to be understood by BIND 8.1+ and patched versions of BIND 4.9.5. The default is one-answer. transfer-format may be overridden on a per-server basis by using the server statement.
transfers-in
The maximum number of inbound zone transfers that can be running concurrently. The default value is 10. Increasing transfers-in may speed up the convergence of slave zones, but it also may increase the load on the local system.
transfers-out
This option will be used in the future to limit the number of concurrent outbound zone transfers. It is checked for syntax, but is otherwise ignored.
transfers-per-ns
The maximum number of inbound zone transfers (named-xfer processes) that can be concurrently transferring from a given remote nameserver. The default value is 2. Increasing transfers-per-ns may speed up the convergence of slave zones, but it also may increase the load on the remote nameserver. transfers-per-ns may be overridden on a per-server basis by using the transfers phrase of the server statement.
transfer-source
transfer-source determines which local address will be bound to the TCP connection used to fetch all zones transferred inbound by the server. If not set, it defaults to a system controlled value which will usually be the address of the interface ``closest to'' the remote end. This address must appear in the remote end's allow-transfer option for the zone being transferred, if one is specified. This statement sets the transfer-source for all zones, but can be overridden on a per-zone basis by including a transfer-source statement within the zone block in the configuration file.
serial-queries
Slave servers will periodically query master servers to find out if zone serial numbers have changed. Each such query uses a minute amount of the slave server's network bandwidth, but more importantly each query uses a small amount of memory in the slave server while waiting for the master server to respond. The serial-queries option sets the maximum number of concurrent serial-number queries allowed to be outstanding at any given time. The default is four (4). Note: If a server loads a large (tens or hundreds of thousands) number of slave zones, this limit should be raised to the high hundreds or low thousands -- otherwise the slave server may never actually become aware of zone changes in the master servers. Beware, though, that setting this limit arbitrarily high can spend a considerable amount of your slave server's network, CPU, and memory resources. As with all tunable limits, this one should be changed gently and monitored for its effects.

Resource Limits

The server's usage of many system resources can be limited. Some operating systems don't support some of the limits. On such systems, a warning will be issued if the unsupported limit is used. Some operating systems don't support limiting resources, and on these systems a cannot set resource limits on this system message will be logged.

Scaled values are allowed when specifying resource limits. For example, 1G can be used instead of 1073741824 to specify a limit of one gigabyte. unlimited requests unlimited use, or the maximum available amount. default uses the limit that was in force when the server was started. See size_spec for more details.

coresize
The maximum size of a core dump. The default is default.
datasize
The maximum amount of data memory the server may use. The default is default.
files
The maximum number of files the server may have open concurrently. The default is unlimited. Note: on some operating systems the server cannot set an unlimited value and cannot determine the maximum number of open files the kernel can support. On such systems, choosing unlimited will cause the server to use the larger of the rlim_max for RLIMIT_NOFILE and the value returned by sysconf(_SC_OPEN_MAX). If the actual kernel limit is larger than this value, use limit files to specify the limit explicitly.
max-ixfr-log-size
Limit the size of the transaction log kept for Incremental Zone Transfer. Default 0 (unlimited).
stacksize
The maximum amount of stack memory the server may use. The default is default.

Periodic Task Intervals

cleaning-interval
The server will remove expired resource records from the cache every cleaning-interval minutes. The default is 60 minutes. If set to 0, no periodic cleaning will occur.
heartbeat-interval
The server will perform zone maintenance tasks for all zones marked dialup yes whenever this interval expires. The default is 60 minutes. Reasonable values are up to 1 day (1440 minutes). If set to 0, no zone maintenance for these zones will occur.
interface-interval
The server will scan the network interface list every interface-interval minutes. The default is 60 minutes. If set to 0, interface scanning will only occur when the configuration file is loaded. After the scan, listeners will be started on any new interfaces (provided they are allowed by the listen-on configuration). Listeners on interfaces that have gone away will be cleaned up.
statistics-interval
Nameserver statistics will be logged every statistics-interval minutes. The default is 60. If set to 0, no statistics will be logged.

Topology

All other things being equal, when the server chooses a nameserver to query from a list of nameservers, it prefers the one that is topologically closest to itself. The topology statement takes an address_match_list and interprets it in a special way. Each top-level list element is assigned a distance. Non-negated elements get a distance based on their position in the list, where the closer the match is to the start of the list, the shorter the distance is between it and the server. A negated match will be assigned the maximum distance from the server. If there is no match, the address will get a distance which is further than any non-negated list element, and closer than any negated element. For example,

     topology {
         10/8;
         !1.2.3/24;
         { 1.2/16; 3/8; };
     };
 

will prefer servers on network 10 the most, followed by hosts on network 1.2.0.0 (netmask 255.255.0.0) and network 3, with the exception of hosts on network 1.2.3 (netmask 255.255.255.0), which is preferred least of all.

The default topology is

     topology { localhost; localnets; };
 

Resource Record sorting

When returning multiple RRs, the nameserver will normally return them in Round Robin, i.e. after each request, the first RR is put to the end of the list. As the order of RRs is not defined, this should not cause any problems.

The client resolver code should re-arrange the RRs as appropriate, i.e. using any addresses on the local net in preference to other addresses. However, not all resolvers can do this, or are not correctly configured.

When a client is using a local server, the sorting can be performed in the server, based on the client's address. This only requires configuring the nameservers, not all the clients.

The sortlist statement takes an address match list and interprets it even more specially than the topology statement does.

Each top level statement in the sortlist must itself be an explicit address match list with one or two elements. The first element (which may be an IP address, an IP prefix, an ACL name or nested address match list) of each top level list is checked against the source address of the query until a match is found.

Once the source address of the query has been matched, if the top level statement contains only one element, the actual primitive element that matched the source address is used to select the address in the response to move to the beginning of the response. If the statement is a list of two elements, the second element is treated like the address match list in a topology statement. Each top level element is assigned a distance and the address in the response with the minimum distance is moved to the beginning of the response.

In the following example, any queries received from any of the addresses of the host itself will get responses preferring addresses on any of the locally connected networks. Next most preferred are addresses on the 192.168.1/24 network, and after that either the 192.168.2/24 or 192.168.3/24 network with no preference shown between these two networks. Queries received from a host on the 192.168.1/24 network will prefer other addresses on that network to the 192.168.2/24 and 192.168.3/24 networks. Queries received from a host on the 192.168.4/24 or the 192.168.5/24 network will only prefer other addresses on their directly connected networks.

 sortlist {
            { localhost;         // IF   the local host
              { localnets;       // THEN first fit on the
                192.168.1/24;    //      following nets
                { 192,168.2/24; 192.168.3/24; }; }; };
            { 192.168.1/24;      // IF   on class C 192.168.1
              { 192.168.1/24;    // THEN use .1, or .2 or .3
                { 192.168.2/24; 192.168.3/24; }; }; };
            { 192.168.2/24;      // IF   on class C 192.168.2
              { 192.168.2/24;    // THEN use .2, or .1 or .3
                { 192.168.1/24; 192.168.3/24; }; }; };
            { 192.168.3/24;      // IF   on class C 192.168.3
              { 192.168.3/24;    // THEN use .3, or .1 or .2
                { 192.168.1/24; 192.168.2/24; }; }; };
            { { 192.168.4/24; 192.168.5/24; }; // if .4 or .5, prefer that net
            };
 };
 
The following example will give reasonable behaviour for the local host and hosts on directly connected networks. It is similar to the behavior of the address sort in BIND 4.9.x. Responses sent to queries from the local host will favor any of the directly connected networks. Responses sent to queries from any other hosts on a directly connected network will prefer addresses on that same network. Responses to other queries will not be sorted.
 sortlist {
             { localhost; localnets; };
             { localnets; };
 };
 

RRset Ordering

When multiple records are returned in an answer it may be useful to configure the order the records are placed into the response. For example the records for a zone might be configured to always be returned in the order they are defined in the zone file. Or perhaps a random shuffle of the records as they are returned is wanted. The rrset-order statement permits configuration of the ordering made of the records in a multiple record response. The default, if no ordering is defined, is a cyclic ordering (round robin).

An order_spec is defined as follows:

   [ class class_name ][ type type_name ][ name "FQDN" ] order ordering
 

If no class is specified, the default is ANY. If no type is specified, the default is ANY. If no name is specified, the default is "*".

The legal values for ordering are:

fixed
Records are returned in the order they are defined in the zone file.
random
Records are returned in some random order.
cyclic
Records are returned in a round-robin order.

For example:

     rrset-order {
 	class IN type A name "rc.vix.com" order random;
         order cyclic;
     };
 

will cause any responses for type A records in class IN that have "rc.vix.com" as a suffix, to always be returned in random order. All other records are returned in cyclic order.

If multiple rrset-order statements appear, they are not combined--the last one applies.

If no rrset-order statement is specified, a default one of:

     rrset-order { class ANY type ANY name "*" order cyclic ; };
 

is used.

Glue Ordering

When running a root nameserver it is sometimes necessary to ensure that other nameservers that are priming are successful. This requires that glue A records for at least of the nameservers are returned in the answer to a priming query. This can be achieved by setting preferred-glue A; which will add A records before other types in the additional section.

Tuning

lame-ttl
Sets the number of seconds to cache a lame server indication. 0 disables caching. Default is 600 (10 minutes). Maximum value is 1800 (30 minutes).
max-ncache-ttl
To reduce network traffic and increase performance the server stores negative answers. max-ncache-ttl is used to set a maximum retention time for these answers in the server is seconds. The default max-ncache-ttl is 10800 seconds (3 hours). max-ncache-ttl cannot exceed the maximum retention time for ordinary (positive) answers (7 days) and will be silently truncated to 7 days if set to a value which is greater that 7 days.
min-roots
The minimum number of root servers that is required for a request for the root servers to be accepted. Default 2.

[ BIND Config. File | BIND Home | ISC ]


-Last Updated: $Id: options.html,v 1.48 2002/04/25 05:27:00 marka Exp $ +Last Updated: $Id: options.html,v 1.49 2002/09/09 00:19:17 marka Exp $
Index: vendor/bind/dist/contrib/bind/doc/man/named.conf.5 =================================================================== --- vendor/bind/dist/contrib/bind/doc/man/named.conf.5 (revision 109982) +++ vendor/bind/dist/contrib/bind/doc/man/named.conf.5 (revision 109983) @@ -1,2129 +1,2134 @@ .\" Copyright (c) 1999-2000 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS .\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE .\" CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL .\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR .\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS .\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS .\" SOFTWARE. .Dd January 7, 1999 .Dt NAMED.CONF 5 .Os BSD 4 .Sh NAME .Nm named.conf .Nd configuration file for .Xr named 8 .Sh OVERVIEW BIND 8 is much more configurable than previous release of BIND. There are entirely new areas of configuration, such as access control lists and categorized logging. Many options that previously applied to all zones can now be used selectively. These features, plus a consideration of future configuration needs led to the creation of a new configuration file format. .Ss General Syntax A BIND 8 configuration consists of two general features, statements and comments. All statements end with a semicolon. Many statements can contain substatements, which are each also terminated with a semicolon. .Pp The following statements are supported: .Bl -tag -width 0n .It Ic logging specifies what the server logs, and where the log messages are sent .It Ic options controls global server configuration options and sets defaults for other statements .It Ic zone defines a zone .It Ic acl defines a named IP address matching list, for access control and other uses .It Ic key specifies key information for use in authentication and authorization .It Ic trusted-keys defines DNSSEC keys that are preconfigured into the server and implicitly trusted .It Ic server sets certain configuration options for individual remote servers .It Ic controls declares control channels to be used by the .Nm ndc utility .It Ic include includes another file .El .Pp The .Ic logging and .Ic options statements may only occur once per configuration, while the rest may appear numerous times. Further detail on each statement is provided in individual sections below. .Pp Comments may appear anywhere that whitespace may appear in a BIND configuration file. To appeal to programmers of all kinds, they can be written in C, C++, or shell/perl constructs. .Pp C-style comments start with the two characters .Li /* (slash, star) and end with .Li */ (star, slash). Because they are completely delimited with these characters, they can be used to comment only a portion of a line or to span multiple lines. .Pp C-style comments cannot be nested. For example, the following is not valid because the entire comment ends with the first .Li */ : .Bd -literal -offset indent /* This is the start of a comment. This is still part of the comment. /* This is an incorrect attempt at nesting a comment. */ This is no longer in any comment. */ .Ed .Pp C++-style comments start with the two characters .Li // (slash, slash) and continue to the end of the physical line. They cannot be continued across multiple physical lines; to have one logical comment span multiple lines, each line must use the .Li // pair. For example: .Bd -literal -offset indent // This is the start of a comment. The next line // is a new comment, even though it is logically // part of the previous comment. .Ed .Pp Shell-style (or perl-style, if you prefer) comments start with the character .Li # (hash or pound or number or octothorpe or whatever) and continue to the end of the physical line, like C++ comments. For example: .Bd -literal -offset indent # This is the start of a comment. The next line # is a new comment, even though it is logically # part of the previous comment. .Ed .Pp .Em WARNING : you cannot use the .Li ; (semicolon) character to start a comment such as you would in a zone file. The semicolon indicates the end of a configuration statement, so whatever follows it will be interpreted as the start of the next statement. .Ss Converting from BIND 4.9.x BIND 4.9.x configuration files can be converted to the new format by using .Pa src/bin/named/named-bootconf , a shell script that is part of the BIND 8.2.x source kit. .Sh DOCUMENTATION DEFINITIONS Described below are elements used throughout the BIND configuration file documentation. Elements which are only associated with one statement are described only in the section describing that statement. .Bl -tag -width 0n .It Va acl_name The name of an .Va address_match_list as defined by the .Ic acl statement. .It Va address_match_list A list of one or more .Va ip_addr , .Va ip_prefix , .Va key_id , or .Va acl_name elements, as described in the .Sx ADDRESS MATCH LISTS section. .It Va dotted-decimal One or more integers valued 0 through 255 separated only by dots (``.''), such as .Li 123 , .Li 45.67 or .Li 89.123.45.67 . .It Va domain_name A quoted string which will be used as a DNS name, for example .Qq Li my.test.domain . .It Va path_name A quoted string which will be used as a pathname, such as .Qq Li zones/master/my.test.domain . .It Va ip_addr An IP address with exactly four elements in .Va dotted-decimal notation. .It Va ip_port An IP port .Va number . .Va number is limited to .Li 0 through .Li 65535 , with values below 1024 typically restricted to root-owned processes. In some cases an asterisk (``*'') character can be used as a placeholder to select a random high-numbered port. .It Va ip_prefix An IP network specified in .Va dotted-decimal form, followed by ``/'' and then the number of bits in the netmask. E.g. .Li 127/8 is the network .Li 127.0.0.0 with netmask .Li 255.0.0.0 . .Li 1.2.3.0/28 is network .Li 1.2.3.0 with netmask .Li 255.255.255.240. .It Va key_name A string representing the name of a shared key, to be used for transaction security. .It Va number A non-negative integer with an entire range limited by the range of a C language signed integer (2,147,483,647 on a machine with 32 bit integers). Its acceptable value might further be limited by the context in which it is used. .It Va size_spec A .Va number , the word .Li unlimited , or the word .Li default . .Pp The maximum value of .Va size_spec is that of unsigned long integers on the machine. .Li unlimited requests unlimited use, or the maximum available amount. .Li default uses the limit that was in force when the server was started. .Pp A .Va number can optionally be followed by a scaling factor: .Li K or .Li k for kilobytes, .Li M or .Li m for megabytes, and .Li G or .Li g for gigabytes, which scale by 1024, 1024*1024, and 1024*1024*1024 respectively. .Pp Integer storage overflow is currently silently ignored during conversion of scaled values, resulting in values less than intended, possibly even negative. Using .Li unlimited is the best way to safely set a really large number. .It Va yes_or_no Either .Li yes or .Li no . The words .Li true and .Li false are also accepted, as are the numbers .Li 1 and .Li 0 . .El .Sh ADDRESS MATCH LISTS .Ss Syntax .Bd -literal \fIaddress_match_list\fR = 1\&*\fIaddress_match_element\fR .Pp \fIaddress_match_element\fR = [ \&"!\&" ] ( \fIaddress_match_list\fR / \fIip_address\fR / \fIip_prefix\fR / \fIacl_name\fR / \&"key \&" \fIkey_id\fR ) \&";\&" .Ed .Ss Definition and Usage Address match lists are primarily used to determine access control for various server operations. They are also used to define priorities for querying other nameservers and to set the addresses on which .Nm named will listen for queries. The elements which constitute an address match list can be any of the following: .Bl -bullet .It an .Va ip-address (in .Va dotted-decimal notation, .It an .Va ip-prefix (in the '/'-notation), .It A .Va key_id , as defined by the .Ic key statement, .It the name of an address match list previously defined with the .Ic acl statement, or .It another .Va address_match_list . .El .Pp Elements can be negated with a leading exclamation mark (``!''), and the match list names .Li any , .Li none , .Li localhost and .Li localnets are predefined. More information on those names can be found in the description of the .Ic acl statement. .Pp The addition of the .Ic key clause made the name of this syntactic element something of a misnomer, since security keys can be used to validate access without regard to a host or network address. Nonetheless, the term ``address match list'' is still used throughout the documentation. .Pp When a given IP address or prefix is compared to an address match list, the list is traversed in order until an element matches. The interpretation of a match depends on whether the list is being used for access control, defining .Ic listen-on ports, or as a topology, and whether the element was negated. .Pp When used as an access control list, a non-negated match allows access and a negated match denies access. If there is no match at all in the list, access is denied. The clauses .Ic allow-query , .Ic allow-transfer , .Ic allow-update , .Ic allow-recursion , and .Ic blackhole all use address match lists like this. Similarly, the .Ic listen-on option will cause the server to not accept queries on any of the machine's addresses which do not match the list. .Pp When used with the .Ic topology option, a non-negated match returns a distance based on its position on the list (the closer the match is to the start of the list, the shorter the distance is between it and the server). A negated match will be assigned the maximum distance from the server. If there is no match, the address will get a distance which is further than any non-negated list element, and closer than any negated element. .Pp Because of the first-match aspect of the algorithm, an element that defines a subset of another element in the list should come before the broader element, regardless of whether either is negated. For example, in .Dl 1.2.3/24; !1.2.3.13 the 1.2.3.13 element is completely useless, because the algorithm will match any lookup for 1.2.3.13 to the 1.2.3/24 element. Using .Dl !1.2.3.13; 1.2.3/24 fixes that problem by having 1.2.3.13 blocked by the negation but all other 1.2.3.* hosts fall through. .Sh THE LOGGING STATEMENT .Ss Syntax .Bd -literal logging { [ channel \fIchannel_name\fR { ( file \fIpath_name\fR [ versions ( \fInumber\fR | unlimited ) ] [ size \fIsize_spec\fR ] | syslog ( kern | user | mail | daemon | auth | syslog | lpr | news | uucp | cron | authpriv | ftp | local0 | local1 | local2 | local3 | local4 | local5 | local6 | local7 ) | null ); .Pp [ severity ( critical | error | warning | notice | info | debug [ \fIlevel\fR ] | dynamic ); ] [ print-category \fIyes_or_no\fR; ] [ print-severity \fIyes_or_no\fR; ] [ print-time \fIyes_or_no\fR; ] }; ] .Pp [ category \fIcategory_name\fR { \fIchannel_name\fR; [ \fIchannel_name\fR; ... ] }; ] ... }; .Ed .Ss Definition and Usage The .Ic logging statement configures a wide variety of logging options for the nameserver. Its .Ic channel phrase associates output methods, format options and severity levels with a name that can then be used with the .Ic category phrase to select how various classes of messages are logged. .Pp Only one .Ic logging statement is used to define as many channels and categories as are wanted. If there are multiple logging statements in a configuration, the first defined determines the logging, and warnings are issued for the others. If there is no logging statement, the logging configuration will be: .Bd -literal logging { category default { default_syslog; default_debug; }; category panic { default_syslog; default_stderr; }; category packet { default_debug; }; category eventlib { default_debug; }; }; .Ed .Pp The logging configuration is established as soon as the .Ic logging statement is parsed. If you want to redirect messages about processing of the entire configuration file, the .Ic logging statement must appear first. Even if you do not redirect configuration file parsing messages, we recommend always putting the .Ic logging statement first so that this rule need not be consciously recalled if you ever do want the parser's messages relocated. .Ss The channel phrase All log output goes to one or more ``channels''; you can make as many of them as you want. .Pp Every channel definition must include a clause that says whether messages selected for the channel go to a file, to a particular syslog facility, or are discarded. It can optionally also limit the message severity level that will be accepted by the channel (default is .Li info ) , and whether to include a time stamp generated by .Nm named , the category name, or severity level. The default is not to include any of those three. .Pp The word .Li null as the destination option for the channel will cause all messages sent to it to be discarded; other options for the channel are meaningless. .Pp The .Ic file clause can include limitations both on how large the file is allowed to become, and how many versions of the file will be saved each time the file is opened. .Pp The .Ic size option for files is simply a hard ceiling on log growth. If the file ever exceeds the size, then .Nm named will just not write anything more to it until the file is reopened; exceeding the size does not automatically trigger a reopen. The default behavior is to not limit the size of the file. .Pp If you use the .Ic version logfile option, then .Nm named will retain that many backup versions of the file by renaming them when opening. For example, if you choose to keep 3 old versions of the file lamers.log then just before it is opened lamers.log.1 is renamed to lames.log.2, lamers.log.0 is renamed to lamers.log.1, and lamers.log is renamed to lamers.log.0. No rolled versions are kept by default; any existing log file is simply appended. The .Li unlimited keyword is synonymous with .Li 99 in current BIND releases. Example usage of size and versions options: .Bd -literal channel an_example_level { file "lamers.log" versions 3 size 20m; print-time yes; print-category yes; }; .Ed .Pp The argument for the .Ic syslog clause is a syslog facility as described in the .Xr syslog 3 manual page. How .Nm syslogd will handle messages sent to this facility is described in the .Xr syslog.conf 5 manual page. If you have a system which uses a very old version of syslog that only uses two arguments to the .Fn openlog function, then this clause is silently ignored. .Pp The .Ic severity clause works like syslog's ``priorities'', except that they can also be used if you are writing straight to a file rather than using syslog. Messages which are not at least of the severity level given will not be selected for the channel; messages of higher severity levels will be accepted. .Pp If you are using syslog, then the .Pa syslog.conf priorities will also determine what eventually passes through. For example, defining a channel facility and severity as .Li daemon and .Li debug but only logging .Li daemon.warning via .Pa syslog.conf will cause messages of severity .Li info and .Li notice to be dropped. If the situation were reversed, with .Nm named writing messages of only .Li warning or higher, then .Nm syslogd would print all messages it received from the channel. .Pp The server can supply extensive debugging information when it is in debugging mode. If the server's global debug level is greater than zero, then debugging mode will be active. The global debug level is set either by starting the .Nm named server with the .Fl d flag followed by a positive integer, or by sending the running server the .Dv SIGUSR1 signal (for example, by using .Ic ndc trace ) . The global debug level can be set to zero, and debugging mode turned off, by sending the server the .Dv SIGUSR2 signal (as with .Ic ndc notrace ) . All debugging messages in the server have a debug level, and higher debug levels give more more detailed output. Channels that specify a specific debug severity, e.g. .Bd -literal channel specific_debug_level { file \&"foo\&"; severity debug 3; }; .Ed .Pp will get debugging output of level 3 or less any time the server is in debugging mode, regardless of the global debugging level. Channels with .Li dynamic severity use the server's global level to determine what messages to print. .Pp If .Ic print-time has been turned on, then the date and time will be logged. .Ic print-time may be specified for a syslog channel, but is usually pointless since syslog also prints the date and time. If .Ic print-category is requested, then the category of the message will be logged as well. Finally, if .Ic print-severity is on, then the severity level of the message will be logged. The .Ic print- options may be used in any combination, and will always be printed in the following order: time, category, severity. Here is an example where all three .Ic print- options are on: .Bd -literal 28-Apr-1997 15:05:32.863 default: notice: Ready to answer queries. .Ed .Pp There are four predefined channels that are used for default logging as follows. How they are used used is described in the next section, .Sx The category phrase . .Bd -literal channel default_syslog { syslog daemon; # send to syslog's daemon facility severity info; # only send priority info and higher }; .Pp channel default_debug { file \&"named.run\&"; # write to named.run in the working directory # Note: stderr is used instead of \&"named.run\&" # if the server is started with the -f option. severity dynamic; # log at the server's current debug level }; .Pp channel default_stderr { # writes to stderr file \&"\&"; # this is illustrative only; there's currently # no way of specifying an internal file # descriptor in the configuration language. severity info; # only send priority info and higher }; .Pp channel null { null; # toss anything sent to this channel }; .Ed .Pp Once a channel is defined, it cannot be redefined. Thus you cannot alter the built-in channels directly, but you can modify the default logging by pointing categories at channels you have defined. .Ss The category phrase There are many categories, so you can send the logs you want to see wherever you want, without seeing logs you don't want. If you don't specify a list of channels for a category, then log messages in that category will be sent to the .Li default category instead. If you don't specify a default category, the following ``default default'' is used: .Bd -literal category default { default_syslog; default_debug; }; .Ed .Pp As an example, let's say you want to log security events to a file, but you also want keep the default logging behavior. You'd specify the following: .Bd -literal channel my_security_channel { file \&"my_security_file\&"; severity info; }; category security { my_security_channel; default_syslog; default_debug; }; .Ed .Pp To discard all messages in a category, specify the .Li null channel: .Bd -literal category lame-servers { null; }; category cname { null; }; .Ed .Pp The following categories are available: .Bl -tag -width 0n .It Ic default The catch-all. Many things still aren't classified into categories, and they all end up here. Also, if you don't specify any channels for a category, the default category is used instead. If you do not define the default category, the following definition is used: .Dl category default { default_syslog; default_debug; }; .It Ic config High-level configuration file processing. .It Ic parser Low-level configuration file processing. .It Ic queries A short log message is generated for every query the server receives. .It Ic lame-servers Messages like ``Lame server on ...'' .It Ic statistics Statistics. .It Ic panic If the server has to shut itself down due to an internal problem, it will log the problem in this category as well as in the problem's native category. If you do not define the panic category, the following definition is used: .Dl category panic { default_syslog; default_stderr; }; .It Ic update Dynamic updates. +.It Ic update-security +Denied dynamic updates due to access controls. .It Ic ncache Negative caching. .It Ic xfer-in Zone transfers the server is receiving. .It Ic xfer-out Zone transfers the server is sending. .It Ic db All database operations. .It Ic eventlib Debugging info from the event system. Only one channel may be specified for this category, and it must be a file channel. If you do not define the eventlib category, the following definition is used: .Dl category eventlib { default_debug; }; .It Ic packet Dumps of packets received and sent. Only one channel may be specified for this category, and it must be a file channel. If you do not define the packet category, the following definition is used: .Dl category packet { default_debug; }; .It Ic notify The NOTIFY protocol. .It Ic cname Messages like ``... points to a CNAME''. .It Ic security Approved/unapproved requests. .It Ic os Operating system problems. .It Ic insist Internal consistency check failures. .It Ic maintenance Periodic maintenance events. .It Ic load Zone loading messages. .It Ic response-checks Messages arising from response checking, such as ``Malformed response ...'', ``wrong ans. name ...'', ``unrelated additional info ...'', ``invalid RR type ...'', and ``bad referral ...''. .El .Sh THE OPTIONS STATEMENT .Ss Syntax .Bd -literal options { [ hostname \fIhostname_string\fR; ] [ version \fIversion_string\fR; ] [ directory \fIpath_name\fR; ] [ named-xfer \fIpath_name\fR; ] [ dump-file \fIpath_name\fR; ] [ memstatistics-file \fIpath_name\fR; ] [ pid-file \fIpath_name\fR; ] [ statistics-file \fIpath_name\fR; ] [ auth-nxdomain \fIyes_or_no\fR; ] [ deallocate-on-exit \fIyes_or_no\fR; ] [ dialup \fIyes_or_no\fR; ] [ fake-iquery \fIyes_or_no\fR; ] [ fetch-glue \fIyes_or_no\fR; ] [ has-old-clients \fIyes_or_no\fR; ] [ host-statistics \fIyes_or_no\fR; ] [ host-statistics-max \fInumber\fR; ] [ multiple-cnames \fIyes_or_no\fR; ] [ notify ( \fIyes_or_no\fR | explicit ); ] [ suppress-initial-notify \fIyes_or_no\fR; ] [ recursion \fIyes_or_no\fR; ] [ rfc2308-type1 \fIyes_or_no\fR; ] [ use-id-pool \fIyes_or_no\fR; ] [ treat-cr-as-space \fIyes_or_no\fR; ] [ also-notify \fIyes_or_no\fR; ] [ forward ( only | first ); ] [ forwarders { [ \fIin_addr\fR ; [ \fIin_addr\fR ; ... ] ] }; ] [ check-names ( master | slave | response ) ( warn | fail | ignore ); ] [ allow-query { \fIaddress_match_list\fR }; ] [ allow-recursion { \fIaddress_match_list\fR }; ] [ allow-transfer { \fIaddress_match_list\fR }; ] [ blackhole { \fIaddress_match_list\fR }; ] [ listen-on [ port \fIip_port\fR ] { \fIaddress_match_list\fR }; ] [ query-source [ address ( \fIip_addr\fR | * ) ] [ port ( \fIip_port\fR | * ) ] ; ] [ lame-ttl \fInumber\fR; ] [ max-transfer-time-in \fInumber\fR; ] [ max-ncache-ttl \fInumber\fR; ] [ min-roots \fInumber\fR; ] [ serial-queries \fInumber\fR; ] [ transfer-format ( one-answer | many-answers ); ] [ transfers-in \fInumber\fR; ] [ transfers-out \fInumber\fR; ] [ transfers-per-ns \fInumber\fR; ] [ transfer-source \fIip_addr\fR; ] [ maintain-ixfr-base \fIyes_or_no\fR; ] [ max-ixfr-log-size \fInumber\fR; ] [ coresize \fIsize_spec\fR ; ] [ datasize \fIsize_spec\fR ; ] [ files \fIsize_spec\fR ; ] [ stacksize \fIsize_spec\fR ; ] [ cleaning-interval \fInumber\fR; ] [ heartbeat-interval \fInumber\fR; ] [ interface-interval \fInumber\fR; ] [ statistics-interval \fInumber\fR; ] [ topology { \fIaddress_match_list\fR }; ] [ sortlist { \fIaddress_match_list\fR }; ] [ rrset-order { \fIorder_spec\fR ; [ \fIorder_spec\fR ; ... ] }; ] [ preferred-glue ( A | AAAA ); ] }; .Ed .Ss Definition and Usage The options statement sets up global options to be used by BIND. This statement may appear at only once in a configuration file; if more than one occurrence is found, the first occurrence determines the actual options used, and a warning will be generated. If there is no options statement, an options block with each option set to its default will be used. .Ss Server Information .Bl -tag -width 0n .It Ic hostname This defaults to the hostname of the machine hosting the nameserver as found by gethostname(). Its prime purpose is to be able to identify which of a number of anycast servers is actually answering your queries by sending a txt query for .Pa hostname.bind in class chaos to the anycast server and geting back a unique name. Setting the hostname to a empty string ("") will disable processing of the queries. .It Ic version The version the server should report via the ndc command or via a query of name .Pa version.bind in class chaos. The default is the real version number of the server, but some server operators prefer the string ( .Ic surely you must be joking ). .El .Ss Pathnames .Bl -tag -width 0n .It Ic directory The working directory of the server. Any non-absolute pathnames in the configuration file will be taken as relative to this directory. The default location for most server output files (e.g. .Pa named.run ) is this directory. If a directory is not specified, the working directory defaults to .Pa \&. , the directory from which the server was started. The directory specified should be an absolute path. .It Ic named-xfer The pathname to the named-xfer program that the server uses for inbound zone transfers. If not specified, the default is system dependent (e.g. .Pa /usr/sbin/named-xfer ). .It Ic dump-file The pathname of the file the server dumps the database to when it receives .Dv SIGINT signal (as sent by .Ic ndc dumpdb ). If not specified, the default is .Pa named_dump.db . .It Ic memstatistics-file The pathname of the file the server writes memory usage statistics to on exit, if .Ic deallocate-on-exit is .Li yes . If not specified, the default is .Pa named.memstats . .It Ic pid-file The pathname of the file the server writes its process ID in. If not specified, the default is operating system dependent, but is usually .Pa /var/run/named.pid or .Pa /etc/named.pid . The pid-file is used by programs like .Nm ndc that want to send signals to the running nameserver. .It Ic statistics-file The pathname of the file the server appends statistics to when it receives .Dv SIGILL signal (from .Ic ndc stats ) . If not specified, the default is .Pa named.stats . .El .Ss Boolean Options .Bl -tag -width 0n .It Ic auth-nxdomain If .Li yes , then the .Li AA bit is always set on .Dv NXDOMAIN responses, even if the server is not actually authoritative. The default is -.Li yes . -Do not turn off -.Ic auth-nxdomain -unless you are sure you know what you are -doing, as some older software won't like it. +.Li no . +Turning +.Lc auth-nxdomain +will allow older clients that require +.Li AA +to be set to accept +.Dv NXDOMAIN +responses to work. .It Ic deallocate-on-exit If .Li yes , then when the server exits it will painstakingly deallocate every object it allocated, and then write a memory usage report to the .Ic memstatistics-file . The default is .Li no , because it is faster to let the operating system clean up. .Ic deallocate-on-exit is handy for detecting memory leaks. .It Ic dialup If .Li yes , then the server treats all zones as if they are doing zone transfers across a dial on demand dialup link, which can be brought up by traffic originating from this server. This has different effects according to zone type and concentrates the zone maintenance so that it all happens in a short interval, once every .Ic heartbeat-interval and hopefully during the one call. It also suppresses some of the normal zone maintenance traffic. The default is .Li no . The .Ic dialup option may also be specified in the .Ic zone statement, in which case it overrides the .Ic options dialup statement. .Pp If the zone is a .Ic master then the server will send out .Dv NOTIFY request to all the slaves. This will trigger the zone up to date checking in the slave (providing it supports .Dv NOTIFY ) allowing the slave to verify the zone while the call us up. .Pp If the zone is a .Ic slave or .Ic stub then the server will suppress the zone regular zone up to date queries and only perform the when the .Ic heartbeat-interval expires. .It Ic fake-iquery If .Li yes , the server will simulate the obsolete DNS query type .Dv IQUERY . The default is .Li no . .It Ic fetch-glue If .Li yes (the default), the server will fetch ``glue'' resource records it doesn't have when constructing the additional data section of a response. .Ic fetch-glue no can be used in conjunction with .Ic recursion no to prevent the server's cache from growing or becoming corrupted (at the cost of requiring more work from the client). .It Ic has-old-clients Setting the option to .Li yes , is equivalent to setting the following three options: .Ic auth-nxdomain yes ; , .Ic maintain-ixfr-base yes ; , and .Ic rfc2308-type1 no ; .Pp The use of .Ic has-old-clients with .Ic auth-nxdomain , .Ic maintain-ixfr-base , and .Ic rfc2308-type1 is order dependant. .It Ic host-statistics If .Li yes , then statistics are kept for every host that the the nameserver interacts with. The default is .Li no . .Em Note : turning on .Ic host-statistics can consume huge amounts of memory. .It Ic maintain-ixfr-base If .Li yes , a IXFR database file is kept for all dynamicaly updated zones. This enables the server to answer IXFR queries which can speed up zone transfers enormously. The default is .Li no . .It Ic multiple-cnames If .Li yes , then multiple CNAME resource records will be allowed for a domain name. The default is .Li no . Allowing multiple CNAME records is against standards and is not recommended. Multiple CNAME support is available because previous versions of BIND allowed multiple CNAME records, and these records have been used for load balancing by a number of sites. .It Ic notify If .Li yes (the default), DNS NOTIFY messages are sent when a zone the server is authoritative for changes. The use of NOTIFY speeds convergence between the master and its slaves. Slave servers that receive a NOTIFY message and understand it will contact the master server for the zone and see if they need to do a zone transfer, and if they do, they will initiate it immediately. If .Li explicit , the DNS NOTIFY messages will only be sent to the addresses in the .Ic also-notify list. The .Ic notify option may also be specified in the .Ic zone statement, in which case it overrides the .Ic options notify statement. .It Ic suppress-initial-notify If .Li yes , suppress the initial notify messages when the server first loads. The default is .Li no . .It Ic recursion If .Li yes , and a DNS query requests recursion, then the server will attempt to do all the work required to answer the query. If recursion is not on, the server will return a referral to the client if it doesn't know the answer. The default is .Li yes . See also .Ic fetch-glue above. .It Ic rfc2308-type1 If .Li yes, the server will send NS records along with the SOA record for negative answers. You need to set this to no if you have an old BIND server using you as a forwarder that does not understand negative answers which contain both SOA and NS records or you have an old version of sendmail. The correct fix is to upgrade the broken server or sendmail. The default is .Li no . .It Ic use-id-pool If .Li yes, the server will keep track of its own outstanding query ID's to avoid duplication and increase randomness. This will result in 128KB more memory being consumed by the server. The default is .Li no . .It Ic treat-cr-as-space If .Li yes, the server will treat CR characters the same way it treats a space or tab. This may be necessary when loading zone files on a UNIX system that were generated on an NT or DOS machine. The default is .Li no . .El .Ss Also-Notify .Ic also-notify .Pp Defines a global list of IP addresses that also get sent NOTIFY messages whenever a fresh copy of the zone is loaded. This helps to ensure that copies of the zones will quickly converge on ``stealth'' servers. If an .Ic also-notify list is given in a .Ic zone statement, it will override the .Ic options also-notify statement. When a .Ic zone notify statement is set to .Ic no , the IP addresses in the global .Ic also-notify list will not get sent NOTIFY messages for that zone. The default is the empty list (no global notification list). .Ss Forwarding The forwarding facility can be used to create a large site-wide cache on a few servers, reducing traffic over links to external nameservers. It can also be used to allow queries by servers that do not have direct access to the Internet, but wish to look up exterior names anyway. Forwarding occurs only on those queries for which the server is not authoritative and does not have the answer in its cache. .Bl -tag -width 0n .It Ic forward This option is only meaningful if the .Ic forwarders list is not empty. A value of .Li first , the default, causes the server to query the forwarders first, and if that doesn't answer the question the server will then look for the answer itself. If .Li only is specified, the server will only query the forwarders. .It Ic forwarders Specifies the IP addresses to be used for forwarding. The default is the empty list (no forwarding). .El .Pp Forwarding can also be configured on a per-zone basis, allowing for the global forwarding options to be overridden in a variety of ways. You can set particular zones to use different forwarders, or have different .Ic forward only/first behavior, or to not forward at all. See .Sx THE ZONE STATEMENT section for more information. .Pp Future versions of BIND 8 will provide a more powerful forwarding system. The syntax described above will continue to be supported. .Ss Name Checking The server can check domain names based upon their expected client contexts. For example, a domain name used as a hostname can be checked for compliance with the RFCs defining valid hostnames. .Pp Three checking methods are available: .Bl -tag -width 0n .It Ic ignore No checking is done. .It Ic warn Names are checked against their expected client contexts. Invalid names are logged, but processing continues normally. .It Ic fail Names are checked against their expected client contexts. Invalid names are logged, and the offending data is rejected. .El .Pp The server can check names three areas: master zone files, slave zone files, and in responses to queries the server has initiated. If .Ic check-names response fail has been specified, and answering the client's question would require sending an invalid name to the client, the server will send a .Dv REFUSED response code to the client. .Pp The defaults are: .Bd -literal check-names master fail; check-names slave warn; check-names response ignore; .Ed .Pp .Ic check-names may also be specified in the .Ic zone statement, in which case it overrides the .Ic options check-names statement. When used in a .Ic zone statement, the area is not specified (because it can be deduced from the zone type). .Ss Access Control Access to the server can be restricted based on the IP address of the requesting system or via shared secret keys. See .Sx ADDRESS MATCH LISTS for details on how to specify access criteria. .Bl -tag -width 0n .It Ic allow-query Specifies which hosts are allowed to ask ordinary questions. .Ic allow-query may also be specified in the .Ic zone statement, in which case it overrides the .Ic options allow-query statement. If not specified, the default is to allow queries from all hosts. .Bl -tag -width 0n .It Ic allow-recursion Specifies which hosts are allowed to ask recursive questions. If not specified, the default is to allow recursive queries from all hosts. .It Ic allow-transfer Specifies which hosts are allowed to receive zone transfers from the server. .Ic allow-transfer may also be specified in the .Ic zone statement, in which case it overrides the .Ic options allow-transfer statement. If not specified, the default is to allow transfers from all hosts. .It Ic blackhole Specifies a list of addresses that the server will not accept queries from or use to resolve a query. Queries from these addresses will not be responded to. .El .El .Ss Interfaces The interfaces and ports that the server will answer queries from may be specified using the .Ic listen-on option. .Ic listen-on takes an optional port, and an address match list. The server will listen on all interfaces allowed by the address match list. If a port is not specified, port 53 will be used. .Pp Multiple .Ic listen-on statements are allowed. For example, .Bd -literal listen-on { 5.6.7.8; }; listen-on port 1234 { !1.2.3.4; 1.2/16; }; .Ed .Pp will enable the nameserver on port 53 for the IP address 5.6.7.8, and on port 1234 of an address on the machine in net 1.2 that is not 1.2.3.4. .Pp If no .Ic listen-on is specified, the server will listen on port 53 on all interfaces. .Ss Query Address If the server doesn't know the answer to a question, it will query other nameservers. .Ic query-source specifies the address and port used for such queries. If .Ic address is .Li * or is omitted, a wildcard IP address ( .Dv INADDR_ANY ) will be used. If .Va port is .Li * or is omitted, a random unprivileged port will be used. The default is .Dl query-source address * port *; .Pp Note: .Ic query-source currently applies only to UDP queries; TCP queries always use a wildcard IP address and a random unprivileged port. .Ss Zone Transfers .Bl -tag -width 0n .It Ic max-transfer-time-in Inbound zone transfers ( .Nm named-xfer processes) running longer than this many minutes will be terminated. The default is 120 minutes (2 hours). .It Ic transfer-format The server supports two zone transfer methods. .Li one-answer uses one DNS message per resource record transferred. .Li many-answers packs as many resource records as possible into a message. .Li many-answers is more efficient, but is only known to be understood by BIND 8.1 and patched versions of BIND 4.9.5. The default is .Li one-answer . .Ic transfer-format may be overridden on a per-server basis by using the .Ic server statement. .It Ic transfers-in The maximum number of inbound zone transfers that can be running concurrently. The default value is 10. Increasing .Ic transfers-in may speed up the convergence of slave zones, but it also may increase the load on the local system. .It Ic transfers-out This option will be used in the future to limit the number of concurrent outbound zone transfers. It is checked for syntax, but is otherwise ignored. .It Ic transfers-per-ns The maximum number of inbound zone transfers ( .Nm named-xfer processes) that can be concurrently transferring from a given remote nameserver. The default value is 2. Increasing .Ic transfers-per-ns may speed up the convergence of slave zones, but it also may increase the load on the remote nameserver. .Ic transfers-per-ns may be overridden on a per-server basis by using the .Ic transfers phrase of the .Ic server statement. .It Ic transfer-source .Nm transfer-source determines which local address will be bound to the TCP connection used to fetch all zones transferred inbound by the server. If not set, it defaults to a system controlled value which will usually be the address of the interface ``closest to`` the remote end. This address must appear in the remote end's .Nm allow-transfer option for the zones being transferred, if one is specified. This statement sets the .Nm transfer-source for all zones, but can be overriden on a per-zone basis by includinga .Nm transfer-source statement within the zone block in the configuration file. .El .Ss Resource Limits The server's usage of many system resources can be limited. Some operating systems don't support some of the limits. On such systems, a warning will be issued if the unsupported limit is used. Some operating systems don't support limiting resources, and on these systems a .D1 cannot set resource limits on this system message will be logged. .Pp Scaled values are allowed when specifying resource limits. For example, .Li 1G can be used instead of .Li 1073741824 to specify a limit of one gigabyte. .Li unlimited requests unlimited use, or the maximum available amount. .Li default uses the limit that was in force when the server was started. See the definition of .Va size_spec in the .Sx DOCUMENTATION DEFINITIONS section for more details. .Bl -tag -width 0n .It Ic coresize The maximum size of a core dump. The default value is .Li default . .It Ic datasize The maximum amount of data memory the server may use. The default value is .Li default . .It Ic files The maximum number of files the server may have open concurrently. The default value is .Li unlimited . Note that on some operating systems the server cannot set an unlimited value and cannot determine the maximum number of open files the kernel can support. On such systems, choosing .Li unlimited will cause the server to use the larger of the .Va rlim_max from .Fn getrlimit RLIMIT_NOFILE and the value returned by .Fn sysconf _SC_OPEN_MAX . If the actual kernel limit is larger than this value, use .Ic limit files to specify the limit explicitly. .It Ic max-ixfr-log-size The .Li max-ixfr-log-size will be used in a future release of the server to limit the size of the transaction log kept for Incremental Zone Transfer. .It Ic stacksize The maximum amount of stack memory the server may use. The default value is .Li default . .El .Ss Periodic Task Intervals .Bl -tag -width 0n .It Ic cleaning-interval The server will remove expired resource records from the cache every .Ic cleaning-interval minutes. The default is 60 minutes. If set to 0, no periodic cleaning will occur. .It Ic heartbeat-interval The server will perform zone maintenance tasks for all zones marked .Ic dialup yes whenever this interval expires. The default is 60 minutes. Reasonable values are up to 1 day (1440 minutes). If set to 0, no zone maintenance for these zones will occur. .It Ic interface-interval The server will scan the network interface list every .Ic interface-interval minutes. The default is 60 minutes. If set to 0, interface scanning will only occur when the configuration file is loaded. After the scan, listeners will be started on any new interfaces (provided they are allowed by the .Ic listen-on configuration). Listeners on interfaces that have gone away will be cleaned up. .It Ic statistics-interval Nameserver statistics will be logged every .Ic statistics-interval minutes. The default is 60. If set to 0, no statistics will be logged. .El .Ss Topology All other things being equal, when the server chooses a nameserver to query from a list of nameservers, it prefers the one that is topologically closest to itself. The .Ic topology statement takes an address match list and interprets it in a special way. Each top-level list element is assigned a distance. Non-negated elements get a distance based on their position in the list, where the closer the match is to the start of the list, the shorter the distance is between it and the server. A negated match will be assigned the maximum distance from the server. If there is no match, the address will get a distance which is further than any non-negated list element, and closer than any negated element. For example, .Bd -literal topology { 10/8; !1.2.3/24; { 1.2/16; 3/8; }; }; .Ed .Pp will prefer servers on network 10 the most, followed by hosts on network 1.2.0.0 (netmask 255.255.0.0) and network 3, with the exception of hosts on network 1.2.3 (netmask 255.255.255.0), which is preferred least of all. .Pp The default topology is .Dl topology { localhost; localnets; }; .Ss Resource Record sorting When returning multiple RRs, the nameserver will normally return them in .Ic Round Robin , i.e. after each request, the first RR is put to the end of the list. As the order of RRs is not defined, this should not cause any problems. .Pp The client resolver code should re-arrange the RRs as appropriate, i.e. using any addresses on the local net in preference to other addresses. However, not all resolvers can do this, or are not correctly configured. .Pp When a client is using a local server, the sorting can be performed in the server, based on the client's address. This only requires configuring the nameservers, not all the clients. .Pp The .Ic sortlist statement takes an address match list and interprets it even more specially than the .Ic topology statement does. .Pp Each top level statement in the sortlist must itself be an explicit address match list with one or two elements. The first element (which may be an IP address, an IP prefix, an ACL name or nested address match list) of each top level list is checked against the source address of the query until a match is found. .Pp Once the source address of the query has been matched, if the top level statement contains only one element, the actual primitive element that matched the source address is used to select the address in the response to move to the beginning of the response. If the statement is a list of two elements, the second element is treated like the address match list in a topology statement. Each top level element is assigned a distance and the address in the response with the minimum distance is moved to the beginning of the response. .Pp In the following example, any queries received from any of the addresses of the host itself will get responses preferring addresses on any of the locally connected networks. Next most preferred are addresses on the 192.168.1/24 network, and after that either the 192.168.2/24 or 192.168.3/24 network with no preference shown between these two networks. Queries received from a host on the 192.168.1/24 network will prefer other addresses on that network to the 192.168.2/24 and 192.168.3/24 networks. Queries received from a host on the 192.168.4/24 or the 192.168.5/24 network will only prefer other addresses on their directly connected networks. .Bd -literal sortlist { { localhost; // IF the local host { localnets; // THEN first fit on the 192.168.1/24; // following nets { 192,168.2/24; 192.168.3/24; }; }; }; { 192.168.1/24; // IF on class C 192.168.1 { 192.168.1/24; // THEN use .1, or .2 or .3 { 192.168.2/24; 192.168.3/24; }; }; }; { 192.168.2/24; // IF on class C 192.168.2 { 192.168.2/24; // THEN use .2, or .1 or .3 { 192.168.1/24; 192.168.3/24; }; }; }; { 192.168.3/24; // IF on class C 192.168.3 { 192.168.3/24; // THEN use .3, or .1 or .2 { 192.168.1/24; 192.168.2/24; }; }; }; { { 192.168.4/24; 192.168.5/24; }; // if .4 or .5, prefer that net }; }; .Ed .Pp The following example will give reasonable behaviour for the local host and hosts on directly connected networks. It is similar to the behavior of the address sort in BIND 4.9.x. Responses sent to queries from the local host will favor any of the directly connected networks. Responses sent to queries from any other hosts on a directly connected network will prefer addresses on that same network. Responses to other queries will not be sorted. .Bd -literal sortlist { { localhost; localnets; }; { localnets; }; }; .Ed .Ss RRset Ordering When multiple records are returned in an answer it may be useful to configure the order the records are placed into the response. For example the records for a zone might be configured to always be returned in the order they are defined in the zone file. Or perhaps a random shuffle of the records as they are returned is wanted. The rrset-order statement permits configuration of the ordering made of the records in a multiple record response. The default, if no ordering is defined, is a cyclic ordering (round robin). .Pp An .Ic order_spec is defined as follows: .Bd -literal [ \fIclass class_name\fR ][ \fItype type_name\fR ][ \fIname\fR "FQDN" ] \fIorder\fR ordering .Ed .Pp If no class is specified, the default is .Ic ANY . If no .Li Ictype is specified, the default is .Ic ANY . If no name is specified, the default is "*". .Pp The legal values for .Ic ordering are: .Bl -tag -width indent .It Ic fixed Records are returned in the order they are defined in the zone file. .It Ic random Records are returned in some random order. .It Ic cyclic Records are returned in a round-robin order. .El .Pp For example: .Bd -literal rrset-order { class IN type A name "rc.vix.com" order random; order cyclic; }; .Ed .Pp will cause any responses for type A records in class IN that have "rc.vix.com" as a suffix, to always be returned in random order. All other records are returned in cyclic order. .Pp If multiple .Ic rrset-order statements appear, they are not combined--the last one applies. .Pp If no .Ic rrset-order statement is specified, a default one of: .Bd -literal rrset-order { class ANY type ANY name "*" order cyclic ; }; .Ed .Pp is used. .Ss Glue Ordering When running a root nameserver it is sometimes necessary to ensure that other nameservers that are priming are successful. This requires that glue A records for at least of the nameservers are returned in the answer to a priming query. This can be achieved by setting .Ic preferred-glue A; which will add A records before other types in the additional section. .Ss Tuning .Bl -tag -width 0n .It Ic lame-ttl Sets the number of seconds to cache a lame server indication. 0 disables caching. Default is 600 (10 minutes). Maximum value is 1800 (30 minutes) .It Ic max-ncache-ttl To reduce network traffic and increase performance the server store negative answers. .Ic max-ncache-ttl is used to set a maximum retention time for these answers in the server is seconds. The default .Ic max-ncache-ttl is 10800 seconds (3 hours). .Ic max-ncache-ttl cannot exceed the maximum retention time for ordinary (positive) answers (7 days) and will be silently truncated to 7 days if set to a value which is greater that 7 days. .It Ic min-roots The minimum number of root servers that is required for a request for the root servers to be accepted. Default is 2. .El .Sh THE ZONE STATEMENT .Ss Syntax .Bd -literal zone \fIdomain_name\fR [ ( in | hs | hesiod | chaos ) ] { type master; file \fIpath_name\fR; [ check-names ( warn | fail | ignore ); ] [ allow-update { \fIaddress_match_list\fR }; ] [ allow-query { \fIaddress_match_list\fR }; ] [ allow-transfer { \fIaddress_match_list\fR }; ] [ forward ( only | first ); ] [ forwarders { [ \fIip_addr\fR ; [ \fIip_addr\fR ; ... ] ] }; ] [ dialup \fIyes_or_no\fR; ] [ notify ( \fIyes_or_no\fR | explicit ); ] [ also-notify { \fIip_addr\fR; [ \fIip_addr\fR; ... ] }; [ pubkey \fInumber\fR \fInumber\fR \fInumber\fR \fIstring\fR; ] }; .Pp zone \fIdomain_name\fR [ ( in | hs | hesiod | chaos ) ] { type ( slave | stub ); [ file \fIpath_name\fR; ] masters [ port \fIip_port\fR ] { \fIip_addr\fR [ key \fIkey_id\fR ]; [ ... ] }; [ check-names ( warn | fail | ignore ); ] [ allow-update { \fIaddress_match_list\fR }; ] [ allow-query { \fIaddress_match_list\fR }; ] [ allow-transfer { \fIaddress_match_list\fR }; ] [ forward ( only | first ); ] [ forwarders { [ \fIip_addr\fR ; [ \fIip_addr\fR ; ... ] ] }; ] [ transfer-source \fIip_addr\fR; ] [ max-transfer-time-in \fInumber\fR; ] [ notify \fIyes_or_no\fR; ] [ also-notify { \fIip_addr\fR; [ \fIip_addr\fR; ... ] }; [ pubkey \fInumber\fR \fInumber\fR \fInumber\fR \fIstring\fR; ] }; .Pp zone \fIdomain_name\fR [ ( in | hs | hesiod | chaos ) ] { type forward; [ forward ( only | first ); ] [ forwarders { [ \fIip_addr\fR ; [ \fIip_addr\fR ; ... ] ] }; ] [ check-names ( warn | fail | ignore ); ] }; .Pp zone \&".\&" [ ( in | hs | hesiod | chaos ) ] { type hint; file \fIpath_name\fR; [ check-names ( warn | fail | ignore ); ] }; .Ed .Ss Definition and Usage The .Ic zone statement is used to define how information about particular DNS zones is managed by the server. There are five different zone types. .Bl -tag -width 0n .It Ic master The server has a master copy of the data for the zone and will be able to provide authoritative answers for it. .It Ic slave A .Ic slave zone is a replica of a master zone. The .Ic masters list specifies one or more IP addresses that the slave contacts to update its copy of the zone. If a .Ic port is specified then checks to see if the zone is current and zone transfers will be done to the port given. If .Ic file is specified, then the replica will be written to the named file. Use of the .Ic file clause is highly recommended, since it often speeds server startup and eliminates a needless waste of bandwidth. .It Ic stub A .Ic stub zone is like a slave zone, except that it replicates only the NS records of a master zone instead of the entire zone. .It Ic forward A .Ic forward zone is used to direct all queries in it to other servers, as described in .Sx THE OPTIONS STATEMENT section. The specification of options in such a zone will override any global options declared in the .Ic options statement. .Pp If either no .Ic forwarders clause is present in the zone or an empty list for .Ic forwarders is given, then no forwarding will be done for the zone, cancelling the effects of any .Ic forwarders in the .Ic options statement. Thus if you want to use this type of zone to change only the behavior of the global .Ic forward option, and not the servers used, then you also need to respecify the global forwarders. .It Ic hint The initial set of root nameservers is specified using a .Ic hint zone. When the server starts up, it uses the root hints to find a root nameserver and get the most recent list of root nameservers. .El .Pp Note: previous releases of BIND used the term .Ic primary for a master zone, .Ic secondary for a slave zone, and .Ic cache for a hint zone. .Ss Classes The zone's name may optionally be followed by a class. If a class is not specified, class .Ic in (for "internet"), is assumed. This is correct for the vast majority of cases. .Pp The .Ic hesiod class is for an information service from MIT's Project Athena. It is used to share information about various systems databases, such as users, groups, printers and so on. More information can be found at ftp://athena-dist.mit.edu/pub/ATHENA/usenix/athena_changes.PS. The keyword .Ic hs is a synonym for .Ic hesiod . .Pp Another MIT development was CHAOSnet, a LAN protocol created in the mid-1970s. It is still sometimes seen on LISP stations and other hardware in the AI community, and zone data for it can be specified with the .Ic chaos class. .Ss Options .Bl -tag -width 0n .It Ic check-names See the subsection on .Sx Name Checking in .Sx THE OPTIONS STATEMENT . .It Ic allow-query See the description of .Ic allow-query in the .Sx Access Control subsection of .Sx THE OPTIONS STATEMENT . .It Ic allow-update Specifies which hosts are allowed to submit Dynamic DNS updates to the server. The default is to deny updates from all hosts. .It Ic allow-transfer See the description of .Ic allow-transfer in the .Sx Access Control subsection of .Sx THE OPTIONS STATEMENT . .It Ic transfer-source .Ic transfer-source determines which local address will be bound to the TCP connection used to fetch this zone. If not set, it defaults to a system controlled value which will usually be the address of the interface ``closest to'' the remote end. This address must appear in the remote end's .Ic allow-transfer option for this zone if one is specified. .It Ic max-transfer-time-in See the description of .Ic max-transfer-time-in in the .Sx Zone Transfers subsection of .Sx THE OPTIONS STATEMENT . .It Ic dialup See the description of .Ic dialup in the .Sx Boolean Options subsection of .Sx THE OPTIONS STATEMENT . .It Ic notify See the description of .Sx notify in the .Sx Boolean Options subsection of the .Sx THE OPTIONS STATEMENT . .It Ic also-notify .Ic also-notify is only meaningful if .Ic notify is active for this zone. The set of machines that will receive a DNS NOTIFY message for this zone is made up of all the listed nameservers for the zone (other than the primary master) plus any IP addresses specified with .Ic also-notify . .Ic also-notify is not meaningful for .Ic stub zones. The default is the empty list. .It Ic forward .Ic forward is only meaningful if the zone has a .Ic forwarders list. The .Ic only value causes the lookup to fail after trying the .Ic forwarders and getting no answer, while .Ic first would allow a normal lookup to be tried. .It Ic forwarders The .Ic forwarders option in a zone is used to override the list of global forwarders. If it is not specified in a zone of type .Ic forward , .Em no forwarding is done for the zone; the global options are not used. .It Ic pubkey The DNSSEC flags, protocol, and algorithm are specified, as well as a base-64 encoded string representing the key. .El .Sh THE ACL STATEMENT .Ss Syntax .Bd -literal acl \fIname\fR { \fIaddress_match_list\fR }; .Ed .Ss Definition and Usage The .Ic acl statement creates a named address match list. It gets its name from a primary use of address match lists: Access Control Lists (ACLs). .Pp Note that an address match list's name must be defined with .Ic acl before it can be used elsewhere; no forward references are allowed. .Pp The following ACLs are built-in: .Bl -tag -width 0n .It Ic any Allows all hosts. .It Ic none Denies all hosts. .It Ic localhost Allows the IP addresses of all interfaces on the system. .It Ic localnets Allows any host on a network for which the system has an interface. .El .Sh THE KEY STATEMENT .Ss Syntax .Bd -literal key \fIkey_id\fR { algorithm \fIalgorithm_id\fR; secret \fIsecret_string\fR; }; .Ed .Ss Definition and Usage The .Ic key statement defines a key ID which can be used in a .Ic server statement to associate a method of authentication with a particular name server that is more rigorous than simple IP address matching. A key ID must be created with the .Ic key statement before it can be used in a .Ic server definition or an address match list. .Pp The .Va algorithm_id is a string that specifies a security/authentication algorithm. .Va secret_string is the secret to be used by the algorithm, and is treated as a base-64 encoded string. It should go without saying, but probably can't, that if you have .Va secret_string 's in your .Pa named.conf , then it should not be readable by anyone but the superuser. .Sh THE TRUSTED-KEYS STATEMENT .Ss Syntax .Bd -literal trusted-keys { [ \fIdomain_name\fR \fIflags\fR \fIprotocol\fR \fIalgorithm\fR \fIkey\fR; ] }; .Ed .Ss Definition and Usage The .Ic trusted-keys statement is for use with DNSSEC-style security, originally specified in RFC 2065. DNSSEC is meant to provide three distinct services: key distribution, data origin authentication, and transaction and request authentication. A complete description of DNSSEC and its use is beyond the scope of this document, and readers interested in more information should start with RFC 2065 and then continue with the Internet Drafts available at http://www.ietf.org/ids.by.wg/dnssec.html. .Pp Each trusted key is associated with a domain name. Its attributes are the non-negative integral .Va flags , .Va protocol , and .Va algorithm , as well as a base-64 encoded string representing the .Va key . .Pp Any number of trusted keys can be specified. .Sh THE SERVER STATEMENT .Ss Syntax .Bd -literal server \fIip_addr\fR { [ edns \fIyes_or_no\fR; ] [ bogus \fIyes_or_no\fR; ] [ support-ixfr \fIyes_or_no\fR; ] [ transfers \fInumber\fR; ] [ transfer-format ( one-answer | many-answers ); ] [ keys { \fIkey_id\fR [ \fIkey_id\fR ... ] }; ] }; .Ed .Ss Definition and Usage The server statement defines the characteristics to be associated with a remote name server. .Pp If you discover that a server does not support EDNS you can prevent named making EDNS queries to it by specifying .Ic edns .Ic no; . The default value of .Ic edns is .Ic yes . .Pp If you discover that a server is giving out bad data, marking it as .Ic bogus will prevent further queries to it. The default value of .Ic bogus is .Li no . .Pp If the server supports IXFR you can tell named to attempt to perform a IXFR style zone transfer by specifing .Ic support-ixfr .Li yes . The default value of .Ic support-ixfr is .Li no . .Pp The server supports two zone transfer methods. The first, .Ic one-answer , uses one DNS message per resource record transferred. .Ic many-answers packs as many resource records as possible into a message. .Ic many-answers is more efficient, but is only known to be understood by BIND 8.1 and patched versions of BIND 4.9.5. You can specify which method to use for a server with the .Ic transfer-format option. If .Ic transfer-format is not specified, the .Ic transfer-format specified by the .Ic options statement will be used. .Pp The .Ic transfers will be used in a future release of the server to limit the number of concurrent in-bound zone transfers from the specified server. It is checked for syntax but is otherwise ignored. .Pp The .Ic keys clause is used to identify a .Va key_id defined by the .Ic key statement, to be used for transaction security when talking to the remote server. The .Ic key statememnt must come before the .Ic server statement that references it. .Pp The .Ic keys statement is intended for future use by the server. It is checked for syntax but is otherwise ignored. .Sh THE CONTROLS STATEMENT .Ss Syntax .Bd -literal controls { [ inet \fIip_addr\fR port \fIip_port\fR allow { \fIaddress_match_list\fR; }; ] [ unix \fIpath_name\fR perm \fInumber\fR owner \fInumber\fR group \fInumber\fR; ] }; .Ed .Ss Definition and Usage The .Ic controls statement declares control channels to be used by system administrators to affect the operation of the local name server. These control channels are used by the .Nm ndc utility to send commands to and retrieve non-DNS results from a name server. .Pp A .Ic unix control channel is a FIFO in the file system, and access to it is controlled by normal file system permissions. It is created by .Nm named with the specified file mode bits (see .Xr chmod 1 ) , user and group owner. Note that, unlike .Nm chmod , the mode bits specified for .Ic perm will normally have a leading .Li 0 so the number is interpreted as octal. Also note that the user and group ownership specified as .Ic owner and .Ic group must be given as numbers, not names. It is recommended that the permissions be restricted to administrative personnel only, or else any user on the system might be able to manage the local name server. .Pp An .Ic inet control channel is a TCP/IP socket accessible to the Internet, created at the specified .Va ip_port on the specified .Va ip_addr . Modern .Nm telnet clients are capable of speaking directly to these sockets, and the control protocol is ARPAnet-style text. It is recommended that 127.0.0.1 be the only .Va ip_addr used, and this only if you trust all non-privileged users on the local host to manage your name server. .Sh THE INCLUDE STATEMENT .Ss Syntax .Bd -literal include \fIpath_name\fR; .Ed .Ss Definition and Usage The .Ic include statement inserts the specified file at the point that the .Ic include statement is encountered. It cannot be used within another statement, though, so a line such as .Dl acl internal_hosts { include "internal_hosts.acl"; }; is not allowed. .Pp Use .Ic include to break the configuration up into easily-managed chunks. For example: .Bd -literal include "/etc/security/keys.bind"; include "/etc/acls.bind"; .Ed .Pp could be used at the top of a BIND configuration file in order to include any ACL or key information. .Pp Be careful not to type ``#include'', like you would in a C program, because ``#'' is used to start a comment. .Sh EXAMPLES The simplest configuration file that is still realistically useful is one which simply defines a hint zone that has a full path to the root servers file. .Bd -literal zone \&".\&" in { type hint; file \&"/var/named/root.cache\&"; }; .Ed .Pp Here's a more typical real-world example. .Bd -literal /* * A simple BIND 8 configuration */ .Pp logging { category lame-servers { null; }; category cname { null; }; }; .Pp options { directory \&"/var/named\&"; }; .Pp controls { inet * port 52 allow { any; }; // a bad idea unix \&"/var/run/ndc\&" perm 0600 owner 0 group 0; // the default }; .Pp zone \&"isc.org\&" in { type master; file \&"master/isc.org\&"; }; .Pp zone \&"vix.com\&" in { type slave; file \&"slave/vix.com\&"; masters { 10.0.0.53; }; }; .Pp zone \&"0.0.127.in-addr.arpa\&" in { type master; file \&"master/127.0.0\&"; }; .Pp zone \&".\&" in { type hint; file \&"root.cache\&"; }; .Ed .Sh FILES .Bl -tag -width 0n -compact .It Pa /etc/named.conf The BIND 8 .Nm named configuration file. .El .Sh SEE ALSO .Xr named 8 , .Xr ndc 8 Index: vendor/bind/dist/contrib/bind/doc/man/resolver.3 =================================================================== --- vendor/bind/dist/contrib/bind/doc/man/resolver.3 (revision 109982) +++ vendor/bind/dist/contrib/bind/doc/man/resolver.3 (revision 109983) @@ -1,606 +1,608 @@ .\" Copyright (c) 1985, 1995 The Regents of the University of California. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms are permitted provided .\" that: (1) source distributions retain this entire copyright notice and .\" comment, and (2) distributions including binaries display the following .\" acknowledgement: ``This product includes software developed by the .\" University of California, Berkeley and its contributors'' in the .\" documentation or other materials provided with the distribution and in .\" all advertising materials mentioning features or use of this software. .\" Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED .\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. .\" .\" @(#)resolver.3 6.5 (Berkeley) 6/23/90 -.\" $Id: resolver.3,v 8.16 2001/12/28 04:24:20 marka Exp $ +.\" $Id: resolver.3,v 8.17 2002/08/07 03:47:33 marka Exp $ .\" .Dd July 4, 2000 .Dt RESOLVER @LIB_NETWORK_EXT_U@ .Os BSD 4 .Sh NAME .Nm res_ninit , .Nm res_ourserver_p , .Nm fp_resstat , .Nm res_hostalias , .Nm res_pquery , .Nm res_nquery , .Nm res_nsearch , .Nm res_nquerydomain , .Nm res_nmkquery , .Nm res_nsend , .Nm res_nupdate , .Nm res_nmkupdate , .Nm res_nclose , .Nm res_nsendsigned , .Nm res_findzonecut , .Nm dn_comp , .Nm dn_expand , .Nm hstrerror , .Nm res_init , .Nm res_isourserver , .Nm fp_nquery , .Nm p_query , .Nm hostalias , .Nm res_query , .Nm res_search , .Nm res_querydomain , .Nm res_mkquery , .Nm res_send , .Nm res_update , .Nm res_close , .Nm herror .Nd resolver routines .Sh SYNOPSIS .Fd #include .Fd #include .Fd #include .Fd #include .Vt typedef struct __res_state *res_state ; .Pp .Fn res_ninit "res_state statp" .Fn res_ourserver_p "const res_state statp" "const struct sockaddr_in *addr" .Fn fp_resstat "const res_state statp" "FILE *fp" .Fn res_hostalias "const res_state statp" "const char *name" "char *buf" "size_t buflen" .Fn res_pquery "const res_state statp" "const u_char *msg" "int msglen" "FILE *fp" .Fn res_nquery "res_state statp" "const char *dname" "int class" "int type" "u_char *answer" "int anslen" .Fn res_nsearch "res_state statp" "const char *dname" "int class" "int type" "u_char * answer" "int anslen" .Fn res_nquerydomain "res_state statp" "const char *name" "const char *domain" "int class" "int type" "u_char *answer" "int anslen" .Fo res_nmkquery .Fa "res_state statp" .Fa "int op" .Fa "const char *dname" .Fa "int class" .Fa "int type" .Fa "const u_char *data" .Fa "int datalen" .Fa "const u_char *newrr" .Fa "u_char *buf" .Fa "int buflen" .Fc .Fn res_nsend "res_state statp" "const u_char *msg" "int msglen" "u_char *answer" "int anslen" .Fn res_nupdate "res_state statp" "ns_updrec *rrecp_in" .Fn res_nmkupdate "res_state statp" "ns_updrec *rrecp_in" "u_char *buf" "int buflen" .Fn res_nclose "res_state statp" .Fn res_nsendsigned "res_state statp" "const u_char *msg" "int msglen" "ns_tsig_key *key" "u_char *answer" "int anslen" .Fn res_findzonecut "res_state statp" "const char *dname" "ns_class class" "int options" "char *zname" "size_t zsize" "struct in_addr *addrs" "int naddrs" .Fn dn_comp "const char *exp_dn" "u_char *comp_dn" "int length" "u_char **dnptrs" "u_char **lastdnptr" .Fn dn_expand "const u_char *msg" "const u_char *eomorig" "const u_char *comp_dn" "char *exp_dn" "int length" .Fn hstrerror "int err" .Ss DEPRECATED .Fd #include .Fd #include .Fd #include .Fd #include .Fn res_init "void" .Fn res_isourserver "const struct sockaddr_in *addr" .Fn fp_nquery "const u_char *msg" "int msglen" "FILE *fp" .Fn p_query "const u_char *msg" "FILE *fp" .Fn hostalias "const char *name" .Fn res_query "const char *dname" "int class" "int type" "u_char *answer" "int anslen" .Fn res_search "const char *dname" "int class" "int type" "u_char *answer" "int anslen" .Fn res_querydomain "const char *name" "const char *domain" "int class" "int type" "u_char *answer" "int anslen" .Fo res_mkquery .Fa "int op" .Fa "const char *dname" .Fa "int class" .Fa "int type" .Fa "const char *data" .Fa "int datalen" .Fa "struct rrec *newrr" .Fa "u_char *buf" .Fa "int buflen" .Fc .Fn res_send "const u_char *msg" "int msglen" "u_char *answer" "int anslen" .Fn res_update "ns_updrec *rrecp_in" .Fn res_close "void" .Fn herror "const char *s" .Sh DESCRIPTION These routines are used for making, sending and interpreting query and reply messages with Internet domain name servers. .Pp State information is kept in .Fa statp and is used to control the behavior of these functions. .Fa statp should be set to all zeros prior to the first call to any of these functions. .Pp The functions .Fn res_init , .Fn res_isourserver , .Fn fp_nquery , .Fn p_query , .Fn hostalias , .Fn res_query , .Fn res_search , .Fn res_querydomain , .Fn res_mkquery , .Fn res_send , .Fn res_update , .Fn res_close and .Fn herror are deprecated and are supplied for compatability with old source code. They use global configuration and state information that is kept in the structure .Ft _res rather than that referenced through .Ft statp . .Pp Most of the values in .Ft statp and .Ft _res are initialized on the first call to .Fn res_ninit / .Fn res_init to reasonable defaults and can be ignored. Options stored in .Ft statp->options / .Ft _res.options are defined in .Pa resolv.h and are as follows. Options are stored as a simple bit mask containing the bitwise .Dq OR of the options enabled. .Bl -tag -width "RES_DEB" .It Dv RES_INIT True if the initial name server address and default domain name are initialized (i.e., .Fn res_ninit / .Fn res_init has been called). .It Dv RES_DEBUG Print debugging messages. .It Dv RES_AAONLY Accept authoritative answers only. Should continue until it finds an authoritative answer or finds an error. Currently this is not implemented. .It Dv RES_USEVC Use TCP connections for queries instead of UDP datagrams. .It Dv RES_STAYOPEN Used with .Dv RES_USEVC to keep the TCP connection open between queries. This is useful only in programs that regularly do many queries. UDP should be the normal mode used. .It Dv RES_IGNTC Ignore truncation errors, i.e., don't retry with TCP. .It Dv RES_RECURSE Set the recursion-desired bit in queries. This is the default. (\c .Fn res_nsend / .Fn res_send does not do iterative queries and expects the name server to handle recursion.) .It Dv RES_DEFNAMES If set, .Fn res_nsearch / .Fn res_search will append the default domain name to single-component names (those that do not contain a dot). This option is enabled by default. .It Dv RES_DNSRCH If this option is set, .Fn res_nsearch / .Fn res_search will search for host names in the current domain and in parent domains; see .Xr hostname @DESC_EXT@ . This is used by the standard host lookup routine .Xr gethostbyname @LIB_NETWORK_EXT@ . This option is enabled by default. .It Dv RES_NOALIASES This option turns off the user level aliasing feature controlled by the .Ev HOSTALIASES environment variable. Network daemons should set this option. .It Dv RES_USE_INET6 This option causes .Xr gethostbyname @LIB_NETWORK_EXT@ to look for AAAA records before looking for A records if none are found. .It Dv RES_ROTATE This options causes the .Fn res_nsend / .Fn res_send to rotate the list of nameservers in .Fa statp->nsaddr_list / .Fa _res.nsaddr_list . .It Dv RES_KEEPTSIG This option causes .Fn res_nsendsigned to leave the message unchanged after TSIG verification; otherwise the TSIG record would be removed and the header updated. .It Dv RES_NOTLDQUERY This option causes .Fn res_nsearch to not attempt to resolve a unqualified name as if it were a top level domain (TLD). This option can cause problems if the site has "localhost" as a TLD rather than having localhost on one or more elements of the search list. This option has no effect if neither .Dv RES_DEFNAMES or .Dv RES_DNSRCH is set. .El .Pp The .Fn res_ninit / .Fn res_init routine reads the configuration file (if any; see .Xr resolver @FORMAT_EXT@ ) to get the default domain name, search list and the Internet address of the local name server(s). If no server is configured, the host running the resolver is tried. The current domain name is defined by the hostname if not specified in the configuration file; it can be overridden by the environment variable .Ev LOCALDOMAIN . This environment variable may contain several blank-separated tokens if you wish to override the .Dq search list on a per-process basis. This is similar to the .Ic search command in the configuration file. Another environment variable .Pq Dq Ev RES_OPTIONS can be set to override certain internal resolver options which are otherwise set by changing fields in the .Ft statp / .Ft _res structure or are inherited from the configuration file's .Ic options command. The syntax of the .Dq Ev RES_OPTIONS environment variable is explained in .Xr resolver @FORMAT_EXT@ . Initialization normally occurs on the first call to one of the other resolver routines. .Pp The .Fn res_nquery / .Fn res_query functions provides interfaces to the server query mechanism. They constructs a query, sends it to the local server, awaits a response, and makes preliminary checks on the reply. The query requests information of the specified .Fa type and .Fa class for the specified fully-qualified domain name .Fa dname . The reply message is left in the .Fa answer buffer with length .Fa anslen supplied by the caller. .Fn res_nquery / .Fn res_query return -1 on error or the length of the answer. .Pp The .Fn res_nsearch / .Fn res_search routines make a query and awaits a response like .Fn res_nquery / .Fn res_query , but in addition, it implements the default and search rules controlled by the .Dv RES_DEFNAMES and .Dv RES_DNSRCH options. It returns the length of the first successful reply which is stored in .Ft answer or -1 on error. .Pp The remaining routines are lower-level routines used by .Fn res_nquery / .Fn res_query . The .Fn res_nmkquery / .Fn res_mkquery functions constructs a standard query message and places it in .Fa buf . It returns the size of the query, or \-1 if the query is larger than .Fa buflen . The query type .Fa op is usually .Dv QUERY , but can be any of the query types defined in .Pa . The domain name for the query is given by .Fa dname . .Fa Newrr is currently unused but is intended for making update messages. .Pp The .Fn res_nsend / .Fn res_send / .Fn res_nsendsigned routines sends a pre-formatted query and returns an answer. It will call .Fn res_ninit / .Fn res_init if .Dv RES_INIT is not set, send the query to the local name server, and handle timeouts and retries. Additionally, .Fn res_nsendsigned will use TSIG signatures to add authentication to the query and verify the response. In this case, only one nameserver will be contacted. The length of the reply message is returned, or \-1 if there were errors. .Pp .Fn res_nquery / .Fn res_query , .Fn res_nsearch / .Fn res_search and .Fn res_nsend / .Fn res_send return a length that may be bigger than .Fa anslen . In that case the query should be retried with a bigger buffer. NOTE the answer to the second query may be larger still so supplying a buffer that bigger that the answer returned by the previous query is recommended. .Pp .Fa answer MUST be big enough to receive a maximum UDP response from the server or parts of the answer will be silently discarded. The default maximum UDP response size is 512 bytes. .Pp The function .Fn res_ourserver_p returns true when .Fa inp is one of the servers in .Fa statp->nsaddr_list / .Fa _res.nsaddr_list . .Pp The functions .Fn fp_nquery / .Fn p_query print out the query and any answer in .Fa msg on .Fa fp . .Fn p_query is equivalent to .Fn fp_nquery with .Fa msglen set to 512. .Pp The function .Fn fp_resstat prints out the active flag bits in .Fa statp->options preceeded by the text ";; res options:" on .Fa file . .Pp The functions .Fn res_hostalias / .Fn hostalias lookup up name in the file referred to by the .Ev HOSTALIASES files return a fully qualified hostname if found or NULL if not found or an error occurred. .Fn res_hostalias uses .Fa buf to store the result in, .Fn hostalias uses a static buffer. .Pp The functions .Fn res_nupdate / .Fn res_update take a list of ns_updrec .Fa rrecp_in . Identifies the containing zone for each record and groups the records according to containing zone maintaining in zone order then sends and update request to the servers for these zones. The number of zones updated is returned or -1 on error. Note that .Fn res_nupdate will perform TSIG authenticated dynamic update operations if the key is not NULL. .Pp The function .Fn res_findzonecut discovers the closest enclosing zone cut for a specified domain name, and finds the IP addresses of the zone's master servers. .Pp The functions .Fn res_nmkupdate / .Fn res_mkupdate take a linked list of ns_updrec .Fa rrecp_in and construct a UPDATE message in .Fa buf . .Fn res_nmkupdate / .Fn res_mkupdate return the length of the constructed message on no error or one of the following error values. .Bl -inset -width "-5" .It -1 An error occurred parsing .Fa rrecp_in . .It -2 The buffer .Fa buf was too small. .It -3 The first record was not a zone section or there was a section order problem. The section order is S_ZONE, S_PREREQ and S_UPDATE. .It -4 A number overflow occurred. .It -5 Unknown operation or no records. .El .Pp The functions .Fn res_nclose / .Fn res_close close any open files referenced through .Fa statp / .Fa _res . .Pp The .Fn dn_comp function compresses the domain name .Fa exp_dn and stores it in .Fa comp_dn . The size of the compressed name is returned or \-1 if there were errors. The size of the array pointed to by .Fa comp_dn is given by .Fa length . The compression uses an array of pointers .Fa dnptrs to previously-compressed names in the current message. The first pointer points to to the beginning of the message and the list ends with .Dv NULL . The limit to the array is specified by .Fa lastdnptr . A side effect of .Fn dn_comp is to update the list of pointers for labels inserted into the message as the name is compressed. If .Fa dnptr is .Dv NULL , names are not compressed. If .Fa lastdnptr is .Dv NULL , the list of labels is not updated. .Pp The .Fn dn_expand entry expands the compressed domain name .Fa comp_dn to a full domain name. The compressed name is contained in a query or reply message; .Fa msg is a pointer to the beginning of the message. +.Fa eomorig +is a pointer to the first location after the message. The uncompressed name is placed in the buffer indicated by .Fa exp_dn which is of size .Fa length . The size of compressed name is returned or \-1 if there was an error. .Pp The variables .Ft statp->res_h_errno / .Ft _res.res_h_errno and external variable .Ft h_errno is set whenever an error occurs during resolver operation. The following definitions are given in .Pa : .Bd -literal #define NETDB_INTERNAL -1 /* see errno */ #define NETDB_SUCCESS 0 /* no problem */ #define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ #define TRY_AGAIN 2 /* Non-Authoritative not found, or SERVFAIL */ #define NO_RECOVERY 3 /* Non-Recoverable: FORMERR, REFUSED, NOTIMP */ #define NO_DATA 4 /* Valid name, no data for requested type */ .Ed .Pp The .Fn herror function writes a message to the diagnostic output consisting of the string parameter .Fa s , the constant string ": ", and a message corresponding to the value of .Ft h_errno . .Pp The .Fn hstrerror function returns a string which is the message text corresponding to the value of the .Fa err parameter. .Sh FILES .Bl -tag -width "/etc/resolv.conf " .It Pa /etc/resolv.conf See .Xr resolver @FORMAT_EXT@ . .El .Sh SEE ALSO .Xr gethostbyname @LIB_NETWORK_EXT@ , .Xr hostname @DESC_EXT@ , .Xr @INDOT@named @SYS_OPS_EXT@ , .Xr resolver @FORMAT_EXT@ ; RFC1032, RFC1033, RFC1034, RFC1035, RFC974; SMM:11, .Dq Name Server Operations Guide for Sy BIND Index: vendor/bind/dist/contrib/bind/lib/nameser/ns_name.c =================================================================== --- vendor/bind/dist/contrib/bind/lib/nameser/ns_name.c (revision 109982) +++ vendor/bind/dist/contrib/bind/lib/nameser/ns_name.c (revision 109983) @@ -1,947 +1,947 @@ /* * Copyright (c) 1996,1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #ifndef lint -static const char rcsid[] = "$Id: ns_name.c,v 8.18 2002/05/24 05:10:40 marka Exp $"; +static const char rcsid[] = "$Id: ns_name.c,v 8.18.4.1 2002/11/14 13:32:08 marka Exp $"; #endif #include "port_before.h" #include #include #include #include #include #include #include #include #include #include "port_after.h" #ifdef SPRINTF_CHAR # define SPRINTF(x) strlen(sprintf/**/x) #else # define SPRINTF(x) ((size_t)sprintf x) #endif #define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */ #define DNS_LABELTYPE_BITSTRING 0x41 /* Data. */ static const char digits[] = "0123456789"; static const char digitvalue[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ }; /* Forward. */ static int special(int); static int printable(int); static int dn_find(const u_char *, const u_char *, const u_char * const *, const u_char * const *); static int encode_bitsring(const char **, const char *, char **, char **, const char *); static int labellen(const u_char *); static int decode_bitstring(const char **, char *, const char *); /* Public. */ /* * ns_name_ntop(src, dst, dstsiz) * Convert an encoded domain name to printable ascii as per RFC1035. * return: * Number of bytes written to buffer, or -1 (with errno set) * notes: * The root is returned as "." * All other domains are returned in non absolute form */ int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) { const u_char *cp; char *dn, *eom; u_char c; u_int n; int l; cp = src; dn = dst; eom = dst + dstsiz; while ((n = *cp++) != 0) { if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { /* Some kind of compression pointer. */ errno = EMSGSIZE; return (-1); } if (dn != dst) { if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '.'; } if ((l = labellen(cp - 1)) < 0) { errno = EMSGSIZE; /* XXX */ return(-1); } if (dn + l >= eom) { errno = EMSGSIZE; return (-1); } if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { int m; if (n != DNS_LABELTYPE_BITSTRING) { /* XXX: labellen should reject this case */ errno = EINVAL; return(-1); } if ((m = decode_bitstring((const char **)&cp, dn, eom)) < 0) { errno = EMSGSIZE; return(-1); } dn += m; continue; } for ((void)NULL; l > 0; l--) { c = *cp++; if (special(c)) { if (dn + 1 >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '\\'; *dn++ = (char)c; } else if (!printable(c)) { if (dn + 3 >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '\\'; *dn++ = digits[c / 100]; *dn++ = digits[(c % 100) / 10]; *dn++ = digits[c % 10]; } else { if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = (char)c; } } } if (dn == dst) { if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '.'; } if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '\0'; return (dn - dst); } /* * ns_name_pton(src, dst, dstsiz) * Convert a ascii string into an encoded domain name as per RFC1035. * return: * -1 if it fails * 1 if string was fully qualified * 0 is string was not fully qualified * notes: * Enforces label and domain length limits. */ int ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { u_char *label, *bp, *eom; int c, n, escaped, e = 0; char *cp; escaped = 0; bp = dst; eom = dst + dstsiz; label = bp++; while ((c = *src++) != 0) { if (escaped) { if (c == '[') { /* start a bit string label */ if ((cp = strchr(src, ']')) == NULL) { errno = EINVAL; /* ??? */ return(-1); } if ((e = encode_bitsring(&src, cp + 2, (char **)&label, (char **)&bp, (const char *)eom)) != 0) { errno = e; return(-1); } escaped = 0; label = bp++; if ((c = *src++) == 0) goto done; else if (c != '.') { errno = EINVAL; return(-1); } continue; } else if ((cp = strchr(digits, c)) != NULL) { n = (cp - digits) * 100; if ((c = *src++) == 0 || (cp = strchr(digits, c)) == NULL) { errno = EMSGSIZE; return (-1); } n += (cp - digits) * 10; if ((c = *src++) == 0 || (cp = strchr(digits, c)) == NULL) { errno = EMSGSIZE; return (-1); } n += (cp - digits); if (n > 255) { errno = EMSGSIZE; return (-1); } c = n; } escaped = 0; } else if (c == '\\') { escaped = 1; continue; } else if (c == '.') { c = (bp - label - 1); if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ errno = EMSGSIZE; return (-1); } if (label >= eom) { errno = EMSGSIZE; return (-1); } *label = c; /* Fully qualified ? */ if (*src == '\0') { if (c != 0) { if (bp >= eom) { errno = EMSGSIZE; return (-1); } *bp++ = '\0'; } if ((bp - dst) > MAXCDNAME) { errno = EMSGSIZE; return (-1); } return (1); } if (c == 0 || *src == '.') { errno = EMSGSIZE; return (-1); } label = bp++; continue; } if (bp >= eom) { errno = EMSGSIZE; return (-1); } *bp++ = (u_char)c; } c = (bp - label - 1); if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ errno = EMSGSIZE; return (-1); } done: if (label >= eom) { errno = EMSGSIZE; return (-1); } *label = c; if (c != 0) { if (bp >= eom) { errno = EMSGSIZE; return (-1); } *bp++ = 0; } if ((bp - dst) > MAXCDNAME) { /* src too big */ errno = EMSGSIZE; return (-1); } return (0); } /* * ns_name_ntol(src, dst, dstsiz) * Convert a network strings labels into all lowercase. * return: * Number of bytes written to buffer, or -1 (with errno set) * notes: * Enforces label and domain length limits. */ int ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) { const u_char *cp; u_char *dn, *eom; u_char c; u_int n; int l; cp = src; dn = dst; eom = dst + dstsiz; if (dn >= eom) { errno = EMSGSIZE; return (-1); } while ((n = *cp++) != 0) { if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { /* Some kind of compression pointer. */ errno = EMSGSIZE; return (-1); } *dn++ = n; if ((l = labellen(cp - 1)) < 0) { errno = EMSGSIZE; return (-1); } if (dn + l >= eom) { errno = EMSGSIZE; return (-1); } for ((void)NULL; l > 0; l--) { c = *cp++; if (isupper(c)) *dn++ = tolower(c); else *dn++ = c; } } *dn++ = '\0'; return (dn - dst); } /* * ns_name_unpack(msg, eom, src, dst, dstsiz) * Unpack a domain name from a message, source may be compressed. * return: * -1 if it fails, or consumed octets if it succeeds. */ int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, u_char *dst, size_t dstsiz) { const u_char *srcp, *dstlim; u_char *dstp; int n, len, checked, l; len = -1; checked = 0; dstp = dst; srcp = src; dstlim = dst + dstsiz; if (srcp < msg || srcp >= eom) { errno = EMSGSIZE; return (-1); } /* Fetch next label in domain name. */ while ((n = *srcp++) != 0) { /* Check for indirection. */ switch (n & NS_CMPRSFLGS) { case 0: case NS_TYPE_ELT: /* Limit checks. */ if ((l = labellen(srcp - 1)) < 0) { errno = EMSGSIZE; return(-1); } if (dstp + l + 1 >= dstlim || srcp + l >= eom) { errno = EMSGSIZE; return (-1); } checked += l + 1; *dstp++ = n; memcpy(dstp, srcp, l); dstp += l; srcp += l; break; case NS_CMPRSFLGS: if (srcp >= eom) { errno = EMSGSIZE; return (-1); } if (len < 0) len = srcp - src + 1; srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); if (srcp < msg || srcp >= eom) { /* Out of range. */ errno = EMSGSIZE; return (-1); } checked += 2; /* * Check for loops in the compressed name; * if we've looked at the whole message, * there must be a loop. */ if (checked >= eom - msg) { errno = EMSGSIZE; return (-1); } break; default: errno = EMSGSIZE; return (-1); /* flag error */ } } *dstp = '\0'; if (len < 0) len = srcp - src; return (len); } /* * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) * Pack domain name 'domain' into 'comp_dn'. * return: * Size of the compressed name, or -1. * notes: * 'dnptrs' is an array of pointers to previous compressed names. * dnptrs[0] is a pointer to the beginning of the message. The array * ends with NULL. * 'lastdnptr' is a pointer to the end of the array pointed to * by 'dnptrs'. * Side effects: * The list of pointers in dnptrs is updated for labels inserted into * the message as we compress the name. If 'dnptr' is NULL, we don't * try to compress names. If 'lastdnptr' is NULL, we don't update the * list. */ int ns_name_pack(const u_char *src, u_char *dst, int dstsiz, const u_char **dnptrs, const u_char **lastdnptr) { u_char *dstp; const u_char **cpp, **lpp, *eob, *msg; const u_char *srcp; int n, l, first = 1; srcp = src; dstp = dst; eob = dstp + dstsiz; lpp = cpp = NULL; if (dnptrs != NULL) { if ((msg = *dnptrs++) != NULL) { for (cpp = dnptrs; *cpp != NULL; cpp++) (void)NULL; lpp = cpp; /* end of list to search */ } } else msg = NULL; /* make sure the domain we are about to add is legal */ l = 0; do { int l0; n = *srcp; if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { errno = EMSGSIZE; return (-1); } if ((l0 = labellen(srcp)) < 0) { errno = EINVAL; return(-1); } l += l0 + 1; if (l > MAXCDNAME) { errno = EMSGSIZE; return (-1); } srcp += l0 + 1; } while (n != 0); /* from here on we need to reset compression pointer array on error */ srcp = src; do { /* Look to see if we can use pointers. */ n = *srcp; if (n != 0 && msg != NULL) { l = dn_find(srcp, msg, (const u_char * const *)dnptrs, (const u_char * const *)lpp); if (l >= 0) { if (dstp + 1 >= eob) { goto cleanup; } *dstp++ = (l >> 8) | NS_CMPRSFLGS; *dstp++ = l % 256; return (dstp - dst); } /* Not found, save it. */ if (lastdnptr != NULL && cpp < lastdnptr - 1 && (dstp - msg) < 0x4000 && first) { *cpp++ = dstp; *cpp = NULL; first = 0; } } /* copy label to buffer */ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { /* Should not happen. */ goto cleanup; } n = labellen(srcp); if (dstp + 1 + n >= eob) { goto cleanup; } memcpy(dstp, srcp, n + 1); srcp += n + 1; dstp += n + 1; } while (n != 0); if (dstp > eob) { cleanup: if (msg != NULL) *lpp = NULL; errno = EMSGSIZE; return (-1); } return (dstp - dst); } /* * ns_name_uncompress(msg, eom, src, dst, dstsiz) * Expand compressed domain name to presentation format. * return: * Number of bytes read out of `src', or -1 (with errno set). * note: * Root domain returns as "." not "". */ int ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, char *dst, size_t dstsiz) { u_char tmp[NS_MAXCDNAME]; int n; if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) return (-1); if (ns_name_ntop(tmp, dst, dstsiz) == -1) return (-1); return (n); } /* * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) * Compress a domain name into wire format, using compression pointers. * return: * Number of bytes consumed in `dst' or -1 (with errno set). * notes: * 'dnptrs' is an array of pointers to previous compressed names. * dnptrs[0] is a pointer to the beginning of the message. * The list ends with NULL. 'lastdnptr' is a pointer to the end of the * array pointed to by 'dnptrs'. Side effect is to update the list of * pointers for labels inserted into the message as we compress the name. * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' * is NULL, we don't update the list. */ int ns_name_compress(const char *src, u_char *dst, size_t dstsiz, const u_char **dnptrs, const u_char **lastdnptr) { u_char tmp[NS_MAXCDNAME]; if (ns_name_pton(src, tmp, sizeof tmp) == -1) return (-1); return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); } /* * Reset dnptrs so that there are no active references to pointers at or * after src. */ void ns_name_rollback(const u_char *src, const u_char **dnptrs, const u_char **lastdnptr) { while (dnptrs < lastdnptr && *dnptrs != NULL) { if (*dnptrs >= src) { *dnptrs = NULL; break; } dnptrs++; } } /* * ns_name_skip(ptrptr, eom) * Advance *ptrptr to skip over the compressed name it points at. * return: * 0 on success, -1 (with errno set) on failure. */ int ns_name_skip(const u_char **ptrptr, const u_char *eom) { const u_char *cp; u_int n; int l; cp = *ptrptr; while (cp < eom && (n = *cp++) != 0) { /* Check for indirection. */ switch (n & NS_CMPRSFLGS) { case 0: /* normal case, n == len */ cp += n; continue; case NS_TYPE_ELT: /* EDNS0 extended label */ if ((l = labellen(cp - 1)) < 0) { errno = EMSGSIZE; /* XXX */ return(-1); } cp += l; continue; case NS_CMPRSFLGS: /* indirection */ cp++; break; default: /* illegal type */ errno = EMSGSIZE; return (-1); } break; } if (cp > eom) { errno = EMSGSIZE; return (-1); } *ptrptr = cp; return (0); } /* Private. */ /* * special(ch) * Thinking in noninternationalized USASCII (per the DNS spec), * is this characted special ("in need of quoting") ? * return: * boolean. */ static int special(int ch) { switch (ch) { case 0x22: /* '"' */ case 0x2E: /* '.' */ case 0x3B: /* ';' */ case 0x5C: /* '\\' */ case 0x28: /* '(' */ case 0x29: /* ')' */ /* Special modifiers in zone files. */ case 0x40: /* '@' */ case 0x24: /* '$' */ return (1); default: return (0); } } /* * printable(ch) * Thinking in noninternationalized USASCII (per the DNS spec), * is this character visible and not a space when printed ? * return: * boolean. */ static int printable(int ch) { return (ch > 0x20 && ch < 0x7f); } /* * Thinking in noninternationalized USASCII (per the DNS spec), * convert this character to lower case if it's upper case. */ static int mklower(int ch) { if (ch >= 0x41 && ch <= 0x5A) return (ch + 0x20); return (ch); } /* * dn_find(domain, msg, dnptrs, lastdnptr) * Search for the counted-label name in an array of compressed names. * return: * offset from msg if found, or -1. * notes: * dnptrs is the pointer to the first name on the list, * not the pointer to the start of the message. */ static int dn_find(const u_char *domain, const u_char *msg, const u_char * const *dnptrs, const u_char * const *lastdnptr) { const u_char *dn, *cp, *sp; const u_char * const *cpp; u_int n; for (cpp = dnptrs; cpp < lastdnptr; cpp++) { sp = *cpp; /* * terminate search on: * root label * compression pointer * unusable offset */ while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && (sp - msg) < 0x4000) { dn = domain; cp = sp; while ((n = *cp++) != 0) { /* * check for indirection */ switch (n & NS_CMPRSFLGS) { case 0: /* normal case, n == len */ n = labellen(cp - 1); /* XXX */ if (n != *dn++) goto next; for ((void)NULL; n > 0; n--) if (mklower(*dn++) != mklower(*cp++)) goto next; /* Is next root for both ? */ if (*dn == '\0' && *cp == '\0') return (sp - msg); if (*dn) continue; goto next; case NS_CMPRSFLGS: /* indirection */ cp = msg + (((n & 0x3f) << 8) | *cp); break; default: /* illegal type */ errno = EMSGSIZE; return (-1); } } next: ; sp += *sp + 1; } } errno = ENOENT; return (-1); } static int decode_bitstring(const char **cpp, char *dn, const char *eom) { const char *cp = *cpp; char *beg = dn, tc; int b, blen, plen; if ((blen = (*cp & 0xff)) == 0) blen = 256; plen = (blen + 3) / 4; plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); if (dn + plen >= eom) return(-1); cp++; dn += SPRINTF((dn, "\\[x")); for (b = blen; b > 7; b -= 8, cp++) dn += SPRINTF((dn, "%02x", *cp & 0xff)); if (b > 4) { tc = *cp++; dn += SPRINTF((dn, "%02x", tc & (0xff << (8 - b)))); } else if (b > 0) { tc = *cp++; dn += SPRINTF((dn, "%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b)))); } dn += SPRINTF((dn, "/%d]", blen)); *cpp = cp; return(dn - beg); } static int encode_bitsring(const char **bp, const char *end, char **labelp, char ** dst, const char *eom) { int afterslash = 0; const char *cp = *bp; char *tp, c; const char *beg_blen; char *end_blen = NULL; int value = 0, count = 0, tbcount = 0, blen = 0; beg_blen = end_blen = NULL; /* a bitstring must contain at least 2 characters */ if (end - cp < 2) return(EINVAL); /* XXX: currently, only hex strings are supported */ if (*cp++ != 'x') return(EINVAL); if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */ return(EINVAL); for (tp = *dst + 1; cp < end && tp < eom; cp++) { switch((c = *cp)) { case ']': /* end of the bitstring */ if (afterslash) { if (beg_blen == NULL) return(EINVAL); blen = (int)strtol(beg_blen, &end_blen, 10); if (*end_blen != ']') return(EINVAL); } if (count) *tp++ = ((value << 4) & 0xff); cp++; /* skip ']' */ goto done; case '/': afterslash = 1; break; default: if (afterslash) { if (!isdigit(c&0xff)) return(EINVAL); if (beg_blen == NULL) { if (c == '0') { /* blen never begings with 0 */ return(EINVAL); } beg_blen = cp; } } else { if (!isxdigit(c&0xff)) return(EINVAL); value <<= 4; value += digitvalue[(int)c]; count += 4; tbcount += 4; if (tbcount > 256) return(EINVAL); if (count == 8) { *tp++ = value; count = 0; } } break; } } done: if (cp >= end || tp >= eom) return(EMSGSIZE); /* * bit length validation: * If a is present, the number of digits in the * MUST be just sufficient to contain the number of bits specified * by the . If there are insignificant bits in a final * hexadecimal or octal digit, they MUST be zero. * RFC 2673, Section 3.2. */ if (blen > 0) { int traillen; if (((blen + 3) & ~3) != tbcount) return(EINVAL); traillen = tbcount - blen; /* between 0 and 3 */ if (((value << (8 - traillen)) & 0xff) != 0) return(EINVAL); } else blen = tbcount; if (blen == 256) blen = 0; /* encode the type and the significant bit fields */ **labelp = DNS_LABELTYPE_BITSTRING; **dst = blen; *bp = cp; *dst = tp; return(0); } static int labellen(const u_char *lp) { int bitlen; u_char l = *lp; if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { /* should be avoided by the caller */ return(-1); } if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { if (l == DNS_LABELTYPE_BITSTRING) { if ((bitlen = *(lp + 1)) == 0) bitlen = 256; return((bitlen + 7 ) / 8 + 1); } return(-1); /* unknwon ELT */ } return(l); } Index: vendor/bind/dist/contrib/bind/lib/nameser/ns_samedomain.c =================================================================== --- vendor/bind/dist/contrib/bind/lib/nameser/ns_samedomain.c (revision 109982) +++ vendor/bind/dist/contrib/bind/lib/nameser/ns_samedomain.c (revision 109983) @@ -1,206 +1,206 @@ /* * Copyright (c) 1995,1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #ifndef lint -static const char rcsid[] = "$Id: ns_samedomain.c,v 8.9 1999/10/15 21:06:51 vixie Exp $"; +static const char rcsid[] = "$Id: ns_samedomain.c,v 8.9.6.2 2002/11/14 22:36:46 marka Exp $"; #endif #include "port_before.h" #include #include #include #include #include "port_after.h" /* * int * ns_samedomain(a, b) * Check whether a name belongs to a domain. * Inputs: * a - the domain whose ancestory is being verified * b - the potential ancestor we're checking against * Return: * boolean - is a at or below b? * Notes: * Trailing dots are first removed from name and domain. * Always compare complete subdomains, not only whether the * domain name is the trailing string of the given name. * * "host.foobar.top" lies in "foobar.top" and in "top" and in "" * but NOT in "bar.top" */ int ns_samedomain(const char *a, const char *b) { size_t la, lb; int diff, i, escaped; const char *cp; la = strlen(a); lb = strlen(b); /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */ if (la != 0 && a[la - 1] == '.') { escaped = 0; /* Note this loop doesn't get executed if la==1. */ for (i = la - 2; i >= 0; i--) if (a[i] == '\\') { if (escaped) escaped = 0; else escaped = 1; } else break; if (!escaped) la--; } /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */ if (lb != 0 && b[lb - 1] == '.') { escaped = 0; /* note this loop doesn't get executed if lb==1 */ for (i = lb - 2; i >= 0; i--) if (b[i] == '\\') { if (escaped) escaped = 0; else escaped = 1; } else break; if (!escaped) lb--; } /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */ if (lb == 0) return (1); /* 'b' longer than 'a' means 'a' can't be in 'b'. */ if (lb > la) return (0); /* 'a' and 'b' being equal at this point indicates sameness. */ if (lb == la) return (strncasecmp(a, b, lb) == 0); /* Ok, we know la > lb. */ diff = la - lb; /* * If 'a' is only 1 character longer than 'b', then it can't be * a subdomain of 'b' (because of the need for the '.' label * separator). */ if (diff < 2) return (0); /* * If the character before the last 'lb' characters of 'b' * isn't '.', then it can't be a match (this lets us avoid * having "foobar.com" match "bar.com"). */ if (a[diff - 1] != '.') return (0); /* * We're not sure about that '.', however. It could be escaped * and thus not a really a label separator. */ escaped = 0; for (i = diff - 2; i >= 0; i--) if (a[i] == '\\') if (escaped) escaped = 0; else escaped = 1; else break; if (escaped) return (0); /* Now compare aligned trailing substring. */ cp = a + diff; return (strncasecmp(cp, b, lb) == 0); } /* * int * ns_subdomain(a, b) * is "a" a subdomain of "b"? */ int ns_subdomain(const char *a, const char *b) { return (ns_samename(a, b) != 1 && ns_samedomain(a, b)); } /* * int * ns_makecanon(src, dst, dstsize) * make a canonical copy of domain name "src" * notes: * foo -> foo. * foo. -> foo. * foo.. -> foo. * foo\. -> foo\.. * foo\\. -> foo\\. */ int ns_makecanon(const char *src, char *dst, size_t dstsize) { size_t n = strlen(src); - if (n + sizeof "." + 1 > dstsize) { + if (n + sizeof "." > dstsize) { errno = EMSGSIZE; return (-1); } strcpy(dst, src); while (n > 0 && dst[n - 1] == '.') /* Ends in "." */ if (n > 1 && dst[n - 2] == '\\' && /* Ends in "\." */ (n < 2 || dst[n - 3] != '\\')) /* But not "\\." */ break; else dst[--n] = '\0'; dst[n++] = '.'; dst[n] = '\0'; return (0); } /* * int * ns_samename(a, b) * determine whether domain name "a" is the same as domain name "b" * return: * -1 on error * 0 if names differ * 1 if names are the same */ int ns_samename(const char *a, const char *b) { char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; if (ns_makecanon(a, ta, sizeof ta) < 0 || ns_makecanon(b, tb, sizeof tb) < 0) return (-1); if (strcasecmp(ta, tb) == 0) return (1); else return (0); }