From 924745da0452e17980132677376a3e8727db1fd9 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Wed, 16 May 2018 00:56:43 +0800 Subject: [PATCH] Update code --- dns.c | 1702 +++++++++++++++++++++++++++----------------------- dns.h | 61 +- dns_client.c | 18 + dns_server.c | 111 +++- fast_ping.c | 18 + smartdns.c | 18 + 6 files changed, 1110 insertions(+), 818 deletions(-) diff --git a/dns.c b/dns.c index 97f3eb0..82cb434 100644 --- a/dns.c +++ b/dns.c @@ -1,458 +1,493 @@ +/************************************************************************* + * + * Copyright (C) 2018 Ruilin Peng (Nick) . + * + * smartdns is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * smartdns is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "dns.h" #include #include -#define DNS_MAX_CNAME_LEN 128 +#define QR_MASK 0x8000 +#define OPCODE_MASK 0x7800 +#define AA_MASK 0x0400 +#define TC_MASK 0x0200 +#define RD_MASK 0x0100 +#define RA_MASK 0x8000 +#define RCODE_MASK 0x000F + +#define DNS_RR_END (0XFFFF) short dns_read_short(unsigned char **buffer) { - unsigned short value; + unsigned short value; - value = *((unsigned short *)(*buffer)); - *buffer += 2; + value = *((unsigned short *)(*buffer)); + *buffer += 2; - return ntohs(value); + return ntohs(value); } void dns_write_char(unsigned char **buffer, unsigned char value) { - **buffer = value; - *buffer += 1; + **buffer = value; + *buffer += 1; } unsigned char dns_read_char(unsigned char **buffer) { - unsigned char value = **buffer; - *buffer += 1; - return value; + unsigned char value = **buffer; + *buffer += 1; + return value; } void dns_write_short(unsigned char **buffer, unsigned short value) { - value = htons(value); - *((unsigned short *)(*buffer)) = value; - *buffer += 2; + value = htons(value); + *((unsigned short *)(*buffer)) = value; + *buffer += 2; } void dns_write_int(unsigned char **buffer, unsigned int value) { - value = htons(value); - *((unsigned int *)(*buffer)) = value; - *buffer += 4; + value = htons(value); + *((unsigned int *)(*buffer)) = value; + *buffer += 4; } unsigned int dns_read_int(unsigned char **buffer) { - unsigned int value; + unsigned int value; - value = *((unsigned int *)(*buffer)); - *buffer += 4; + value = *((unsigned int *)(*buffer)); + *buffer += 4; - return ntohs(value); + return ntohs(value); } -struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, int type, int *count) +struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, int *count) { - unsigned short start; - struct dns_head *head = &packet->head; + unsigned short start; + struct dns_head *head = &packet->head; - switch (type) { - case DNS_RRS_QD: - *count = head->qdcount; - start = packet->questions; - break; - case DNS_RRS_AN: - *count = head->ancount; - start = packet->answers; - break; - case DNS_RRS_NS: - *count = head->nscount; - start = packet->nameservers; - break; - case DNS_RRS_NR: - *count = head->nrcount; - start = packet->additional; - break; - default: - return NULL; - break; - } + switch (type) { + case DNS_RRS_QD: + *count = head->qdcount; + start = packet->questions; + break; + case DNS_RRS_AN: + *count = head->ancount; + start = packet->answers; + break; + case DNS_RRS_NS: + *count = head->nscount; + start = packet->nameservers; + break; + case DNS_RRS_NR: + *count = head->nrcount; + start = packet->additional; + break; + default: + return NULL; + break; + } - if (start == DNS_RR_END) { - return NULL; - } + if (start == DNS_RR_END) { + return NULL; + } - return (struct dns_rrs *)(packet->data + start); + return (struct dns_rrs *)(packet->data + start); } struct dns_rrs *dns_get_rrs_next(struct dns_packet *packet, struct dns_rrs *rrs) { - if (rrs->next == DNS_RR_END) { - return NULL; - } + if (rrs->next == DNS_RR_END) { + return NULL; + } - return (struct dns_rrs *)(packet->data + rrs->next); + return (struct dns_rrs *)(packet->data + rrs->next); } unsigned char *_dns_add_rrs_start(struct dns_packet *packet, int *maxlen) { - struct dns_rrs *rrs; - unsigned char *end = packet->data + packet->len; - rrs = (struct dns_rrs *)end; - *maxlen = packet->size - packet->len - sizeof(*packet); - if (packet->len >= packet->size - sizeof(*packet)) { - return NULL; - } - return rrs->data; + struct dns_rrs *rrs; + unsigned char *end = packet->data + packet->len; + rrs = (struct dns_rrs *)end; + *maxlen = packet->size - packet->len - sizeof(*packet); + if (packet->len >= packet->size - sizeof(*packet)) { + return NULL; + } + return rrs->data; } int dns_rr_add_end(struct dns_packet *packet, int type, dns_type_t rrtype, int len) { - struct dns_rrs *rrs; - struct dns_rrs *rrs_next; - struct dns_head *head = &packet->head; - unsigned char *end = packet->data + packet->len; - rrs = (struct dns_rrs *)end; - unsigned short *count; - unsigned short *start; + struct dns_rrs *rrs; + struct dns_rrs *rrs_next; + struct dns_head *head = &packet->head; + unsigned char *end = packet->data + packet->len; + rrs = (struct dns_rrs *)end; + unsigned short *count; + unsigned short *start; - if (packet->len + len > packet->size - sizeof(*packet)) { - return -1; - } + if (packet->len + len > packet->size - sizeof(*packet)) { + return -1; + } - switch (type) { - case DNS_RRS_QD: - count = &head->qdcount; - start = &packet->questions; - break; - case DNS_RRS_AN: - count = &head->ancount; - start = &packet->answers; - break; - case DNS_RRS_NS: - count = &head->nscount; - start = &packet->nameservers; - break; - case DNS_RRS_NR: - count = &head->nrcount; - start = &packet->additional; - break; - default: - return -1; - break; - } + switch (type) { + case DNS_RRS_QD: + count = &head->qdcount; + start = &packet->questions; + break; + case DNS_RRS_AN: + count = &head->ancount; + start = &packet->answers; + break; + case DNS_RRS_NS: + count = &head->nscount; + start = &packet->nameservers; + break; + case DNS_RRS_NR: + count = &head->nrcount; + start = &packet->additional; + break; + default: + return -1; + break; + } - if (*start != DNS_RR_END) { - rrs_next = (struct dns_rrs *)(packet->data + *start); - while (rrs_next->next != DNS_RR_END) { - rrs_next = (struct dns_rrs *)(packet->data + rrs_next->next); - } + if (*start != DNS_RR_END) { + rrs_next = (struct dns_rrs *)(packet->data + *start); + while (rrs_next->next != DNS_RR_END) { + rrs_next = (struct dns_rrs *)(packet->data + rrs_next->next); + } rrs_next->next = packet->len; - } else { + } else { *start = packet->len; - } + } - rrs->next = DNS_RR_END;//*start; - *count += 1; - rrs->len = len; - rrs->type = rrtype; - //*start = packet->len; - packet->len += len + sizeof(*rrs); - return 0; + rrs->next = DNS_RR_END; //*start; + *count += 1; + rrs->len = len; + rrs->type = rrtype; + packet->len += len + sizeof(*rrs); + return 0; } static inline int _dns_data_left_len(struct dns_data_context *data_context) { - return data_context->maxsize - (data_context->ptr - data_context->data); + return data_context->maxsize - (data_context->ptr - data_context->data); } int _dns_add_qr_head(struct dns_data_context *data_context, char *domain, int qtype, int qclass) { - while (1) { - if (_dns_data_left_len(data_context) < 1) { - return -1; - } - *data_context->ptr = *domain; - if (*domain == '\0') { - data_context->ptr++; - break; - } - data_context->ptr++; - domain++; - } + while (1) { + if (_dns_data_left_len(data_context) < 1) { + return -1; + } + *data_context->ptr = *domain; + if (*domain == '\0') { + data_context->ptr++; + break; + } + data_context->ptr++; + domain++; + } - if (_dns_data_left_len(data_context) < 4) { - return -1; - } + if (_dns_data_left_len(data_context) < 4) { + return -1; + } - *((unsigned short *)(data_context->ptr)) = qtype; - data_context->ptr += 2; + *((unsigned short *)(data_context->ptr)) = qtype; + data_context->ptr += 2; - *((unsigned short *)(data_context->ptr)) = qclass; - data_context->ptr += 2; + *((unsigned short *)(data_context->ptr)) = qclass; + data_context->ptr += 2; - return 0; + return 0; } int _dns_get_qr_head(struct dns_data_context *data_context, char *domain, int maxsize, int *qtype, int *qclass) { - int i; + int i; - for (i = 0; i < maxsize; i++) { - if (_dns_data_left_len(data_context) < 1) { - return -1; - } - *domain = *data_context->ptr; - if (*data_context->ptr == '\0') { - domain++; - data_context->ptr++; - i++; - break; - } - *domain = *data_context->ptr; - domain++; - data_context->ptr++; - } + for (i = 0; i < maxsize; i++) { + if (_dns_data_left_len(data_context) < 1) { + return -1; + } + *domain = *data_context->ptr; + if (*data_context->ptr == '\0') { + domain++; + data_context->ptr++; + i++; + break; + } + *domain = *data_context->ptr; + domain++; + data_context->ptr++; + } - if (_dns_data_left_len(data_context) < 4) { - return -1; - } + if (_dns_data_left_len(data_context) < 4) { + return -1; + } - *qtype = *((unsigned short *)(data_context->ptr)); - data_context->ptr += 2; + *qtype = *((unsigned short *)(data_context->ptr)); + data_context->ptr += 2; - *qclass = *((unsigned short *)(data_context->ptr)); - data_context->ptr += 2; + *qclass = *((unsigned short *)(data_context->ptr)); + data_context->ptr += 2; - return 0; + return 0; } int _dns_add_rr_head(struct dns_data_context *data_context, char *domain, int qtype, int qclass, int ttl, int rr_len) { - int len = 0; + int len = 0; - len = _dns_add_qr_head(data_context, domain, qtype, qclass); - if (len < 0) { - return -1; - } + len = _dns_add_qr_head(data_context, domain, qtype, qclass); + if (len < 0) { + return -1; + } - if (_dns_data_left_len(data_context) < 6) { - return -1; - } + if (_dns_data_left_len(data_context) < 6) { + return -1; + } - *((unsigned int *)(data_context->ptr)) = ttl; - data_context->ptr += 4; + *((unsigned int *)(data_context->ptr)) = ttl; + data_context->ptr += 4; - *((unsigned short *)(data_context->ptr)) = rr_len; - data_context->ptr += 2; + *((unsigned short *)(data_context->ptr)) = rr_len; + data_context->ptr += 2; - return 0; + return 0; } int _dns_get_rr_head(struct dns_data_context *data_context, char *domain, int maxsize, int *qtype, int *qclass, int *ttl, int *rr_len) { - int len = 0; + int len = 0; - len = _dns_get_qr_head(data_context, domain, maxsize, qtype, qclass); + len = _dns_get_qr_head(data_context, domain, maxsize, qtype, qclass); - if (_dns_data_left_len(data_context) < 6) { - return -1; - } + if (_dns_data_left_len(data_context) < 6) { + return -1; + } - *ttl = *((unsigned int *)(data_context->ptr)); - data_context->ptr += 4; + *ttl = *((unsigned int *)(data_context->ptr)); + data_context->ptr += 4; - *rr_len = *((unsigned short *)(data_context->ptr)); - data_context->ptr += 2; + *rr_len = *((unsigned short *)(data_context->ptr)); + data_context->ptr += 2; - return len; + return len; } -int dns_add_CNAME(struct dns_packet *packet, char *domain, int ttl, char *cname) +int dns_add_CNAME(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, char *cname) { - int maxlen = 0; - int len = 0; - struct dns_data_context data_context; - int rr_len = 0; + int maxlen = 0; + int len = 0; + struct dns_data_context data_context; + int rr_len = 0; - rr_len = strnlen(cname, maxlen - 1) + 1; - unsigned char *data = _dns_add_rrs_start(packet, &maxlen); - if (data == NULL) { - return -1; - } + rr_len = strnlen(cname, maxlen - 1) + 1; + unsigned char *data = _dns_add_rrs_start(packet, &maxlen); + if (data == NULL) { + return -1; + } - if (rr_len >= maxlen) { - return -1; - } + if (rr_len >= maxlen) { + return -1; + } - data_context.data = data; - data_context.ptr = data; - data_context.maxsize = maxlen; + data_context.data = data; + data_context.ptr = data; + data_context.maxsize = maxlen; - len = _dns_add_rr_head(&data_context, domain, DNS_T_CNAME, DNS_C_IN, ttl, rr_len); - if (len < 0) { - return -1; - } + len = _dns_add_rr_head(&data_context, domain, DNS_T_CNAME, DNS_C_IN, ttl, rr_len); + if (len < 0) { + return -1; + } - memcpy(data_context.ptr, cname, rr_len); - data_context.ptr += rr_len; - len = data_context.ptr - data_context.data; + memcpy(data_context.ptr, cname, rr_len); + data_context.ptr += rr_len; + len = data_context.ptr - data_context.data; - return dns_rr_add_end(packet, DNS_RRS_AN, DNS_T_CNAME, len); + return dns_rr_add_end(packet, type, DNS_T_CNAME, len); } int dns_get_CNAME(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size) { - int qtype = 0; - int qclass = 0; - int rr_len = 0; - int ret = 0; - struct dns_data_context data_context; + int qtype = 0; + int qclass = 0; + int rr_len = 0; + int ret = 0; + struct dns_data_context data_context; - unsigned char *data = rrs->data; + unsigned char *data = rrs->data; - if (rrs->type != DNS_T_CNAME) { - return -1; - } + if (rrs->type != DNS_T_CNAME) { + return -1; + } - data_context.data = data; - data_context.ptr = data; - data_context.maxsize = rrs->len; + data_context.data = data; + data_context.ptr = data; + data_context.maxsize = rrs->len; - ret = _dns_get_rr_head(&data_context, domain, maxsize, &qtype, &qclass, ttl, &rr_len); - if (ret < 0) { - return -1; - } + ret = _dns_get_rr_head(&data_context, domain, maxsize, &qtype, &qclass, ttl, &rr_len); + if (ret < 0) { + return -1; + } - if (qtype != DNS_T_CNAME || rr_len > cname_size) { - return -1; - } + if (qtype != DNS_T_CNAME || rr_len > cname_size) { + return -1; + } - memcpy(cname, data_context.ptr, rr_len); + memcpy(cname, data_context.ptr, rr_len); - return 0; + return 0; } -int dns_add_A(struct dns_packet *packet, char *domain, int ttl, unsigned char addr[4]) +int dns_add_A(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, unsigned char addr[4]) { - int maxlen = 0; - int len = 0; - struct dns_data_context data_context; + int maxlen = 0; + int len = 0; + struct dns_data_context data_context; - unsigned char *data = _dns_add_rrs_start(packet, &maxlen); - if (data == NULL) { - return -1; - } + unsigned char *data = _dns_add_rrs_start(packet, &maxlen); + if (data == NULL) { + return -1; + } - data_context.data = data; - data_context.ptr = data; - data_context.maxsize = maxlen; + data_context.data = data; + data_context.ptr = data; + data_context.maxsize = maxlen; - len = _dns_add_rr_head(&data_context, domain, DNS_T_A, DNS_C_IN, ttl, DNS_RR_A_LEN); - if (len < 0) { - return -1; - } + len = _dns_add_rr_head(&data_context, domain, DNS_T_A, DNS_C_IN, ttl, DNS_RR_A_LEN); + if (len < 0) { + return -1; + } - memcpy(data_context.ptr, addr, DNS_RR_A_LEN); - data_context.ptr += DNS_RR_A_LEN; - len = data_context.ptr - data_context.data; + memcpy(data_context.ptr, addr, DNS_RR_A_LEN); + data_context.ptr += DNS_RR_A_LEN; + len = data_context.ptr - data_context.data; - return dns_rr_add_end(packet, DNS_RRS_AN, DNS_T_A, len); + return dns_rr_add_end(packet, type, DNS_T_A, len); +} + +int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, char *cname) +{ + return dns_add_CNAME(packet, type, domain, ttl, cname); +} + +int dns_get_PTR(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size) +{ + return dns_get_CNAME(rrs, domain, maxsize, ttl, cname, cname_size); } int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[4]) { - int qtype = 0; - int qclass = 0; - int rr_len = 0; - int ret = 0; - struct dns_data_context data_context; + int qtype = 0; + int qclass = 0; + int rr_len = 0; + int ret = 0; + struct dns_data_context data_context; - unsigned char *data = rrs->data; + unsigned char *data = rrs->data; - if (rrs->type != DNS_T_A) { - return -1; - } + if (rrs->type != DNS_T_A) { + return -1; + } - data_context.data = data; - data_context.ptr = data; - data_context.maxsize = rrs->len; + data_context.data = data; + data_context.ptr = data; + data_context.maxsize = rrs->len; - ret = _dns_get_rr_head(&data_context, domain, maxsize, &qtype, &qclass, ttl, &rr_len); - if (ret < 0) { - return -1; - } + ret = _dns_get_rr_head(&data_context, domain, maxsize, &qtype, &qclass, ttl, &rr_len); + if (ret < 0) { + return -1; + } - if (qtype != DNS_T_A || rr_len != DNS_RR_A_LEN) { - return -1; - } + if (qtype != DNS_T_A || rr_len != DNS_RR_A_LEN) { + return -1; + } - memcpy(addr, data_context.ptr, DNS_RR_A_LEN); + memcpy(addr, data_context.ptr, DNS_RR_A_LEN); - return 0; + return 0; } -int dns_add_AAAA(struct dns_packet *packet, char *domain, int ttl, unsigned char addr[16]) +int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, unsigned char addr[16]) { - int maxlen = 0; - int len = 0; - struct dns_data_context data_context; + int maxlen = 0; + int len = 0; + struct dns_data_context data_context; - unsigned char *data = _dns_add_rrs_start(packet, &maxlen); - if (data == NULL) { - return -1; - } + unsigned char *data = _dns_add_rrs_start(packet, &maxlen); + if (data == NULL) { + return -1; + } - data_context.data = data; - data_context.ptr = data; - data_context.maxsize = maxlen; + data_context.data = data; + data_context.ptr = data; + data_context.maxsize = maxlen; - len = _dns_add_rr_head(&data_context, domain, DNS_T_AAAA, DNS_C_IN, ttl, DNS_RR_AAAA_LEN); - if (len < 0) { - return -1; - } + len = _dns_add_rr_head(&data_context, domain, DNS_T_AAAA, DNS_C_IN, ttl, DNS_RR_AAAA_LEN); + if (len < 0) { + return -1; + } - memcpy(data_context.ptr, addr, DNS_RR_AAAA_LEN); - data_context.ptr += DNS_RR_AAAA_LEN; - len = data_context.ptr - data_context.data; + memcpy(data_context.ptr, addr, DNS_RR_AAAA_LEN); + data_context.ptr += DNS_RR_AAAA_LEN; + len = data_context.ptr - data_context.data; - return dns_rr_add_end(packet, DNS_RRS_AN, DNS_T_AAAA, len); + return dns_rr_add_end(packet, type, DNS_T_AAAA, len); } int dns_get_AAAA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[16]) { - int qtype = 0; - int qclass = 0; - int rr_len = 0; - int ret = 0; - struct dns_data_context data_context; + int qtype = 0; + int qclass = 0; + int rr_len = 0; + int ret = 0; + struct dns_data_context data_context; - if (rrs->type != DNS_T_AAAA) { - return -1; - } + if (rrs->type != DNS_T_AAAA) { + return -1; + } - unsigned char *data = rrs->data; + unsigned char *data = rrs->data; - if (rrs->type != DNS_T_AAAA) { - return -1; - } + if (rrs->type != DNS_T_AAAA) { + return -1; + } - data_context.data = data; - data_context.ptr = data; - data_context.maxsize = rrs->len; + data_context.data = data; + data_context.ptr = data; + data_context.maxsize = rrs->len; - ret = _dns_get_rr_head(&data_context, domain, maxsize, &qtype, &qclass, ttl, &rr_len); - if (ret < 0) { - return -1; - } + ret = _dns_get_rr_head(&data_context, domain, maxsize, &qtype, &qclass, ttl, &rr_len); + if (ret < 0) { + return -1; + } - if (qtype != DNS_T_AAAA || rr_len != DNS_RR_AAAA_LEN) { - return -1; - } + if (qtype != DNS_T_AAAA || rr_len != DNS_RR_AAAA_LEN) { + return -1; + } - memcpy(addr, data_context.ptr, DNS_RR_AAAA_LEN); + memcpy(addr, data_context.ptr, DNS_RR_AAAA_LEN); - return 0; + return 0; } /* @@ -461,655 +496,792 @@ int dns_get_AAAA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsig */ int dns_add_domain(struct dns_packet *packet, char *domain, int qtype, int qclass) { - int len = 0; - int maxlen = 0; - unsigned char *data = _dns_add_rrs_start(packet, &maxlen); - struct dns_data_context data_context; + int len = 0; + int maxlen = 0; + unsigned char *data = _dns_add_rrs_start(packet, &maxlen); + struct dns_data_context data_context; - if (data == NULL) { - return -1; - } + if (data == NULL) { + return -1; + } - data_context.data = data; - data_context.ptr = data; - data_context.maxsize = maxlen; + data_context.data = data; + data_context.ptr = data; + data_context.maxsize = maxlen; - len = _dns_add_qr_head(&data_context, domain, qtype, qclass); - if (len < 0) { - return -1; - } + len = _dns_add_qr_head(&data_context, domain, qtype, qclass); + if (len < 0) { + return -1; + } - len = data_context.ptr - data_context.data; + len = data_context.ptr - data_context.data; - return dns_rr_add_end(packet, DNS_RRS_QD, DNS_T_CNAME, len); + return dns_rr_add_end(packet, DNS_RRS_QD, DNS_T_CNAME, len); } int dns_get_domain(struct dns_rrs *rrs, char *domain, int maxsize, int *qtype, int *qclass) { - struct dns_data_context data_context; - unsigned char *data = rrs->data; + struct dns_data_context data_context; + unsigned char *data = rrs->data; - if (rrs->type != DNS_T_CNAME) { - return -1; - } + if (rrs->type != DNS_T_CNAME) { + return -1; + } - data_context.data = data; - data_context.ptr = data; - data_context.maxsize = rrs->len; + data_context.data = data; + data_context.ptr = data; + data_context.maxsize = rrs->len; - return _dns_get_qr_head(&data_context, domain, maxsize, qtype, qclass); + return _dns_get_qr_head(&data_context, domain, maxsize, qtype, qclass); } static inline int _dns_left_len(struct dns_context *context) { - return context->maxsize - (context->ptr - context->data); + return context->maxsize - (context->ptr - context->data); } int _dns_decode_head(struct dns_context *context) { - unsigned int fields; - int len = 12; - struct dns_head *head = &context->packet->head; + unsigned int fields; + int len = 12; + struct dns_head *head = &context->packet->head; - if (_dns_left_len(context) < len) { - return -1; - } + if (_dns_left_len(context) < len) { + return -1; + } - head->id = dns_read_short(&context->ptr); - fields = dns_read_short(&context->ptr); - head->qr = (fields & QR_MASK) >> 15; - head->opcode = (fields & OPCODE_MASK) >> 11; - head->aa = (fields & AA_MASK) >> 10; - head->tc = (fields & TC_MASK) >> 9; - head->rd = (fields & RD_MASK) >> 8; - head->ra = (fields & RA_MASK) >> 7; - head->rcode = (fields & RCODE_MASK) >> 0; - head->qdcount = dns_read_short(&context->ptr); - head->ancount = dns_read_short(&context->ptr); - head->nscount = dns_read_short(&context->ptr); - head->nrcount = dns_read_short(&context->ptr); + head->id = dns_read_short(&context->ptr); + fields = dns_read_short(&context->ptr); + head->qr = (fields & QR_MASK) >> 15; + head->opcode = (fields & OPCODE_MASK) >> 11; + head->aa = (fields & AA_MASK) >> 10; + head->tc = (fields & TC_MASK) >> 9; + head->rd = (fields & RD_MASK) >> 8; + head->ra = (fields & RA_MASK) >> 7; + head->rcode = (fields & RCODE_MASK) >> 0; + head->qdcount = dns_read_short(&context->ptr); + head->ancount = dns_read_short(&context->ptr); + head->nscount = dns_read_short(&context->ptr); + head->nrcount = dns_read_short(&context->ptr); - return 0; + return 0; } int _dns_encode_head(struct dns_context *context) { - int len = 12; - struct dns_head *head = &context->packet->head; + int len = 12; + struct dns_head *head = &context->packet->head; - if (_dns_left_len(context) < len) { - return -1; - } + if (_dns_left_len(context) < len) { + return -1; + } - dns_write_short(&context->ptr, head->id); + dns_write_short(&context->ptr, head->id); - int fields = 0; - fields |= (head->qr << 15) & QR_MASK; - fields |= (head->rcode << 0) & RCODE_MASK; - dns_write_short(&context->ptr, fields); + int fields = 0; + fields |= (head->qr << 15) & QR_MASK; + fields |= (head->rcode << 0) & RCODE_MASK; + dns_write_short(&context->ptr, fields); - dns_write_short(&context->ptr, head->qdcount); - dns_write_short(&context->ptr, head->ancount); - dns_write_short(&context->ptr, head->nscount); - dns_write_short(&context->ptr, head->nrcount); - return len; + dns_write_short(&context->ptr, head->qdcount); + dns_write_short(&context->ptr, head->ancount); + dns_write_short(&context->ptr, head->nscount); + dns_write_short(&context->ptr, head->nrcount); + return len; } int _dns_decode_domain(struct dns_context *context, char *output, int size) { - int output_len = 0; - int copy_len = 0; - int len = *(context->ptr); - unsigned char *ptr = context->ptr; - int is_compressed = 0; + int output_len = 0; + int copy_len = 0; + int len = *(context->ptr); + unsigned char *ptr = context->ptr; + int is_compressed = 0; - while (1) { - len = *ptr; - if (len == 0) { - *output = 0; - ptr++; - break; - } + while (1) { + len = *ptr; + if (len == 0) { + *(output - 1) = 0; + ptr++; + break; + } - if (len >= 0xC0) { - len = dns_read_short(&ptr) & 0x3FFF; - if (is_compressed == 0) { - context->ptr = ptr; - } - ptr = context->data + len; - if (context->maxsize - (ptr - context->data) < 1) { - return -1; - } - is_compressed = 1; - continue; - } + if (len >= 0xC0) { + len = dns_read_short(&ptr) & 0x3FFF; + if (is_compressed == 0) { + context->ptr = ptr; + } + ptr = context->data + len; + if (context->maxsize - (ptr - context->data) < 1) { + return -1; + } + is_compressed = 1; + continue; + } - if (context->maxsize - (ptr - context->data) < 1) { - return -1; - } + if (context->maxsize - (ptr - context->data) < 1) { + return -1; + } - ptr++; - if (output_len < size - 1) { - copy_len = (len < size - output_len) ? len : size - 1 - output_len; - if (context->maxsize - (ptr - context->data) < 1) { - return -1; - } - memcpy(output, ptr, copy_len); - } + ptr++; + if (output_len < size - 1) { + copy_len = (len < size - output_len) ? len : size - 1 - output_len; + if (context->maxsize - (ptr - context->data) < 1) { + return -1; + } + memcpy(output, ptr, copy_len); + } - ptr += len; - output += len; - output_len += len; - *output = '.'; - output++; - } + ptr += len; + output += len; + output_len += len; + *output = '.'; + output++; + } - if (is_compressed == 0) { - context->ptr = ptr; - } + if (is_compressed == 0) { + context->ptr = ptr; + } - return 0; + return 0; } int _dns_encode_domain(struct dns_context *context, char *domain) { - int num = 0; - unsigned char *ptr_num = context->ptr++; + int num = 0; + unsigned char *ptr_num = context->ptr++; - while (_dns_left_len(context) > 1 && *domain != 0) { - if (*domain == '.') { - *ptr_num = num; - num = 0; - ptr_num = context->ptr; - domain++; - context->ptr++; - continue; - } - *context->ptr = *domain; - num++; - context->ptr++; - domain++; - } + while (_dns_left_len(context) > 1 && *domain != 0) { + if (*domain == '.') { + *ptr_num = num; + num = 0; + ptr_num = context->ptr; + domain++; + context->ptr++; + continue; + } + *context->ptr = *domain; + num++; + context->ptr++; + domain++; + } - *ptr_num = num; - *(context->ptr) = 0; - context->ptr++; - return 0; + *ptr_num = num; + *(context->ptr) = 0; + context->ptr++; + return 0; } int _dns_decode_qr_head(struct dns_context *context, char *domain, int domain_size, int *qtype, int *qclass) { - int ret = 0; + int ret = 0; - ret = _dns_decode_domain(context, domain, domain_size); - if (ret < 0) { - return -1; - } + ret = _dns_decode_domain(context, domain, domain_size); + if (ret < 0) { + return -1; + } - if (_dns_left_len(context) < 4) { - return -1; - } + if (_dns_left_len(context) < 4) { + return -1; + } - *qtype = dns_read_short(&context->ptr); - *qclass = dns_read_short(&context->ptr); + *qtype = dns_read_short(&context->ptr); + *qclass = dns_read_short(&context->ptr); - return 0; + return 0; } int _dns_encode_qr_head(struct dns_context *context, char *domain, int qtype, int qclass) { - int ret = 0; - ret = _dns_encode_domain(context, domain); - if (ret < 0) { - return -1; - } + int ret = 0; + ret = _dns_encode_domain(context, domain); + if (ret < 0) { + return -1; + } - if (_dns_left_len(context) < 4) { - return -1; - } + if (_dns_left_len(context) < 4) { + return -1; + } - dns_write_short(&context->ptr, qtype); - dns_write_short(&context->ptr, qclass); + dns_write_short(&context->ptr, qtype); + dns_write_short(&context->ptr, qclass); - return 0; + return 0; } int _dns_decode_rr_head(struct dns_context *context, char *domain, int domain_size, int *qtype, int *qclass, int *ttl, int *rr_len) { - int len = 0; + int len = 0; - len = _dns_decode_qr_head(context, domain, domain_size, qtype, qclass); - if (len < 0) { - return -1; - } + len = _dns_decode_qr_head(context, domain, domain_size, qtype, qclass); + if (len < 0) { + return -1; + } - if (_dns_left_len(context) < 6) { - return -1; - } + if (_dns_left_len(context) < 6) { + return -1; + } - *ttl = dns_read_int(&context->ptr); - *rr_len = dns_read_short(&context->ptr); + *ttl = dns_read_int(&context->ptr); + *rr_len = dns_read_short(&context->ptr); - return 0; + return 0; } int _dns_encode_rr_head(struct dns_context *context, char *domain, int qtype, int qclass, int ttl, int rr_len) { - int ret = 0; - ret = _dns_encode_qr_head(context, domain, qtype, qclass); - if (ret < 0) { - return -1; - } + int ret = 0; + ret = _dns_encode_qr_head(context, domain, qtype, qclass); + if (ret < 0) { + return -1; + } - if (_dns_left_len(context) < 6) { - return -1; - } + if (_dns_left_len(context) < 6) { + return -1; + } - dns_write_int(&context->ptr, ttl); - dns_write_short(&context->ptr, rr_len); + dns_write_int(&context->ptr, ttl); + dns_write_short(&context->ptr, rr_len); - return 0; + return 0; } int _dns_decode_CNAME(struct dns_context *context, char *cname, int cname_size) { - int ret = 0; - ret = _dns_decode_domain(context, cname, cname_size); - if (ret < 0) { - return -1; - } + int ret = 0; + ret = _dns_decode_domain(context, cname, cname_size); + if (ret < 0) { + return -1; + } - return 0; + return 0; } int _dns_encode_CNAME(struct dns_context *context, struct dns_rrs *rrs) { - int ret; - int qtype = 0; - int qclass = 0; - int ttl = 0; - char domain[DNS_MAX_CNAME_LEN]; - int rr_len; - struct dns_data_context data_context; + int ret; + int qtype = 0; + int qclass = 0; + int ttl = 0; + char domain[DNS_MAX_CNAME_LEN]; + int rr_len; + struct dns_data_context data_context; - data_context.data = rrs->data; - data_context.ptr = rrs->data; - data_context.maxsize = rrs->len; + data_context.data = rrs->data; + data_context.ptr = rrs->data; + data_context.maxsize = rrs->len; - ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len); - if (ret < 0) { - return -1; - } + ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len); + if (ret < 0) { + return -1; + } - if (rr_len > rrs->len) { - return -1; - } + if (rr_len > rrs->len) { + return -1; + } - ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, rr_len); - if (ret < 0) { - return -1; - } + ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, rr_len); + if (ret < 0) { + return -1; + } - ret = _dns_encode_domain(context, (char *)rrs->data); - if (ret < 0) { - return -1; - } + ret = _dns_encode_domain(context, (char *)rrs->data); + if (ret < 0) { + return -1; + } - return 0; + return 0; } int _dns_decode_A(struct dns_context *context, unsigned char addr[4]) { - if (_dns_left_len(context) < DNS_RR_A_LEN) { - return -1; - } + if (_dns_left_len(context) < DNS_RR_A_LEN) { + return -1; + } - memcpy(addr, context->ptr, DNS_RR_A_LEN); - context->ptr += DNS_RR_A_LEN; - return 0; + memcpy(addr, context->ptr, DNS_RR_A_LEN); + context->ptr += DNS_RR_A_LEN; + return 0; } int _dns_encode_A(struct dns_context *context, struct dns_rrs *rrs) { - int ret; - int qtype = 0; - int qclass = 0; - int ttl = 0; - char domain[DNS_MAX_CNAME_LEN]; - int rr_len; - struct dns_data_context data_context; + int ret; + int qtype = 0; + int qclass = 0; + int ttl = 0; + char domain[DNS_MAX_CNAME_LEN]; + int rr_len; + struct dns_data_context data_context; - data_context.data = rrs->data; - data_context.ptr = rrs->data; - data_context.maxsize = rrs->len; + data_context.data = rrs->data; + data_context.ptr = rrs->data; + data_context.maxsize = rrs->len; - ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len); + ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len); + if (ret < 0) { + return -1; + } + + if (rr_len != DNS_RR_A_LEN) { + return -1; + } + + ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, DNS_RR_A_LEN); + if (ret < 0) { + return -1; + } + + if (_dns_left_len(context) < DNS_RR_A_LEN) { + return -1; + } + + memcpy(context->ptr, data_context.ptr, DNS_RR_A_LEN); + context->ptr += DNS_RR_A_LEN; + + return 0; +} + +int _dns_decode_PTR(struct dns_context *context, char *name, int name_size) +{ + int ret; + + ret = _dns_decode_domain(context, name, name_size); + return ret; +} + +int _dns_encode_PTR(struct dns_context *context, struct dns_rrs *rrs) +{ + int ret; + int qtype = 0; + int qclass = 0; + int ttl = 0; + char domain[DNS_MAX_CNAME_LEN]; + int rr_len; + struct dns_data_context data_context; + + data_context.data = rrs->data; + data_context.ptr = rrs->data; + data_context.maxsize = rrs->len; + + ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len); + if (ret < 0) { + return -1; + } + + if (rr_len >= data_context.maxsize) { + return -1; + } + + ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, rr_len); + if (ret < 0) { + return -1; + } + + if (_dns_left_len(context) < rr_len) { + return -1; + } + + ret = _dns_encode_domain(context, (char *)data_context.ptr); if (ret < 0) { - return -1; - } + return -1; + } - if (rr_len != DNS_RR_A_LEN) { - return -1; - } - - ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, DNS_RR_A_LEN); - if (ret < 0) { - return -1; - } - - if (_dns_left_len(context) < DNS_RR_A_LEN) { - return -1; - } - - memcpy(context->ptr, rrs->data, DNS_RR_A_LEN); - context->ptr += DNS_RR_A_LEN; - - return 0; + return 0; } int _dns_decode_AAAA(struct dns_context *context, unsigned char addr[DNS_RR_AAAA_LEN]) { - if (_dns_left_len(context) < DNS_RR_AAAA_LEN) { - return -1; - } + if (_dns_left_len(context) < DNS_RR_AAAA_LEN) { + return -1; + } - memcpy(addr, context->ptr, DNS_RR_AAAA_LEN); - context->ptr += DNS_RR_AAAA_LEN; - return 0; + memcpy(addr, context->ptr, DNS_RR_AAAA_LEN); + context->ptr += DNS_RR_AAAA_LEN; + return 0; } int _dns_encode_AAAA(struct dns_context *context, struct dns_rrs *rrs) { - int ret; - int qtype = 0; - int qclass = 0; - int ttl = 0; - char domain[DNS_MAX_CNAME_LEN]; - int rr_len; - struct dns_data_context data_context; + int ret; + int qtype = 0; + int qclass = 0; + int ttl = 0; + char domain[DNS_MAX_CNAME_LEN]; + int rr_len; + struct dns_data_context data_context; - data_context.data = rrs->data; - data_context.ptr = rrs->data; - data_context.maxsize = rrs->len; + data_context.data = rrs->data; + data_context.ptr = rrs->data; + data_context.maxsize = rrs->len; - ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len); - if (ret < 0) { - return -1; - } + ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len); + if (ret < 0) { + return -1; + } - if (rr_len != DNS_RR_AAAA_LEN) { - return -1; - } + if (rr_len != DNS_RR_AAAA_LEN) { + return -1; + } - ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, DNS_RR_AAAA_LEN); - if (ret < 0) { - return -1; - } + ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, DNS_RR_AAAA_LEN); + if (ret < 0) { + return -1; + } - if (_dns_left_len(context) < DNS_RR_AAAA_LEN) { - return -1; - } + if (_dns_left_len(context) < DNS_RR_AAAA_LEN) { + return -1; + } - memcpy(context->ptr, rrs->data, DNS_RR_AAAA_LEN); - context->ptr += DNS_RR_AAAA_LEN; + memcpy(context->ptr, context->ptr, DNS_RR_AAAA_LEN); + context->ptr += DNS_RR_AAAA_LEN; - return 0; + return 0; +} + +int _dns_decode_NS(struct dns_context *context, unsigned char addr[4]) +{ + if (_dns_left_len(context) < DNS_RR_A_LEN) { + return -1; + } + + memcpy(addr, context->ptr, DNS_RR_A_LEN); + context->ptr += DNS_RR_A_LEN; + return 0; +} + +int _dns_encode_NS(struct dns_context *context, struct dns_rrs *rrs) +{ + int ret; + int qtype = 0; + int qclass = 0; + int ttl = 0; + char domain[DNS_MAX_CNAME_LEN]; + int rr_len; + struct dns_data_context data_context; + + data_context.data = rrs->data; + data_context.ptr = rrs->data; + data_context.maxsize = rrs->len; + + ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len); + if (ret < 0) { + return -1; + } + + if (rr_len != DNS_RR_A_LEN) { + return -1; + } + + ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, DNS_RR_A_LEN); + if (ret < 0) { + return -1; + } + + if (_dns_left_len(context) < DNS_RR_A_LEN) { + return -1; + } + + memcpy(context->ptr, rrs->data, DNS_RR_A_LEN); + context->ptr += DNS_RR_A_LEN; + + return 0; } int _dns_decode_qd(struct dns_context *context) { - struct dns_packet *packet = context->packet; - int len; - int qtype = 0; - int qclass = 0; - char domain[DNS_MAX_CNAME_LEN]; + struct dns_packet *packet = context->packet; + int len; + int qtype = 0; + int qclass = 0; + char domain[DNS_MAX_CNAME_LEN]; - len = _dns_decode_qr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass); - if (len < 0) { - return -1; - } + len = _dns_decode_qr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass); + if (len < 0) { + return -1; + } - len = dns_add_domain(packet, domain, qtype, qclass); - if (len < 0) { - return -1; - } + len = dns_add_domain(packet, domain, qtype, qclass); + if (len < 0) { + return -1; + } - return 0; + return 0; } -int _dns_decode_an(struct dns_context *context) +int _dns_decode_an(struct dns_context *context, dns_rr_type type) { - int ret; - int qtype = 0; - int qclass = 0; - int ttl; - int rr_len = 0; - char domain[DNS_MAX_CNAME_LEN]; - struct dns_packet *packet = context->packet; + int ret; + int qtype = 0; + int qclass = 0; + int ttl; + int rr_len = 0; + char domain[DNS_MAX_CNAME_LEN]; + struct dns_packet *packet = context->packet; + unsigned char *start; - ret = _dns_decode_rr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len); - if (ret < 0) { - return -1; - } + ret = _dns_decode_rr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len); + if (ret < 0) { + return -1; + } + start = context->ptr; - switch (qtype) { - case DNS_T_CNAME: { - char cname[DNS_MAX_CNAME_LEN]; - ret = _dns_decode_CNAME(context, cname, DNS_MAX_CNAME_LEN); - if (ret < 0) { - return -1; - } + switch (qtype) { + case DNS_T_A: { + unsigned char addr[DNS_RR_A_LEN]; + ret = _dns_decode_A(context, addr); + if (ret < 0) { + return -1; + } - ret = dns_add_CNAME(packet, domain, ttl, cname); - if (ret < 0) { - return -1; - } - } break; - case DNS_T_A: { - unsigned char addr[DNS_RR_A_LEN]; - ret = _dns_decode_A(context, addr); - if (ret < 0) { - return -1; - } + ret = dns_add_A(packet, type, domain, ttl, addr); + if (ret < 0) { + return -1; + } + } break; + case DNS_T_CNAME: { + char cname[DNS_MAX_CNAME_LEN]; + ret = _dns_decode_CNAME(context, cname, DNS_MAX_CNAME_LEN); + if (ret < 0) { + return -1; + } - ret = dns_add_A(packet, domain, ttl, addr); - if (ret < 0) { - return -1; - } - } break; - case DNS_T_AAAA: { - unsigned char addr[DNS_RR_AAAA_LEN]; - ret = _dns_decode_AAAA(context, addr); - if (ret < 0) { - return -1; - } + ret = dns_add_CNAME(packet, type, domain, ttl, cname); + if (ret < 0) { + return -1; + } + } break; + case DNS_T_PTR: { + char name[DNS_MAX_CNAME_LEN]; + ret = _dns_decode_PTR(context, name, DNS_MAX_CNAME_LEN); + if (ret < 0) { + return -1; + } - ret = dns_add_AAAA(packet, domain, ttl, addr); - if (ret < 0) { - return -1; - } - } break; - default: - context->ptr += rr_len; - break; - } + ret = dns_add_PTR(packet, type, domain, ttl, name); + if (ret < 0) { + return -1; + } + } break; + case DNS_T_AAAA: { + unsigned char addr[DNS_RR_AAAA_LEN]; + ret = _dns_decode_AAAA(context, addr); + if (ret < 0) { + return -1; + } - return 0; + ret = dns_add_AAAA(packet, type, domain, ttl, addr); + if (ret < 0) { + return -1; + } + } break; + default: + context->ptr += rr_len; + break; + } + + if (context->ptr - start != rr_len) { + return -1; + } + + return 0; } int _dns_encode_qd(struct dns_context *context, struct dns_rrs *rrs) { - int ret; - int qtype = 0; - int qclass = 0; - char domain[DNS_MAX_CNAME_LEN]; - struct dns_data_context data_context; + int ret; + int qtype = 0; + int qclass = 0; + char domain[DNS_MAX_CNAME_LEN]; + struct dns_data_context data_context; - data_context.data = rrs->data; - data_context.ptr = rrs->data; - data_context.maxsize = rrs->len; + data_context.data = rrs->data; + data_context.ptr = rrs->data; + data_context.maxsize = rrs->len; - ret = _dns_get_qr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass); - if (ret < 0) { - return -1; - } + ret = _dns_get_qr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass); + if (ret < 0) { + return -1; + } - ret = _dns_encode_qr_head(context, domain, qtype, qclass); - if (ret < 0) { - return -1; - } + ret = _dns_encode_qr_head(context, domain, qtype, qclass); + if (ret < 0) { + return -1; + } - return 0; + return 0; } int _dns_encode_an(struct dns_context *context, struct dns_rrs *rrs) { - int ret; - switch (rrs->type) { - case DNS_T_A: { - ret = _dns_encode_A(context, rrs); - if (ret < 0) { - return -1; - } - } break; - case DNS_T_AAAA: - ret = _dns_encode_AAAA(context, rrs); - if (ret < 0) { - return -1; - } - break; - default: - break; - } + int ret; + switch (rrs->type) { + case DNS_T_A: { + ret = _dns_encode_A(context, rrs); + if (ret < 0) { + return -1; + } + } break; + case DNS_T_PTR: + ret = _dns_encode_PTR(context, rrs); + if (ret < 0) { + return -1; + } + break; + case DNS_T_AAAA: + ret = _dns_encode_AAAA(context, rrs); + if (ret < 0) { + return -1; + } + break; + default: + break; + } - return 0; + return 0; } int _dns_decode_body(struct dns_context *context) { - struct dns_packet *packet = context->packet; - struct dns_head *head = &packet->head; - int i = 0; - int ret = 0; + struct dns_packet *packet = context->packet; + struct dns_head *head = &packet->head; + int i = 0; + int ret = 0; - for (i = 0; i < head->qdcount; i++) { - ret = _dns_decode_qd(context); - if (ret < 0) { - return -1; - } - head->qdcount--; - } + for (i = 0; i < head->qdcount; i++) { + ret = _dns_decode_qd(context); + if (ret < 0) { + return -1; + } + head->qdcount--; + } - for (i = 0; i < head->ancount; i++) { - ret = _dns_decode_an(context); - if (ret < 0) { - return -1; - } - head->ancount--; - } + for (i = 0; i < head->ancount; i++) { + ret = _dns_decode_an(context, DNS_RRS_AN); + if (ret < 0) { + return -1; + } + head->ancount--; + } - return 0; + for (i = 0; i < head->nscount; i++) { + ret = _dns_decode_an(context, DNS_RRS_NS); + if (ret < 0) { + return -1; + } + head->nscount--; + } + + for (i = 0; i < head->nrcount; i++) { + ret = _dns_decode_an(context, DNS_RRS_NR); + if (ret < 0) { + return -1; + } + head->nrcount--; + } + + return 0; } int _dns_encode_body(struct dns_context *context) { - struct dns_packet *packet = context->packet; - struct dns_head *head = &packet->head; - int i = 0; - int len = 0; - struct dns_rrs *rrs; - int count; + struct dns_packet *packet = context->packet; + struct dns_head *head = &packet->head; + int i = 0; + int len = 0; + struct dns_rrs *rrs; + int count; - rrs = dns_get_rrs_start(packet, DNS_RRS_QD, &count); - head->qdcount = count; - for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { - len = _dns_encode_qd(context, rrs); - if (len < 0) { - return -1; - } - } + rrs = dns_get_rrs_start(packet, DNS_RRS_QD, &count); + head->qdcount = count; + for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { + len = _dns_encode_qd(context, rrs); + if (len < 0) { + return -1; + } + } - rrs = dns_get_rrs_start(packet, DNS_RRS_AN, &count); - head->ancount = count; - for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { - len = _dns_encode_an(context, rrs); - if (len < 0) { - return -1; - } - } + rrs = dns_get_rrs_start(packet, DNS_RRS_AN, &count); + head->ancount = count; + for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { + len = _dns_encode_an(context, rrs); + if (len < 0) { + return -1; + } + } - return 0; + return 0; } int dns_packet_init(struct dns_packet *packet, int size, struct dns_head *head) { - struct dns_head *init_head = &packet->head; - memset(packet, 0, size); - packet->size = size; - init_head->id = head->id; - init_head->qr = head->qr; - init_head->opcode = head->opcode; - init_head->aa = head->aa; - init_head->tc = 0; - init_head->rd = head->rd; - init_head->ra = head->ra; - init_head->rcode = head->rcode; - packet->questions = DNS_RR_END; - packet->answers = DNS_RR_END; - packet->nameservers = DNS_RR_END; - packet->additional = DNS_RR_END; + struct dns_head *init_head = &packet->head; + memset(packet, 0, size); + packet->size = size; + init_head->id = head->id; + init_head->qr = head->qr; + init_head->opcode = head->opcode; + init_head->aa = head->aa; + init_head->tc = 0; + init_head->rd = head->rd; + init_head->ra = head->ra; + init_head->rcode = head->rcode; + packet->questions = DNS_RR_END; + packet->answers = DNS_RR_END; + packet->nameservers = DNS_RR_END; + packet->additional = DNS_RR_END; - return 0; + return 0; } int dns_decode(struct dns_packet *packet, int maxsize, unsigned char *data, int size) { - struct dns_head *head = &packet->head; - struct dns_context context; - int ret = 0; + struct dns_head *head = &packet->head; + struct dns_context context; + int ret = 0; - memset(&context, 0, sizeof(context)); - memset(packet, 0, sizeof(*packet)); + memset(&context, 0, sizeof(context)); + memset(packet, 0, sizeof(*packet)); - context.data = data; - context.packet = packet; - context.ptr = data; - context.maxsize = size; + context.data = data; + context.packet = packet; + context.ptr = data; + context.maxsize = size; - dns_packet_init(packet, maxsize, head); - ret = _dns_decode_head(&context); - if (ret < 0) { - return -1; - } + dns_packet_init(packet, maxsize, head); + ret = _dns_decode_head(&context); + if (ret < 0) { + return -1; + } - ret = _dns_decode_body(&context); - if (ret < 0) { - return -1; - } + ret = _dns_decode_body(&context); + if (ret < 0) { + return -1; + } - return 0; + return 0; } int dns_encode(unsigned char *data, int size, struct dns_packet *packet) { - int ret = 0; - struct dns_context context; + int ret = 0; + struct dns_context context; - memset(&context, 0, sizeof(context)); - context.data = data; - context.packet = packet; - context.ptr = data; - context.maxsize = size; + memset(&context, 0, sizeof(context)); + context.data = data; + context.packet = packet; + context.ptr = data; + context.maxsize = size; - ret = _dns_encode_head(&context); - if (ret < 0) { - return -1; - } + ret = _dns_encode_head(&context); + if (ret < 0) { + return -1; + } - ret = _dns_encode_body(&context); - if (ret < 0) { - return -1; - } + ret = _dns_encode_body(&context); + if (ret < 0) { + return -1; + } - return context.ptr - context.data; + return context.ptr - context.data; } diff --git a/dns.h b/dns.h index 64662e3..2e27f01 100644 --- a/dns.h +++ b/dns.h @@ -6,23 +6,17 @@ #include #include -#define QR_MASK 0x8000 -#define OPCODE_MASK 0x7800 -#define AA_MASK 0x0400 -#define TC_MASK 0x0200 -#define RD_MASK 0x0100 -#define RA_MASK 0x8000 -#define RCODE_MASK 0x000F - #define DNS_RR_A_LEN 4 #define DNS_RR_AAAA_LEN 16 +#define DNS_MAX_CNAME_LEN 128 -#define DNS_RRS_QD 0 -#define DNS_RRS_AN 1 -#define DNS_RRS_NS 2 -#define DNS_RRS_NR 3 - -#define DNS_RR_END (0XFFFF) +typedef enum dns_rr_type { + DNS_RRS_QD = 0, + DNS_RRS_AN = 1, + DNS_RRS_NS = 2, + DNS_RRS_NR = 3, + DNS_RRS_END = 4, +} dns_rr_type; typedef enum dns_class { DNS_C_IN = 1, DNS_C_ANY = 255 } dns_class_t; @@ -100,8 +94,7 @@ struct dns_packet { unsigned char data[0]; }; -struct dns_data_context -{ +struct dns_data_context { unsigned char *data; unsigned char *ptr; unsigned int maxsize; @@ -116,23 +109,33 @@ struct dns_context { struct dns_rrs *dns_get_rrs_next(struct dns_packet *packet, struct dns_rrs *rrs); -struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, int type, int *count); +struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, int *count); -int dns_add_CNAME(struct dns_packet *packet, char *domain, int ttl, char *cname); - -int dns_get_CNAME(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size); - -int dns_add_A(struct dns_packet *packet, char *domain, int ttl, unsigned char addr[4]); - -int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[4]); - -int dns_add_AAAA(struct dns_packet *packet, char *domain, int ttl, unsigned char addr[16]); - -int dns_get_AAAA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[16]); +/* + * Question + */ +int dns_add_domain(struct dns_packet *packet, char *domain, int qtype, int qclass); int dns_get_domain(struct dns_rrs *rrs, char *domain, int maxsize, int *qtype, int *qclass); -int dns_add_domain(struct dns_packet *packet, char *domain, int qtype, int qclass); +/* + * Answers + */ +int dns_add_CNAME(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, char *cname); + +int dns_get_CNAME(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size); + +int dns_add_A(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, unsigned char addr[4]); + +int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[4]); + +int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, char *cname); + +int dns_get_PTR(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size); + +int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, unsigned char addr[16]); + +int dns_get_AAAA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[16]); int dns_decode(struct dns_packet *packet, int maxsize, unsigned char *data, int size); diff --git a/dns_client.c b/dns_client.c index 40f206f..9560398 100644 --- a/dns_client.c +++ b/dns_client.c @@ -1,3 +1,21 @@ +/************************************************************************* +* +* Copyright (C) 2018 Ruilin Peng (Nick) . +* + * smartdns is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * smartdns is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "dns_client.h" #include "atomic.h" #include "fast_ping.h" diff --git a/dns_server.c b/dns_server.c index 8942b88..cc71f3c 100644 --- a/dns_server.c +++ b/dns_server.c @@ -1,3 +1,21 @@ +/************************************************************************* + * + * Copyright (C) 2018 Ruilin Peng (Nick) . + * + * smartdns is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * smartdns is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "dns_server.h" #include "dns.h" #include "hashtable.h" @@ -46,7 +64,6 @@ static void tv_sub(struct timeval *out, struct timeval *in) void _dns_server_period_run() { - unsigned char packet_data[DNS_INPACKET_SIZE]; unsigned char data[DNS_INPACKET_SIZE]; @@ -56,6 +73,7 @@ void _dns_server_period_run() memset(&head, 0, sizeof(head)); head.rcode = 0; head.qr = 0; + head.rd = 1; head.ra = 0; head.id = 1; @@ -82,7 +100,12 @@ static int _dns_server_process(struct timeval *now) int len; unsigned char inpacket[DNS_INPACKET_SIZE]; unsigned char rsppacket[DNS_INPACKET_SIZE]; + unsigned char aswpacket[DNS_INPACKET_SIZE]; + unsigned char outpacket[DNS_INPACKET_SIZE]; + struct dns_packet *packet = (struct dns_packet *)rsppacket; + struct dns_packet *anspacket = (struct dns_packet *)aswpacket; + struct sockaddr_storage from; socklen_t from_len = sizeof(from); int data_len; @@ -105,41 +128,81 @@ static int _dns_server_process(struct timeval *now) struct dns_rrs *rrs; char name[128]; int i = 0; + int j = 0; int ttl; int qtype; int qclass; - printf("qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d\n", - packet->head.qdcount, packet->head.ancount, packet->head.nscount, - packet->head.nrcount, data_len); - + struct dns_head head; + memset(&head, 0, sizeof(head)); + head.rcode = 0; + head.qr = 1; + head.rd = 1; + head.ra = 0; + head.id = packet->head.id; + int n = 0; + + dns_packet_init(anspacket, DNS_INPACKET_SIZE, &head); + + printf("qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d\n", packet->head.qdcount, packet->head.ancount, packet->head.nscount, + packet->head.nrcount, data_len); + rrs = dns_get_rrs_start(packet, DNS_RRS_QD, &count); for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { - switch (rrs->type) { - case DNS_T_CNAME: { - dns_get_domain(rrs, name, 128, &qtype, &qclass); - printf("domain: %s qtype: %d qclass: %d\n", name, qtype, qclass); + dns_get_domain(rrs, name, 128, &qtype, &qclass); + printf("domain: %s qtype: %d qclass: %d\n", name, qtype, qclass); + switch (qtype) { + case DNS_T_A: { + unsigned char addr[4]; + addr[0] = 192; + addr[1] = 188; + addr[2] = 9; + addr[3] = 8; + dns_add_A(anspacket, DNS_RRS_AN, name, 60 * 60, addr); + n++; + } break; + case DNS_T_AAAA: { + unsigned char addr[16]; + addr[0] = 192; + addr[1] = 188; + addr[2] = 9; + addr[3] = 8; + dns_add_AAAA(anspacket, DNS_RRS_AN, name, 60 * 60, addr); + n++; + } break; + case DNS_T_PTR:{ + dns_add_PTR(anspacket, DNS_RRS_AN, name, 60 * 60, "raspberrypi.larva-family.com"); + n++; } break; default: break; } } - rrs = dns_get_rrs_start(packet, DNS_RRS_AN, &count); - for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { - switch (rrs->type) { - case DNS_T_A: { - unsigned char addr[4]; - dns_get_A(rrs, name, 128, &ttl, addr); - printf("%s %d : %d.%d.%d.%d\n", name, ttl, addr[0], addr[1], addr[2], addr[3]); - } break; - case DNS_T_CNAME: { - char cname[128]; - dns_get_CNAME(rrs, name, 128, &ttl, cname, 128); - printf("%s %d : %s\n", name, ttl, cname); - } break; - default: - break; + if (n > 0 && packet->head.qr == 0) { + dns_add_CNAME(anspacket, DNS_RRS_AN, name, 60 * 60, name); + len = dns_encode(outpacket, DNS_INPACKET_SIZE, anspacket); + sendto(server.fd, outpacket, len, 0, (struct sockaddr *)&from, from_len); + } + + for (j = 1; j < DNS_RRS_END; j++) { + rrs = dns_get_rrs_start(packet, j, &count); + for (i = 0; i < count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { + switch (rrs->type) { + case DNS_T_A: { + unsigned char addr[4]; + dns_get_A(rrs, name, 128, &ttl, addr); + printf("%s %d : %d.%d.%d.%d\n", name, ttl, addr[0], addr[1], addr[2], addr[3]); + } break; + case DNS_T_NS: + case DNS_T_CNAME: { + char cname[128]; + dns_get_CNAME(rrs, name, 128, &ttl, cname, 128); + printf("%s %d : %s\n", name, ttl, cname); + } break; + default: + break; + } } } diff --git a/fast_ping.c b/fast_ping.c index 233f005..f8d3e0c 100755 --- a/fast_ping.c +++ b/fast_ping.c @@ -1,3 +1,21 @@ +/************************************************************************* +* +* Copyright (C) 2018 Ruilin Peng (Nick) . +* + * smartdns is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * smartdns is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "fast_ping.h" #include "atomic.h" #include "hashtable.h" diff --git a/smartdns.c b/smartdns.c index db747a7..08d9aab 100755 --- a/smartdns.c +++ b/smartdns.c @@ -1,3 +1,21 @@ +/************************************************************************* +* +* Copyright (C) 2018 Ruilin Peng (Nick) . +* + * smartdns is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * smartdns is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "fast_ping.h" #include "dns_client.h" #include "dns_server.h"