dns.c 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756
  1. /*
  2. Copyright (c) 2003-2006 by Juliusz Chroboczek
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. #include "polipo.h"
  20. #ifndef NO_STANDARD_RESOLVER
  21. #ifndef NO_FANCY_RESOLVER
  22. int dnsUseGethostbyname = 1;
  23. #else
  24. const int dnsUseGethostbyname = 3;
  25. #endif
  26. #else
  27. #ifndef NO_FANCY_RESOLVER
  28. const int dnsUseGethostbyname = 0;
  29. #else
  30. #error use no resolver at all?
  31. #endif
  32. #endif
  33. #ifndef NO_FANCY_RESOLVER
  34. AtomPtr dnsNameServer = NULL;
  35. int dnsMaxTimeout = 60;
  36. int dnsNameServerPort = 53;
  37. #endif
  38. #ifndef NO_STANDARD_RESOLVER
  39. int dnsGethostbynameTtl = 1200;
  40. #endif
  41. int dnsNegativeTtl = 120;
  42. #ifdef HAVE_IPv6
  43. int dnsQueryIPv6 = 2;
  44. #else
  45. const int dnsQueryIPv6 = 0;
  46. #endif
  47. typedef struct _DnsQuery {
  48. unsigned id;
  49. AtomPtr name;
  50. ObjectPtr object;
  51. AtomPtr inet4, inet6;
  52. time_t ttl4, ttl6;
  53. time_t time;
  54. int timeout;
  55. TimeEventHandlerPtr timeout_handler;
  56. struct _DnsQuery *next;
  57. } DnsQueryRec, *DnsQueryPtr;
  58. union {
  59. struct sockaddr sa;
  60. struct sockaddr_in sin;
  61. #ifdef HAVE_IPv6
  62. struct sockaddr_in6 sin6;
  63. #endif
  64. } nameserverAddress_storage;
  65. #ifndef NO_FANCY_RESOLVER
  66. static AtomPtr atomLocalhost, atomLocalhostDot;
  67. #define nameserverAddress nameserverAddress_storage.sa
  68. static DnsQueryPtr inFlightDnsQueries;
  69. static DnsQueryPtr inFlightDnsQueriesLast;
  70. #endif
  71. static int really_do_gethostbyname(AtomPtr name, ObjectPtr object);
  72. static int really_do_dns(AtomPtr name, ObjectPtr object);
  73. #ifndef NO_FANCY_RESOLVER
  74. static int stringToLabels(char *buf, int offset, int n, char *string);
  75. static int labelsToString(char *buf, int offset, int n, char *d,
  76. int m, int *j_return);
  77. static int dnsBuildQuery(int id, char *buf, int offset, int n,
  78. AtomPtr name, int af);
  79. static int dnsReplyHandler(int abort, FdEventHandlerPtr event);
  80. static int dnsReplyId(char *buf, int offset, int n, int *id_return);
  81. static int dnsDecodeReply(char *buf, int offset, int n,
  82. int *id_return,
  83. AtomPtr *name_return, AtomPtr *value_return,
  84. int *af_return, unsigned *ttl_return);
  85. static int dnsHandler(int status, ConditionHandlerPtr chandler);
  86. static int dnsGethostbynameFallback(int id, AtomPtr message);
  87. static int sendQuery(DnsQueryPtr query);
  88. static int idSeed;
  89. #endif
  90. #if !defined(NO_FANCY_RESOLVER) && !defined(WIN32)
  91. static int
  92. parseResolvConf(char *filename)
  93. {
  94. FILE *f;
  95. char buf[512];
  96. char *p, *q;
  97. int n;
  98. AtomPtr nameserver = NULL;
  99. f = fopen(filename, "r");
  100. if(f == NULL) {
  101. do_log_error(L_ERROR, errno, "DNS: couldn't open %s", filename);
  102. return 0;
  103. }
  104. while(1) {
  105. p = fgets(buf, 512, f);
  106. if(p == NULL)
  107. break;
  108. n = strlen(buf);
  109. if(buf[n - 1] != '\n') {
  110. int c;
  111. do_log(L_WARN, "DNS: overly long line in %s -- skipping.\n",
  112. filename);
  113. do {
  114. c = fgetc(f);
  115. if(c == EOF)
  116. break;
  117. } while(c != '\n');
  118. if(c == EOF)
  119. break;
  120. }
  121. while(*p == ' ' || *p == '\t')
  122. p++;
  123. if(strcasecmp_n("nameserver", p, 10) != 0)
  124. continue;
  125. p += 10;
  126. while(*p == ' ' || *p == '\t')
  127. p++;
  128. q = p;
  129. while(*q == '.' || *q == ':' || digit(*q) || letter(*q))
  130. q++;
  131. if(*q != ' ' && *q != '\t' && *q != '\r' && *q != '\n') {
  132. do_log(L_WARN, "DNS: couldn't parse line in %s -- skipping.\n",
  133. filename);
  134. continue;
  135. }
  136. nameserver = internAtomLowerN(p, q - p);
  137. break;
  138. }
  139. fclose(f);
  140. if(nameserver) {
  141. dnsNameServer = nameserver;
  142. return 1;
  143. } else {
  144. return 0;
  145. }
  146. }
  147. #endif
  148. void
  149. preinitDns()
  150. {
  151. #ifdef HAVE_IPv6
  152. int fd;
  153. #endif
  154. assert(sizeof(struct in_addr) == 4);
  155. #ifdef HAVE_IPv6
  156. assert(sizeof(struct in6_addr) == 16);
  157. #endif
  158. #ifndef NO_STANDARD_RESOLVER
  159. CONFIG_VARIABLE(dnsGethostbynameTtl, CONFIG_TIME,
  160. "TTL for gethostbyname addresses.");
  161. #endif
  162. #ifdef HAVE_IPv6
  163. fd = socket(PF_INET6, SOCK_STREAM, 0);
  164. if(fd < 0) {
  165. if(errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {
  166. dnsQueryIPv6 = 0;
  167. } else {
  168. do_log_error(L_WARN, errno, "DNS: couldn't create socket");
  169. }
  170. } else {
  171. close(fd);
  172. }
  173. #endif
  174. #ifndef NO_FANCY_RESOLVER
  175. #ifndef WIN32
  176. parseResolvConf("/etc/resolv.conf");
  177. #endif
  178. if(dnsNameServer == NULL || dnsNameServer->string[0] == '\0')
  179. dnsNameServer = internAtom("127.0.0.1");
  180. CONFIG_VARIABLE(dnsMaxTimeout, CONFIG_TIME,
  181. "Max timeout for DNS queries.");
  182. CONFIG_VARIABLE(dnsNegativeTtl, CONFIG_TIME,
  183. "TTL for negative DNS replies with no TTL.");
  184. CONFIG_VARIABLE(dnsNameServer, CONFIG_ATOM_LOWER,
  185. "The name server to use.");
  186. CONFIG_VARIABLE(dnsNameServerPort, CONFIG_INT,
  187. "The name server port to use.");
  188. #ifndef NO_STANDARD_RESOLVER
  189. CONFIG_VARIABLE(dnsUseGethostbyname, CONFIG_TETRASTATE,
  190. "Use the system resolver.");
  191. #endif
  192. #endif
  193. #ifdef HAVE_IPv6
  194. CONFIG_VARIABLE(dnsQueryIPv6, CONFIG_TETRASTATE,
  195. "Query for IPv6 addresses.");
  196. #endif
  197. }
  198. void
  199. initDns()
  200. {
  201. #ifndef NO_FANCY_RESOLVER
  202. int rc;
  203. struct timeval t;
  204. struct sockaddr_in *sin = (struct sockaddr_in*)&nameserverAddress;
  205. #ifdef HAVE_IPv6
  206. struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&nameserverAddress;
  207. #endif
  208. atomLocalhost = internAtom("localhost");
  209. atomLocalhostDot = internAtom("localhost.");
  210. inFlightDnsQueries = NULL;
  211. inFlightDnsQueriesLast = NULL;
  212. gettimeofday(&t, NULL);
  213. idSeed = t.tv_usec & 0xFFFF;
  214. sin->sin_family = AF_INET;
  215. sin->sin_port = htons(dnsNameServerPort);
  216. rc = inet_aton(dnsNameServer->string, &sin->sin_addr);
  217. #ifdef HAVE_IPv6
  218. if(rc != 1) {
  219. sin6->sin6_family = AF_INET6;
  220. sin6->sin6_port = htons(dnsNameServerPort);
  221. rc = inet_pton(AF_INET6, dnsNameServer->string, &sin6->sin6_addr);
  222. }
  223. #endif
  224. if(rc != 1) {
  225. do_log(L_ERROR, "DNS: couldn't parse name server %s.\n",
  226. dnsNameServer->string);
  227. exit(1);
  228. }
  229. #endif
  230. }
  231. int
  232. do_gethostbyname(char *origname,
  233. int count,
  234. int (*handler)(int, GethostbynameRequestPtr),
  235. void *data)
  236. {
  237. ObjectPtr object;
  238. int n = strlen(origname);
  239. AtomPtr name;
  240. GethostbynameRequestRec request;
  241. int done, rc;
  242. memset(&request, 0, sizeof(request));
  243. request.name = NULL;
  244. request.addr = NULL;
  245. request.error_message = NULL;
  246. request.count = count;
  247. request.handler = handler;
  248. request.data = data;
  249. if(n <= 0 || n > 131) {
  250. if(n <= 0) {
  251. request.error_message = internAtom("empty name");
  252. do_log(L_ERROR, "Empty DNS name.\n");
  253. done = handler(-EINVAL, &request);
  254. } else {
  255. request.error_message = internAtom("name too long");
  256. do_log(L_ERROR, "DNS name too long.\n");
  257. done = handler(-ENAMETOOLONG, &request);
  258. }
  259. assert(done);
  260. releaseAtom(request.error_message);
  261. return 1;
  262. }
  263. if(origname[n - 1] == '.')
  264. n--;
  265. name = internAtomLowerN(origname, n);
  266. if(name == NULL) {
  267. request.error_message = internAtom("couldn't allocate name");
  268. do_log(L_ERROR, "Couldn't allocate DNS name.\n");
  269. done = handler(-ENOMEM, &request);
  270. assert(done);
  271. releaseAtom(request.error_message);
  272. return 1;
  273. }
  274. request.name = name;
  275. request.addr = NULL;
  276. request.error_message = NULL;
  277. request.count = count;
  278. request.object = NULL;
  279. request.handler = handler;
  280. request.data = data;
  281. object = findObject(OBJECT_DNS, name->string, name->length);
  282. if(object == NULL || objectMustRevalidate(object, NULL)) {
  283. if(object) {
  284. privatiseObject(object, 0);
  285. releaseObject(object);
  286. }
  287. object = makeObject(OBJECT_DNS, name->string, name->length, 1, 0,
  288. NULL, NULL);
  289. if(object == NULL) {
  290. request.error_message = internAtom("Couldn't allocate object");
  291. do_log(L_ERROR, "Couldn't allocate DNS object.\n");
  292. done = handler(-ENOMEM, &request);
  293. assert(done);
  294. releaseAtom(name);
  295. releaseAtom(request.error_message);
  296. return 1;
  297. }
  298. }
  299. if((object->flags & (OBJECT_INITIAL | OBJECT_INPROGRESS)) ==
  300. OBJECT_INITIAL) {
  301. if(dnsUseGethostbyname >= 3)
  302. rc = really_do_gethostbyname(name, object);
  303. else
  304. rc = really_do_dns(name, object);
  305. if(rc < 0) {
  306. assert(!(object->flags & (OBJECT_INITIAL | OBJECT_INPROGRESS)));
  307. goto fail;
  308. }
  309. }
  310. if(dnsUseGethostbyname >= 3)
  311. assert(!(object->flags & OBJECT_INITIAL));
  312. #ifndef NO_FANCY_RESOLVER
  313. if(object->flags & OBJECT_INITIAL) {
  314. ConditionHandlerPtr chandler;
  315. assert(object->flags & OBJECT_INPROGRESS);
  316. request.object = object;
  317. chandler = conditionWait(&object->condition, dnsHandler,
  318. sizeof(request), &request);
  319. if(chandler == NULL)
  320. goto fail;
  321. return 1;
  322. }
  323. #endif
  324. if(object->headers && object->headers->length > 0) {
  325. if(object->headers->string[0] == DNS_A)
  326. assert(((object->headers->length - 1) %
  327. sizeof(HostAddressRec)) == 0);
  328. else
  329. assert(object->headers->string[0] == DNS_CNAME);
  330. request.addr = retainAtom(object->headers);
  331. } else if(object->message) {
  332. request.error_message = retainAtom(object->message);
  333. }
  334. releaseObject(object);
  335. if(request.addr && request.addr->length > 0)
  336. done = handler(1, &request);
  337. else
  338. done = handler(-EDNS_HOST_NOT_FOUND, &request);
  339. assert(done);
  340. releaseAtom(request.addr); request.addr = NULL;
  341. releaseAtom(request.name); request.name = NULL;
  342. releaseAtom(request.error_message); request.error_message = NULL;
  343. return 1;
  344. fail:
  345. releaseNotifyObject(object);
  346. done = handler(-errno, &request);
  347. assert(done);
  348. releaseAtom(name);
  349. return 1;
  350. }
  351. static int
  352. dnsDelayedErrorNotifyHandler(TimeEventHandlerPtr event)
  353. {
  354. int done;
  355. GethostbynameRequestRec request =
  356. *(GethostbynameRequestPtr)event->data;
  357. done = request.handler(-EDNS_HOST_NOT_FOUND, &request);
  358. assert(done);
  359. releaseAtom(request.name); request.name = NULL;
  360. releaseAtom(request.addr); request.addr = NULL;
  361. releaseAtom(request.error_message); request.error_message = NULL;
  362. return 1;
  363. }
  364. static int
  365. dnsDelayedDoneNotifyHandler(TimeEventHandlerPtr event)
  366. {
  367. int done;
  368. GethostbynameRequestRec request = *(GethostbynameRequestPtr)event->data;
  369. done = request.handler(1, &request);
  370. assert(done);
  371. releaseAtom(request.name); request.name = NULL;
  372. releaseAtom(request.addr); request.addr = NULL;
  373. releaseAtom(request.error_message); request.error_message = NULL;
  374. return 1;
  375. }
  376. static int
  377. dnsDelayedNotify(int error, GethostbynameRequestPtr request)
  378. {
  379. TimeEventHandlerPtr handler;
  380. if(error)
  381. handler = scheduleTimeEvent(0,
  382. dnsDelayedErrorNotifyHandler,
  383. sizeof(*request), request);
  384. else
  385. handler = scheduleTimeEvent(0,
  386. dnsDelayedDoneNotifyHandler,
  387. sizeof(*request), request);
  388. if(handler == NULL) {
  389. do_log(L_ERROR, "Couldn't schedule DNS notification.\n");
  390. return -1;
  391. }
  392. return 1;
  393. }
  394. #ifdef HAVE_IPv6
  395. AtomPtr
  396. rfc2732(AtomPtr name)
  397. {
  398. char buf[40]; /* 8*4 (hexdigits) + 7 (colons) + 1 ('\0') */
  399. int rc;
  400. AtomPtr a = NULL;
  401. if(name->length < 40+2 &&
  402. name->string[0] == '[' && name->string[name->length - 1] == ']') {
  403. struct in6_addr in6a;
  404. memcpy(buf, name->string + 1, name->length - 2);
  405. buf[name->length - 2] = '\0';
  406. rc = inet_pton(AF_INET6, buf, &in6a);
  407. if(rc == 1) {
  408. char s[1 + sizeof(HostAddressRec)];
  409. memset(s, 0, sizeof(s));
  410. s[0] = DNS_A;
  411. s[1] = 6;
  412. memcpy(s + 2, &in6a, 16);
  413. a = internAtomN(s, 1 + sizeof(HostAddressRec));
  414. if(a == NULL)
  415. return NULL;
  416. }
  417. }
  418. return a;
  419. }
  420. /* Used for sorting host addresses depending on the value of dnsQueryIPv6 */
  421. int
  422. compare_hostaddr(const void *av, const void *bv)
  423. {
  424. const HostAddressRec *a = av, *b = bv;
  425. int r;
  426. if(a->af == 4) {
  427. if(b->af == 4)
  428. r = 0;
  429. else
  430. r = -1;
  431. } else {
  432. if(b->af == 6)
  433. r = 0;
  434. else
  435. r = 1;
  436. }
  437. if(dnsQueryIPv6 >= 2)
  438. return -r;
  439. else
  440. return r;
  441. }
  442. #ifndef NO_STANDARD_RESOLVER
  443. static int
  444. really_do_gethostbyname(AtomPtr name, ObjectPtr object)
  445. {
  446. struct addrinfo *ai, *entry, hints;
  447. int rc;
  448. int error, i;
  449. char buf[1024];
  450. AtomPtr a;
  451. a = rfc2732(name);
  452. if(a) {
  453. object->headers = a;
  454. object->age = current_time.tv_sec;
  455. object->expires = current_time.tv_sec + 240;
  456. object->flags &= ~(OBJECT_INITIAL | OBJECT_INPROGRESS);
  457. notifyObject(object);
  458. return 0;
  459. }
  460. memset(&hints, 0, sizeof(hints));
  461. hints.ai_protocol = IPPROTO_TCP;
  462. if(dnsQueryIPv6 <= 0)
  463. hints.ai_family = AF_INET;
  464. else if(dnsQueryIPv6 >= 3)
  465. hints.ai_family = AF_INET6;
  466. rc = getaddrinfo(name->string, NULL, &hints, &ai);
  467. switch(rc) {
  468. case 0: error = 0; break;
  469. case EAI_FAMILY:
  470. #ifdef EAI_ADDRFAMILY
  471. case EAI_ADDRFAMILY:
  472. #endif
  473. case EAI_SOCKTYPE:
  474. error = EAFNOSUPPORT; break;
  475. case EAI_BADFLAGS: error = EINVAL; break;
  476. case EAI_SERVICE: error = EDNS_NO_RECOVERY; break;
  477. #ifdef EAI_NONAME
  478. case EAI_NONAME:
  479. #endif
  480. #ifdef EAI_NODATA
  481. case EAI_NODATA:
  482. #endif
  483. error = EDNS_NO_ADDRESS; break;
  484. case EAI_FAIL: error = EDNS_NO_RECOVERY; break;
  485. case EAI_AGAIN: error = EDNS_TRY_AGAIN; break;
  486. #ifdef EAI_MEMORY
  487. case EAI_MEMORY: error = ENOMEM; break;
  488. #endif
  489. case EAI_SYSTEM: error = errno; break;
  490. default: error = EUNKNOWN;
  491. }
  492. if(error == EDNS_NO_ADDRESS) {
  493. object->headers = NULL;
  494. object->age = current_time.tv_sec;
  495. object->expires = current_time.tv_sec + dnsNegativeTtl;
  496. object->flags &= ~(OBJECT_INITIAL | OBJECT_INPROGRESS);
  497. notifyObject(object);
  498. return 0;
  499. } else if(error) {
  500. do_log_error(L_ERROR, error, "Getaddrinfo failed");
  501. object->flags &= ~OBJECT_INPROGRESS;
  502. abortObject(object, 404,
  503. internAtomError(error, "Getaddrinfo failed"));
  504. notifyObject(object);
  505. return 0;
  506. }
  507. entry = ai;
  508. buf[0] = DNS_A;
  509. i = 0;
  510. while(entry) {
  511. HostAddressRec host;
  512. int host_valid = 0;
  513. if(entry->ai_family == AF_INET && entry->ai_protocol == IPPROTO_TCP) {
  514. if(dnsQueryIPv6 < 3) {
  515. host.af = 4;
  516. memset(host.data, 0, sizeof(host.data));
  517. memcpy(&host.data,
  518. &((struct sockaddr_in*)entry->ai_addr)->sin_addr,
  519. 4);
  520. host_valid = 1;
  521. }
  522. } else if(entry->ai_family == AF_INET6 &&
  523. entry->ai_protocol == IPPROTO_TCP) {
  524. if(dnsQueryIPv6 > 0) {
  525. host.af = 6;
  526. memset(&host.data, 0, sizeof(host.data));
  527. memcpy(&host.data,
  528. &((struct sockaddr_in6*)entry->ai_addr)->sin6_addr,
  529. 16);
  530. host_valid = 1;
  531. }
  532. }
  533. if(host_valid) {
  534. if(i >= 1024 / sizeof(HostAddressRec) - 2) {
  535. do_log(L_ERROR, "Too many addresses for host %s\n",
  536. name->string);
  537. break;
  538. }
  539. memcpy(buf + 1 + i * sizeof(HostAddressRec),
  540. &host, sizeof(HostAddressRec));
  541. i++;
  542. }
  543. entry = entry->ai_next;
  544. }
  545. freeaddrinfo(ai);
  546. if(i == 0) {
  547. do_log(L_ERROR, "Getaddrinfo returned no useful addresses\n");
  548. object->flags &= ~OBJECT_INPROGRESS;
  549. abortObject(object, 404,
  550. internAtom("Getaddrinfo returned no useful addresses"));
  551. notifyObject(object);
  552. return 0;
  553. }
  554. if(1 <= dnsQueryIPv6 && dnsQueryIPv6 <= 2)
  555. qsort(buf + 1, i, sizeof(HostAddressRec), compare_hostaddr);
  556. a = internAtomN(buf, 1 + i * sizeof(HostAddressRec));
  557. if(a == NULL) {
  558. object->flags &= ~OBJECT_INPROGRESS;
  559. abortObject(object, 501, internAtom("Couldn't allocate address"));
  560. notifyObject(object);
  561. return 0;
  562. }
  563. object->headers = a;
  564. object->age = current_time.tv_sec;
  565. object->expires = current_time.tv_sec + dnsGethostbynameTtl;
  566. object->flags &= ~(OBJECT_INITIAL | OBJECT_INPROGRESS);
  567. notifyObject(object);
  568. return 0;
  569. }
  570. #endif
  571. #else
  572. #ifndef NO_STANDARD_RESOLVER
  573. static int
  574. really_do_gethostbyname(AtomPtr name, ObjectPtr object)
  575. {
  576. struct hostent *host;
  577. char *s;
  578. AtomPtr a;
  579. int i, j;
  580. int error;
  581. host = gethostbyname(name->string);
  582. if(host == NULL) {
  583. switch(h_errno) {
  584. case HOST_NOT_FOUND: error = EDNS_HOST_NOT_FOUND; break;
  585. #ifdef NO_ADDRESS
  586. case NO_ADDRESS: error = EDNS_NO_ADDRESS; break;
  587. #endif
  588. case NO_RECOVERY: error = EDNS_NO_RECOVERY; break;
  589. case TRY_AGAIN: error = EDNS_TRY_AGAIN; break;
  590. default: error = EUNKNOWN; break;
  591. }
  592. if(error == EDNS_HOST_NOT_FOUND) {
  593. object->headers = NULL;
  594. object->age = current_time.tv_sec;
  595. object->expires = current_time.tv_sec + dnsNegativeTtl;
  596. object->flags &= ~(OBJECT_INITIAL | OBJECT_INPROGRESS);
  597. object->flags &= ~OBJECT_INPROGRESS;
  598. notifyObject(object);
  599. return 0;
  600. } else {
  601. do_log_error(L_ERROR, error, "Gethostbyname failed");
  602. abortObject(object, 404,
  603. internAtomError(error, "Gethostbyname failed"));
  604. object->flags &= ~OBJECT_INPROGRESS;
  605. notifyObject(object);
  606. return 0;
  607. }
  608. }
  609. if(host->h_addrtype != AF_INET) {
  610. do_log(L_ERROR, "Address is not AF_INET.\n");
  611. object->flags &= ~OBJECT_INPROGRESS;
  612. abortObject(object, 404, internAtom("Address is not AF_INET"));
  613. notifyObject(object);
  614. return -1;
  615. }
  616. if(host->h_length != sizeof(struct in_addr)) {
  617. do_log(L_ERROR, "Address size inconsistent.\n");
  618. object->flags &= ~OBJECT_INPROGRESS;
  619. abortObject(object, 404, internAtom("Address size inconsistent"));
  620. notifyObject(object);
  621. return 0;
  622. }
  623. i = 0;
  624. while(host->h_addr_list[i] != NULL) i++;
  625. s = malloc(1 + i * sizeof(HostAddressRec));
  626. if(s == NULL) {
  627. a = NULL;
  628. } else {
  629. memset(s, 0, 1 + i * sizeof(HostAddressRec));
  630. s[0] = DNS_A;
  631. for(j = 0; j < i; j++) {
  632. s[j * sizeof(HostAddressRec) + 1] = 4;
  633. memcpy(&s[j * sizeof(HostAddressRec) + 2], host->h_addr_list[j],
  634. sizeof(struct in_addr));
  635. }
  636. a = internAtomN(s, i * sizeof(HostAddressRec) + 1);
  637. free(s);
  638. }
  639. if(!a) {
  640. object->flags &= ~OBJECT_INPROGRESS;
  641. abortObject(object, 501, internAtom("Couldn't allocate address"));
  642. notifyObject(object);
  643. return 0;
  644. }
  645. object->headers = a;
  646. object->age = current_time.tv_sec;
  647. object->expires = current_time.tv_sec + dnsGethostbynameTtl;
  648. object->flags &= ~(OBJECT_INITIAL | OBJECT_INPROGRESS);
  649. notifyObject(object);
  650. return 0;
  651. }
  652. #endif
  653. #endif
  654. #ifdef NO_STANDARD_RESOLVER
  655. static int
  656. really_do_gethostbyname(AtomPtr name, ObjectPtr object)
  657. {
  658. abort();
  659. }
  660. #endif
  661. #ifndef NO_FANCY_RESOLVER
  662. static int dnsSocket = -1;
  663. static FdEventHandlerPtr dnsSocketHandler = NULL;
  664. static int
  665. dnsHandler(int status, ConditionHandlerPtr chandler)
  666. {
  667. GethostbynameRequestRec request = *(GethostbynameRequestPtr)chandler->data;
  668. ObjectPtr object = request.object;
  669. assert(!(object->flags & OBJECT_INPROGRESS));
  670. if(object->headers) {
  671. request.addr = retainAtom(object->headers);
  672. dnsDelayedNotify(0, &request);
  673. } else {
  674. if(object->message)
  675. request.error_message = retainAtom(object->message);
  676. dnsDelayedNotify(1, &request);
  677. }
  678. releaseObject(object);
  679. return 1;
  680. }
  681. static int
  682. queryInFlight(DnsQueryPtr query)
  683. {
  684. DnsQueryPtr other;
  685. other = inFlightDnsQueries;
  686. while(other) {
  687. if(other == query)
  688. return 1;
  689. other = other->next;
  690. }
  691. return 0;
  692. }
  693. static void
  694. removeQuery(DnsQueryPtr query)
  695. {
  696. DnsQueryPtr previous;
  697. if(query == inFlightDnsQueries) {
  698. inFlightDnsQueries = query->next;
  699. if(inFlightDnsQueries == NULL)
  700. inFlightDnsQueriesLast = NULL;
  701. } else {
  702. previous = inFlightDnsQueries;
  703. while(previous->next) {
  704. if(previous->next == query)
  705. break;
  706. previous = previous->next;
  707. }
  708. assert(previous->next != NULL);
  709. previous->next = query->next;
  710. if(previous->next == NULL)
  711. inFlightDnsQueriesLast = previous;
  712. }
  713. }
  714. static void
  715. insertQuery(DnsQueryPtr query)
  716. {
  717. if(inFlightDnsQueriesLast)
  718. inFlightDnsQueriesLast->next = query;
  719. else
  720. inFlightDnsQueries = query;
  721. inFlightDnsQueriesLast = query;
  722. }
  723. static DnsQueryPtr
  724. findQuery(int id, AtomPtr name)
  725. {
  726. DnsQueryPtr query;
  727. query = inFlightDnsQueries;
  728. while(query) {
  729. if(query->id == id && (name == NULL || query->name == name))
  730. return query;
  731. query = query->next;
  732. }
  733. return NULL;
  734. }
  735. static int
  736. dnsTimeoutHandler(TimeEventHandlerPtr event)
  737. {
  738. DnsQueryPtr query = *(DnsQueryPtr*)event->data;
  739. ObjectPtr object = query->object;
  740. int rc;
  741. /* People are reporting that this does happen. And I have no idea why. */
  742. if(!queryInFlight(query)) {
  743. do_log(L_ERROR, "BUG: timing out martian query (%s, flags: 0x%x).\n",
  744. scrub(query->name->string), (unsigned)object->flags);
  745. return 1;
  746. }
  747. query->timeout = MAX(10, query->timeout * 2);
  748. if(query->timeout > dnsMaxTimeout) {
  749. abortObject(object, 501, internAtom("Timeout"));
  750. goto fail;
  751. } else {
  752. rc = sendQuery(query);
  753. if(rc < 0) {
  754. if(rc != -EWOULDBLOCK && rc != -EAGAIN && rc != -ENOBUFS) {
  755. abortObject(object, 501,
  756. internAtomError(-rc,
  757. "Couldn't send DNS query"));
  758. goto fail;
  759. }
  760. /* else let it timeout */
  761. }
  762. query->timeout_handler =
  763. scheduleTimeEvent(query->timeout, dnsTimeoutHandler,
  764. sizeof(query), &query);
  765. if(query->timeout_handler == NULL) {
  766. do_log(L_ERROR, "Couldn't schedule DNS timeout handler.\n");
  767. abortObject(object, 501,
  768. internAtom("Couldn't schedule DNS timeout handler"));
  769. goto fail;
  770. }
  771. return 1;
  772. }
  773. fail:
  774. removeQuery(query);
  775. object->flags &= ~OBJECT_INPROGRESS;
  776. if(query->inet4) releaseAtom(query->inet4);
  777. if(query->inet6) releaseAtom(query->inet6);
  778. free(query);
  779. releaseNotifyObject(object);
  780. return 1;
  781. }
  782. static int
  783. establishDnsSocket()
  784. {
  785. int rc;
  786. #ifdef HAVE_IPv6
  787. int inet6 = (nameserverAddress.sa_family == AF_INET6);
  788. int pf = inet6 ? PF_INET6 : PF_INET;
  789. int sa_size =
  790. inet6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
  791. #else
  792. int pf = PF_INET;
  793. int sa_size = sizeof(struct sockaddr_in);
  794. #endif
  795. if(dnsSocket < 0) {
  796. assert(!dnsSocketHandler);
  797. dnsSocket = socket(pf, SOCK_DGRAM, 0);
  798. if(dnsSocket < 0) {
  799. do_log_error(L_ERROR, errno, "Couldn't create DNS socket");
  800. return -errno;
  801. }
  802. rc = connect(dnsSocket, &nameserverAddress, sa_size);
  803. if(rc < 0) {
  804. CLOSE(dnsSocket);
  805. dnsSocket = -1;
  806. do_log_error(L_ERROR, errno, "Couldn't create DNS \"connection\"");
  807. return -errno;
  808. }
  809. }
  810. if(!dnsSocketHandler) {
  811. dnsSocketHandler =
  812. registerFdEvent(dnsSocket, POLLIN, dnsReplyHandler, 0, NULL);
  813. if(dnsSocketHandler == NULL) {
  814. do_log(L_ERROR, "Couldn't register DNS socket handler.\n");
  815. CLOSE(dnsSocket);
  816. dnsSocket = -1;
  817. return -ENOMEM;
  818. }
  819. }
  820. return 1;
  821. }
  822. static int
  823. sendQuery(DnsQueryPtr query)
  824. {
  825. char buf[512];
  826. int buflen;
  827. int rc;
  828. int af[2];
  829. int i;
  830. if(dnsSocket < 0)
  831. return -1;
  832. if(dnsQueryIPv6 <= 0) {
  833. af[0] = 4; af[1] = 0;
  834. } else if(dnsQueryIPv6 <= 2) {
  835. af[0] = 4; af[1] = 6;
  836. } else {
  837. af[0] = 6; af[1] = 0;
  838. }
  839. for(i = 0; i < 2; i++) {
  840. if(af[i] == 0)
  841. continue;
  842. if(af[i] == 4 && query->inet4)
  843. continue;
  844. else if(af[i] == 6 && query->inet6)
  845. continue;
  846. buflen = dnsBuildQuery(query->id, buf, 0, 512, query->name, af[i]);
  847. if(buflen <= 0) {
  848. do_log(L_ERROR, "Couldn't build DNS query.\n");
  849. return buflen;
  850. }
  851. rc = send(dnsSocket, buf, buflen, 0);
  852. if(rc < buflen) {
  853. if(rc >= 0) {
  854. do_log(L_ERROR, "Couldn't send DNS query: partial send.\n");
  855. return -EAGAIN;
  856. } else {
  857. do_log_error(L_ERROR, errno, "Couldn't send DNS query");
  858. return -errno;
  859. }
  860. }
  861. }
  862. return 1;
  863. }
  864. static int
  865. really_do_dns(AtomPtr name, ObjectPtr object)
  866. {
  867. int rc;
  868. DnsQueryPtr query;
  869. AtomPtr message = NULL;
  870. int id;
  871. AtomPtr a = NULL;
  872. if(a == NULL) {
  873. if(name == atomLocalhost || name == atomLocalhostDot) {
  874. char s[1 + sizeof(HostAddressRec)];
  875. memset(s, 0, sizeof(s));
  876. s[0] = DNS_A;
  877. s[1] = 4;
  878. s[2] = 127;
  879. s[3] = 0;
  880. s[4] = 0;
  881. s[5] = 1;
  882. a = internAtomN(s, 1 + sizeof(HostAddressRec));
  883. if(a == NULL) {
  884. abortObject(object, 501,
  885. internAtom("Couldn't allocate address"));
  886. notifyObject(object);
  887. errno = ENOMEM;
  888. return -1;
  889. }
  890. }
  891. }
  892. if(a == NULL) {
  893. struct in_addr ina;
  894. rc = inet_aton(name->string, &ina);
  895. if(rc == 1) {
  896. char s[1 + sizeof(HostAddressRec)];
  897. memset(s, 0, sizeof(s));
  898. s[0] = DNS_A;
  899. s[1] = 4;
  900. memcpy(s + 2, &ina, 4);
  901. a = internAtomN(s, 1 + sizeof(HostAddressRec));
  902. if(a == NULL) {
  903. abortObject(object, 501,
  904. internAtom("Couldn't allocate address"));
  905. notifyObject(object);
  906. errno = ENOMEM;
  907. return -1;
  908. }
  909. }
  910. }
  911. #ifdef HAVE_IPv6
  912. if(a == NULL)
  913. a = rfc2732(name);
  914. #endif
  915. if(a) {
  916. object->headers = a;
  917. object->age = current_time.tv_sec;
  918. object->expires = current_time.tv_sec + 240;
  919. object->flags &= ~(OBJECT_INITIAL | OBJECT_INPROGRESS);
  920. notifyObject(object);
  921. return 0;
  922. }
  923. rc = establishDnsSocket();
  924. if(rc < 0) {
  925. do_log_error(L_ERROR, -rc, "Couldn't establish DNS socket.\n");
  926. message = internAtomError(-rc, "Couldn't establish DNS socket");
  927. goto fallback;
  928. }
  929. /* The id is used to speed up detecting replies to queries that
  930. are no longer current -- see dnsReplyHandler. */
  931. id = (idSeed++) & 0xFFFF;
  932. query = malloc(sizeof(DnsQueryRec));
  933. if(query == NULL) {
  934. do_log(L_ERROR, "Couldn't allocate DNS query.\n");
  935. message = internAtom("Couldn't allocate DNS query");
  936. goto fallback;
  937. }
  938. query->id = id;
  939. query->inet4 = NULL;
  940. query->inet6 = NULL;
  941. query->name = name;
  942. query->time = current_time.tv_sec;
  943. query->object = retainObject(object);
  944. query->timeout = 4;
  945. query->timeout_handler = NULL;
  946. query->next = NULL;
  947. query->timeout_handler =
  948. scheduleTimeEvent(query->timeout, dnsTimeoutHandler,
  949. sizeof(query), &query);
  950. if(query->timeout_handler == NULL) {
  951. do_log(L_ERROR, "Couldn't schedule DNS timeout handler.\n");
  952. message = internAtom("Couldn't schedule DNS timeout handler");
  953. goto free_fallback;
  954. }
  955. insertQuery(query);
  956. object->flags |= OBJECT_INPROGRESS;
  957. rc = sendQuery(query);
  958. if(rc < 0) {
  959. if(rc != -EWOULDBLOCK && rc != -EAGAIN && rc != -ENOBUFS) {
  960. object->flags &= ~OBJECT_INPROGRESS;
  961. message = internAtomError(-rc, "Couldn't send DNS query");
  962. goto remove_fallback;
  963. }
  964. /* else let it timeout */
  965. }
  966. releaseAtom(message);
  967. return 1;
  968. remove_fallback:
  969. removeQuery(query);
  970. free_fallback:
  971. releaseObject(query->object);
  972. cancelTimeEvent(query->timeout_handler);
  973. free(query);
  974. fallback:
  975. if(dnsUseGethostbyname >= 1) {
  976. releaseAtom(message);
  977. do_log(L_WARN, "Falling back on gethostbyname.\n");
  978. return really_do_gethostbyname(name, object);
  979. } else {
  980. abortObject(object, 501, message);
  981. notifyObject(object);
  982. return 1;
  983. }
  984. }
  985. static int
  986. dnsReplyHandler(int abort, FdEventHandlerPtr event)
  987. {
  988. int fd = event->fd;
  989. char buf[2048];
  990. int len, rc;
  991. ObjectPtr object;
  992. unsigned ttl = 0;
  993. AtomPtr name, value, message = NULL;
  994. int id;
  995. int af;
  996. DnsQueryPtr query;
  997. AtomPtr cname = NULL;
  998. if(abort) {
  999. dnsSocketHandler = NULL;
  1000. rc = establishDnsSocket();
  1001. if(rc < 0) {
  1002. do_log(L_ERROR, "Couldn't reestablish DNS socket.\n");
  1003. /* At this point, we should abort all in-flight
  1004. DNS requests. Oh, well, they'll timeout anyway. */
  1005. }
  1006. return 1;
  1007. }
  1008. len = recv(fd, buf, 2048, 0);
  1009. if(len <= 0) {
  1010. if(errno == EINTR || errno == EAGAIN) return 0;
  1011. /* This is where we get ECONNREFUSED for an ICMP port unreachable */
  1012. do_log_error(L_ERROR, errno, "DNS: recv failed");
  1013. dnsGethostbynameFallback(-1, message);
  1014. return 0;
  1015. }
  1016. /* This could be a late reply to a query that timed out and was
  1017. resent, a reply to a query that timed out, or a reply to an
  1018. AAAA query when we already got a CNAME reply to the associated
  1019. A. We filter such replies straight away, without trying to
  1020. parse them. */
  1021. rc = dnsReplyId(buf, 0, len, &id);
  1022. if(rc < 0) {
  1023. do_log(L_WARN, "Short DNS reply.\n");
  1024. return 0;
  1025. }
  1026. if(!findQuery(id, NULL)) {
  1027. return 0;
  1028. }
  1029. rc = dnsDecodeReply(buf, 0, len, &id, &name, &value, &af, &ttl);
  1030. if(rc < 0) {
  1031. assert(value == NULL);
  1032. /* We only want to fallback on gethostbyname if we received a
  1033. reply that we could not understand. What about truncated
  1034. replies? */
  1035. if(rc < 0) {
  1036. do_log_error(L_WARN, -rc, "DNS");
  1037. if(dnsUseGethostbyname >= 2 ||
  1038. (dnsUseGethostbyname &&
  1039. (rc != -EDNS_HOST_NOT_FOUND && rc != -EDNS_NO_RECOVERY &&
  1040. rc != -EDNS_FORMAT))) {
  1041. dnsGethostbynameFallback(id, message);
  1042. return 0;
  1043. } else {
  1044. message = internAtom(pstrerror(-rc));
  1045. }
  1046. } else {
  1047. assert(name != NULL && id >= 0 && af >= 0);
  1048. }
  1049. }
  1050. query = findQuery(id, name);
  1051. if(query == NULL) {
  1052. /* Duplicate id ? */
  1053. releaseAtom(value);
  1054. releaseAtom(name);
  1055. return 0;
  1056. }
  1057. /* We're going to use the information in this reply. If it was an
  1058. error, construct an empty atom to distinguish it from information
  1059. we're still waiting for. */
  1060. if(value == NULL)
  1061. value = internAtom("");
  1062. again:
  1063. if(af == 4) {
  1064. if(query->inet4 == NULL) {
  1065. query->inet4 = value;
  1066. query->ttl4 = current_time.tv_sec + ttl;
  1067. } else
  1068. releaseAtom(value);
  1069. } else if(af == 6) {
  1070. if(query->inet6 == NULL) {
  1071. query->inet6 = value;
  1072. query->ttl6 = current_time.tv_sec + ttl;
  1073. } else
  1074. releaseAtom(value);
  1075. } else if(af == 0) {
  1076. /* Ignore errors in this case. */
  1077. if(query->inet4 && query->inet4->length == 0) {
  1078. releaseAtom(query->inet4);
  1079. query->inet4 = NULL;
  1080. }
  1081. if(query->inet6 && query->inet6->length == 0) {
  1082. releaseAtom(query->inet6);
  1083. query->inet6 = NULL;
  1084. }
  1085. if(query->inet4 || query->inet6) {
  1086. do_log(L_WARN, "Host %s has both %s and CNAME -- "
  1087. "ignoring CNAME.\n", scrub(query->name->string),
  1088. query->inet4 ? "A" : "AAAA");
  1089. releaseAtom(value);
  1090. value = internAtom("");
  1091. af = query->inet4 ? 4 : 6;
  1092. goto again;
  1093. } else {
  1094. cname = value;
  1095. }
  1096. }
  1097. if(rc >= 0 && !cname &&
  1098. ((dnsQueryIPv6 < 3 && query->inet4 == NULL) ||
  1099. (dnsQueryIPv6 > 0 && query->inet6 == NULL)))
  1100. return 0;
  1101. /* This query is complete */
  1102. cancelTimeEvent(query->timeout_handler);
  1103. object = query->object;
  1104. if(object->flags & OBJECT_INITIAL) {
  1105. assert(!object->headers);
  1106. if(cname) {
  1107. assert(query->inet4 == NULL && query->inet6 == NULL);
  1108. object->headers = cname;
  1109. object->expires = current_time.tv_sec + ttl;
  1110. } else if((!query->inet4 || query->inet4->length == 0) &&
  1111. (!query->inet6 || query->inet6->length == 0)) {
  1112. releaseAtom(query->inet4);
  1113. releaseAtom(query->inet6);
  1114. object->expires = current_time.tv_sec + dnsNegativeTtl;
  1115. abortObject(object, 500, retainAtom(message));
  1116. } else if(!query->inet4 || query->inet4->length == 0) {
  1117. object->headers = query->inet6;
  1118. object->expires = query->ttl6;
  1119. releaseAtom(query->inet4);
  1120. } else if(!query->inet6 || query->inet6->length == 0) {
  1121. object->headers = query->inet4;
  1122. object->expires = query->ttl4;
  1123. releaseAtom(query->inet6);
  1124. } else {
  1125. /* need to merge results */
  1126. char buf[1024];
  1127. if(query->inet4->length + query->inet6->length > 1024) {
  1128. releaseAtom(query->inet4);
  1129. releaseAtom(query->inet6);
  1130. abortObject(object, 500, internAtom("DNS reply too long"));
  1131. } else {
  1132. if(dnsQueryIPv6 <= 1) {
  1133. memcpy(buf, query->inet4->string, query->inet4->length);
  1134. memcpy(buf + query->inet4->length,
  1135. query->inet6->string + 1, query->inet6->length - 1);
  1136. } else {
  1137. memcpy(buf, query->inet6->string, query->inet6->length);
  1138. memcpy(buf + query->inet6->length,
  1139. query->inet4->string + 1, query->inet4->length - 1);
  1140. }
  1141. object->headers =
  1142. internAtomN(buf,
  1143. query->inet4->length +
  1144. query->inet6->length - 1);
  1145. if(object->headers == NULL)
  1146. abortObject(object, 500,
  1147. internAtom("Couldn't allocate DNS atom"));
  1148. }
  1149. object->expires = MIN(query->ttl4, query->ttl6);
  1150. }
  1151. object->age = current_time.tv_sec;
  1152. object->flags &= ~(OBJECT_INITIAL | OBJECT_INPROGRESS);
  1153. } else {
  1154. do_log(L_WARN, "DNS object ex nihilo for %s.\n",
  1155. scrub(query->name->string));
  1156. }
  1157. removeQuery(query);
  1158. free(query);
  1159. releaseAtom(name);
  1160. releaseAtom(message);
  1161. releaseNotifyObject(object);
  1162. return 0;
  1163. }
  1164. static int
  1165. dnsGethostbynameFallback(int id, AtomPtr message)
  1166. {
  1167. DnsQueryPtr query, previous;
  1168. ObjectPtr object;
  1169. if(inFlightDnsQueries == NULL) {
  1170. releaseAtom(message);
  1171. return 1;
  1172. }
  1173. query = NULL;
  1174. if(id < 0 || inFlightDnsQueries->id == id) {
  1175. previous = NULL;
  1176. query = inFlightDnsQueries;
  1177. } else {
  1178. previous = inFlightDnsQueries;
  1179. while(previous->next) {
  1180. if(previous->next->id == id) {
  1181. query = previous->next;
  1182. break;
  1183. }
  1184. previous = previous->next;
  1185. }
  1186. if(!query) {
  1187. previous = NULL;
  1188. query = inFlightDnsQueries;
  1189. }
  1190. }
  1191. if(previous == NULL) {
  1192. inFlightDnsQueries = query->next;
  1193. if(inFlightDnsQueries == NULL)
  1194. inFlightDnsQueriesLast = NULL;
  1195. } else {
  1196. previous->next = query->next;
  1197. if(query->next == NULL)
  1198. inFlightDnsQueriesLast = NULL;
  1199. }
  1200. object = makeObject(OBJECT_DNS, query->name->string, query->name->length,
  1201. 1, 0, NULL, NULL);
  1202. if(!object) {
  1203. do_log(L_ERROR, "Couldn't make DNS object.\n");
  1204. releaseAtom(query->name);
  1205. releaseAtom(message);
  1206. releaseObject(query->object);
  1207. cancelTimeEvent(query->timeout_handler);
  1208. free(query);
  1209. return -1;
  1210. }
  1211. if(dnsUseGethostbyname >= 1) {
  1212. releaseAtom(message);
  1213. do_log(L_WARN, "Falling back to using system resolver.\n");
  1214. really_do_gethostbyname(retainAtom(query->name), object);
  1215. } else {
  1216. releaseAtom(object->message);
  1217. object->message = message;
  1218. object->flags &= ~OBJECT_INPROGRESS;
  1219. releaseNotifyObject(object);
  1220. }
  1221. cancelTimeEvent(query->timeout_handler);
  1222. releaseAtom(query->name);
  1223. if(query->inet4) releaseAtom(query->inet4);
  1224. if(query->inet6) releaseAtom(query->inet6);
  1225. releaseObject(query->object);
  1226. free(query);
  1227. return 1;
  1228. }
  1229. static int
  1230. stringToLabels(char *buf, int offset, int n, char *string)
  1231. {
  1232. int i = offset;
  1233. int j = 0, k = 0;
  1234. while(1) {
  1235. while(string[k] != '.' && string[k] != '\0')
  1236. k++;
  1237. if(k >= j + 256) return -1;
  1238. buf[i] = (unsigned char)(k - j); i++; if(i >= n) return -1;
  1239. while(j < k) {
  1240. buf[i] = string[j]; i++; j++; if(i >= n) return -1;
  1241. }
  1242. if(string[j] == '\0') {
  1243. buf[i] = '\0';
  1244. i++; if(i >= n) return -1;
  1245. break;
  1246. }
  1247. j++; k++;
  1248. }
  1249. return i;
  1250. }
  1251. #ifdef UNALIGNED_ACCESS
  1252. #define DO_NTOHS(_d, _s) _d = ntohs(*(unsigned short*)(_s));
  1253. #define DO_NTOHL(_d, _s) _d = ntohl(*(unsigned*)(_s))
  1254. #define DO_HTONS(_d, _s) *(unsigned short*)(_d) = htons(_s);
  1255. #define DO_HTONL(_d, _s) *(unsigned*)(_d) = htonl(_s)
  1256. #else
  1257. #define DO_NTOHS(_d, _s) \
  1258. do { unsigned short _dd; \
  1259. memcpy(&(_dd), (_s), sizeof(unsigned short)); \
  1260. _d = ntohs(_dd); } while(0)
  1261. #define DO_NTOHL(_d, _s) \
  1262. do { unsigned _dd; \
  1263. memcpy(&(_dd), (_s), sizeof(unsigned)); \
  1264. _d = ntohl(_dd); } while(0)
  1265. #define DO_HTONS(_d, _s) \
  1266. do { unsigned short _dd; \
  1267. _dd = htons(_s); \
  1268. memcpy((_d), &(_dd), sizeof(unsigned short)); } while(0);
  1269. #define DO_HTONL(_d, _s) \
  1270. do { unsigned _dd; \
  1271. _dd = htonl(_s); \
  1272. memcpy((_d), &(_dd), sizeof(unsigned)); } while(0);
  1273. #endif
  1274. static int
  1275. labelsToString(char *buf, int offset, int n, char *d, int m, int *j_return)
  1276. {
  1277. int i = offset, j, k;
  1278. int ll, rc;
  1279. j = 0;
  1280. while(1) {
  1281. if(i >= n) return -1;
  1282. ll = *(unsigned char*)&buf[i]; i++;
  1283. if(ll == 0) {
  1284. break;
  1285. }
  1286. if((ll & (3 << 6)) == (3 << 6)) {
  1287. /* RFC 1035, 4.1.4 */
  1288. int o;
  1289. if(i >= n) return -1;
  1290. o = (ll & ~(3 << 6)) << 8 | *(unsigned char*)&buf[i];
  1291. i++;
  1292. rc = labelsToString(buf, o, n, &d[j], m - j, &k);
  1293. if(rc < 0)
  1294. return -1;
  1295. j += k;
  1296. break;
  1297. } else if((ll & (3 << 6)) == 0) {
  1298. for(k = 0; k < ll; k++) {
  1299. if(i >= n || j >= m) return -1;
  1300. d[j++] = buf[i++];
  1301. }
  1302. if(i >= n) return -1;
  1303. if(buf[i] != '\0') {
  1304. if(j >= m) return -1;
  1305. d[j++] = '.';
  1306. }
  1307. } else {
  1308. return -1;
  1309. }
  1310. }
  1311. *j_return = j;
  1312. return i;
  1313. }
  1314. static int
  1315. dnsBuildQuery(int id, char *buf, int offset, int n, AtomPtr name, int af)
  1316. {
  1317. int i = offset;
  1318. int type;
  1319. switch(af) {
  1320. case 4: type = 1; break;
  1321. case 6: type = 28; break;
  1322. default: return -EINVAL;
  1323. }
  1324. if(i + 12 >= n) return -1;
  1325. DO_HTONS(&buf[i], id); i += 2;
  1326. DO_HTONS(&buf[i], 1<<8); i += 2;
  1327. DO_HTONS(&buf[i], 1); i += 2;
  1328. DO_HTONS(&buf[i], 0); i += 2;
  1329. DO_HTONS(&buf[i], 0); i += 2;
  1330. DO_HTONS(&buf[i], 0); i += 2;
  1331. i = stringToLabels(buf, i, n, name->string);
  1332. if(i < 0) return -ENAMETOOLONG;
  1333. if(i + 4 >= n) return -ENAMETOOLONG;
  1334. DO_HTONS(&buf[i], type); i += 2;
  1335. DO_HTONS(&buf[i], 1); i += 2;
  1336. return i;
  1337. }
  1338. static int
  1339. dnsReplyId(char *buf, int offset, int n, int *id_return)
  1340. {
  1341. if(n - offset < 12)
  1342. return -1;
  1343. DO_NTOHS(*id_return, &buf[offset]);
  1344. return 1;
  1345. }
  1346. static int
  1347. dnsDecodeReply(char *buf, int offset, int n, int *id_return,
  1348. AtomPtr *name_return, AtomPtr *value_return,
  1349. int *af_return, unsigned *ttl_return)
  1350. {
  1351. int i = offset, j, m;
  1352. int id = -1, b23, qdcount, ancount, nscount, arcount, rdlength;
  1353. int class, type;
  1354. unsigned int ttl;
  1355. char b[2048];
  1356. int af = -1;
  1357. AtomPtr name = NULL, value;
  1358. char addresses[1024];
  1359. int addr_index = 0;
  1360. int error = EDNS_NO_ADDRESS;
  1361. unsigned final_ttl = 7 * 24 * 3600;
  1362. int dnserror;
  1363. if(n - i < 12) {
  1364. error = EDNS_INVALID;
  1365. goto fail;
  1366. }
  1367. DO_NTOHS(id, &buf[i]); i += 2;
  1368. DO_NTOHS(b23, &buf[i]); i += 2;
  1369. DO_NTOHS(qdcount, &buf[i]); i += 2;
  1370. DO_NTOHS(ancount, &buf[i]); i += 2;
  1371. DO_NTOHS(nscount, &buf[i]); i += 2;
  1372. DO_NTOHS(arcount, &buf[i]); i += 2;
  1373. do_log(D_DNS,
  1374. "DNS id %d, b23 0x%x, qdcount %d, ancount %d, "
  1375. "nscount %d, arcount %d\n",
  1376. id, b23, qdcount, ancount, nscount, arcount);
  1377. if((b23 & (0xF870)) != 0x8000) {
  1378. do_log(L_ERROR, "Incorrect DNS reply (b23 = 0x%x).\n", b23);
  1379. error = EDNS_INVALID;
  1380. goto fail;
  1381. }
  1382. dnserror = b23 & 0xF;
  1383. if(b23 & 0x200) {
  1384. do_log(L_WARN, "Truncated DNS reply (b23 = 0x%x).\n", b23);
  1385. }
  1386. if(dnserror || qdcount != 1) {
  1387. if(!dnserror)
  1388. do_log(L_ERROR,
  1389. "Unexpected number %d of DNS questions.\n", qdcount);
  1390. if(dnserror == 1)
  1391. error = EDNS_FORMAT;
  1392. else if(dnserror == 2)
  1393. error = EDNS_NO_RECOVERY;
  1394. else if(dnserror == 3)
  1395. error = EDNS_HOST_NOT_FOUND;
  1396. else if(dnserror == 4 || dnserror == 5)
  1397. error = EDNS_REFUSED;
  1398. else if(dnserror == 0)
  1399. error = EDNS_INVALID;
  1400. else
  1401. error = EUNKNOWN;
  1402. goto fail;
  1403. }
  1404. /* We do this early, so that we can return the address family to
  1405. the caller in case of error. */
  1406. i = labelsToString(buf, i, n, b, 2048, &m);
  1407. if(i < 0) {
  1408. error = EDNS_FORMAT;
  1409. goto fail;
  1410. }
  1411. DO_NTOHS(type, &buf[i]); i += 2;
  1412. DO_NTOHS(class, &buf[i]); i += 2;
  1413. if(type == 1)
  1414. af = 4;
  1415. else if(type == 28)
  1416. af = 6;
  1417. else {
  1418. error = EDNS_FORMAT;
  1419. goto fail;
  1420. }
  1421. do_log(D_DNS, "DNS q: ");
  1422. do_log_n(D_DNS, b, m);
  1423. do_log(D_DNS, " (%d, %d)\n", type, class);
  1424. name = internAtomLowerN(b, m);
  1425. if(name == NULL) {
  1426. error = ENOMEM;
  1427. goto fail;
  1428. }
  1429. if(class != 1) {
  1430. error = EDNS_FORMAT;
  1431. goto fail;
  1432. }
  1433. #define PARSE_ANSWER(kind, label) \
  1434. do { \
  1435. i = labelsToString(buf, i, 1024, b, 2048, &m); \
  1436. if(i < 0) goto label; \
  1437. DO_NTOHS(type, &buf[i]); i += 2; if(i > 1024) goto label; \
  1438. DO_NTOHS(class, &buf[i]); i += 2; if(i > 1024) goto label; \
  1439. DO_NTOHL(ttl, &buf[i]); i += 4; if(i > 1024) goto label; \
  1440. DO_NTOHS(rdlength, &buf[i]); i += 2; if(i > 1024) goto label; \
  1441. do_log(D_DNS, "DNS " kind ": "); \
  1442. do_log_n(D_DNS, b, m); \
  1443. do_log(D_DNS, " (%d, %d): %d bytes, ttl %u\n", \
  1444. type, class, rdlength, ttl); \
  1445. } while(0)
  1446. for(j = 0; j < ancount; j++) {
  1447. PARSE_ANSWER("an", fail);
  1448. if(strcasecmp_n(name->string, b, m) == 0) {
  1449. if(class != 1) {
  1450. do_log(D_DNS, "DNS: %s: unknown class %d.\n",
  1451. name->string, class);
  1452. error = EDNS_UNSUPPORTED;
  1453. goto cont;
  1454. }
  1455. if(type == 1 || type == 28) {
  1456. if((type == 1 && rdlength != 4) ||
  1457. (type == 28 && rdlength != 16)) {
  1458. do_log(L_ERROR,
  1459. "DNS: %s: unexpected length %d of %s record.\n",
  1460. scrub(name->string),
  1461. rdlength, type == 1 ? "A" : "AAAA");
  1462. error = EDNS_INVALID;
  1463. if(rdlength <= 0 || rdlength >= 32)
  1464. goto fail;
  1465. goto cont;
  1466. }
  1467. if(af == 0) {
  1468. do_log(L_WARN, "DNS: %s: host has both A and CNAME -- "
  1469. "ignoring CNAME.\n", scrub(name->string));
  1470. addr_index = 0;
  1471. af = -1;
  1472. }
  1473. if(type == 1) {
  1474. if(af < 0)
  1475. af = 4;
  1476. else if(af == 6) {
  1477. do_log(L_WARN, "Unexpected AAAA reply.\n");
  1478. goto cont;
  1479. }
  1480. } else {
  1481. if(af < 0)
  1482. af = 6;
  1483. else if(af == 4) {
  1484. do_log(L_WARN, "Unexpected A reply.\n");
  1485. goto cont;
  1486. }
  1487. }
  1488. if(addr_index == 0) {
  1489. addresses[0] = DNS_A;
  1490. addr_index++;
  1491. } else {
  1492. if(addr_index > 1000) {
  1493. error = EDNS_INVALID;
  1494. goto fail;
  1495. }
  1496. }
  1497. assert(addresses[0] == DNS_A);
  1498. if(final_ttl > ttl)
  1499. final_ttl = ttl;
  1500. memset(&addresses[addr_index], 0, sizeof(HostAddressRec));
  1501. if(type == 1) {
  1502. addresses[addr_index] = 4;
  1503. memcpy(addresses + addr_index + 1, buf + i, 4);
  1504. } else {
  1505. addresses[addr_index] = 6;
  1506. memcpy(addresses + addr_index + 1, buf + i, 16);
  1507. }
  1508. addr_index += sizeof(HostAddressRec);
  1509. } else if(type == 5) {
  1510. int j, k;
  1511. if(af != 0 && addr_index > 0) {
  1512. do_log(L_WARN, "DNS: host has both CNAME and A -- "
  1513. "ignoring CNAME.\n");
  1514. goto cont;
  1515. }
  1516. af = 0;
  1517. if(addr_index != 0) {
  1518. /* Only warn if the CNAMEs are not identical */
  1519. char tmp[512]; int jj, kk;
  1520. assert(addresses[0] == DNS_CNAME);
  1521. jj = labelsToString(buf, i, n,
  1522. tmp, 512, &kk);
  1523. if(jj < 0 ||
  1524. kk != strlen(addresses + 1) ||
  1525. memcmp(addresses + 1, tmp, kk) != 0) {
  1526. do_log(L_WARN, "DNS: "
  1527. "%s: host has multiple CNAMEs -- "
  1528. "ignoring subsequent.\n",
  1529. scrub(name->string));
  1530. }
  1531. goto cont;
  1532. }
  1533. addresses[0] = DNS_CNAME;
  1534. addr_index++;
  1535. j = labelsToString(buf, i, n,
  1536. addresses + 1, 1020, &k);
  1537. if(j < 0) {
  1538. addr_index = 0;
  1539. error = ENAMETOOLONG;
  1540. continue;
  1541. }
  1542. addr_index = k + 1;
  1543. } else {
  1544. error = EDNS_NO_ADDRESS;
  1545. i += rdlength;
  1546. continue;
  1547. }
  1548. }
  1549. cont:
  1550. i += rdlength;
  1551. }
  1552. #if (LOGGING_MAX & D_DNS)
  1553. for(j = 0; j < nscount; j++) {
  1554. PARSE_ANSWER("ns", nofail);
  1555. i += rdlength;
  1556. }
  1557. for(j = 0; j < arcount; j++) {
  1558. PARSE_ANSWER("ar", nofail);
  1559. i += rdlength;
  1560. }
  1561. nofail:
  1562. #endif
  1563. #undef PARSE_ANSWER
  1564. do_log(D_DNS, "DNS: %d bytes\n", addr_index);
  1565. if(af < 0)
  1566. goto fail;
  1567. value = internAtomN(addresses, addr_index);
  1568. if(value == NULL) {
  1569. error = ENOMEM;
  1570. goto fail;
  1571. }
  1572. assert(af >= 0);
  1573. *id_return = id;
  1574. *name_return = name;
  1575. *value_return = value;
  1576. *af_return = af;
  1577. *ttl_return = final_ttl;
  1578. return 1;
  1579. fail:
  1580. *id_return = id;
  1581. *name_return = name;
  1582. *value_return = NULL;
  1583. *af_return = af;
  1584. return -error;
  1585. }
  1586. #else
  1587. static int
  1588. really_do_dns(AtomPtr name, ObjectPtr object)
  1589. {
  1590. abort();
  1591. }
  1592. #endif