static uchar * ixfr_gobble_authority_rr(TASK *t, uchar *query, size_t querylen, uchar *current, IARR *rr){ uchar * src = current; int rdlength = 0; task_error_t errcode = TASK_FAILED; if (!(IARR_NAME(rr) = name_unencode2(query, querylen, &src, &errcode))) { formerr(t, DNS_RCODE_FORMERR, errcode, NULL); return NULL; } DNS_GET16(rr->type, src); DNS_GET16(rr->class, src); DNS_GET32(rr->ttl, src); DNS_GET16(rdlength, src); if (!(IARR_MNAME(rr) = name_unencode2(query, querylen, &src, &errcode))) { formerr(t, DNS_RCODE_FORMERR, errcode, NULL); return NULL; } if (!(IARR_RNAME(rr) = name_unencode2(query, querylen, &src, &errcode))) { formerr(t, DNS_RCODE_FORMERR, errcode, NULL); return NULL; } DNS_GET32(rr->serial, src); DNS_GET32(rr->refresh, src); DNS_GET32(rr->retry, src); DNS_GET32(rr->expire, src); DNS_GET32(rr->minimum, src); return src; }
int make_dns_query(char *buf, int query_len, time_t *ttl, int *Anum) { struct sockaddr_in addr; int sockfd = -1; struct timeval timeout = { RETRANS_INTERVAL, 0 }; int i, ret = -1; int addrlen, send_len, result_len; int try_num = 0; dns_head_type *dns_head; #ifdef WIN32 WSADATA wsa; WSAStartup(MAKEWORD(2, 2), &wsa); #endif addr.sin_family = AF_INET; //addr.sin_addr.s_addr = inet_addr(PUBLIC_DNS_DEFAULT_SERVER); inet_pton(AF_INET, PUBLIC_DNS_DEFAULT_SERVER, &(addr.sin_addr.s_addr)); addr.sin_port = htons((uint16_t)PUBLIC_DNS_DEFAULT_PORT); sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (-1 == sockfd) { fprintf(stderr, "socket error\n"); goto clear; } ret = wait_writable(sockfd, timeout); if (ret != 0) { fprintf(stderr, "wait writable timeout\n"); goto clear; } while (try_num++ <= RETRANS_TRY_NUM) { send_len = sendto(sockfd, buf, query_len, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr)); if (send_len != query_len) { fprintf(stderr, "sendto dns query failed\n"); ret = -1; goto clear; } ret = wait_readable(sockfd, timeout); if (ret == 0) { break; } } if (try_num > RETRANS_TRY_NUM) { fprintf(stderr, "dns query failed over try num\n"); ret = -1; goto clear; } addrlen = sizeof(struct sockaddr); result_len = recvfrom(sockfd, buf, DNS_DEFAULT_DATA_SIZE, 0/*MSG_WAITALL*/, (struct sockaddr *)&addr, (socklen_t*)&addrlen); if (result_len <= 0) { fprintf(stderr, "receve dns response failed\n"); ret = -1; goto clear; } //只支持A记录 dns_head = (dns_head_type *)buf; int off = 0; int num = DNS_GET16(dns_head->numA); for (i = 0; i < num; i++) { char *result_set = buf + query_len + off; response *rp = (response *)(result_set + 2); //2 bytes' offsets uint16_t type = DNS_GET16(rp->type); *ttl = DNS_GET32(rp->ttl); //解析A记录 if (TYPE_A == type) { memcpy(buf + (*Anum) * 4, (char *)(rp + 1), 4); (*Anum)++; off += (2 + sizeof(response) + 4); } else if (TYPE_CNAME == type) { //如果是CNAME记录则直接查找下一条记录 off += (2 + sizeof(response) + DNS_GET16(rp->length)); } else { //其他类型不支持 goto clear; } } ret = 0; clear: if (sockfd != -1) { #ifdef WIN32 closesocket(sockfd); WSACleanup(); #else close(sockfd); #endif } return ret; }