00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "stdinc.h"
00023 #include "tools.h"
00024 #include "client.h"
00025 #include "list.h"
00026 #include "common.h"
00027 #include "event.h"
00028 #include "irc_string.h"
00029 #include "sprintf_irc.h"
00030 #include "ircd.h"
00031 #include "numeric.h"
00032 #include "restart.h"
00033 #include "fdlist.h"
00034 #include "fileio.h"
00035 #include "s_bsd.h"
00036 #include "s_log.h"
00037 #include "send.h"
00038 #include "memory.h"
00039 #include "irc_res.h"
00040 #include "irc_reslib.h"
00041 #include "irc_getnameinfo.h"
00042
00043 #if (CHAR_BIT != 8)
00044 #error this code needs to be able to address individual octets
00045 #endif
00046
00047 static PF res_readreply;
00048
00049 #define MAXPACKET 1024
00050 #define RES_MAXALIASES 35
00051 #define RES_MAXADDRS 35
00052 #define AR_TTL 600
00053
00054
00055
00056
00057
00058 #define TYPE_SIZE (size_t)2
00059 #define CLASS_SIZE (size_t)2
00060 #define TTL_SIZE (size_t)4
00061 #define RDLENGTH_SIZE (size_t)2
00062 #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
00063
00064 typedef enum
00065 {
00066 REQ_IDLE,
00067 REQ_PTR,
00068 REQ_A,
00069 #ifdef IPV6
00070 REQ_AAAA,
00071 #endif
00072 REQ_CNAME,
00073 REQ_INT
00074 } request_state;
00075
00076 struct reslist
00077 {
00078 dlink_node node;
00079 int id;
00080 int sent;
00081 request_state state;
00082 time_t ttl;
00083 char type;
00084 char retries;
00085 char sends;
00086 char resend;
00087 time_t sentat;
00088 time_t timeout;
00089 struct irc_ssaddr addr;
00090 char *name;
00091 struct DNSQuery *query;
00092 };
00093
00094 static fde_t ResolverFileDescriptor;
00095 static dlink_list request_list = { NULL, NULL, 0 };
00096
00097 static void rem_request(struct reslist *request);
00098 static struct reslist *make_request(struct DNSQuery *query);
00099 static void do_query_name(struct DNSQuery *query,
00100 const char* name, struct reslist *request, int);
00101 static void do_query_number(struct DNSQuery *query,
00102 const struct irc_ssaddr *,
00103 struct reslist *request);
00104 static void query_name(const char *name, int query_class, int query_type,
00105 struct reslist *request);
00106 static int send_res_msg(const char *buf, int len, int count);
00107 static void resend_query(struct reslist *request);
00108 static int proc_answer(struct reslist *request, HEADER *header, char *, char *);
00109 static struct reslist *find_id(int id);
00110 static struct DNSReply *make_dnsreply(struct reslist *request);
00111
00112 extern struct irc_ssaddr irc_nsaddr_list[IRCD_MAXNS];
00113 extern int irc_nscount;
00114 extern char irc_domain[HOSTLEN+1];
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 static int
00129 res_ourserver(const struct irc_ssaddr *inp)
00130 {
00131 #ifdef IPV6
00132 struct sockaddr_in6 *v6;
00133 struct sockaddr_in6 *v6in = (struct sockaddr_in6 *)inp;
00134 #endif
00135 struct sockaddr_in *v4;
00136 struct sockaddr_in *v4in = (struct sockaddr_in *)inp;
00137 int ns;
00138
00139 for (ns = 0; ns < irc_nscount; ns++)
00140 {
00141 const struct irc_ssaddr *srv = &irc_nsaddr_list[ns];
00142 #ifdef IPV6
00143 v6 = (struct sockaddr_in6 *)srv;
00144 #endif
00145 v4 = (struct sockaddr_in *)srv;
00146
00147
00148
00149
00150
00151 switch (srv->ss.ss_family)
00152 {
00153 #ifdef IPV6
00154 case AF_INET6:
00155 if (srv->ss.ss_family == inp->ss.ss_family)
00156 if (v6->sin6_port == v6in->sin6_port)
00157 if ((memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr,
00158 sizeof(struct in6_addr)) == 0) ||
00159 (memcmp(&v6->sin6_addr.s6_addr, &in6addr_any,
00160 sizeof(struct in6_addr)) == 0))
00161 return(1);
00162 break;
00163 #endif
00164 case AF_INET:
00165 if (srv->ss.ss_family == inp->ss.ss_family)
00166 if (v4->sin_port == v4in->sin_port)
00167 if ((v4->sin_addr.s_addr == INADDR_ANY) ||
00168 (v4->sin_addr.s_addr == v4in->sin_addr.s_addr))
00169 return(1);
00170 break;
00171 default:
00172 break;
00173 }
00174 }
00175
00176 return(0);
00177 }
00178
00179
00180
00181
00182
00183 static time_t
00184 timeout_query_list(time_t now)
00185 {
00186 dlink_node *ptr;
00187 dlink_node *next_ptr;
00188 struct reslist *request;
00189 time_t next_time = 0;
00190 time_t timeout = 0;
00191
00192 DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
00193 {
00194 request = ptr->data;
00195 timeout = request->sentat + request->timeout;
00196
00197 if (now >= timeout)
00198 {
00199 if (--request->retries <= 0)
00200 {
00201 (*request->query->callback)(request->query->ptr, NULL);
00202 rem_request(request);
00203 continue;
00204 }
00205 else
00206 {
00207 request->sentat = now;
00208 request->timeout += request->timeout;
00209 resend_query(request);
00210 }
00211 }
00212
00213 if ((next_time == 0) || timeout < next_time)
00214 {
00215 next_time = timeout;
00216 }
00217 }
00218
00219 return((next_time > now) ? next_time : (now + AR_TTL));
00220 }
00221
00222
00223
00224
00225 static void
00226 timeout_resolver(void *notused)
00227 {
00228 timeout_query_list(CurrentTime);
00229 }
00230
00231
00232
00233
00234
00235 static void
00236 start_resolver(void)
00237 {
00238 irc_res_init();
00239
00240 if (!ResolverFileDescriptor.flags.open)
00241 {
00242 if (comm_open(&ResolverFileDescriptor, irc_nsaddr_list[0].ss.ss_family,
00243 SOCK_DGRAM, 0, "Resolver socket") == -1)
00244 return;
00245
00246
00247 comm_setselect(&ResolverFileDescriptor, COMM_SELECT_READ,
00248 res_readreply, NULL, 0);
00249 eventAdd("timeout_resolver", timeout_resolver, NULL, 1);
00250 }
00251 }
00252
00253
00254
00255
00256 void
00257 init_resolver(void)
00258 {
00259 #ifdef HAVE_SRAND48
00260 srand48(CurrentTime);
00261 #endif
00262 memset(&ResolverFileDescriptor, 0, sizeof(fde_t));
00263 start_resolver();
00264 }
00265
00266
00267
00268
00269 void
00270 restart_resolver(void)
00271 {
00272 fd_close(&ResolverFileDescriptor);
00273 eventDelete(timeout_resolver, NULL);
00274 start_resolver();
00275 }
00276
00277
00278
00279
00280
00281 void
00282 add_local_domain(char *hname, size_t size)
00283 {
00284
00285
00286 if (strchr(hname, '.') == NULL)
00287 {
00288 if (irc_domain[0])
00289 {
00290 size_t len = strlen(hname);
00291
00292 if ((strlen(irc_domain) + len + 2) < size)
00293 {
00294 hname[len++] = '.';
00295 strcpy(hname + len, irc_domain);
00296 }
00297 }
00298 }
00299 }
00300
00301
00302
00303
00304
00305
00306 static void
00307 rem_request(struct reslist *request)
00308 {
00309 dlinkDelete(&request->node, &request_list);
00310 MyFree(request->name);
00311 MyFree(request);
00312 }
00313
00314
00315
00316
00317 static struct reslist *
00318 make_request(struct DNSQuery* query)
00319 {
00320 struct reslist *request;
00321
00322 request = (struct reslist *)MyMalloc(sizeof(struct reslist));
00323
00324 request->sentat = CurrentTime;
00325 request->retries = 3;
00326 request->resend = 1;
00327 request->timeout = 4;
00328 request->query = query;
00329 request->state = REQ_IDLE;
00330
00331 dlinkAdd(request, &request->node, &request_list);
00332 return(request);
00333 }
00334
00335
00336
00337
00338
00339 void
00340 delete_resolver_queries(const struct DNSQuery *query)
00341 {
00342 dlink_node *ptr;
00343 dlink_node *next_ptr;
00344 struct reslist *request;
00345
00346 DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
00347 {
00348 if ((request = ptr->data) != NULL)
00349 {
00350 if (query == request->query)
00351 rem_request(request);
00352 }
00353 }
00354 }
00355
00356
00357
00358
00359
00360
00361
00362
00363 static int
00364 send_res_msg(const char *msg, int len, int rcount)
00365 {
00366 int i;
00367 int sent = 0;
00368 int max_queries = IRCD_MIN(irc_nscount, rcount);
00369
00370
00371
00372
00373 if (max_queries == 0)
00374 max_queries = 1;
00375
00376 for (i = 0; i < max_queries; i++)
00377 {
00378 if (sendto(ResolverFileDescriptor.fd, msg, len, 0,
00379 (struct sockaddr*)&(irc_nsaddr_list[i]),
00380 irc_nsaddr_list[i].ss_len) == len)
00381 ++sent;
00382 }
00383
00384 return(sent);
00385 }
00386
00387
00388
00389
00390 static struct reslist *
00391 find_id(int id)
00392 {
00393 dlink_node *ptr;
00394 struct reslist *request;
00395
00396 DLINK_FOREACH(ptr, request_list.head)
00397 {
00398 request = ptr->data;
00399
00400 if (request->id == id)
00401 return(request);
00402 }
00403
00404 return(NULL);
00405 }
00406
00407
00408
00409
00410
00411 void
00412 gethost_byname_type(const char *name, struct DNSQuery *query, int type)
00413 {
00414 assert(name != 0);
00415 do_query_name(query, name, NULL, type);
00416 }
00417
00418
00419
00420
00421 void
00422 gethost_byname(const char *name, struct DNSQuery *query)
00423 {
00424 #ifdef IPV6
00425 gethost_byname_type(name, query, T_AAAA);
00426 #else
00427 gethost_byname_type(name, query, T_A);
00428 #endif
00429 }
00430
00431
00432
00433
00434 void
00435 gethost_byaddr(const struct irc_ssaddr *addr, struct DNSQuery *query)
00436 {
00437 do_query_number(query, addr, NULL);
00438 }
00439
00440
00441
00442
00443 static void
00444 do_query_name(struct DNSQuery *query, const char *name,
00445 struct reslist *request, int type)
00446 {
00447 char host_name[HOSTLEN + 1];
00448
00449 strlcpy(host_name, name, HOSTLEN);
00450 add_local_domain(host_name, HOSTLEN);
00451
00452 if (request == NULL)
00453 {
00454 request = make_request(query);
00455 request->name = (char *)MyMalloc(strlen(host_name) + 1);
00456 request->type = type;
00457 strcpy(request->name, host_name);
00458 #ifdef IPV6
00459 if (type == T_A)
00460 request->state = REQ_A;
00461 else
00462 request->state = REQ_AAAA;
00463 #else
00464 request->state = REQ_A;
00465 #endif
00466 }
00467
00468 request->type = type;
00469 query_name(host_name, C_IN, type, request);
00470 }
00471
00472
00473
00474
00475 static void
00476 do_query_number(struct DNSQuery *query, const struct irc_ssaddr *addr,
00477 struct reslist *request)
00478 {
00479 char ipbuf[128];
00480 const unsigned char *cp;
00481 #ifdef IPV6
00482 const char *intarpa;
00483 #endif
00484 if (addr->ss.ss_family == AF_INET)
00485 {
00486 struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
00487 cp = (const unsigned char*)&v4->sin_addr.s_addr;
00488
00489 ircsprintf(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
00490 (unsigned int)(cp[3]), (unsigned int)(cp[2]),
00491 (unsigned int)(cp[1]), (unsigned int)(cp[0]));
00492 }
00493 #ifdef IPV6
00494 else if (addr->ss.ss_family == AF_INET6)
00495 {
00496 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
00497 cp = (const unsigned char *)&v6->sin6_addr.s6_addr;
00498
00499 if (request != NULL && request->state == REQ_INT)
00500 intarpa = "int";
00501 else
00502 intarpa = "arpa";
00503
00504 (void)sprintf(ipbuf, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
00505 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.%s.",
00506 (unsigned int)(cp[15]&0xf), (unsigned int)(cp[15]>>4),
00507 (unsigned int)(cp[14]&0xf), (unsigned int)(cp[14]>>4),
00508 (unsigned int)(cp[13]&0xf), (unsigned int)(cp[13]>>4),
00509 (unsigned int)(cp[12]&0xf), (unsigned int)(cp[12]>>4),
00510 (unsigned int)(cp[11]&0xf), (unsigned int)(cp[11]>>4),
00511 (unsigned int)(cp[10]&0xf), (unsigned int)(cp[10]>>4),
00512 (unsigned int)(cp[9]&0xf), (unsigned int)(cp[9]>>4),
00513 (unsigned int)(cp[8]&0xf), (unsigned int)(cp[8]>>4),
00514 (unsigned int)(cp[7]&0xf), (unsigned int)(cp[7]>>4),
00515 (unsigned int)(cp[6]&0xf), (unsigned int)(cp[6]>>4),
00516 (unsigned int)(cp[5]&0xf), (unsigned int)(cp[5]>>4),
00517 (unsigned int)(cp[4]&0xf), (unsigned int)(cp[4]>>4),
00518 (unsigned int)(cp[3]&0xf), (unsigned int)(cp[3]>>4),
00519 (unsigned int)(cp[2]&0xf), (unsigned int)(cp[2]>>4),
00520 (unsigned int)(cp[1]&0xf), (unsigned int)(cp[1]>>4),
00521 (unsigned int)(cp[0]&0xf), (unsigned int)(cp[0]>>4), intarpa);
00522 }
00523 #endif
00524 if (request == NULL)
00525 {
00526 request = make_request(query);
00527 request->type = T_PTR;
00528 memcpy(&request->addr, addr, sizeof(struct irc_ssaddr));
00529 request->name = (char *)MyMalloc(HOSTLEN + 1);
00530 }
00531
00532 query_name(ipbuf, C_IN, T_PTR, request);
00533 }
00534
00535
00536
00537
00538 static void
00539 query_name(const char *name, int query_class, int type,
00540 struct reslist *request)
00541 {
00542 char buf[MAXPACKET];
00543 int request_len = 0;
00544
00545 memset(buf, 0, sizeof(buf));
00546
00547 if ((request_len = irc_res_mkquery(name, query_class, type,
00548 (unsigned char *)buf, sizeof(buf))) > 0)
00549 {
00550 HEADER *header = (HEADER *)buf;
00551 #ifndef HAVE_LRAND48
00552 int k = 0;
00553 struct timeval tv;
00554 #endif
00555
00556
00557
00558
00559
00560
00561 #ifdef HAVE_LRAND48
00562 do
00563 {
00564 header->id = (header->id + lrand48()) & 0xffff;
00565 } while (find_id(header->id));
00566 #else
00567 gettimeofday(&tv, NULL);
00568 do
00569 {
00570 header->id = (header->id + k + tv.tv_usec) & 0xffff;
00571 k++;
00572 } while (find_id(header->id));
00573 #endif
00574 request->id = header->id;
00575 ++request->sends;
00576
00577 request->sent += send_res_msg(buf, request_len, request->sends);
00578 }
00579 }
00580
00581 static void
00582 resend_query(struct reslist *request)
00583 {
00584 if (request->resend == 0)
00585 return;
00586
00587 switch(request->type)
00588 {
00589 case T_PTR:
00590 do_query_number(NULL, &request->addr, request);
00591 break;
00592 case T_A:
00593 do_query_name(NULL, request->name, request, request->type);
00594 break;
00595 #ifdef IPV6
00596 case T_AAAA:
00597
00598 if (request->state == REQ_AAAA)
00599 do_query_name(NULL, request->name, request, T_A);
00600 #endif
00601 default:
00602 break;
00603 }
00604 }
00605
00606
00607
00608
00609 static int
00610 proc_answer(struct reslist *request, HEADER* header, char* buf, char* eob)
00611 {
00612 char hostbuf[HOSTLEN + 100];
00613 unsigned char *current;
00614 int query_class;
00615 int type;
00616 int n;
00617 int rd_length;
00618 struct sockaddr_in *v4;
00619 #ifdef IPV6
00620 struct sockaddr_in6 *v6;
00621 #endif
00622 current = (unsigned char *)buf + sizeof(HEADER);
00623
00624 for (; header->qdcount > 0; --header->qdcount)
00625 {
00626 if ((n = irc_dn_skipname(current, (unsigned char *)eob)) < 0)
00627 break;
00628
00629 current += (size_t) n + QFIXEDSZ;
00630 }
00631
00632
00633
00634
00635 while (header->ancount > 0 && (char *)current < eob)
00636 {
00637 header->ancount--;
00638
00639 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current,
00640 hostbuf, sizeof(hostbuf));
00641
00642 if (n < 0)
00643 {
00644
00645
00646
00647 return(0);
00648 }
00649 else if (n == 0)
00650 {
00651
00652
00653
00654 return(0);
00655 }
00656
00657 hostbuf[HOSTLEN] = '\0';
00658
00659
00660
00661
00662
00663 current += (size_t) n;
00664
00665 if (!(((char *)current + ANSWER_FIXED_SIZE) < eob))
00666 break;
00667
00668 type = irc_ns_get16(current);
00669 current += TYPE_SIZE;
00670
00671 query_class = irc_ns_get16(current);
00672 current += CLASS_SIZE;
00673
00674 request->ttl = irc_ns_get32(current);
00675 current += TTL_SIZE;
00676
00677 rd_length = irc_ns_get16(current);
00678 current += RDLENGTH_SIZE;
00679
00680
00681
00682
00683 switch (type)
00684 {
00685 case T_A:
00686 if (request->type != T_A)
00687 return(0);
00688
00689
00690
00691
00692 if (rd_length != sizeof(struct in_addr))
00693 return(0);
00694 v4 = (struct sockaddr_in *)&request->addr;
00695 request->addr.ss_len = sizeof(struct sockaddr_in);
00696 v4->sin_family = AF_INET;
00697 memcpy(&v4->sin_addr, current, sizeof(struct in_addr));
00698 return(1);
00699 break;
00700 #ifdef IPV6
00701 case T_AAAA:
00702 if (request->type != T_AAAA)
00703 return(0);
00704 if (rd_length != sizeof(struct in6_addr))
00705 return(0);
00706 request->addr.ss_len = sizeof(struct sockaddr_in6);
00707 v6 = (struct sockaddr_in6 *)&request->addr;
00708 v6->sin6_family = AF_INET6;
00709 memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr));
00710 return(1);
00711 break;
00712 #endif
00713 case T_PTR:
00714 if (request->type != T_PTR)
00715 return(0);
00716 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
00717 current, hostbuf, sizeof(hostbuf));
00718 if (n < 0)
00719 return(0);
00720 else if (n == 0)
00721 return(0);
00722
00723 strlcpy(request->name, hostbuf, HOSTLEN);
00724
00725 return(1);
00726 break;
00727 case T_CNAME:
00728
00729 if (request->type != T_PTR)
00730 return(0);
00731
00732 if (request->state == REQ_CNAME)
00733 {
00734 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
00735 current, hostbuf, sizeof(hostbuf));
00736
00737 if (n < 0)
00738 return(0);
00739 return(1);
00740 }
00741
00742 request->state = REQ_CNAME;
00743 current += rd_length;
00744 break;
00745
00746 default:
00747
00748
00749
00750
00751 ilog(L_ERROR, "irc_res.c bogus type %d", type);
00752 break;
00753 }
00754 }
00755
00756 return(1);
00757 }
00758
00759
00760
00761
00762 static void
00763 res_readreply(fde_t *fd, void *data)
00764 {
00765 char buf[sizeof(HEADER) + MAXPACKET]
00766
00767
00768
00769
00770 #if defined(__sparc__) || defined(__alpha__)
00771 __attribute__((aligned (16)))
00772 #endif
00773 ;
00774 HEADER *header;
00775 struct reslist *request = NULL;
00776 struct DNSReply *reply = NULL;
00777 int rc;
00778 int answer_count;
00779 socklen_t len = sizeof(struct irc_ssaddr);
00780 struct irc_ssaddr lsin;
00781
00782 rc = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
00783
00784
00785
00786
00787 comm_setselect(fd, COMM_SELECT_READ, res_readreply, NULL, 0);
00788
00789 if (rc <= (int)(sizeof(HEADER)))
00790 return;
00791
00792
00793
00794
00795 header = (HEADER *)buf;
00796 header->ancount = ntohs(header->ancount);
00797 header->qdcount = ntohs(header->qdcount);
00798 header->nscount = ntohs(header->nscount);
00799 header->arcount = ntohs(header->arcount);
00800
00801
00802
00803
00804
00805 if (0 == (request = find_id(header->id)))
00806 return;
00807
00808
00809
00810
00811 if (!res_ourserver(&lsin))
00812 return;
00813
00814 if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
00815 {
00816 if (NXDOMAIN == header->rcode)
00817 {
00818
00819
00820
00821
00822 #ifdef IPV6
00823 if (request->state == REQ_AAAA && request->type == T_AAAA)
00824 {
00825 request->timeout += 4;
00826 resend_query(request);
00827 }
00828 else if (request->type == T_PTR && request->state != REQ_INT &&
00829 request->addr.ss.ss_family == AF_INET6)
00830 {
00831 request->state = REQ_INT;
00832 request->timeout += 4;
00833 request->retries--;
00834 resend_query(request);
00835 }
00836 else
00837 #endif
00838 {
00839
00840
00841
00842
00843 (*request->query->callback)(request->query->ptr, NULL);
00844 rem_request(request);
00845 }
00846 }
00847 else
00848 {
00849
00850
00851
00852
00853 (*request->query->callback)(request->query->ptr, NULL);
00854 rem_request(request);
00855 }
00856 return;
00857 }
00858
00859
00860
00861
00862 answer_count = proc_answer(request, header, buf, buf + rc);
00863
00864 if (answer_count)
00865 {
00866 if (request->type == T_PTR)
00867 {
00868 if (request->name == NULL)
00869 {
00870
00871
00872
00873
00874 (*request->query->callback)(request->query->ptr, reply);
00875 rem_request(request);
00876 return;
00877 }
00878
00879
00880
00881
00882
00883
00884 #ifdef IPV6
00885 if (request->addr.ss.ss_family == AF_INET6)
00886 gethost_byname_type(request->name, request->query, T_AAAA);
00887 else
00888 #endif
00889 gethost_byname_type(request->name, request->query, T_A);
00890 rem_request(request);
00891 }
00892 else
00893 {
00894
00895
00896
00897 reply = make_dnsreply(request);
00898 (*request->query->callback)(request->query->ptr, reply);
00899 MyFree(reply);
00900 rem_request(request);
00901 }
00902 }
00903 else if (!request->sent)
00904 {
00905
00906
00907
00908 assert(0);
00909
00910
00911 rem_request(request);
00912 }
00913 }
00914
00915 static struct DNSReply *
00916 make_dnsreply(struct reslist *request)
00917 {
00918 struct DNSReply *cp;
00919 assert(request != 0);
00920
00921 cp = (struct DNSReply *)MyMalloc(sizeof(struct DNSReply));
00922
00923 cp->h_name = request->name;
00924 memcpy(&cp->addr, &request->addr, sizeof(cp->addr));
00925 return(cp);
00926 }
00927
00928 void
00929 report_dns_servers(struct Client *source_p)
00930 {
00931 int i;
00932 char ipaddr[HOSTIPLEN];
00933
00934 for (i = 0; i < irc_nscount; i++)
00935 {
00936 irc_getnameinfo((struct sockaddr *)&(irc_nsaddr_list[i]),
00937 irc_nsaddr_list[i].ss_len, ipaddr, HOSTIPLEN, NULL, 0,
00938 NI_NUMERICHOST);
00939 sendto_one(source_p, form_str(RPL_STATSALINE),
00940 me.name, source_p->name, ipaddr);
00941 }
00942 }