--- dnsmasq-2.57/work/dnsmasq-2.57/src/dnsmasq.h 2011-02-17 15:30:15.000000000 +0000
+++ dnsmasq-2.57_patched_alternate_ip/work/dnsmasq-2.57/src/dnsmasq.h 2011-11-20 07:15:07.000000000 +0000
@@ -14,6 +14,8 @@
along with this program. If not, see .
*/
+// USE_LINUX_GETIFADDRS patch by Martin Suefke 2011
+
#define COPYRIGHT "Copyright (c) 2000-2011 Simon Kelley"
#ifndef NO_LARGEFILE
@@ -109,6 +111,12 @@
#if defined(HAVE_LINUX_NETWORK)
#include
+
+//TODO: Find a better place to define USE_LINUX_GETIFADDRS
+#define USE_LINUX_GETIFADDRS
+#if defined(USE_LINUX_GETIFADDRS)
+# include
+#endif
/* There doesn't seem to be a universally-available
userpace header for these. */
extern int capset(cap_user_header_t header, cap_user_data_t data);
--- dnsmasq-2.57/work/dnsmasq-2.57/src/dhcp.c 2011-02-17 15:30:15.000000000 +0000
+++ dnsmasq-2.57_patched_alternate_ip/work/dnsmasq-2.57/src/dhcp.c 2011-11-20 07:14:47.000000000 +0000
@@ -14,6 +14,8 @@
along with this program. If not, see .
*/
+// USE_LINUX_GETIFADDRS patch by Martin Suefke 2011
+
#include "dnsmasq.h"
#ifdef HAVE_DHCP
@@ -129,6 +131,14 @@
struct iface_param parm;
#ifdef HAVE_LINUX_NETWORK
struct arpreq arp_req;
+ struct in_addr recvd_addr4; // need one for ipv6, too ?
+ struct ifaddrs *ifa, *ifEntry;
+ int rc;
+ char addressBuffer[INET6_ADDRSTRLEN];
+ struct all_addr srcaddr; // DHCP server source address as determined during interface examination
+ int srcaddrAF; //Set address family if special src address available
+ memset(&srcaddr, 0, sizeof(srcaddr));
+ srcaddrAF=0;
#endif
union {
@@ -153,6 +163,7 @@
{
msg.msg_flags = 0;
while ((sz = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
+ my_syslog(MS_DHCP | LOG_DEBUG, _("dhcp.c +156 size %d"), sz);
if (sz == -1)
return;
@@ -166,14 +177,18 @@
{
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
return;
+ my_syslog(MS_DHCP | LOG_DEBUG, _("DHCP packet received: %d bytes or less"), sz+100);
}
else
{
expand_buf(&daemon->dhcp_packet, sz);
+ my_syslog(MS_DHCP | LOG_DEBUG, _("DHCP packet received: %d bytes"), sz);
break;
}
}
+ my_syslog(MS_DHCP | LOG_DEBUG, _("dhcp.c +180 size %d"), sz);
+
/* expand_buf may have moved buffer */
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
msg.msg_controllen = sizeof(control_u);
@@ -184,10 +199,13 @@
while ((sz = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
+ my_syslog(MS_DHCP | LOG_DEBUG, _("dhcp.c +192 size %d"), sz);
+
if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
return;
#if defined (HAVE_LINUX_NETWORK)
+ recvd_addr4.s_addr = 0;
if (msg.msg_controllen >= sizeof(struct cmsghdr))
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
@@ -198,6 +216,8 @@
} p;
p.c = CMSG_DATA(cmptr);
iface_index = p.p->ipi_ifindex;
+ my_syslog(MS_DHCP | LOG_DEBUG, _("dhcp.c +215 ipi_saddr = %s"), inet_ntoa(p.p->ipi_addr));
+ recvd_addr4 = p.p->ipi_addr; //TODO: Do this for BSD, Solaris, too (?)
if (p.p->ipi_addr.s_addr != INADDR_BROADCAST)
unicast_dest = 1;
}
@@ -229,9 +249,13 @@
}
#endif
+ my_syslog(MS_DHCP | LOG_DEBUG, _("dhcp.c +239 indextoname( %d )" ), iface_index);
+
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
return;
+ my_syslog(MS_DHCP | LOG_DEBUG, _("dhcp.c +244 IFNAME=%s"), ifr.ifr_name);
+
#ifdef HAVE_LINUX_NETWORK
/* ARP fiddling uses original interface even if we pretend to use a different one. */
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
@@ -243,15 +267,75 @@
unicast_dest = 1;
#endif
+#ifdef USE_LINUX_GETIFADDRS
+ /* Check all IPs assigned to the interface named ifr.ifr_name */
+ ifa = NULL;
+ ifEntry = NULL;
+ rc = getifaddrs(&ifa);
+ if (rc == 0) {
+ my_syslog(MS_DHCP | LOG_DEBUG, _("getifaddrs() ok") );
+ for(ifEntry=ifa; ifEntry!=NULL; ifEntry=ifEntry->ifa_next) {
+ my_syslog(MS_DHCP | LOG_DEBUG, _("got entry for %s, flags 0x%x"), ifEntry->ifa_name, ifEntry->ifa_flags );
+ //TODO: may check ifEntry->ifa_flags for values in net/if.h ; e.g. IFF_UP, IFF_RUNNING
+ if (strcmp(ifEntry->ifa_name,ifr.ifr_name) == 0 ) {
+ my_syslog(MS_DHCP | LOG_DEBUG, _("entry matches ifr_name") );
+ } else continue;
+ if(ifEntry->ifa_addr == NULL) {
+ continue;
+ }
+ if(ifEntry->ifa_addr->sa_data == NULL) {
+ continue;
+ }
+ if(ifEntry->ifa_addr->sa_family==AF_INET) {
+ addrp = &((struct sockaddr_in *)ifEntry->ifa_addr)->sin_addr;
+ srcaddr.addr.addr4 = *addrp;
+ srcaddrAF = AF_INET;
+ const char *a = inet_ntop(ifEntry->ifa_addr->sa_family, addrp, addressBuffer, sizeof(addressBuffer));
+ my_syslog(MS_DHCP | LOG_DEBUG, _("got AF_INET: %s") , (a!=NULL) ? a : "" );
+ if ((recvd_addr4.s_addr == srcaddr.addr.addr4.s_addr ) || (recvd_addr4.s_addr == INADDR_BROADCAST) ) {
+ my_syslog(MS_DHCP | LOG_DEBUG, _("recvd unicast to this IF or broadcast, checking interface"));
+ if (iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index)) {
+ rc=1;
+ my_syslog(MS_DHCP | LOG_DEBUG, _("iface_check ok") );
+ break;
+ }
+ }
+ } else if(ifEntry->ifa_addr->sa_family==AF_INET6) {
+ const char *a = inet_ntop(ifEntry->ifa_addr->sa_family, addrp, addressBuffer, sizeof(addressBuffer));
+ my_syslog(MS_DHCP | LOG_DEBUG, _("got AF_INET6: %s"), (a!=NULL) ? a : "" );
+ addrp = (struct in_addr *) &((struct sockaddr_in6 *)ifEntry->ifa_addr)->sin6_addr;
+ srcaddr.addr.addr6 = ((struct sockaddr_in6 *)ifEntry->ifa_addr)->sin6_addr;
+ srcaddrAF=AF_INET6;
+ if (iface_check(AF_INET6, (struct all_addr *)addrp, ifr.ifr_name, &iface_index)) {
+ rc=1;
+ my_syslog(MS_DHCP | LOG_DEBUG, _("iface_check ok") );
+ break;
+ }
+ } else {
+ //It isn't IPv4 or IPv6
+ continue;
+ }
+ }
+ freeifaddrs(ifa);
+ if ( rc != 1 ) return; // no suitable interface found
+ } else return; // cannot determine any addresses
+
+#else
+ /* This simple version gets only the interface's 1st address. May fail iface_check later. */
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
{
addrp = &iface_addr;
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
+ my_syslog(MS_DHCP | LOG_DEBUG, _("dhcp.c +262 got iface_addr %08x"),iface_addr);
}
+
+ my_syslog(MS_DHCP | LOG_DEBUG, _("dhcp.c +265 before iface_check"));
if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
return;
+ my_syslog(MS_DHCP | LOG_DEBUG, _("dhcp.c +268 after iface_check"));
+#endif
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
@@ -320,6 +404,9 @@
dest.sin_len = sizeof(struct sockaddr_in);
#endif
+ my_syslog(MS_DHCP | LOG_DEBUG, _("dhcp.c +398") );
+ struct in_pktinfo *pkt = NULL;
+
if (pxe_fd)
{
if (mess->ciaddr.s_addr != 0)
@@ -337,6 +424,7 @@
the source address in the request packet, we believe the
source port too, and send back to that. If we're replying
to a DHCPINFORM, trust the source address always. */
+ my_syslog(MS_DHCP | LOG_DEBUG, _("dhcp.c +417 src addr tallys") );
if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
{
@@ -349,7 +437,7 @@
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
{
/* broadcast to 255.255.255.255 (or mac address invalid) */
- struct in_pktinfo *pkt;
+ my_syslog(MS_DHCP | LOG_DEBUG, _("answer with broadcast") );
msg.msg_control = control_u.control;
msg.msg_controllen = sizeof(control_u);
cmptr = CMSG_FIRSTHDR(&msg);
@@ -366,6 +454,7 @@
{
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
struct sockaddr limits size to 14 bytes. */
+ my_syslog(MS_DHCP | LOG_DEBUG, _("answer with unicast") );
dest.sin_addr = mess->yiaddr;
dest.sin_port = htons(daemon->dhcp_client_port);
memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
@@ -411,6 +500,27 @@
setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
#endif
+#ifdef USE_LINUX_GETIFADDRS
+ // Set specific sender address if available
+ if (srcaddrAF == AF_INET) {
+ my_syslog(MS_DHCP | LOG_DEBUG, _("adding IPv4 source") );
+ if (! (pkt) ) { // make pktinfo if not yet available
+ my_syslog(MS_DHCP | LOG_DEBUG, _("making pktinfo structure") );
+ msg.msg_control = control_u.control;
+ msg.msg_controllen = sizeof(control_u);
+ cmptr = CMSG_FIRSTHDR(&msg);
+ pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
+ pkt->ipi_ifindex = iface_index;
+ msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+ cmptr->cmsg_level = SOL_IP;
+ cmptr->cmsg_type = IP_PKTINFO;
+ }
+ pkt->ipi_spec_dst = srcaddr.addr.addr4;
+ } else if (srcaddrAF == AF_INET6) {
+ my_syslog(MS_DHCP | LOG_WARNING, _("TODO: set correct source address for IPv6. Btw, what are you doing with DHCP on IPv6 ?!?") );
+ }
+#endif
+
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
}