diff options
author | Samuel Ortiz <sameo@linux.intel.com> | 2010-09-24 17:57:55 +0200 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2010-09-24 17:57:55 +0200 |
commit | eadb99ab231b2400ed8f7b535d7421f7ddac7eaf (patch) | |
tree | 67059504ba71485d7af62391090819191171e764 /plugins | |
parent | 18870e6fc590cecfe573d1cac0879c1ae97a2c3e (diff) | |
download | connman-eadb99ab231b2400ed8f7b535d7421f7ddac7eaf.tar.gz connman-eadb99ab231b2400ed8f7b535d7421f7ddac7eaf.tar.bz2 connman-eadb99ab231b2400ed8f7b535d7421f7ddac7eaf.zip |
Send SERVFAIL when nameservers are not listening on TCP port 53
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/dnsproxy.c | 86 |
1 files changed, 63 insertions, 23 deletions
diff --git a/plugins/dnsproxy.c b/plugins/dnsproxy.c index 135f7f5f..f12fd27f 100644 --- a/plugins/dnsproxy.c +++ b/plugins/dnsproxy.c @@ -354,6 +354,42 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol) return err; } +static void send_response(int sk, unsigned char *buf, int len, + const struct sockaddr *to, socklen_t tolen, + int protocol) +{ + struct domain_hdr *hdr; + int err, offset; + + switch (protocol) { + case IPPROTO_UDP: + offset = 0; + break; + + case IPPROTO_TCP: + offset = 2; + break; + + default: + return; + } + + if (len < 12) + return; + + hdr = (void*) (buf + offset); + + DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode); + + hdr->qr = 1; + hdr->rcode = 2; + + hdr->ancount = 0; + hdr->nscount = 0; + hdr->arcount = 0; + + err = sendto(sk, buf, len, 0, to, tolen); +} static void destroy_server(struct server_data *server) { @@ -410,8 +446,32 @@ static gboolean tcp_server_event(GIOChannel *channel, GIOCondition condition, return FALSE; if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) { + GSList *list; + DBG("TCP server channel closed"); + for (list = request_list; list; list = list->next) { + struct request_data *req = list->data; + struct domain_hdr *hdr = (void *) (req->request + 2); + + if (!req->client_sk) + continue; + + /* + * If we're not waiting for any further response + * from another name server, then we send an error + * response to the client. + */ + if (req->numserv && --(req->numserv)) + continue; + + hdr->id = req->srcid; + send_response(req->client_sk, req->request, + req->request_len, NULL, 0, IPPROTO_TCP); + + request_list = g_slist_remove(request_list, req); + } + server_list = g_slist_remove(server_list, server); destroy_server(server); @@ -826,27 +886,6 @@ static int parse_request(unsigned char *buf, int len, return 0; } -static void send_response(int sk, unsigned char *buf, int len, - const struct sockaddr *to, socklen_t tolen) -{ - struct domain_hdr *hdr = (void *) buf; - int err; - - if (len < 12) - return; - - DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode); - - hdr->qr = 1; - hdr->rcode = 2; - - hdr->ancount = 0; - hdr->nscount = 0; - hdr->arcount = 0; - - err = sendto(sk, buf, len, 0, to, tolen); -} - static gboolean tcp_listener_event(GIOChannel *channel, GIOCondition condition, gpointer user_data) { @@ -890,7 +929,7 @@ static gboolean tcp_listener_event(GIOChannel *channel, GIOCondition condition, err = parse_request(buf + 2, len - 2, query, sizeof(query)); if (err < 0 || (g_slist_length(server_list) == 0 && connman_ondemand_connected())) { - send_response(client_sk, buf, len, NULL, 0); + send_response(client_sk, buf, len, NULL, 0, IPPROTO_TCP); return TRUE; } @@ -989,7 +1028,8 @@ static gboolean udp_listener_event(GIOChannel *channel, GIOCondition condition, err = parse_request(buf, len, query, sizeof(query)); if (err < 0 || (g_slist_length(server_list) == 0 && connman_ondemand_connected())) { - send_response(sk, buf, len, (struct sockaddr *) &sin, size); + send_response(sk, buf, len, (struct sockaddr *) &sin, size, + IPPROTO_UDP); return TRUE; } |