Fix IPv4 address in replies to A or NS queries (github issue #38)
The destination field in struct query was changed from in_addr_t to struct sockaddr_storage, wihtout updating the functions sending it in src/dns.c. Only add extra A answer for NS queries if destination refers to an IPv4 address, and fail if trying to encode a reply to an A query if destination is not IPv4. This means NS requests received over IPv6 will not contain an address and A requests will be ignored, unless the -n option is used, or the www subdomain is requested which sets a fixed address (127.0.0.1).
This commit is contained in:
parent
d09c3e4f0b
commit
ec6a1ac308
53
src/dns.c
53
src/dns.c
|
@ -299,21 +299,25 @@ int dns_encode_ns_response(char *buf, size_t buflen, struct query *q,
|
|||
putbyte(&p, 's');
|
||||
putshort(&p, topname); /* Name Server */
|
||||
|
||||
/* Additional data (A-record of NS server) */
|
||||
CHECKLEN(12);
|
||||
putshort(&p, nsname); /* Name Server */
|
||||
putshort(&p, T_A); /* Type */
|
||||
putshort(&p, C_IN); /* Class */
|
||||
putlong(&p, 3600); /* TTL */
|
||||
putshort(&p, 4); /* Data length */
|
||||
/* Do we have an IPv4 address to send? */
|
||||
if (q->destination.ss_family == AF_INET) {
|
||||
struct sockaddr_in *dest = (struct sockaddr_in *) &q->destination;
|
||||
/* Additional data (A-record of NS server) */
|
||||
CHECKLEN(12);
|
||||
putshort(&p, nsname); /* Name Server */
|
||||
putshort(&p, T_A); /* Type */
|
||||
putshort(&p, C_IN); /* Class */
|
||||
putlong(&p, 3600); /* TTL */
|
||||
putshort(&p, 4); /* Data length */
|
||||
|
||||
/* ugly hack to output IP address */
|
||||
ipp = (char *) &q->destination;
|
||||
CHECKLEN(4);
|
||||
putbyte(&p, *(ipp++));
|
||||
putbyte(&p, *(ipp++));
|
||||
putbyte(&p, *(ipp++));
|
||||
putbyte(&p, *ipp);
|
||||
/* ugly hack to output IP address */
|
||||
ipp = (char *) &dest->sin_addr.s_addr;
|
||||
CHECKLEN(4);
|
||||
putbyte(&p, *(ipp++));
|
||||
putbyte(&p, *(ipp++));
|
||||
putbyte(&p, *(ipp++));
|
||||
putbyte(&p, *ipp);
|
||||
}
|
||||
|
||||
len = p - buf;
|
||||
return len;
|
||||
|
@ -323,12 +327,17 @@ int dns_encode_ns_response(char *buf, size_t buflen, struct query *q,
|
|||
* www.topdomain . Mostly same as dns_encode_ns_response() above */
|
||||
int dns_encode_a_response(char *buf, size_t buflen, struct query *q)
|
||||
{
|
||||
struct sockaddr_in *dest = (struct sockaddr_in *) &q->destination;
|
||||
HEADER *header;
|
||||
int len;
|
||||
short name;
|
||||
char *ipp;
|
||||
char *p;
|
||||
|
||||
/* Check if we have an IPv4 address to send */
|
||||
if (q->destination.ss_family != AF_INET)
|
||||
return -1;
|
||||
|
||||
if (buflen < sizeof(HEADER))
|
||||
return 0;
|
||||
|
||||
|
@ -355,19 +364,19 @@ int dns_encode_a_response(char *buf, size_t buflen, struct query *q)
|
|||
/* Query section */
|
||||
putname(&p, buflen - (p - buf), q->name); /* Name */
|
||||
CHECKLEN(4);
|
||||
putshort(&p, q->type); /* Type */
|
||||
putshort(&p, C_IN); /* Class */
|
||||
putshort(&p, q->type); /* Type */
|
||||
putshort(&p, C_IN); /* Class */
|
||||
|
||||
/* Answer section */
|
||||
CHECKLEN(12);
|
||||
putshort(&p, name); /* Name */
|
||||
putshort(&p, q->type); /* Type */
|
||||
putshort(&p, C_IN); /* Class */
|
||||
putlong(&p, 3600); /* TTL */
|
||||
putshort(&p, 4); /* Data length */
|
||||
putshort(&p, name); /* Name */
|
||||
putshort(&p, q->type); /* Type */
|
||||
putshort(&p, C_IN); /* Class */
|
||||
putlong(&p, 3600); /* TTL */
|
||||
putshort(&p, 4); /* Data length */
|
||||
|
||||
/* ugly hack to output IP address */
|
||||
ipp = (char *) &q->destination;
|
||||
ipp = (char *) &dest->sin_addr.s_addr;
|
||||
CHECKLEN(4);
|
||||
putbyte(&p, *(ipp++));
|
||||
putbyte(&p, *(ipp++));
|
||||
|
|
|
@ -1549,7 +1549,9 @@ handle_ns_request(int dns_fd, struct query *q)
|
|||
/* If ns_ip set, overwrite destination addr with it.
|
||||
* Destination addr will be sent as additional record (A, IN) */
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
||||
addr->sin_family = AF_INET;
|
||||
memcpy(&addr->sin_addr, &ns_ip, sizeof(ns_ip));
|
||||
q->dest_len = sizeof(*addr);
|
||||
}
|
||||
|
||||
len = dns_encode_ns_response(buf, sizeof(buf), q, topdomain);
|
||||
|
@ -1577,15 +1579,23 @@ handle_a_request(int dns_fd, struct query *q, int fakeip)
|
|||
if (fakeip) {
|
||||
in_addr_t ip = inet_addr("127.0.0.1");
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
||||
addr->sin_family = AF_INET;
|
||||
memcpy(&addr->sin_addr, &ip, sizeof(ip));
|
||||
|
||||
q->dest_len = sizeof(*addr);
|
||||
} else if (ns_ip != INADDR_ANY) {
|
||||
/* If ns_ip set, overwrite destination addr with it.
|
||||
* Destination addr will be sent as additional record (A, IN) */
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
||||
addr->sin_family = AF_INET;
|
||||
memcpy(&addr->sin_addr, &ns_ip, sizeof(ns_ip));
|
||||
q->dest_len = sizeof(*addr);
|
||||
}
|
||||
|
||||
/* Give up if no IPv4 address known (when A request received over IPv6
|
||||
* and destination was not overwritten above) */
|
||||
if (q->destination.ss_family != AF_INET)
|
||||
return;
|
||||
|
||||
len = dns_encode_a_response(buf, sizeof(buf), q);
|
||||
if (len < 1) {
|
||||
warnx("dns_encode_a_response doesn't fit");
|
||||
|
|
Loading…
Reference in New Issue