static void dns_handle_local() { struct sockaddr *src_addr = malloc(sizeof(struct sockaddr)); socklen_t src_addrlen = sizeof(struct sockaddr); uint16_t query_id; ssize_t len; int i; const char *question_hostname; ns_msg msg; len = recvfrom(local_sock, global_buf, BUF_SIZE, 0, src_addr, &src_addrlen); if (len > 0) { if (ns_initparse((const u_char *)global_buf, len, &msg) < 0) { ERR("ns_initparse"); free(src_addr); return; } // parse DNS query id // TODO generate id for each request to avoid conflicts query_id = ns_msg_id(msg); question_hostname = hostname_from_question(msg); LOG("request %s\n", question_hostname); id_addr_t id_addr; id_addr.id = query_id; id_addr.addr = src_addr; id_addr.addrlen = src_addrlen; queue_add(id_addr); for (i = 0; i < dns_servers_len; i++) { if (-1 == sendto(remote_sock, global_buf, len, 0, dns_server_addrs[i].addr, dns_server_addrs[i].addrlen)) ERR("sendto"); } } else ERR("recvfrom"); }
static void dns_handle_remote() { struct sockaddr *src_addr = malloc(sizeof(struct sockaddr)); socklen_t src_len = sizeof(struct sockaddr); uint16_t query_id; ssize_t len; const char *question_hostname; int r; ns_msg msg; len = recvfrom(remote_sock, global_buf, BUF_SIZE, 0, src_addr, &src_len); if (len > 0) { if (ns_initparse((const u_char *)global_buf, len, &msg) < 0) { ERR("ns_initparse"); free(src_addr); return; } // parse DNS query id query_id = ns_msg_id(msg); question_hostname = hostname_from_question(msg); if (question_hostname) { LOG("response %s from %s:%d - ", question_hostname, inet_ntoa(((struct sockaddr_in *)src_addr)->sin_addr), htons(((struct sockaddr_in *)src_addr)->sin_port)); } id_addr_t *id_addr = queue_lookup(query_id); if (id_addr) { id_addr->addr->sa_family = AF_INET; uint16_t ns_old_id = htons(id_addr->old_id); memcpy(global_buf, &ns_old_id, 2); r = should_filter_query(msg, ((struct sockaddr_in *)src_addr)->sin_addr); if (r == 0) { if (verbose) printf("pass\n"); if (-1 == sendto(local_sock, global_buf, len, 0, id_addr->addr, id_addr->addrlen)) ERR("sendto"); } else if (r == -1) { schedule_delay(query_id, global_buf, len, id_addr->addr, id_addr->addrlen); if (verbose) printf("delay\n"); } else { if (verbose) printf("filter\n"); } } else { if (verbose) printf("skip\n"); } free(src_addr); } else ERR("recvfrom"); }
/* Initialize a "newmsg" object by copying an existing parsed message. */ int ns_newmsg_copy(ns_newmsg *handle, ns_msg *msg) { ns_flag flag; ns_sect sect; ns_newmsg_id(handle, ns_msg_id(*msg)); for (flag = ns_f_qr; flag < ns_f_max; flag++) ns_newmsg_flag(handle, flag, ns_msg_getflag(*msg, flag)); for (sect = ns_s_qd; sect < ns_s_max; sect++) { int i, count; count = ns_msg_count(*msg, sect); for (i = 0; i < count; i++) { ns_rr2 rr; int x; if (ns_parserr2(msg, sect, i, &rr) < 0) return (-1); if (sect == ns_s_qd) x = ns_newmsg_q(handle, ns_rr_nname(rr), ns_rr_type(rr), ns_rr_class(rr)); else x = ns_newmsg_rr(handle, sect, ns_rr_nname(rr), ns_rr_type(rr), ns_rr_class(rr), ns_rr_ttl(rr), ns_rr_rdlen(rr), ns_rr_rdata(rr)); if (x < 0) return (-1); } } return (0); }
void dump_dns(const u_char *payload, size_t paylen, FILE *trace, const char *endline) { u_int opcode, rcode, id; const char *sep; ns_msg msg; fprintf(trace, " %sdns ", endline); if (ns_initparse(payload, paylen, &msg) < 0) { fputs(strerror(errno), trace); return; } opcode = ns_msg_getflag(msg, ns_f_opcode); rcode = ns_msg_getflag(msg, ns_f_rcode); id = ns_msg_id(msg); fprintf(trace, "%s,%s,%u", p_opcode(opcode), p_rcode(rcode), id); sep = ","; #define FLAG(t,f) if (ns_msg_getflag(msg, f)) { \ fprintf(trace, "%s%s", sep, t); \ sep = "|"; \ } FLAG("qr", ns_f_qr); FLAG("aa", ns_f_aa); FLAG("tc", ns_f_tc); FLAG("rd", ns_f_rd); FLAG("ra", ns_f_ra); FLAG("z", ns_f_z); FLAG("ad", ns_f_ad); FLAG("cd", ns_f_cd); #undef FLAG dump_dns_sect(&msg, ns_s_qd, trace, endline); dump_dns_sect(&msg, ns_s_an, trace, endline); dump_dns_sect(&msg, ns_s_ns, trace, endline); dump_dns_sect(&msg, ns_s_ar, trace, endline); }
void royparse_output(const char* descr, iaddr from, iaddr to, uint8_t proto, unsigned flags, unsigned sport, unsigned dport, my_bpftimeval ts, const u_char* pkt_copy, unsigned olen, const u_char* payload, unsigned payloadlen) { if (flags & DNSCAP_OUTPUT_ISDNS) { int rrmax; ns_msg msg; ns_rr rr; if (ns_initparse(payload, payloadlen, &msg) < 0) { fprintf(r_out, "ERR\n"); return; } if (ns_msg_getflag(msg, ns_f_qr) != 0 && sport == 53) { fprintf(r_out, "%cD_", ns_msg_getflag(msg, ns_f_rd) ? 'R' : 'N'); switch (ns_msg_getflag(msg, ns_f_opcode)) { case ns_o_query: fprintf(r_out, "QUERY"); break; case ns_o_notify: fprintf(r_out, "NOTIFY"); break; case ns_o_update: fprintf(r_out, "UPDATE"); break; default: fprintf(r_out, "ELSE"); } fprintf(r_out, "_%u_%cA_", ns_msg_count(msg, ns_s_an) ? 1 : 0, ns_msg_getflag(msg, ns_f_aa) ? 'A' : 'N'); switch (ns_msg_getflag(msg, ns_f_rcode)) { case ns_r_noerror: fprintf(r_out, "NOERROR"); break; case ns_r_formerr: fprintf(r_out, "FORMERR"); break; case ns_r_nxdomain: fprintf(r_out, "NXDOMAIN"); break; case ns_r_notimpl: fprintf(r_out, "NOTIMP"); break; case ns_r_refused: fprintf(r_out, "REFUSED"); break; case ns_r_notauth: fprintf(r_out, "NOTAUTH"); break; default: fprintf(r_out, "ELSE"); } fprintf(r_out, " %s,", royparse_ia_str(to)); if (ns_msg_count(msg, ns_s_qd) > 0) { if (ns_parserr(&msg, ns_s_qd, 0, &rr) == 0) { royparse_normalize(ns_rr_name(rr)); fprintf(r_out, "%s%s,%u", ns_rr_name(rr), (ns_rr_name(rr)[0] == '.') ? "" : ".", ns_rr_type(rr)); } else fprintf(r_out, "ERR,ERR"); } else fprintf(r_out, ","); fprintf(r_out, ",%ld,%s%s%s%s", ns_msg_size(msg), ns_msg_id(msg) < 256 ? "-L" : "", ns_msg_getflag(msg, ns_f_tc) ? "-TC" : "", ns_msg_getflag(msg, ns_f_ad) ? "-AD" : "", ns_msg_getflag(msg, ns_f_cd) ? "-CD" : ""); rrmax = ns_msg_count(msg, ns_s_ar); while (rrmax > 0) { rrmax--; if (ns_parserr(&msg, ns_s_ar, rrmax, &rr) == 0) { if (ns_rr_type(rr) == ns_t_opt) { fprintf(r_out, "-%c", (u_long)ns_rr_ttl(rr) & NS_OPT_DNSSEC_OK ? 'D' : 'E'); break; } } } fprintf(r_out, "\n"); } else if (opt_q != 0 && ns_msg_getflag(msg, ns_f_qr) == 0 && dport == 53) { struct pcap_pkthdr h; if (flags & DNSCAP_OUTPUT_ISLAYER) return; memset(&h, 0, sizeof h); h.ts = ts; h.len = h.caplen = olen; pcap_dump((u_char*)q_out, &h, pkt_copy); } } }
void txtout_output(const char* descr, iaddr from, iaddr to, uint8_t proto, unsigned flags, unsigned sport, unsigned dport, my_bpftimeval ts, const u_char* pkt_copy, unsigned olen, const u_char* payload, unsigned payloadlen) { /* * Short output, only print QTYPE and QNAME for IN records */ if (opt_s) { if (flags & DNSCAP_OUTPUT_ISDNS) { ns_msg msg; int qdcount, err = 0; ns_rr rr; if (ns_initparse(payload, payloadlen, &msg) < 0) { if (tcpstate_getcurr && tcpstate_reset) tcpstate_reset(tcpstate_getcurr(), ""); return; } qdcount = ns_msg_count(msg, ns_s_qd); if (qdcount > 0 && 0 == (err = ns_parserr(&msg, ns_s_qd, 0, &rr)) && ns_rr_class(rr) == 1) { fprintf(out, "%s %s\n", p_type(ns_rr_type(rr)), ns_rr_name(rr)); } if (err < 0) { if (tcpstate_getcurr && tcpstate_reset) tcpstate_reset(tcpstate_getcurr(), ""); } } return; } /* * IP Stuff */ fprintf(out, "%10ld.%06ld", (long)ts.tv_sec, (long)ts.tv_usec); fprintf(out, " %s %u", ia_str(from), sport); fprintf(out, " %s %u", ia_str(to), dport); fprintf(out, " %hhu", proto); if (flags & DNSCAP_OUTPUT_ISDNS) { ns_msg msg; int qdcount, err = 0; ns_rr rr; if (ns_initparse(payload, payloadlen, &msg) < 0) { if (tcpstate_getcurr && tcpstate_reset) tcpstate_reset(tcpstate_getcurr(), ""); fprintf(out, "\n"); return; } /* * DNS Header */ fprintf(out, " %u", ns_msg_id(msg)); fprintf(out, " %u", ns_msg_getflag(msg, ns_f_opcode)); fprintf(out, " %u", ns_msg_getflag(msg, ns_f_rcode)); fprintf(out, " |"); if (ns_msg_getflag(msg, ns_f_qr)) fprintf(out, "QR|"); if (ns_msg_getflag(msg, ns_f_aa)) fprintf(out, "AA|"); if (ns_msg_getflag(msg, ns_f_tc)) fprintf(out, "TC|"); if (ns_msg_getflag(msg, ns_f_rd)) fprintf(out, "RD|"); if (ns_msg_getflag(msg, ns_f_ra)) fprintf(out, "RA|"); if (ns_msg_getflag(msg, ns_f_ad)) fprintf(out, "AD|"); if (ns_msg_getflag(msg, ns_f_cd)) fprintf(out, "CD|"); qdcount = ns_msg_count(msg, ns_s_qd); if (qdcount > 0 && 0 == (err = ns_parserr(&msg, ns_s_qd, 0, &rr))) { fprintf(out, " %s %s %s", p_class(ns_rr_class(rr)), p_type(ns_rr_type(rr)), ns_rr_name(rr)); } if (err < 0) { if (tcpstate_getcurr && tcpstate_reset) tcpstate_reset(tcpstate_getcurr(), ""); } } /* * Done */ fprintf(out, "\n"); }
/* * Print the contents of a query. * This is intended to be primarily a debugging routine. */ void fp_nquery(const u_char *msg, int len, FILE *file) { ns_msg handle; int qdcount, ancount, nscount, arcount; u_int opcode, rcode, id; if ((_res.options & RES_INIT) == 0 && res_init() == -1) return; if (ns_initparse(msg, len, &handle) < 0) { fprintf(file, ";; ns_initparse: %s\n", strerror(errno)); return; } opcode = ns_msg_getflag(handle, ns_f_opcode); rcode = ns_msg_getflag(handle, ns_f_rcode); id = ns_msg_id(handle); qdcount = ns_msg_count(handle, ns_s_qd); ancount = ns_msg_count(handle, ns_s_an); nscount = ns_msg_count(handle, ns_s_ns); arcount = ns_msg_count(handle, ns_s_ar); /* * Print header fields. */ if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || rcode) fprintf(file, ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n", _res_opcodes[opcode], _res_resultcodes[rcode], (int)id); if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX)) putc(';', file); if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) { fprintf(file, "; flags:"); if (ns_msg_getflag(handle, ns_f_qr)) fprintf(file, " qr"); if (ns_msg_getflag(handle, ns_f_aa)) fprintf(file, " aa"); if (ns_msg_getflag(handle, ns_f_tc)) fprintf(file, " tc"); if (ns_msg_getflag(handle, ns_f_rd)) fprintf(file, " rd"); if (ns_msg_getflag(handle, ns_f_ra)) fprintf(file, " ra"); if (ns_msg_getflag(handle, ns_f_z)) fprintf(file, " ??"); if (ns_msg_getflag(handle, ns_f_ad)) fprintf(file, " ad"); if (ns_msg_getflag(handle, ns_f_cd)) fprintf(file, " cd"); } if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) { fprintf(file, "; %s: %d", p_section(ns_s_qd, (int)opcode), qdcount); fprintf(file, ", %s: %d", p_section(ns_s_an, (int)opcode), ancount); fprintf(file, ", %s: %d", p_section(ns_s_ns, (int)opcode), nscount); fprintf(file, ", %s: %d", p_section(ns_s_ar, (int)opcode), arcount); } if ((!_res.pfcode) || (_res.pfcode & (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) { putc('\n',file); } /* * Print the various sections. */ do_section(&handle, ns_s_qd, RES_PRF_QUES, file); do_section(&handle, ns_s_an, RES_PRF_ANS, file); do_section(&handle, ns_s_ns, RES_PRF_AUTH, file); do_section(&handle, ns_s_ar, RES_PRF_ADD, file); if (qdcount == 0 && ancount == 0 && nscount == 0 && arcount == 0) putc('\n', file); }
/* * Print the contents of a query. * This is intended to be primarily a debugging routine. */ void fp_nquery (const unsigned char *msg, int len, FILE *file) { ns_msg handle; int qdcount, ancount, nscount, arcount; u_int opcode, rcode, id; /* There is no need to initialize _res: If _res is not yet initialized, _res.pfcode is zero. But initialization will leave it at zero, too. _res.pfcode is an unsigned long, but the code here assumes that the flags fit into an int, so use that. */ int pfcode = _res.pfcode; if (ns_initparse(msg, len, &handle) < 0) { fprintf(file, ";; ns_initparse: %s\n", strerror(errno)); return; } opcode = ns_msg_getflag(handle, ns_f_opcode); rcode = ns_msg_getflag(handle, ns_f_rcode); id = ns_msg_id(handle); qdcount = ns_msg_count(handle, ns_s_qd); ancount = ns_msg_count(handle, ns_s_an); nscount = ns_msg_count(handle, ns_s_ns); arcount = ns_msg_count(handle, ns_s_ar); /* * Print header fields. */ if ((!pfcode) || (pfcode & RES_PRF_HEADX) || rcode) fprintf(file, ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n", res_opcodes[opcode], p_rcode(rcode), id); if ((!pfcode) || (pfcode & RES_PRF_HEADX)) putc(';', file); if ((!pfcode) || (pfcode & RES_PRF_HEAD2)) { fprintf(file, "; flags:"); if (ns_msg_getflag(handle, ns_f_qr)) fprintf(file, " qr"); if (ns_msg_getflag(handle, ns_f_aa)) fprintf(file, " aa"); if (ns_msg_getflag(handle, ns_f_tc)) fprintf(file, " tc"); if (ns_msg_getflag(handle, ns_f_rd)) fprintf(file, " rd"); if (ns_msg_getflag(handle, ns_f_ra)) fprintf(file, " ra"); if (ns_msg_getflag(handle, ns_f_z)) fprintf(file, " ??"); if (ns_msg_getflag(handle, ns_f_ad)) fprintf(file, " ad"); if (ns_msg_getflag(handle, ns_f_cd)) fprintf(file, " cd"); } if ((!pfcode) || (pfcode & RES_PRF_HEAD1)) { fprintf(file, "; %s: %d", p_section(ns_s_qd, opcode), qdcount); fprintf(file, ", %s: %d", p_section(ns_s_an, opcode), ancount); fprintf(file, ", %s: %d", p_section(ns_s_ns, opcode), nscount); fprintf(file, ", %s: %d", p_section(ns_s_ar, opcode), arcount); } if ((!pfcode) || (pfcode & (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) { putc('\n',file); } /* * Print the various sections. */ do_section (pfcode, &handle, ns_s_qd, RES_PRF_QUES, file); do_section (pfcode, &handle, ns_s_an, RES_PRF_ANS, file); do_section (pfcode, &handle, ns_s_ns, RES_PRF_AUTH, file); do_section (pfcode, &handle, ns_s_ar, RES_PRF_ADD, file); if (qdcount == 0 && ancount == 0 && nscount == 0 && arcount == 0) putc('\n', file); }
/* Returns 1 with an answer, 0 when reply was old, -1 on fatal errors */ int nb_dns_activity(struct nb_dns_info *nd, struct nb_dns_result *nr, char *errstr) { register int msglen, qtype, atype, n, i; register struct nb_dns_entry *ne, *lastne; socklen_t fromlen; struct sockaddr_storage from; u_long msg[MAXPACKET / sizeof(u_long)]; register char *bp, *ep; register char **ap, **hap; register u_int16_t id; register const u_char *rdata; register u_int32_t rttl = 0; // make compiler happy. register struct hostent *he; register size_t rdlen; ns_msg handle; ns_rr rr; /* This comes from the second half of do_query() */ fromlen = sizeof(from); msglen = recvfrom(nd->s, (char *)msg, sizeof(msg), 0, (struct sockaddr*)&from, &fromlen); if (msglen <= 0) { snprintf(errstr, NB_DNS_ERRSIZE, "recvfrom(): %s", my_strerror(errno)); return (-1); } if (msglen < HFIXEDSZ) { snprintf(errstr, NB_DNS_ERRSIZE, "recvfrom(): undersized: %d", msglen); return (-1); } if (ns_initparse((u_char *)msg, msglen, &handle) < 0) { snprintf(errstr, NB_DNS_ERRSIZE, "ns_initparse(): %s", my_strerror(errno)); nr->host_errno = NO_RECOVERY; return (-1); } /* RES_INSECURE1 style check */ if (_nb_dns_cmpsockaddr((struct sockaddr*)&nd->server, (struct sockaddr*)&from, errstr) < 0) { nr->host_errno = NO_RECOVERY; return (-1); } /* Search for this request */ lastne = NULL; id = ns_msg_id(handle); for (ne = nd->list; ne != NULL; ne = ne->next) { if (ne->id == id) break; lastne = ne; } /* Not an answer to a question we care about anymore */ if (ne == NULL) return (0); /* Unlink this entry */ if (lastne == NULL) nd->list = ne->next; else lastne->next = ne->next; ne->next = NULL; /* RES_INSECURE2 style check */ /* XXX not implemented */ /* Initialize result struct */ memset(nr, 0, sizeof(*nr)); nr->cookie = ne->cookie; qtype = ne->qtype; /* Deal with various errors */ switch (ns_msg_getflag(handle, ns_f_rcode)) { case ns_r_nxdomain: nr->host_errno = HOST_NOT_FOUND; free(ne); return (1); case ns_r_servfail: nr->host_errno = TRY_AGAIN; free(ne); return (1); case ns_r_noerror: break; case ns_r_formerr: case ns_r_notimpl: case ns_r_refused: default: nr->host_errno = NO_RECOVERY; free(ne); return (1); } /* Loop through records in packet */ memset(&rr, 0, sizeof(rr)); memset(&nd->dns_hostent, 0, sizeof(nd->dns_hostent)); he = &nd->dns_hostent.hostent; /* XXX no support for aliases */ he->h_aliases = nd->dns_hostent.host_aliases; he->h_addr_list = nd->dns_hostent.h_addr_ptrs; he->h_addrtype = ne->atype; he->h_length = ne->asize; free(ne); bp = nd->dns_hostent.hostbuf; ep = bp + sizeof(nd->dns_hostent.hostbuf); hap = he->h_addr_list; ap = he->h_aliases; for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) { /* Parse next record */ if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) { if (errno != ENODEV) { nr->host_errno = NO_RECOVERY; return (1); } /* All done */ break; } /* Ignore records that don't answer our query (e.g. CNAMEs) */ atype = ns_rr_type(rr); if (atype != qtype) continue; rdata = ns_rr_rdata(rr); rdlen = ns_rr_rdlen(rr); rttl = ns_rr_ttl(rr); switch (atype) { case T_A: case T_AAAA: if (rdlen != (unsigned int) he->h_length) { snprintf(errstr, NB_DNS_ERRSIZE, "nb_dns_activity(): bad rdlen %d", (int) rdlen); nr->host_errno = NO_RECOVERY; return (-1); } if (bp + rdlen >= ep) { snprintf(errstr, NB_DNS_ERRSIZE, "nb_dns_activity(): overflow 1"); nr->host_errno = NO_RECOVERY; return (-1); } if (nd->dns_hostent.numaddrs + 1 >= MAXADDRS) { snprintf(errstr, NB_DNS_ERRSIZE, "nb_dns_activity(): overflow 2"); nr->host_errno = NO_RECOVERY; return (-1); } memcpy(bp, rdata, rdlen); *hap++ = bp; bp += rdlen; ++nd->dns_hostent.numaddrs; /* Keep looking for more A records */ break; case T_TXT: if (bp + rdlen >= ep) { snprintf(errstr, NB_DNS_ERRSIZE, "nb_dns_activity(): overflow 1 for txt"); nr->host_errno = NO_RECOVERY; return (-1); } memcpy(bp, rdata, rdlen); he->h_name = bp+1; /* First char is a control character. */ nr->hostent = he; nr->ttl = rttl; return (1); case T_PTR: n = dn_expand((const u_char *)msg, (const u_char *)msg + msglen, rdata, bp, ep - bp); if (n < 0) { /* XXX return -1 here ??? */ nr->host_errno = NO_RECOVERY; return (1); } he->h_name = bp; /* XXX check for overflow */ bp += n; /* returned len includes EOS */ /* "Find first satisfactory answer" */ nr->hostent = he; nr->ttl = rttl; return (1); } } nr->hostent = he; nr->ttl = rttl; return (1); }
static void dns_handle_local() { struct sockaddr *src_addr = malloc(sizeof(struct sockaddr)); socklen_t src_addrlen = sizeof(struct sockaddr); uint16_t query_id; ssize_t len; int i; int sended = 0; const char *question_hostname; ns_msg msg; len = recvfrom(local_sock, global_buf, BUF_SIZE, 0, src_addr, &src_addrlen); if (len > 0) { if (ns_initparse((const u_char *)global_buf, len, &msg) < 0) { ERR("ns_initparse"); free(src_addr); return; } // parse DNS query id // TODO generate id for each request to avoid conflicts query_id = ns_msg_id(msg); question_hostname = hostname_from_question(msg); LOG("request %s\n", question_hostname); // assign a new id uint16_t new_id; do { struct timeval tv; gettimeofday(&tv, 0); int randombits = (tv.tv_sec << 8) ^ tv.tv_usec; new_id = randombits & 0xffff; } while (queue_lookup(new_id)); uint16_t ns_new_id = htons(new_id); memcpy(global_buf, &ns_new_id, 2); id_addr_t id_addr; id_addr.id = new_id; id_addr.old_id = query_id; id_addr.addr = src_addr; id_addr.addrlen = src_addrlen; queue_add(id_addr); if (compression) { if (len > 16) { size_t off = 12; int ended = 0; while (off < len - 4) { if (global_buf[off] & 0xc0) break; if (global_buf[off] == 0) { ended = 1; off ++; break; } off += 1 + global_buf[off]; } if (ended) { memcpy(compression_buf, global_buf, off-1); memcpy(compression_buf + off + 1, global_buf + off, len - off); compression_buf[off-1] = '\xc0'; compression_buf[off] = '\x04'; for (i = 0; i < has_chn_dns; i++) { if (-1 == sendto(remote_sock, global_buf, len, 0, dns_server_addrs[i].addr, dns_server_addrs[i].addrlen)) ERR("sendto"); } for (i = has_chn_dns; i < dns_servers_len; i++) { if (-1 == sendto(remote_sock, compression_buf, len + 1, 0, dns_server_addrs[i].addr, dns_server_addrs[i].addrlen)) ERR("sendto"); sended = 1; } } } } if (!sended) { for (i = 0; i < dns_servers_len; i++) { if (-1 == sendto(remote_sock, global_buf, len, 0, dns_server_addrs[i].addr, dns_server_addrs[i].addrlen)) ERR("sendto"); } } } else ERR("recvfrom"); }