From 8a911ccc75ceeb7229b4bf9619b36652e01ef3d9 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Tue, 16 Mar 2004 18:35:52 +0000 Subject: [PATCH] import of dnsmasq-2.5.tar.gz --- CHANGELOG | 16 +++++++++++++ dnsmasq-mdk.spec | 2 +- dnsmasq-rh.spec | 2 +- dnsmasq-suse.spec | 2 +- dnsmasq.8 | 13 +++++++++-- src/config.h | 2 +- src/dhcp.c | 57 +++++++++++++++++++++++++++++++++-------------- src/dnsmasq.h | 3 ++- src/forward.c | 37 +++++++++++++++++------------- src/network.c | 2 +- src/option.c | 24 +++++++++++--------- src/rfc2131.c | 14 ++++++------ 12 files changed, 116 insertions(+), 58 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 22ff7b6..bebe3f3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -843,5 +843,21 @@ release 2.4 Added "bind-interfaces" option correctly. +release 2.5 + Made "where are we allocating addresses?" code in DHCP + server cope with requests via a relay which is on a + directly connected network for which there is not a + configured netmask. This strange state of affairs occurs + with win4lin. Thanks to Alex Melt and Jim Horner for bug + reports and testing with this. + + Fixed trivial-but-irritating missing #include which broke + compilation on *BSD. + + Force --bind-interfaces if IP-aliased interface + specifications are used, since the sockets API provides + no other sane way to determine which alias of an + interface a packet was sent to. Thanks to Javier Kohen + for the bug report. diff --git a/dnsmasq-mdk.spec b/dnsmasq-mdk.spec index 9d29891..89a247a 100644 --- a/dnsmasq-mdk.spec +++ b/dnsmasq-mdk.spec @@ -5,7 +5,7 @@ ############################################################################### Name: dnsmasq -Version: 2.4 +Version: 2.5 Release: 1 Copyright: GPL Group: System Environment/Daemons diff --git a/dnsmasq-rh.spec b/dnsmasq-rh.spec index e0b578f..ac36c85 100644 --- a/dnsmasq-rh.spec +++ b/dnsmasq-rh.spec @@ -5,7 +5,7 @@ ############################################################################### Name: dnsmasq -Version: 2.4 +Version: 2.5 Release: 1 Copyright: GPL Group: System Environment/Daemons diff --git a/dnsmasq-suse.spec b/dnsmasq-suse.spec index e4d9f76..339a8ad 100644 --- a/dnsmasq-suse.spec +++ b/dnsmasq-suse.spec @@ -5,7 +5,7 @@ ############################################################################### Name: dnsmasq -Version: 2.4 +Version: 2.5 Release: 1 Copyright: GPL Group: Productivity/Networking/DNS/Servers diff --git a/dnsmasq.8 b/dnsmasq.8 index 81e80ff..3cd6dd0 100644 --- a/dnsmasq.8 +++ b/dnsmasq.8 @@ -82,7 +82,14 @@ flags are given, dnsmasq listens on all available interfaces unless overridden b .B \-a or .B \-I -flags. +flags. If IP alias interfaces (eg "eth1:0") are used with +.B --interface +or +.B --except-interface +options, then the +.B --bind-interfaces +option will be automatically set. This is required for deeply boring +sockets-API reasons. .TP .B \-I, --except-interface= Do not listen on the specified interface. @@ -108,7 +115,9 @@ requests that it shouldn't reply to. This has the advantage of working even when interfaces come and go and change address. This option forces dnsmasq to really bind only the interfaces it is listening on. About the only time when this is useful is when -running another nameserver on the same machine. +running another nameserver on the same machine or using IP +alias. Specifying interfaces with IP alias automatically turns this +option on. .TP .B \-b, --bogus-priv Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192.168.x.x, etc) diff --git a/src/config.h b/src/config.h index 610deb7..ea503f9 100644 --- a/src/config.h +++ b/src/config.h @@ -12,7 +12,7 @@ /* Author's email: simon@thekelleys.org.uk */ -#define VERSION "2.4" +#define VERSION "2.5" #define FTABSIZ 150 /* max number of outstanding requests */ #define TIMEOUT 20 /* drop queries after TIMEOUT seconds */ diff --git a/src/dhcp.c b/src/dhcp.c index c7e0e60..f4f71a6 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -75,7 +75,8 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet, struct iovec iov[2]; struct cmsghdr *cmptr; int sz, newlen, iface_index = 0; - struct in_addr source, real_netmask, iface_addr, netmask_save, broadcast_save; + struct in_addr source, iface_netmask, iface_addr, iface_broadcast; + struct in_addr netmask_save, broadcast_save, router; #ifdef HAVE_BPF unsigned char iface_hwaddr[ETHER_ADDR_LEN]; #endif @@ -112,7 +113,8 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet, if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO) iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex; - if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name)) + if (!(ifr.ifr_ifindex = iface_index) || + ioctl(dhcp_fd, SIOCGIFNAME, &ifr) == -1) return; #elif defined(IP_RECVIF) @@ -169,17 +171,30 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet, /* If the packet came via a relay, use that address to look up the context, else use the address of the interface is arrived on. */ source = mess->giaddr.s_addr ? mess->giaddr : iface_addr; + + iface_netmask.s_addr = 0; + iface_broadcast.s_addr = 0; + if (ioctl(dhcp_fd, SIOCGIFNETMASK, &ifr) != -1) + { + iface_netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; + /* we can use the interface netmask if either the packet came direct, + or it came via a relay listening on the same network. This sounds unlikely, + but it happens with win4lin. */ + if ((source.s_addr & iface_netmask.s_addr) != (iface_addr.s_addr & iface_netmask.s_addr)) + iface_netmask.s_addr = 0; + else if (ioctl(dhcp_fd, SIOCGIFBRDADDR, &ifr) != -1) + iface_broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; + + } + for (context = contexts; context; context = context->next) { - if (!context->netmask.s_addr && !mess->giaddr.s_addr && ioctl(dhcp_fd, SIOCGIFNETMASK, &ifr) != -1) - real_netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; - else - real_netmask = context->netmask; - - if (real_netmask.s_addr && - (source.s_addr & real_netmask.s_addr) == (context->start.s_addr & real_netmask.s_addr) && - (source.s_addr & real_netmask.s_addr) == (context->end.s_addr & real_netmask.s_addr)) + struct in_addr netmask = context->netmask.s_addr ? context->netmask : iface_netmask; + + if (netmask.s_addr && + (source.s_addr & netmask.s_addr) == (context->start.s_addr & netmask.s_addr) && + (source.s_addr & netmask.s_addr) == (context->end.s_addr & netmask.s_addr)) break; } @@ -192,26 +207,34 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet, netmask_save = context->netmask; broadcast_save = context->broadcast; - context->netmask = real_netmask; + if (!context->netmask.s_addr) + context->netmask = iface_netmask; if (!context->broadcast.s_addr) { - if (mess->giaddr.s_addr) - context->broadcast.s_addr = (mess->giaddr.s_addr & real_netmask.s_addr) | ~real_netmask.s_addr; - else if (ioctl(dhcp_fd, SIOCGIFBRDADDR, &ifr) != -1) - context->broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; + if (iface_broadcast.s_addr) + context->broadcast = iface_broadcast; else - context->broadcast.s_addr = (iface_addr.s_addr & real_netmask.s_addr) | ~real_netmask.s_addr; + context->broadcast.s_addr = (source.s_addr & context->netmask.s_addr) | ~context->netmask.s_addr; } if (ioctl(dhcp_fd, SIOCGIFMTU, &ifr) == -1) ifr.ifr_mtu = ETHERMTU; + + /* Normally, we set the default route to point to the machine which is getting the + DHCP broadcast, either this machine or a relay. In the special case that the relay + is on the same network as us, we set the default route to us, not the relay. + This is the win4lin scenario again. */ + if ((source.s_addr & context->netmask.s_addr) == (iface_addr.s_addr & context->netmask.s_addr)) + router = iface_addr; + else + router = source; lease_prune(NULL, now); /* lose any expired leases */ newlen = dhcp_reply(context, iface_addr, ifr.ifr_name, ifr.ifr_mtu, rawpacket, sz, now, namebuff, dhcp_opts, dhcp_configs, domain_suffix, dhcp_file, - dhcp_sname, dhcp_next_server); + dhcp_sname, dhcp_next_server, router); lease_update_file(0, now); lease_update_dns(); diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 4b05749..a67e488 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -40,6 +40,7 @@ # include #endif #include +#include #include #include #include @@ -403,5 +404,5 @@ int dhcp_reply(struct dhcp_context *context, unsigned int sz, time_t now, char *namebuff, struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs, char *domain_suffix, char *dhcp_file, char *dhcp_sname, - struct in_addr dhcp_next_server); + struct in_addr dhcp_next_server, struct in_addr router); diff --git a/src/forward.c b/src/forward.c index 71426b6..1f4ad0f 100644 --- a/src/forward.c +++ b/src/forward.c @@ -104,7 +104,6 @@ static void send_from(int fd, int nowild, char *packet, int len, msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); cmptr->cmsg_type = IPV6_PKTINFO; cmptr->cmsg_level = IPV6_LEVEL; - cmptr->cmsg_level = IPPROTO_IPV6; } #endif @@ -368,11 +367,10 @@ struct server *receive_query(struct listener *listen, char *packet, char *mxname union mysockaddr source_addr; struct iname *tmp; struct all_addr dst_addr; - int m, n, gotit = 0; + int m, n, if_index = 0; struct iovec iov[1]; struct msghdr msg; struct cmsghdr *cmptr; - char if_name[IF_NAMESIZE]; union { struct cmsghdr align; /* this ensures alignment */ #ifdef HAVE_IPV6 @@ -414,20 +412,16 @@ struct server *receive_query(struct listener *listen, char *packet, char *mxname if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO) { dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst; - if_indextoname(((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex, if_name); - gotit = 1; + if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex; } #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF) if (!(options & OPT_NOWILD) && listen->family == AF_INET) { for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR) - { - dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr)); - gotit = 1; - } + dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr)); else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) - if_indextoname(((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index, if_name); + if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index; } #endif @@ -438,8 +432,7 @@ struct server *receive_query(struct listener *listen, char *packet, char *mxname if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO) { dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr; - if_indextoname(((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex, if_name); - gotit = 1; + if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex; } } #endif @@ -450,17 +443,31 @@ struct server *receive_query(struct listener *listen, char *packet, char *mxname /* enforce available interface configuration */ if (!(options & OPT_NOWILD)) { - if (!gotit) + struct ifreq ifr; + + if (if_index == 0) return last_server; + if (except || names) + { +#ifdef SIOCGIFNAME + ifr.ifr_ifindex = if_index; + if (ioctl(listen->fd, SIOCGIFNAME, &ifr) == -1) + return last_server; +#else + if (!if_indextoname(if_index, ifr.ifr_name)) + return last_server; +#endif + } + for (tmp = except; tmp; tmp = tmp->next) - if (tmp->name && (strcmp(tmp->name, if_name) == 0)) + if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) return last_server; if (names || addrs) { for (tmp = names; tmp; tmp = tmp->next) - if (tmp->name && (strcmp(tmp->name, if_name) == 0)) + if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) break; if (!tmp) for (tmp = addrs; tmp; tmp = tmp->next) diff --git a/src/network.c b/src/network.c index 2f4168f..54edf9d 100644 --- a/src/network.c +++ b/src/network.c @@ -145,7 +145,7 @@ struct irec *enumerate_interfaces(struct iname *names, lo->next = names->next; names->next = lo; } - + if ((new = add_iface(iface, ifr->ifr_name, &addr, names, addrs, except))) { diff --git a/src/option.c b/src/option.c index c1c8ea5..8fe6a44 100644 --- a/src/option.c +++ b/src/option.c @@ -165,7 +165,6 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso char *conffile = CONFFILE; int conffile_set = 0; int lineno = 0; - opterr = 0; *min_leasetime = UINT_MAX; @@ -359,6 +358,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso /* new->name may be NULL if someone does "interface=" to disable all interfaces except loop. */ new->name = safe_string_alloc(optarg); + if (strchr(optarg, ':')) + flags |= OPT_NOWILD; break; } @@ -368,6 +369,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso new->next = *if_except; *if_except = new; new->name = safe_string_alloc(optarg); + if (strchr(optarg, ':')) + flags |= OPT_NOWILD; break; } @@ -684,14 +687,13 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso } new->lease_time = atoi(a[leasepos]) * fac; - if (new->lease_time < *min_leasetime) - *min_leasetime = new->lease_time; } } } new->last = new->start; - + if (new->lease_time < *min_leasetime) + *min_leasetime = new->lease_time; break; } @@ -803,17 +805,17 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso new->hostname = safe_string_alloc(a[j]); } else - { - new->lease_time = atoi(a[j]) * fac; - if (new->lease_time < *min_leasetime) - *min_leasetime = new->lease_time; - } + new->lease_time = atoi(a[j]) * fac; } if (option == '?') free(new); else - *dhcp_conf = new; + { + if (new->lease_time < *min_leasetime) + *min_leasetime = new->lease_time; + *dhcp_conf = new; + } break; } @@ -1023,7 +1025,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso *resolv_files = 0; else if (*resolv_files && (*resolv_files)->next && (flags & OPT_NO_POLL)) die("only one resolv.conf file allowed in no-poll mode.", NULL); - + return flags; } diff --git a/src/rfc2131.c b/src/rfc2131.c index 6e2d9c6..a4bd5c0 100644 --- a/src/rfc2131.c +++ b/src/rfc2131.c @@ -61,7 +61,7 @@ static unsigned char *do_req_options(struct dhcp_context *context, unsigned char *req_options, struct dhcp_opt *config_opts, char *domainname, char *hostname, - struct in_addr relay, + struct in_addr router, struct in_addr iface_addr, int iface_mtu); @@ -74,7 +74,7 @@ int dhcp_reply(struct dhcp_context *context, unsigned int sz, time_t now, char *namebuff, struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs, char *domain_suffix, char *dhcp_file, char *dhcp_sname, - struct in_addr dhcp_next_server) + struct in_addr dhcp_next_server, struct in_addr router) { unsigned char *opt, *clid; struct dhcp_lease *lease; @@ -265,7 +265,7 @@ int dhcp_reply(struct dhcp_context *context, p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr)); p = option_put(p, end, OPTION_LEASE_TIME, 4, expires_time); p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix, - NULL, mess->giaddr, iface_addr, iface_mtu); + NULL, router, iface_addr, iface_mtu); p = option_put(p, end, OPTION_END, 0, 0); log_packet("OFFER" , &mess->yiaddr, mess->chaddr, iface_name, NULL); @@ -354,7 +354,7 @@ int dhcp_reply(struct dhcp_context *context, p = option_put(p, end, OPTION_T2, 4, ((renewal_time * 7)/8) - fuzz); } p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix, - hostname, mess->giaddr, iface_addr, iface_mtu); + hostname, router, iface_addr, iface_mtu); p = option_put(p, end, OPTION_END, 0, 0); return p - (unsigned char *)mess; @@ -364,7 +364,7 @@ int dhcp_reply(struct dhcp_context *context, p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK); p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr)); p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix, - hostname, mess->giaddr, iface_addr, iface_mtu); + hostname, router, iface_addr, iface_mtu); p = option_put(p, end, OPTION_END, 0, 0); log_packet("ACK", &mess->ciaddr, mess->chaddr, iface_name, hostname); @@ -538,7 +538,7 @@ static unsigned char *do_req_options(struct dhcp_context *context, unsigned char *req_options, struct dhcp_opt *config_opts, char *domainname, char *hostname, - struct in_addr relay, + struct in_addr router, struct in_addr iface_addr, int iface_mtu) { @@ -563,7 +563,7 @@ static unsigned char *do_req_options(struct dhcp_context *context, if (in_list(req_options, OPTION_ROUTER) && !option_find2(context, config_opts, OPTION_ROUTER)) p = option_put(p, end, OPTION_ROUTER, INADDRSZ, - ntohl(relay.s_addr ? relay.s_addr : iface_addr.s_addr )); + ntohl(router.s_addr)); if (in_list(req_options, OPTION_DNSSERVER) && !option_find2(context, config_opts, OPTION_DNSSERVER))