00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] = "$Id: dns.c,v 1.21 2007-09-13 22:20:55 sven Exp $";
00022 #endif
00023
00024 #include <eggdrop/eggdrop.h>
00025 #include <netinet/in.h>
00026 #include <sys/socket.h>
00027 #include <arpa/inet.h>
00028
00029 #ifdef IPV6
00030 # define DO_IPV6
00031 #endif
00032 #define DO_IPV4
00033
00034 typedef struct {
00035 char **list;
00036 time_t ttl;
00037 int len;
00038 } dns_answer_t;
00039
00040 typedef struct dns_query {
00041 struct dns_query *next;
00042 char *query;
00043 int id;
00044 int remaining;
00045 dns_answer_t answer;
00046 dns_callback_t callback;
00047 void *client_data;
00048 event_owner_t *owner;
00049 } dns_query_t;
00050
00051 typedef struct {
00052 unsigned short id;
00053 unsigned short flags;
00054 unsigned short question_count;
00055 unsigned short answer_count;
00056 unsigned short ns_count;
00057 unsigned short ar_count;
00058 } dns_header_t;
00059
00060 typedef struct {
00061
00062 unsigned short type;
00063 unsigned short class;
00064 int ttl;
00065 unsigned short rdlength;
00066
00067 } dns_rr_t;
00068
00069
00070 typedef struct dns_server {
00071 char *ip;
00072 int idx;
00073 } dns_server_t;
00074
00075
00076 typedef struct {
00077 char *host;
00078 char *ip;
00079 } dns_host_t;
00080
00081 typedef struct {
00082 dns_answer_t answer;
00083 char *query;
00084 time_t expiretime;
00085 } dns_cache_t;
00086
00087 static int query_id = 1;
00088 static dns_header_t _dns_header = {0};
00089 static dns_query_t *query_head = NULL;
00090 static dns_host_t *hosts = NULL;
00091 static int nhosts = 0;
00092 static dns_cache_t *cache = NULL;
00093 static int ncache = 0;
00094 static dns_server_t *servers = NULL;
00095 static int nservers = 0;
00096 static int cur_server = -1;
00097
00098 static char separators[] = " ,\t\r\n";
00099
00100 static int dns_idx = -1;
00101 static const char *dns_ip = NULL;
00102
00103 static int make_header(char *buf, int id);
00104 static int cut_host(const char *host, char *query);
00105 static int reverse_ip(const char *host, char *reverse);
00106 static void read_resolv(char *fname);
00107 static void read_hosts(char *fname);
00108 static void get_dns_idx();
00109 static int cache_find(const char *);
00110 static int dns_on_read(void *client_data, int idx, char *buf, int len);
00111 static int dns_on_eof(void *client_data, int idx, int err, const char *errmsg);
00112 static const char *dns_next_server();
00113 static void parse_reply(char *response, int nbytes);
00114
00115 static sockbuf_handler_t dns_handler = {
00116 "dns",
00117 NULL, dns_on_eof, NULL,
00118 dns_on_read, NULL
00119 };
00120
00121 static void answer_init(dns_answer_t *answer)
00122 {
00123 memset(answer, 0, sizeof(*answer));
00124 }
00125
00126 static void answer_add(dns_answer_t *answer, const char *what)
00127 {
00128 answer->list = realloc(answer->list, sizeof(*answer->list) * (answer->len+2));
00129 answer->list[answer->len] = strdup(what);
00130 answer->len++;
00131 answer->list[answer->len] = NULL;
00132 }
00133
00134 static void answer_free(dns_answer_t *answer)
00135 {
00136 int i;
00137 for (i = 0; i < answer->len; i++) free(answer->list[i]);
00138 if (answer->list) free(answer->list);
00139 }
00140
00141 static void get_dns_idx()
00142 {
00143 int i, sock;
00144
00145 sock = -1;
00146 for (i = 0; i < 5; i++) {
00147 if (!dns_ip) dns_ip = dns_next_server();
00148 sock = socket_create(dns_ip, DNS_PORT, NULL, 0, SOCKET_CLIENT | SOCKET_NONBLOCK | SOCKET_UDP);
00149 if (sock < 0) {
00150
00151 dns_ip = NULL;
00152 }
00153 else break;
00154 }
00155 if (i == 5) return;
00156 dns_idx = sockbuf_new();
00157 sockbuf_set_handler(dns_idx, &dns_handler, NULL, NULL);
00158 sockbuf_set_sock(dns_idx, sock, 0);
00159 }
00160
00161 void egg_dns_send(char *query, int len)
00162 {
00163 if (dns_idx < 0) {
00164 get_dns_idx();
00165 if (dns_idx < 0) return;
00166 }
00167 sockbuf_write(dns_idx, query, len);
00168 }
00169
00170
00171
00172
00173 int egg_dns_lookup(const char *host, int timeout, dns_callback_t callback, void *client_data, event_owner_t *owner)
00174 {
00175 char buf[512];
00176 dns_query_t *q;
00177 int i, len, cache_id;
00178
00179 if (socket_valid_ip(host)) {
00180
00181 dns_answer_t answer;
00182
00183 answer_init(&answer);
00184 answer_add(&answer, host);
00185 callback(client_data, host, answer.list);
00186 answer_free(&answer);
00187 if (owner && owner->on_delete) owner->on_delete(owner, client_data);
00188 return(-1);
00189 }
00190
00191
00192 cache_id = cache_find(host);
00193 if (cache_id >= 0) {
00194 shuffleArray(cache[cache_id].answer.list, cache[cache_id].answer.len);
00195 callback(client_data, host, cache[cache_id].answer.list);
00196 if (owner && owner->on_delete) owner->on_delete(owner, client_data);
00197 return(-1);
00198 }
00199
00200
00201 for (i = 0; i < nhosts; i++) {
00202 if (!strcasecmp(host, hosts[i].host)) {
00203 dns_answer_t answer;
00204
00205 answer_init(&answer);
00206 answer_add(&answer, hosts[i].ip);
00207 callback(client_data, host, answer.list);
00208 answer_free(&answer);
00209 if (owner && owner->on_delete) owner->on_delete(owner, client_data);
00210 return(-1);
00211 }
00212 }
00213
00214
00215 q = calloc(1, sizeof(*q));
00216 q->id = query_id;
00217 query_id++;
00218 q->query = strdup(host);
00219 q->callback = callback;
00220 q->client_data = client_data;
00221 q->owner = owner;
00222 q->next = query_head;
00223 query_head = q;
00224
00225
00226 q->remaining = 1;
00227 len = make_header(buf, q->id);
00228 len += cut_host(host, buf + len);
00229 buf[len] = 0; len++; buf[len] = 1; len++;
00230 buf[len] = 0; len++; buf[len] = 1; len++;
00231
00232 egg_dns_send(buf, len);
00233
00234 #ifdef IPV6
00235
00236 q->remaining++;
00237 len = make_header(buf, q->id);
00238 len += cut_host(host, buf + len);
00239 buf[len] = 0; len++; buf[len] = 28; len++;
00240 buf[len] = 0; len++; buf[len] = 1; len++;
00241
00242 egg_dns_send(buf, len);
00243 #endif
00244
00245 return(q->id);
00246 }
00247
00248
00249
00250
00251 int egg_dns_reverse(const char *ip, int timeout, dns_callback_t callback, void *client_data, event_owner_t *owner)
00252 {
00253 dns_query_t *q;
00254 char buf[512], *reversed_ip;
00255 int i, len, cache_id;
00256
00257 if (!socket_valid_ip(ip)) {
00258
00259 callback(client_data, ip, NULL);
00260 if (owner && owner->on_delete) owner->on_delete(owner, client_data);
00261 return(-1);
00262 }
00263
00264
00265 for (i = 0; i < nhosts; i++) {
00266 if (!strcasecmp(hosts[i].ip, ip)) {
00267 dns_answer_t answer;
00268
00269 answer_init(&answer);
00270 answer_add(&answer, hosts[i].host);
00271 callback(client_data, ip, answer.list);
00272 answer_free(&answer);
00273 if (owner && owner->on_delete) owner->on_delete(owner, client_data);
00274 return(-1);
00275 }
00276 }
00277
00278
00279 cache_id = cache_find(ip);
00280 if (cache_id >= 0) {
00281 shuffleArray(cache[cache_id].answer.list, cache[cache_id].answer.len);
00282 callback(client_data, ip, cache[cache_id].answer.list);
00283 if (owner && owner->on_delete) owner->on_delete(owner, client_data);
00284 return(-1);
00285 }
00286
00287
00288
00289 if (strchr(ip, ':')) {
00290 char temp[64];
00291
00292 socket_ipv6_to_dots(ip, temp);
00293 reversed_ip = malloc(strlen(temp) + 10);
00294 reverse_ip(temp, reversed_ip);
00295 strcat(reversed_ip, ".ip6.arpa");
00296 }
00297 else {
00298 reversed_ip = malloc(strlen(ip) + 14);
00299 reverse_ip(ip, reversed_ip);
00300 strcat(reversed_ip, ".in-addr.arpa");
00301 }
00302
00303 len = make_header(buf, query_id);
00304 len += cut_host(reversed_ip, buf + len);
00305 buf[len] = 0; len++; buf[len] = 12; len++;
00306 buf[len] = 0; len++; buf[len] = 1; len++;
00307
00308 free(reversed_ip);
00309
00310 q = calloc(1, sizeof(*q));
00311 q->id = query_id;
00312 query_id++;
00313 q->query = strdup(ip);
00314 q->callback = callback;
00315 q->client_data = client_data;
00316 q->owner = owner;
00317 q->next = query_head;
00318 query_head = q;
00319
00320 egg_dns_send(buf, len);
00321
00322 return(q->id);
00323 }
00324
00325 static int dns_on_read(void *client_data, int idx, char *buf, int len)
00326 {
00327 parse_reply(buf, len);
00328 return(0);
00329 }
00330
00331 static int dns_on_eof(void *client_data, int idx, int err, const char *errmsg)
00332 {
00333 sockbuf_delete(idx);
00334 dns_idx = -1;
00335 dns_ip = NULL;
00336 return(0);
00337 }
00338
00339 static int cache_expired(int id)
00340 {
00341 if (cache[id].expiretime && (timer_get_now_sec(NULL) >= cache[id].expiretime)) return(1);
00342 return (0);
00343 }
00344
00345 static void cache_del(int id)
00346 {
00347 answer_free(&cache[id].answer);
00348 free(cache[id].query);
00349 cache[id].expiretime = 0;
00350
00351 ncache--;
00352
00353 if (id < ncache) memcpy(&cache[id], &cache[ncache], sizeof(dns_cache_t));
00354 else memset(&cache[id], 0, sizeof(dns_cache_t));
00355
00356 cache = (dns_cache_t *) realloc(cache, (ncache+1)*sizeof(*cache));
00357 }
00358
00359 static void cache_add(const char *query, dns_answer_t *answer)
00360 {
00361 int i;
00362
00363 cache = (dns_cache_t *) realloc(cache, (ncache+1)*sizeof(*cache));
00364 cache[ncache].query = strdup(query);
00365 answer_init(&cache[ncache].answer);
00366 for (i = 0; i < answer->len; i++)
00367 answer_add(&cache[ncache].answer, answer->list[i]);
00368 cache[ncache].expiretime = timer_get_now_sec(NULL) + answer->ttl;
00369 ncache++;
00370 }
00371
00372 static int cache_find(const char *query)
00373 {
00374 int i;
00375
00376 for (i = 0; i < ncache; i++)
00377 if (!strcasecmp(cache[i].query, query)) return (i);
00378
00379 return (-1);
00380 }
00381
00382
00383 void expire_queries()
00384 {
00385 int cache_id = 0;
00386
00387 for (cache_id = 0; cache_id < ncache; cache_id++) {
00388 if (cache_expired(cache_id)) {
00389 cache_del(cache_id);
00390 if (cache_id == ncache) break;
00391 cache_id--;
00392 }
00393 }
00394 }
00395
00396
00397
00398 int egg_dns_init()
00399 {
00400 _dns_header.flags = htons(1 << 8 | 1 << 7);
00401 read_resolv("/etc/resolv.conf");
00402 read_resolv(".resolv.conf");
00403 read_hosts("/etc/hosts");
00404 read_hosts(".hosts");
00405 timer_create_secs(1, "dns_check_expires", (Function) expire_queries);
00406 return(0);
00407 }
00408
00409 int egg_dns_shutdown(void)
00410 {
00411 int i;
00412
00413 if (nservers > 0) {
00414 for (i = 0; i < nservers; i++) {
00415 if (servers[i].ip) free(servers[i].ip);
00416 }
00417 free(servers); servers = NULL;
00418 nservers = 0;
00419 }
00420
00421 if (nhosts > 0) {
00422 for (i = 0; i < nhosts; i++) {
00423 if (hosts[i].host) free(hosts[i].host);
00424 if (hosts[i].ip) free(hosts[i].ip);
00425 }
00426 free(hosts); hosts = NULL;
00427 nhosts = 0;
00428 }
00429
00430 return (0);
00431 }
00432
00433 static const char *dns_next_server()
00434 {
00435 if (!servers || nservers < 1) return("127.0.0.1");
00436 cur_server++;
00437 if (cur_server >= nservers) cur_server = 0;
00438 return(servers[cur_server].ip);
00439 }
00440
00441 static void add_server(char *ip)
00442 {
00443 servers = realloc(servers, (nservers+1)*sizeof(*servers));
00444 servers[nservers].ip = strdup(ip);
00445 nservers++;
00446 }
00447
00448 static void add_host(char *host, char *ip)
00449 {
00450 hosts = realloc(hosts, (nhosts+1)*sizeof(*hosts));
00451 hosts[nhosts].host = strdup(host);
00452 hosts[nhosts].ip = strdup(ip);
00453 nhosts++;
00454 }
00455
00456 static int read_thing(char *buf, char *ip)
00457 {
00458 int skip, len;
00459
00460 skip = strspn(buf, separators);
00461 buf += skip;
00462 len = strcspn(buf, separators);
00463 memcpy(ip, buf, len);
00464 ip[len] = 0;
00465 return(skip + len);
00466 }
00467
00468 static void read_resolv(char *fname)
00469 {
00470 FILE *fp;
00471 char buf[512], ip[512];
00472
00473 fp = fopen(fname, "r");
00474 if (!fp) return;
00475 while (fgets(buf, sizeof(buf), fp)) {
00476 if (!strncasecmp(buf, "nameserver", 10)) {
00477 read_thing(buf+10, ip);
00478 if (strlen(ip)) add_server(ip);
00479 }
00480 }
00481 fclose(fp);
00482 }
00483
00484 static void read_hosts(char *fname)
00485 {
00486 FILE *fp;
00487 char buf[512], ip[512], host[512];
00488 int skip, n;
00489
00490 fp = fopen(fname, "r");
00491 if (!fp) return;
00492 while (fgets(buf, sizeof(buf), fp)) {
00493 if (strchr(buf, '#')) continue;
00494 skip = read_thing(buf, ip);
00495 if (!strlen(ip)) continue;
00496 while ((n = read_thing(buf+skip, host))) {
00497 skip += n;
00498 if (strlen(host)) add_host(host, ip);
00499 }
00500 }
00501 fclose(fp);
00502 }
00503
00504 static int make_header(char *buf, int id)
00505 {
00506 _dns_header.question_count = htons(1);
00507 _dns_header.id = htons(id);
00508 memcpy(buf, &_dns_header, 12);
00509 return(12);
00510 }
00511
00512 static int cut_host(const char *host, char *query)
00513 {
00514 char *period, *orig;
00515 int len;
00516
00517 orig = query;
00518 while ((period = strchr(host, '.'))) {
00519 len = period - host;
00520 if (len > 63) return(-1);
00521 *query++ = len;
00522 memcpy(query, host, len);
00523 query += len;
00524 host = period+1;
00525 }
00526 len = strlen(host);
00527 if (len) {
00528 *query++ = len;
00529 memcpy(query, host, len);
00530 query += len;
00531 }
00532 *query++ = 0;
00533 return(query-orig);
00534 }
00535
00536 static int reverse_ip(const char *host, char *reverse)
00537 {
00538 char *period;
00539 int offset, len;
00540
00541 period = strchr(host, '.');
00542 if (!period) {
00543 len = strlen(host);
00544 memcpy(reverse, host, len);
00545 return(len);
00546 }
00547 else {
00548 len = period - host;
00549 offset = reverse_ip(host+len+1, reverse);
00550 reverse[offset++] = '.';
00551 memcpy(reverse+offset, host, len);
00552 reverse[offset+len] = 0;
00553 return(offset+len);
00554 }
00555 }
00556
00557 int egg_dns_cancel(int id, int issue_callback)
00558 {
00559 dns_query_t *q, *prev;
00560
00561 prev = NULL;
00562 for (q = query_head; q; q = q->next) {
00563 if (q->id == id) break;
00564 prev = q;
00565 }
00566 if (!q) return(-1);
00567 if (prev) prev->next = q->next;
00568 else query_head = q->next;
00569
00570 if (issue_callback) q->callback(q->client_data, q->query, NULL);
00571 if (q->owner && q->owner->on_delete) q->owner->on_delete(q->owner, q->client_data);
00572 free(q);
00573 return(0);
00574 }
00575
00576 int egg_dns_cancel_by_owner(egg_module_t *module, void *script)
00577 {
00578 int removed = 0;
00579 dns_query_t *q, *prev= NULL, *next;
00580
00581 for (q = query_head; q; q = next) {
00582 next = q->next;
00583 if (!q->owner || q->owner->module != module || (script && q->owner->client_data != script)) {
00584 prev = q;
00585 continue;
00586 }
00587 if (prev) prev->next = q->next;
00588 else query_head = q->next;
00589 ++removed;
00590
00591 if (q->owner && q->owner->on_delete) q->owner->on_delete(q->owner, q->client_data);
00592 free(q);
00593 }
00594 return removed;
00595 }
00596
00597 static int skip_name(unsigned char *ptr)
00598 {
00599 int len;
00600 unsigned char *start = ptr;
00601
00602 while ((len = *ptr++) > 0) {
00603 if (len > 63) {
00604 ptr++;
00605 break;
00606 }
00607 else {
00608 ptr += len;
00609 }
00610 }
00611 return(ptr - start);
00612 }
00613
00614 static void parse_reply(char *response, int nbytes)
00615 {
00616 dns_header_t header;
00617 dns_rr_t reply;
00618 dns_query_t *q, *prev;
00619 char result[512];
00620 unsigned char *ptr;
00621 int i;
00622
00623 ptr = (unsigned char *)response;
00624 memcpy(&header, ptr, 12);
00625 ptr += 12;
00626
00627 header.id = ntohs(header.id);
00628 header.flags = ntohs(header.flags);
00629 header.question_count = ntohs(header.question_count);
00630 header.answer_count = ntohs(header.answer_count);
00631
00632
00633 prev = NULL;
00634 for (q = query_head; q; q = q->next) {
00635 if (q->id == header.id) break;
00636 prev = q;
00637 }
00638 if (!q) return;
00639
00640
00641 for (i = 0; i < header.question_count; i++) {
00642 ptr += skip_name(ptr);
00643 ptr += 4;
00644 }
00645
00646
00647 for (i = 0; i < header.answer_count; i++) {
00648 result[0] = 0;
00649
00650 ptr += skip_name(ptr);
00651 memcpy(&reply, ptr, 10);
00652 reply.type = ntohs(reply.type);
00653 reply.rdlength = ntohs(reply.rdlength);
00654 reply.ttl = ntohl(reply.ttl);
00655
00656 if (reply.ttl && ((!q->answer.ttl) || (q->answer.ttl > reply.ttl))) q->answer.ttl = reply.ttl;
00657
00658 ptr += 10;
00659 #ifdef DO_IPV4
00660 if (reply.type == 1) {
00661
00662 inet_ntop(AF_INET, ptr, result, 512);
00663 answer_add(&q->answer, result);
00664 }
00665 #endif
00666 #ifdef DO_IPV6
00667 if (reply.type == 28) {
00668
00669 inet_ntop(AF_INET6, ptr, result, 512);
00670 answer_add(&q->answer, result);
00671 }
00672 #endif
00673 if (reply.type == 12) {
00674 unsigned char *placeholder;
00675 int len, dot;
00676
00677
00678 placeholder = ptr;
00679 result[0] = 0;
00680 while ((len = *ptr++) != 0) {
00681 if (len > 63) {
00682 ptr++;
00683 break;
00684 }
00685 else {
00686 dot = ptr[len];
00687 ptr[len] = 0;
00688 strcat(result, (char *) ptr);
00689 strcat(result, ".");
00690 ptr[len] = dot;
00691 ptr += len;
00692 }
00693 }
00694 if (strlen(result)) {
00695 result[strlen(result)-1] = 0;
00696 answer_add(&q->answer, result);
00697 }
00698 ptr = placeholder;
00699 }
00700 ptr += reply.rdlength;
00701 }
00702
00703 q->remaining--;
00704
00705 if (q->remaining > 0) return;
00706
00707
00708 if (prev) prev->next = q->next;
00709 else query_head = q->next;
00710
00711 cache_add(q->query, &q->answer);
00712
00713 q->callback(q->client_data, q->query, q->answer.list);
00714 if (q->owner && q->owner->on_delete) q->owner->on_delete(q->owner, q->client_data);
00715 answer_free(&q->answer);
00716 free(q->query);
00717 free(q);
00718 }