mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.53.tar.gz
This commit is contained in:
156
src/dhcp.c
156
src/dhcp.c
@@ -127,7 +127,10 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
int iface_index = 0, unicast_dest = 0, is_inform = 0;
|
||||
struct in_addr iface_addr, *addrp = NULL;
|
||||
struct iface_param parm;
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
struct arpreq arp_req;
|
||||
#endif
|
||||
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
@@ -189,8 +192,13 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
||||
if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_pktinfo *p;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
iface_index = p.p->ipi_ifindex;
|
||||
if (p.p->ipi_addr.s_addr != INADDR_BROADCAST)
|
||||
unicast_dest = 1;
|
||||
}
|
||||
|
||||
@@ -198,20 +206,37 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct sockaddr_dl *s;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
iface_index = p.s->sdl_index;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
iface_index = *((unsigned int *)CMSG_DATA(cmptr));
|
||||
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
unsigned int *i;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
iface_index = *(p.i);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
#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);
|
||||
#endif
|
||||
|
||||
#ifdef MSG_BCAST
|
||||
/* OpenBSD tells us when a packet was broadcast */
|
||||
if (!(msg.msg_flags & MSG_BCAST))
|
||||
@@ -231,18 +256,14 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return;
|
||||
|
||||
/* interface may have been changed by alias in iface_check */
|
||||
if (!addrp)
|
||||
{
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
}
|
||||
|
||||
/* weird libvirt-inspired access control */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
||||
break;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
@@ -253,6 +274,27 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
parm.current = NULL;
|
||||
parm.ind = iface_index;
|
||||
|
||||
/* interface may have been changed by alias in iface_check, make sure it gets priority in case
|
||||
there is more than one address on the interface in the same subnet */
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFNETMASK, &ifr) != -1)
|
||||
{
|
||||
struct in_addr netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) != -1)
|
||||
{
|
||||
struct in_addr broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
complete_context(iface_addr, iface_index, netmask, broadcast, &parm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!iface_enumerate(&parm, complete_context, NULL))
|
||||
return;
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
@@ -324,15 +366,14 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
{
|
||||
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
|
||||
struct sockaddr limits size to 14 bytes. */
|
||||
struct arpreq req;
|
||||
dest.sin_addr = mess->yiaddr;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
*((struct sockaddr_in *)&req.arp_pa) = dest;
|
||||
req.arp_ha.sa_family = mess->htype;
|
||||
memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
|
||||
strncpy(req.arp_dev, ifr.ifr_name, 16);
|
||||
req.arp_flags = ATF_COM;
|
||||
ioctl(daemon->dhcpfd, SIOCSARP, &req);
|
||||
memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
|
||||
arp_req.arp_ha.sa_family = mess->htype;
|
||||
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
|
||||
/* interface name already copied in */
|
||||
arp_req.arp_flags = ATF_COM;
|
||||
ioctl(daemon->dhcpfd, SIOCSARP, &arp_req);
|
||||
}
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
|
||||
@@ -491,13 +532,15 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
|
||||
if (!(tmp = address_available(context, taddr, netids)))
|
||||
{
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (is_same_net(taddr, tmp->start, tmp->netmask) &&
|
||||
if (match_netid(tmp->filter, netids, 1) &&
|
||||
is_same_net(taddr, tmp->start, tmp->netmask) &&
|
||||
(tmp->flags & CONTEXT_STATIC))
|
||||
break;
|
||||
|
||||
if (!tmp)
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (is_same_net(taddr, tmp->start, tmp->netmask))
|
||||
if (match_netid(tmp->filter, netids, 1) &&
|
||||
is_same_net(taddr, tmp->start, tmp->netmask))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -530,7 +573,8 @@ int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotnee
|
||||
|
||||
for (; check; check = check->next)
|
||||
{
|
||||
if (check->net[0] != '#')
|
||||
/* '#' for not is for backwards compat. */
|
||||
if (check->net[0] != '!' && check->net[0] != '#')
|
||||
{
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp(check->net, tmp1->net) == 0)
|
||||
@@ -546,6 +590,22 @@ int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotnee
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
|
||||
{
|
||||
struct tag_if *exprs;
|
||||
struct dhcp_netid_list *list;
|
||||
|
||||
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
|
||||
if (match_netid(exprs->tag, tags, 1))
|
||||
for (list = exprs->set; list; list = list->next)
|
||||
{
|
||||
list->list->next = tags;
|
||||
tags = list->list;
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
int address_allocate(struct dhcp_context *context,
|
||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||
struct dhcp_netid *netids, time_t now)
|
||||
@@ -559,9 +619,10 @@ int address_allocate(struct dhcp_context *context,
|
||||
int i, pass;
|
||||
unsigned int j;
|
||||
|
||||
/* hash hwaddr */
|
||||
/* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
|
||||
dispersal even with similarly-valued "strings". */
|
||||
for (j = 0, i = 0; i < hw_len; i++)
|
||||
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
|
||||
j += hwaddr[i] + (j << 6) + (j << 16) - j;
|
||||
|
||||
for (pass = 0; pass <= 1; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
@@ -977,29 +1038,40 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
|
||||
for this address. If it has a domain part, that must match the set domain and
|
||||
it gets stripped. The set of legal domain names is bigger than the set of legal 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. */
|
||||
char *host_from_dns(struct in_addr addr)
|
||||
{
|
||||
struct crec *lookup;
|
||||
char *hostname = NULL;
|
||||
char *d1, *d2;
|
||||
|
||||
if (daemon->port == 0)
|
||||
return NULL; /* DNS disabled. */
|
||||
|
||||
lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
|
||||
|
||||
if (lookup && (lookup->flags & F_HOSTS))
|
||||
{
|
||||
hostname = daemon->dhcp_buff;
|
||||
strncpy(hostname, cache_get_name(lookup), 256);
|
||||
hostname[255] = 0;
|
||||
d1 = strip_hostname(hostname);
|
||||
d2 = get_domain(addr);
|
||||
if (!legal_hostname(hostname) || (d1 && (!d2 || !hostname_isequal(d1, d2))))
|
||||
hostname = NULL;
|
||||
char *dot, *hostname = cache_get_name(lookup);
|
||||
dot = strchr(hostname, '.');
|
||||
|
||||
if (dot && strlen(dot+1) != 0)
|
||||
{
|
||||
char *d2 = get_domain(addr);
|
||||
if (!d2 || !hostname_isequal(dot+1, d2))
|
||||
return NULL; /* wrong domain */
|
||||
}
|
||||
|
||||
if (!legal_hostname(hostname))
|
||||
return NULL;
|
||||
|
||||
strncpy(daemon->dhcp_buff, hostname, 256);
|
||||
daemon->dhcp_buff[255] = 0;
|
||||
strip_hostname(daemon->dhcp_buff);
|
||||
|
||||
return daemon->dhcp_buff;
|
||||
}
|
||||
|
||||
return hostname;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return domain or NULL if none. */
|
||||
|
||||
Reference in New Issue
Block a user