--- Hi, this 3rd version fixes the alignment macro namespace issue.
Jukka include/types.h | 16 ++++++++ src/dnsproxy.c | 114 +++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 97 insertions(+), 33 deletions(-) diff --git a/include/types.h b/include/types.h index 70aff9e..f722e65 100644 --- a/include/types.h +++ b/include/types.h @@ -38,6 +38,22 @@ typedef int connman_bool_t; typedef unsigned char connman_uint8_t; typedef unsigned short connman_uint16_t; +#define connman_get_unaligned(ptr) \ +({ \ + struct __attribute__((packed)) { \ + typeof(*(ptr)) __v; \ + } *__p = (void *) (ptr); \ + __p->__v; \ +}) + +#define connman_put_unaligned(val, ptr) \ +do { \ + struct __attribute__((packed)) { \ + typeof(*(ptr)) __v; \ + } *__p = (void *) (ptr); \ + __p->__v = (val); \ +} while(0) + #ifdef __cplusplus } #endif diff --git a/src/dnsproxy.c b/src/dnsproxy.c index d9e291c..dd67aff 100644 --- a/src/dnsproxy.c +++ b/src/dnsproxy.c @@ -187,12 +187,56 @@ static struct server_data *find_server(const char *interface, return NULL; } +static struct domain_hdr *get_hdr(unsigned char *buf, struct domain_hdr *hdr) +{ + if (hdr == NULL) + return NULL; + + hdr->id = ntohs(connman_get_unaligned((uint16_t *)buf)); + hdr->qr = (buf[2] & 0x80) >> 7; + hdr->opcode = (buf[2] & 0x78) >> 3; + hdr->aa = (buf[2] & 0x04) >> 2; + hdr->tc = (buf[2] & 0x02) >> 1; + hdr->rd = buf[2] & 0x01; + hdr->ra = (buf[3] & 0x80) >> 7; + hdr->z = 0; + hdr->rcode = buf[3] & 0x0f; + + hdr->qdcount = ntohs(connman_get_unaligned((uint16_t *)&buf[4])); + hdr->ancount = ntohs(connman_get_unaligned((uint16_t *)&buf[6])); + hdr->nscount = ntohs(connman_get_unaligned((uint16_t *)&buf[8])); + hdr->arcount = ntohs(connman_get_unaligned((uint16_t *)&buf[10])); + + return hdr; +} + +static void put_hdr(struct domain_hdr *hdr, unsigned char *buf) +{ + if (hdr == NULL) + return; + + connman_put_unaligned(htons(hdr->id), (uint16_t *)buf); + + buf[2] |= hdr->qr << 7; + buf[2] |= hdr->opcode << 3; + buf[2] |= hdr->aa << 2; + buf[2] |= hdr->tc << 1; + buf[2] |= hdr->rd << 0; + buf[3] |= hdr->ra << 7; + buf[3] &= ~0x70; + buf[3] |= hdr->rcode; + + connman_put_unaligned(htons(hdr->qdcount), (uint16_t *)&buf[4]); + connman_put_unaligned(htons(hdr->ancount), (uint16_t *)&buf[6]); + connman_put_unaligned(htons(hdr->nscount), (uint16_t *)&buf[8]); + connman_put_unaligned(htons(hdr->arcount), (uint16_t *)&buf[10]); +} static void send_response(int sk, unsigned char *buf, int len, const struct sockaddr *to, socklen_t tolen, int protocol) { - struct domain_hdr *hdr; + struct domain_hdr *hdr, header; int err, offset = protocol_offset(protocol); DBG(""); @@ -203,7 +247,7 @@ static void send_response(int sk, unsigned char *buf, int len, if (len < 12) return; - hdr = (void *) (buf + offset); + hdr = get_hdr(buf + offset, &header); DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode); @@ -214,6 +258,8 @@ static void send_response(int sk, unsigned char *buf, int len, hdr->nscount = 0; hdr->arcount = 0; + put_hdr(hdr, buf + offset); + err = sendto(sk, buf, len, 0, to, tolen); if (err < 0) { connman_error("Failed to send DNS response: %s", @@ -247,19 +293,18 @@ static gboolean request_timeout(gpointer user_data) if (err < 0) return FALSE; } else if (req->request && req->numserv == 0) { - struct domain_hdr *hdr; if (req->protocol == IPPROTO_TCP) { - hdr = (void *) (req->request + 2); - hdr->id = req->srcid; + connman_put_unaligned(htons(req->srcid), + (uint16_t *)(req->request + 2)); send_response(req->client_sk, req->request, req->request_len, NULL, 0, IPPROTO_TCP); } else if (req->protocol == IPPROTO_UDP) { int sk; - hdr = (void *) (req->request); - hdr->id = req->srcid; + connman_put_unaligned(htons(req->srcid), + (uint16_t *)req->request); sk = g_io_channel_unix_get_fd( ifdata->udp_listener_channel); send_response(sk, req->request, req->request_len, @@ -349,7 +394,6 @@ static int ns_resolv(struct server_data *server, struct request_data *req, for (list = server->domains; list; list = list->next) { char *domain; unsigned char alt[1024]; - struct domain_hdr *hdr = (void *) &alt; int altlen, domlen, offset; domain = list->data; @@ -365,11 +409,12 @@ static int ns_resolv(struct server_data *server, struct request_data *req, if (domlen < 5) return -EINVAL; - alt[offset] = req->altid & 0xff; - alt[offset + 1] = req->altid >> 8; + connman_put_unaligned(htons(req->altid), + (uint16_t *)(alt + offset)); memcpy(alt + offset + 2, request + offset + 2, 10); - hdr->qdcount = htons(1); + + alt[5] = 1; /* qdcount */ altlen = append_query(alt + offset + 12, sizeof(alt) - 12, name, domain); @@ -401,7 +446,7 @@ static int ns_resolv(struct server_data *server, struct request_data *req, static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol) { - struct domain_hdr *hdr; + struct domain_hdr *hdr, header; struct request_data *req; int dns_id, sk, err, offset = protocol_offset(protocol); struct listener_data *ifdata; @@ -409,8 +454,7 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol) if (offset < 0) return offset; - hdr = (void *)(reply + offset); - dns_id = reply[offset] | reply[offset + 1] << 8; + dns_id = ntohs(connman_get_unaligned((uint16_t *)(reply + offset))); DBG("Received %d bytes (id 0x%04x)", reply_len, dns_id); @@ -418,12 +462,12 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol) if (req == NULL) return -EINVAL; + hdr = get_hdr(reply + offset, &header); DBG("id 0x%04x rcode %d", hdr->id, hdr->rcode); ifdata = req->ifdata; - reply[offset] = req->srcid & 0xff; - reply[offset + 1] = req->srcid >> 8; + connman_put_unaligned(htons(req->srcid), (uint16_t *)(reply + offset)); req->numresp++; @@ -545,7 +589,6 @@ hangup: for (list = request_list; list; list = list->next) { struct request_data *req = list->data; - struct domain_hdr *hdr; if (req->protocol == IPPROTO_UDP) continue; @@ -561,8 +604,8 @@ hangup: if (req->numserv && --(req->numserv)) continue; - hdr = (void *) (req->request + 2); - hdr->id = req->srcid; + connman_put_unaligned(htons(req->srcid), + (uint16_t *)(req->request + 2)); send_response(req->client_sk, req->request, req->request_len, NULL, 0, IPPROTO_TCP); @@ -1038,9 +1081,7 @@ static unsigned char opt_edns0_type[2] = { 0x00, 0x29 }; static int parse_request(unsigned char *buf, int len, char *name, unsigned int size) { - struct domain_hdr *hdr = (void *) buf; - uint16_t qdcount = ntohs(hdr->qdcount); - uint16_t arcount = ntohs(hdr->arcount); + struct domain_hdr *hdr, header; unsigned char *ptr; char *last_label = NULL; unsigned int remain, used = 0; @@ -1048,11 +1089,12 @@ static int parse_request(unsigned char *buf, int len, if (len < 12) return -EINVAL; + hdr = get_hdr(buf, &header); DBG("id 0x%04x qr %d opcode %d qdcount %d arcount %d", hdr->id, hdr->qr, hdr->opcode, - qdcount, arcount); + hdr->qdcount, hdr->arcount); - if (hdr->qr != 0 || qdcount != 1) + if (hdr->qr != 0 || hdr->qdcount != 1) return -EINVAL; memset(name, 0, size); @@ -1080,7 +1122,7 @@ static int parse_request(unsigned char *buf, int len, remain -= len + 1; } - if (last_label && arcount && remain >= 9 && last_label[4] == 0 && + if (last_label && hdr->arcount && remain >= 9 && last_label[4] == 0 && !memcmp(last_label + 5, opt_edns0_type, 2)) { uint16_t edns0_bufsize; @@ -1119,6 +1161,7 @@ static gboolean tcp_listener_event(GIOChannel *channel, GIOCondition condition, socklen_t client_addr_len = sizeof(client_addr); GSList *list; struct listener_data *ifdata = user_data; + uint16_t id; DBG("condition 0x%x", condition); @@ -1145,7 +1188,9 @@ static gboolean tcp_listener_event(GIOChannel *channel, GIOCondition condition, if (len < 2) return TRUE; - DBG("Received %d bytes (id 0x%04x)", len, buf[2] | buf[3] << 8); + id = buf[2] << 8 | buf[3]; + + DBG("Received %d bytes (id 0x%04x)", len, id); err = parse_request(buf + 2, len - 2, query, sizeof(query)); if (err < 0 || (g_slist_length(server_list) == 0)) { @@ -1166,13 +1211,13 @@ static gboolean tcp_listener_event(GIOChannel *channel, GIOCondition condition, if (request_id == 0x0000 || request_id == 0xffff) request_id += 2; - req->srcid = buf[2] | (buf[3] << 8); + req->srcid = id; req->dstid = request_id; req->altid = request_id + 1; req->request_len = len; - buf[2] = req->dstid & 0xff; - buf[3] = req->dstid >> 8; + buf[2] = req->dstid >> 8; + buf[3] = req->dstid; req->numserv = 0; req->ifdata = (struct listener_data *) ifdata; @@ -1242,6 +1287,7 @@ static gboolean udp_listener_event(GIOChannel *channel, GIOCondition condition, socklen_t client_addr_len = sizeof(client_addr); int sk, err, len; struct listener_data *ifdata = user_data; + uint16_t id; if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) { connman_error("Error with UDP listener channel"); @@ -1257,7 +1303,9 @@ static gboolean udp_listener_event(GIOChannel *channel, GIOCondition condition, if (len < 2) return TRUE; - DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8); + id = buf[0] << 8 | buf[1]; + + DBG("Received %d bytes (id 0x%04x)", len, id); err = parse_request(buf, len, query, sizeof(query)); if (err < 0 || (g_slist_length(server_list) == 0)) { @@ -1279,13 +1327,13 @@ static gboolean udp_listener_event(GIOChannel *channel, GIOCondition condition, if (request_id == 0x0000 || request_id == 0xffff) request_id += 2; - req->srcid = buf[0] | (buf[1] << 8); + req->srcid = id; req->dstid = request_id; req->altid = request_id + 1; req->request_len = len; - buf[0] = req->dstid & 0xff; - buf[1] = req->dstid >> 8; + buf[0] = req->dstid >> 8; + buf[1] = req->dstid; req->numserv = 0; req->ifdata = (struct listener_data *) ifdata; -- 1.7.1 _______________________________________________ connman mailing list connman@connman.net http://lists.connman.net/listinfo/connman