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');
|
putbyte(&p, 's');
|
||||||
putshort(&p, topname); /* Name Server */
|
putshort(&p, topname); /* Name Server */
|
||||||
|
|
||||||
/* Additional data (A-record of NS server) */
|
/* Do we have an IPv4 address to send? */
|
||||||
CHECKLEN(12);
|
if (q->destination.ss_family == AF_INET) {
|
||||||
putshort(&p, nsname); /* Name Server */
|
struct sockaddr_in *dest = (struct sockaddr_in *) &q->destination;
|
||||||
putshort(&p, T_A); /* Type */
|
/* Additional data (A-record of NS server) */
|
||||||
putshort(&p, C_IN); /* Class */
|
CHECKLEN(12);
|
||||||
putlong(&p, 3600); /* TTL */
|
putshort(&p, nsname); /* Name Server */
|
||||||
putshort(&p, 4); /* Data length */
|
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 */
|
/* ugly hack to output IP address */
|
||||||
ipp = (char *) &q->destination;
|
ipp = (char *) &dest->sin_addr.s_addr;
|
||||||
CHECKLEN(4);
|
CHECKLEN(4);
|
||||||
putbyte(&p, *(ipp++));
|
putbyte(&p, *(ipp++));
|
||||||
putbyte(&p, *(ipp++));
|
putbyte(&p, *(ipp++));
|
||||||
putbyte(&p, *(ipp++));
|
putbyte(&p, *(ipp++));
|
||||||
putbyte(&p, *ipp);
|
putbyte(&p, *ipp);
|
||||||
|
}
|
||||||
|
|
||||||
len = p - buf;
|
len = p - buf;
|
||||||
return len;
|
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 */
|
* www.topdomain . Mostly same as dns_encode_ns_response() above */
|
||||||
int dns_encode_a_response(char *buf, size_t buflen, struct query *q)
|
int dns_encode_a_response(char *buf, size_t buflen, struct query *q)
|
||||||
{
|
{
|
||||||
|
struct sockaddr_in *dest = (struct sockaddr_in *) &q->destination;
|
||||||
HEADER *header;
|
HEADER *header;
|
||||||
int len;
|
int len;
|
||||||
short name;
|
short name;
|
||||||
char *ipp;
|
char *ipp;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
|
/* Check if we have an IPv4 address to send */
|
||||||
|
if (q->destination.ss_family != AF_INET)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (buflen < sizeof(HEADER))
|
if (buflen < sizeof(HEADER))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -355,19 +364,19 @@ int dns_encode_a_response(char *buf, size_t buflen, struct query *q)
|
||||||
/* Query section */
|
/* Query section */
|
||||||
putname(&p, buflen - (p - buf), q->name); /* Name */
|
putname(&p, buflen - (p - buf), q->name); /* Name */
|
||||||
CHECKLEN(4);
|
CHECKLEN(4);
|
||||||
putshort(&p, q->type); /* Type */
|
putshort(&p, q->type); /* Type */
|
||||||
putshort(&p, C_IN); /* Class */
|
putshort(&p, C_IN); /* Class */
|
||||||
|
|
||||||
/* Answer section */
|
/* Answer section */
|
||||||
CHECKLEN(12);
|
CHECKLEN(12);
|
||||||
putshort(&p, name); /* Name */
|
putshort(&p, name); /* Name */
|
||||||
putshort(&p, q->type); /* Type */
|
putshort(&p, q->type); /* Type */
|
||||||
putshort(&p, C_IN); /* Class */
|
putshort(&p, C_IN); /* Class */
|
||||||
putlong(&p, 3600); /* TTL */
|
putlong(&p, 3600); /* TTL */
|
||||||
putshort(&p, 4); /* Data length */
|
putshort(&p, 4); /* Data length */
|
||||||
|
|
||||||
/* ugly hack to output IP address */
|
/* ugly hack to output IP address */
|
||||||
ipp = (char *) &q->destination;
|
ipp = (char *) &dest->sin_addr.s_addr;
|
||||||
CHECKLEN(4);
|
CHECKLEN(4);
|
||||||
putbyte(&p, *(ipp++));
|
putbyte(&p, *(ipp++));
|
||||||
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.
|
/* If ns_ip set, overwrite destination addr with it.
|
||||||
* Destination addr will be sent as additional record (A, IN) */
|
* Destination addr will be sent as additional record (A, IN) */
|
||||||
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
||||||
|
addr->sin_family = AF_INET;
|
||||||
memcpy(&addr->sin_addr, &ns_ip, sizeof(ns_ip));
|
memcpy(&addr->sin_addr, &ns_ip, sizeof(ns_ip));
|
||||||
|
q->dest_len = sizeof(*addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
len = dns_encode_ns_response(buf, sizeof(buf), q, topdomain);
|
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) {
|
if (fakeip) {
|
||||||
in_addr_t ip = inet_addr("127.0.0.1");
|
in_addr_t ip = inet_addr("127.0.0.1");
|
||||||
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
||||||
|
addr->sin_family = AF_INET;
|
||||||
memcpy(&addr->sin_addr, &ip, sizeof(ip));
|
memcpy(&addr->sin_addr, &ip, sizeof(ip));
|
||||||
|
q->dest_len = sizeof(*addr);
|
||||||
} else if (ns_ip != INADDR_ANY) {
|
} else if (ns_ip != INADDR_ANY) {
|
||||||
/* If ns_ip set, overwrite destination addr with it.
|
/* If ns_ip set, overwrite destination addr with it.
|
||||||
* Destination addr will be sent as additional record (A, IN) */
|
* Destination addr will be sent as additional record (A, IN) */
|
||||||
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;
|
||||||
|
addr->sin_family = AF_INET;
|
||||||
memcpy(&addr->sin_addr, &ns_ip, sizeof(ns_ip));
|
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);
|
len = dns_encode_a_response(buf, sizeof(buf), q);
|
||||||
if (len < 1) {
|
if (len < 1) {
|
||||||
warnx("dns_encode_a_response doesn't fit");
|
warnx("dns_encode_a_response doesn't fit");
|
||||||
|
|
Loading…
Reference in New Issue