📄 srv_resolv.c
字号:
register HEADER* rheader; /* Reply header*/ unsigned char* rrptr; /* Current Resource record ptr */ int exprc; /* dn_expand return code */ int rrtype; long rrpayloadsz; srv_list svrlist = NULL; srv_list tempnode = NULL; srv_list iternode = NULL; xht arr_table; /* Hash of A records (name, ip) */ spool result; int result_is_empty = 1; char* ipname; char* ipaddr;#ifdef WITH_IPV6 int error_code; struct addrinfo hints; struct addrinfo* addr_res;#else struct hostent* hp;#endif /* If no service is specified, use a standard gethostbyname call */ if (service == NULL) { result = spool_new(p); if (srv_lookup_aaaa_a(result, domain) == 0) { return spool_print(result); } else { return NULL; } } log_debug2(ZONE, LOGT_IO, "srv: SRV resolution of %s.%s", service, domain); /* Setup A record hash table */ arr_table = xhash_new(11); /* Initialize lookup system if needed (check global _res structure) */ if (((_res.options & RES_INIT) == 0) && (res_init() == -1)) { log_debug2(ZONE, LOGT_IO, "srv: initialization failed on res_init."); return NULL; } /* Run a SRV query against the specified domain */ replylen = res_querydomain(service, domain, C_IN, /* Class */ T_SRV, /* Type */ (unsigned char*)&reply, /* Answer buffer */ sizeof(reply)); /* Answer buffer sz */ /* Setup a pointer to the reply header */ rheader = (HEADER*)reply; /* Process SRV response if all conditions are met per RFC 2052: * 1.) reply has some data available * 2.) no error occurred * 3.) there are 1 or more answers available */ if ( (replylen > 0) && (ntohs(rheader->rcode) == NOERROR) && (ntohs(rheader->ancount) > 0) ) { /* Parse out the Question section, and get to the following * RRs (see RFC 1035-4.1.2) */ exprc = dn_expand(reply, /* Msg ptr */ reply + replylen, /* End of msg ptr */ reply + sizeof(HEADER), /* Offset into msg */ host, sizeof(host)); /* Dest buffer for expansion */ if (exprc < 0) { log_debug2(ZONE, LOGT_IO, "srv: DN expansion failed for Question section."); return NULL; } /* Determine offset of the first RR */ rrptr = reply + sizeof(HEADER) + exprc + 4; /* Walk the RRs, building a list of targets */ while (rrptr < (reply + replylen)) { /* Expand the domain name */ exprc = dn_expand(reply, reply + replylen, rrptr, host, sizeof(host)); if (exprc < 0) { log_debug2(ZONE, LOGT_IO, "srv: Whoa nelly! DN expansion failed for RR."); return NULL; } /* Jump to RR info */ rrptr += exprc; rrtype = (rrptr[0] << 8 | rrptr[1]); /* Extract RR type */ rrpayloadsz = (rrptr[8] << 8 | rrptr[9]); /* Extract RR payload size */ rrptr += 10; /* Process the RR */ switch(rrtype) {#ifdef WITH_IPV6 /* AAAA records should be hashed for the duration of this lookup */ case T_AAAA: /* Allocate a new string to hold the IP address */ ipaddr = srv_inet_ntop(p, rrptr, AF_INET6); /* Copy the domain name */ ipname = pstrdup(p, host); /* Insert name/ip into hash table for future reference */ srv_xhash_join(p, arr_table, ipname, ipaddr); break;#endif /* A records should be hashed for the duration of this lookup */ case T_A: /* Allocate a new string to hold the IP address */ ipaddr = srv_inet_ntoa(p, rrptr); /* Copy the domain name */ ipname = pstrdup(p, host); /* Insert name/ip into hash table for future reference */ srv_xhash_join(p, arr_table, ipname, ipaddr); break; /* SRV records should be stored in a sorted list */ case T_SRV: /* Expand the target name */ exprc = dn_expand(reply, reply + replylen, rrptr + 6, host, sizeof(host)); if (exprc < 0) { log_debug2(ZONE, LOGT_IO, "srv: DN expansion failed for SRV."); return NULL; } /* Create a new node */ tempnode = pmalloco(p, sizeof(_srv_list)); tempnode->priority = (rrptr[0] << 8 | rrptr[1]); tempnode->port = srv_port2str(p, (rrptr[4] << 8 | rrptr[5])); tempnode->host = pstrdup(p, host); log_debug2(ZONE, LOGT_IO, "found SRV record pointing to %s", tempnode->host); /* Insert the node in the list */ if (svrlist == NULL) { /* first result */ svrlist = tempnode; } else { srv_list iternode_before = NULL; /* insert result in ordered list */ iternode = svrlist; /* HEAD of list (smallest priority value) */ /* find element that stays in front of the new one */ /* XXX for elements with the same priority we should use the weight to order * the elements in the list. We are now just ignoring the weight resulting * in an equal distribution across results of the same priority */ while (iternode != NULL && iternode->priority < tempnode->priority) { iternode_before = iternode; /* keep pointer to the element before */ iternode = iternode->next; /* switch to next element */ } /* iternode now either points to NULL (insert as last element) * or it points to the element after the new one * * iternode_before now either point to NULL (insert as first element) * or it points to the element in front of the new one */ /* insert the new element in the list */ /* update pointers in the new element */ tempnode->next = iternode; tempnode->last = iternode_before; /* update pointer in the previous element */ if (iternode_before != NULL) { iternode_before->next = tempnode; } else { /* we are the first element */ svrlist = tempnode; } /* update pointer in the following element */ if (iternode != NULL) { iternode->last = tempnode; } } } /* end..switch */ /* Increment to next RR */ rrptr += rrpayloadsz; } /* Now, walk the nicely sorted list and resolve the target's A records, sticking the resolved name in * a spooler -- hopefully these have been pre-cached, and arrived along with the SRV reply */ result = spool_new(p); iternode = svrlist; while (iternode != NULL) { log_debug2(ZONE, LOGT_IO, "processing SRV record pointing to %s", iternode->host); /* Check the AAAA/A record hash table first.. */ ipaddr = (char*)xhash_get(arr_table, iternode->host); /* it hasn't been in the additional section, we have to lookup the IP address */ if (ipaddr == NULL) { spool temp_result = spool_new(p); log_debug2(ZONE, LOGT_IO, "'%s' not in additional section of DNS reply, looking it up using AAAA/A query", iternode->host); srv_lookup_aaaa_a(temp_result, iternode->host); ipaddr = spool_print(temp_result); } if (j_strlen(ipaddr) > 0) { /* copy the ipaddr as we will modify it */ char *ptrptr, *token, *ipaddr_copy = strdup(ipaddr); /* if there has been a result already, we have to separate by a "," */ if (!result_is_empty) { spool_add(result, ","); } else { result_is_empty = 0; } /* add the port number for each address */ token = strtok_r(ipaddr_copy, ",", &ptrptr); while (token != NULL) { if (strchr(token, ':')) { /* IPv6 format */ spooler(result, "[", token, "]:", iternode->port, result); } else { /* IPv4 format */ spooler(result, token, ":", iternode->port, result); } /* get next token */ token = strtok_r(NULL, ",", &ptrptr); if (token) { spool_add(result, ","); /* separate results by ',' */ } } /* free our tokenized copy */ free(ipaddr_copy); } iternode = iternode->next; } /* Finally, turn the fully resolved list into a string <ip>:<host>,... */ return spool_print(result); } /* Otherwise, return NULL -- it's for the caller to finish up by using * standard A records */ return NULL; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -