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"); }
int filter_query(uint8_t *buf, int buflen) { ns_msg msg; if (local_ns_initparse(buf, buflen, &msg) < 0) { logger_log(LOG_ERR, "local_ns_initparse"); return -1; } else { int i; const char *host = hostname_from_question(msg); for (i = 0; i < black_list.elements; i++) { int rc = domain_match(host, black_list.domains[i]); if (rc) { logger_log(LOG_INFO, "request %s", host); return 0; } } } 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"); }