diff --git a/src/common.c b/src/common.c index 9c851dc..cb0e08e 100644 --- a/src/common.c +++ b/src/common.c @@ -104,6 +104,9 @@ open_dns(int localport, in_addr_t listen_ip) #endif setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); + /* To get destination address from each UDP datagram, see iodined.c:read_dns() */ + setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, &flag, sizeof(flag)); + if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) err(1, "bind"); diff --git a/src/common.h b/src/common.h index 255ff24..46f6d3c 100644 --- a/src/common.h +++ b/src/common.h @@ -30,6 +30,14 @@ #define QUERY_NAME_SIZE 256 +#if defined IP_RECVDSTADDR +# define DSTADDR_SOCKOPT IP_RECVDSTADDR +# define dstaddr(x) (CMSG_DATA(x)) +#elif defined IP_PKTINFO +# define DSTADDR_SOCKOPT IP_PKTINFO +# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr)) +#endif + struct packet { int len; /* Total packet length */ @@ -42,6 +50,7 @@ struct query { char name[QUERY_NAME_SIZE]; short type; short id; + struct in_addr destination; struct sockaddr from; int fromlen; }; diff --git a/src/iodined.c b/src/iodined.c index 7f062c0..69fade3 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -510,17 +510,39 @@ static int read_dns(int fd, struct query *q) { struct sockaddr_in from; - char packet[64*1024]; socklen_t addrlen; + char packet[64*1024]; + char address[96]; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsg; int r; addrlen = sizeof(struct sockaddr); - r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen); + iov.iov_base = packet; + iov.iov_len = sizeof(packet); + + msg.msg_name = (caddr_t) &from; + msg.msg_namelen = (unsigned) addrlen; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = address; + msg.msg_controllen = sizeof(address); + msg.msg_flags = 0; + + r = recvmsg(fd, &msg, 0); if (r > 0) { dns_decode(NULL, 0, q, QR_QUERY, packet, r); memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen); q->fromlen = addrlen; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == DSTADDR_SOCKOPT) { + q->destination = *dstaddr(cmsg); + break; + } + } return strlen(q->name); } else if (r < 0) {