"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/dhcp.c" between
dnsmasq-2.80.tar.gz and dnsmasq-2.81.tar.xz

About: Dnsmasq is a lightweight caching DNS forwarder and DHCP server.

dhcp.c  (dnsmasq-2.80):dhcp.c  (dnsmasq-2.81.tar.xz)
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley /* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007. (at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
skipping to change at line 313 skipping to change at line 313
context->current = context; context->current = context;
for (relay = daemon->relay4; relay; relay = relay->next) for (relay = daemon->relay4; relay; relay = relay->next)
relay->current = relay; relay->current = relay;
parm.current = NULL; parm.current = NULL;
parm.relay = NULL; parm.relay = NULL;
parm.relay_local.s_addr = 0; parm.relay_local.s_addr = 0;
parm.ind = iface_index; parm.ind = iface_index;
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NU LL)) if (!iface_check(AF_INET, (union all_addr *)&iface_addr, ifr.ifr_name, NUL L))
{ {
/* If we failed to match the primary address of the interface, see if w e've got a --listen-address /* If we failed to match the primary address of the interface, see if w e've got a --listen-address
for a secondary */ for a secondary */
struct match_param match; struct match_param match;
match.matched = 0; match.matched = 0;
match.ind = iface_index; match.ind = iface_index;
if (!daemon->if_addrs || if (!daemon->if_addrs ||
!iface_enumerate(AF_INET, &match, check_listen_addrs) || !iface_enumerate(AF_INET, &match, check_listen_addrs) ||
skipping to change at line 404 skipping to change at line 404
else else
{ {
/* fill cmsg for outbound interface (both broadcast & unicast) */ /* fill cmsg for outbound interface (both broadcast & unicast) */
struct in_pktinfo *pkt; struct in_pktinfo *pkt;
msg.msg_control = control_u.control; msg.msg_control = control_u.control;
msg.msg_controllen = sizeof(control_u); msg.msg_controllen = sizeof(control_u);
cmptr = CMSG_FIRSTHDR(&msg); cmptr = CMSG_FIRSTHDR(&msg);
pkt = (struct in_pktinfo *)CMSG_DATA(cmptr); pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
pkt->ipi_ifindex = rcvd_iface_index; pkt->ipi_ifindex = rcvd_iface_index;
pkt->ipi_spec_dst.s_addr = 0; pkt->ipi_spec_dst.s_addr = 0;
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)) msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
; cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
cmptr->cmsg_level = IPPROTO_IP; cmptr->cmsg_level = IPPROTO_IP;
cmptr->cmsg_type = IP_PKTINFO; cmptr->cmsg_type = IP_PKTINFO;
if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 || if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0) mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
{ {
/* broadcast to 255.255.255.255 (or mac address invalid) */ /* broadcast to 255.255.255.255 (or mac address invalid) */
dest.sin_addr.s_addr = INADDR_BROADCAST; dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(daemon->dhcp_client_port); dest.sin_port = htons(daemon->dhcp_client_port);
} }
skipping to change at line 510 skipping to change at line 511
/* This is a complex routine: it gets called with each (address,netmask,broadcas t) triple /* This is a complex routine: it gets called with each (address,netmask,broadcas t) triple
of each interface (and any relay address) and does the following things: of each interface (and any relay address) and does the following things:
1) Discards stuff for interfaces other than the one on which a DHCP packet ju st arrived. 1) Discards stuff for interfaces other than the one on which a DHCP packet ju st arrived.
2) Fills in any netmask and broadcast addresses which have not been explicitl y configured. 2) Fills in any netmask and broadcast addresses which have not been explicitl y configured.
3) Fills in local (this host) and router (this host or relay) addresses. 3) Fills in local (this host) and router (this host or relay) addresses.
4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current. 4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
Note that the current chain may be superseded later for configured hosts or t hose coming via gateways. */ Note that the current chain may be superseded later for configured hosts or t hose coming via gateways. */
static int complete_context(struct in_addr local, int if_index, char *label, static void guess_range_netmask(struct in_addr addr, struct in_addr netmask)
struct in_addr netmask, struct in_addr broadcast, voi
d *vparam)
{ {
struct dhcp_context *context; struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param *param = vparam;
(void)label;
for (context = daemon->dhcp; context; context = context->next) for (context = daemon->dhcp; context; context = context->next)
{ if (!(context->flags & CONTEXT_NETMASK) &&
if (!(context->flags & CONTEXT_NETMASK) && (is_same_net(addr, context->start, netmask) ||
(is_same_net(local, context->start, netmask) || is_same_net(addr, context->end, netmask)))
is_same_net(local, context->end, netmask)))
{ {
if (context->netmask.s_addr != netmask.s_addr && if (context->netmask.s_addr != netmask.s_addr &&
!(is_same_net(local, context->start, netmask) && !(is_same_net(addr, context->start, netmask) &&
is_same_net(local, context->end, netmask))) is_same_net(addr, context->end, netmask)))
{ {
strcpy(daemon->dhcp_buff, inet_ntoa(context->start)); strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
strcpy(daemon->dhcp_buff2, inet_ntoa(context->end)); strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consis tent with netmask %s"), my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consis tent with netmask %s"),
daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask)); daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
} }
context->netmask = netmask; context->netmask = netmask;
} }
}
static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, voi
d *vparam)
{
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param *param = vparam;
struct shared_network *share;
(void)label;
for (share = daemon->shared_networks; share; share = share->next)
{
#ifdef HAVE_DHCP6
if (share->shared_addr.s_addr == 0)
continue;
#endif
if (share->if_index != 0)
{
if (share->if_index != if_index)
continue;
}
else
{
if (share->match_addr.s_addr != local.s_addr)
continue;
}
for (context = daemon->dhcp; context; context = context->next)
{
if (context->netmask.s_addr != 0 &&
is_same_net(share->shared_addr, context->start, context->netmask) &
&
is_same_net(share->shared_addr, context->end, context->netmask))
{
/* link it onto the current chain if we've not seen it before */
if (context->current == context)
{
/* For a shared network, we have no way to guess what the defau
lt route should be. */
context->router.s_addr = 0;
context->local = local; /* Use configured address for Server Id
entifier */
context->current = param->current;
param->current = context;
}
if (!(context->flags & CONTEXT_BRDCAST))
context->broadcast.s_addr = context->start.s_addr | ~context->ne
tmask.s_addr;
}
}
}
guess_range_netmask(local, netmask);
for (context = daemon->dhcp; context; context = context->next)
{
if (context->netmask.s_addr != 0 && if (context->netmask.s_addr != 0 &&
is_same_net(local, context->start, context->netmask) && is_same_net(local, context->start, context->netmask) &&
is_same_net(local, context->end, context->netmask)) is_same_net(local, context->end, context->netmask))
{ {
/* link it onto the current chain if we've not seen it before */ /* link it onto the current chain if we've not seen it before */
if (if_index == param->ind && context->current == context) if (if_index == param->ind && context->current == context)
{ {
context->router = local; context->router = local;
context->local = local; context->local = local;
context->current = param->current; context->current = param->current;
skipping to change at line 561 skipping to change at line 612
{ {
if (is_same_net(broadcast, context->start, context->netmask)) if (is_same_net(broadcast, context->start, context->netmask))
context->broadcast = broadcast; context->broadcast = broadcast;
else else
context->broadcast.s_addr = context->start.s_addr | ~context->ne tmask.s_addr; context->broadcast.s_addr = context->start.s_addr | ~context->ne tmask.s_addr;
} }
} }
} }
for (relay = daemon->relay4; relay; relay = relay->next) for (relay = daemon->relay4; relay; relay = relay->next)
if (if_index == param->ind && relay->local.addr.addr4.s_addr == local.s_addr && relay->current == relay && if (if_index == param->ind && relay->local.addr4.s_addr == local.s_addr && r elay->current == relay &&
(param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_a ddr)) (param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_a ddr))
{ {
relay->current = param->relay; relay->current = param->relay;
param->relay = relay; param->relay = relay;
param->relay_local = local; param->relay_local = local;
} }
return 1; return 1;
} }
skipping to change at line 768 skipping to change at line 819
supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254. 0 supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254. 0
then 192.168.0.255 is a valid IP address, but not for Windows as i t's then 192.168.0.255 is a valid IP address, but not for Windows as i t's
in the class C range. See KB281579. We therefore don't allocate t hese in the class C range. See KB281579. We therefore don't allocate t hese
addresses to avoid hard-to-diagnose problems. Thanks Bill. */ addresses to avoid hard-to-diagnose problems. Thanks Bill. */
if (!d && if (!d &&
!lease_find_by_addr(addr) && !lease_find_by_addr(addr) &&
!config_find_by_address(daemon->dhcp_conf, addr) && !config_find_by_address(daemon->dhcp_conf, addr) &&
(!IN_CLASSC(ntohl(addr.s_addr)) || (!IN_CLASSC(ntohl(addr.s_addr)) ||
((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0 xff) != 0x0)))) ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0 xff) != 0x0))))
{ {
struct ping_result *r; /* in consec-ip mode, skip addresses equal to
the number of addresses rejected by clients. This
should avoid the same client being offered the same
address after it has rjected it. */
if (option_bool(OPT_CONSEC_ADDR) && c->addr_epoch)
c->addr_epoch--;
else
{
struct ping_result *r;
if ((r = do_icmp_ping(now, addr, j, loopback))) if ((r = do_icmp_ping(now, addr, j, loopback)))
{
/* consec-ip mode: we offered this address for another client
(different hash) recently, don't offer it to this one. */
if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
{ {
*addrp = addr; /* consec-ip mode: we offered this address for another cl
return 1; ient
(different hash) recently, don't offer it to this one.
*/
if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
{
*addrp = addr;
return 1;
}
}
else
{
/* address in use: perturb address selection so that we a
re
less likely to try this address again. */
if (!option_bool(OPT_CONSEC_ADDR))
c->addr_epoch++;
} }
}
else
{
/* address in use: perturb address selection so that we are
less likely to try this address again. */
if (!option_bool(OPT_CONSEC_ADDR))
c->addr_epoch++;
} }
} }
addr.s_addr = htonl(ntohl(addr.s_addr) + 1); addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1)) if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
addr = c->start; addr = c->start;
} while (addr.s_addr != start.s_addr); } while (addr.s_addr != start.s_addr);
} }
skipping to change at line 973 skipping to change at line 1033
it gets stripped. The set of legal domain names is bigger than the set of leg al hostnames it gets stripped. The set of legal domain names is bigger than the set of leg al hostnames
so check here that the domain name is legal as a hostname. so check here that the domain name is legal as a hostname.
NOTE: we're only allowed to overwrite daemon->dhcp_buff if we succeed. */ NOTE: we're only allowed to overwrite daemon->dhcp_buff if we succeed. */
char *host_from_dns(struct in_addr addr) char *host_from_dns(struct in_addr addr)
{ {
struct crec *lookup; struct crec *lookup;
if (daemon->port == 0) if (daemon->port == 0)
return NULL; /* DNS disabled. */ return NULL; /* DNS disabled. */
lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4); lookup = cache_find_by_addr(NULL, (union all_addr *)&addr, 0, F_IPV4);
if (lookup && (lookup->flags & F_HOSTS)) if (lookup && (lookup->flags & F_HOSTS))
{ {
char *dot, *hostname = cache_get_name(lookup); char *dot, *hostname = cache_get_name(lookup);
dot = strchr(hostname, '.'); dot = strchr(hostname, '.');
if (dot && strlen(dot+1) != 0) if (dot && strlen(dot+1) != 0)
{ {
char *d2 = get_domain(addr); char *d2 = get_domain(addr);
if (!d2 || !hostname_isequal(dot+1, d2)) if (!d2 || !hostname_isequal(dot+1, d2))
skipping to change at line 1002 skipping to change at line 1062
return daemon->dhcp_buff; return daemon->dhcp_buff;
} }
return NULL; return NULL;
} }
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index) static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
{ {
/* ->local is same value for all relays on ->current chain */ /* ->local is same value for all relays on ->current chain */
struct all_addr from; union all_addr from;
if (mess->op != BOOTREQUEST) if (mess->op != BOOTREQUEST)
return 0; return 0;
/* source address == relay address */ /* source address == relay address */
from.addr.addr4 = relay->local.addr.addr4; from.addr4 = relay->local.addr4;
/* already gatewayed ? */ /* already gatewayed ? */
if (mess->giaddr.s_addr) if (mess->giaddr.s_addr)
{ {
/* if so check if by us, to stomp on loops. */ /* if so check if by us, to stomp on loops. */
if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr) if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
return 1; return 1;
} }
else else
{ {
/* plug in our address */ /* plug in our address */
mess->giaddr.s_addr = relay->local.addr.addr4.s_addr; mess->giaddr.s_addr = relay->local.addr4.s_addr;
} }
if ((mess->hops++) > 20) if ((mess->hops++) > 20)
return 1; return 1;
for (; relay; relay = relay->current) for (; relay; relay = relay->current)
{ {
union mysockaddr to; union mysockaddr to;
to.sa.sa_family = AF_INET; to.sa.sa_family = AF_INET;
to.in.sin_addr = relay->server.addr.addr4; to.in.sin_addr = relay->server.addr4;
to.in.sin_port = htons(daemon->dhcp_server_port); to.in.sin_port = htons(daemon->dhcp_server_port);
send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0); send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
if (option_bool(OPT_LOG_OPTS)) if (option_bool(OPT_LOG_OPTS))
{ {
inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN); inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuf f, inet_ntoa(relay->server.addr.addr4)); my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuf f, inet_ntoa(relay->server.addr4));
} }
/* Save this for replies */ /* Save this for replies */
relay->iface_index = iface_index; relay->iface_index = iface_index;
} }
return 1; return 1;
} }
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_i nterface) static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_i nterface)
{ {
struct dhcp_relay *relay; struct dhcp_relay *relay;
if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY) if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
return NULL; return NULL;
for (relay = daemon->relay4; relay; relay = relay->next) for (relay = daemon->relay4; relay; relay = relay->next)
{ {
if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr) if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
{ {
if (!relay->interface || wildcard_match(relay->interface, arrival_inter face)) if (!relay->interface || wildcard_match(relay->interface, arrival_inter face))
return relay->iface_index != 0 ? relay : NULL; return relay->iface_index != 0 ? relay : NULL;
} }
} }
return NULL; return NULL;
} }
#endif #endif
 End of changes. 23 change blocks. 
42 lines changed or deleted 108 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)