mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
import of dnsmasq-2.14.tar.gz
This commit is contained in:
15
src/config.h
15
src/config.h
@@ -12,7 +12,7 @@
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#define VERSION "2.13"
|
||||
#define VERSION "2.14"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
@@ -64,6 +64,15 @@
|
||||
# define DNSMASQ_LOG_FAC(debug) LOG_DAEMON
|
||||
#endif
|
||||
|
||||
/* A small collection of RR-types which are missing on some platforms */
|
||||
|
||||
#ifndef T_SRV
|
||||
# define T_SRV 33
|
||||
#endif
|
||||
|
||||
#ifndef T_OPT
|
||||
# define T_OPT 41
|
||||
#endif
|
||||
|
||||
/* Decide if we're going to support IPv6 */
|
||||
/* We assume that systems which don't have IPv6
|
||||
@@ -218,7 +227,6 @@ NOTES:
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_PSELECT
|
||||
/* Fix various misfeatures of libc5 headers */
|
||||
#define T_SRV 33
|
||||
typedef unsigned long in_addr_t;
|
||||
typedef size_t socklen_t;
|
||||
|
||||
@@ -267,9 +275,8 @@ typedef unsigned long in_addr_t;
|
||||
#define BIND_8_COMPAT
|
||||
/* Define before sys/socket.h is included so we get socklen_t */
|
||||
#define _BSD_SOCKLEN_T_
|
||||
/* The two below are not defined in Mac OS X arpa/nameserv.h */
|
||||
/* The three below are not defined in Mac OS X arpa/nameserv.h */
|
||||
#define IN6ADDRSZ 16
|
||||
#define T_SRV 33
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
#undef HAVE_LINUX_IPV6_PROC
|
||||
|
||||
299
src/dhcp.c
299
src/dhcp.c
@@ -14,70 +14,91 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
void dhcp_init(int *fdp, int* rfdp, struct dhcp_config *configs)
|
||||
void dhcp_init(struct daemon *daemon)
|
||||
{
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
struct sockaddr_in saddr;
|
||||
int opt = 1;
|
||||
struct dhcp_config *cp;
|
||||
int oneopt = 1, zeroopt = 0;
|
||||
struct dhcp_config *configs, *cp;
|
||||
|
||||
if (fd == -1)
|
||||
die ("cannot create DHCP socket : %s", NULL);
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
if (
|
||||
#if defined(IP_PKTINFO)
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
||||
#elif defined(IP_RECVIF)
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
|
||||
#endif
|
||||
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) == -1)
|
||||
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
|
||||
die("failed to set options on DHCP socket: %s", NULL);
|
||||
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(DHCP_SERVER_PORT);
|
||||
saddr.sin_addr.s_addr = INADDR_ANY;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
saddr.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
|
||||
die("failed to bind DHCP server socket: %s", NULL);
|
||||
|
||||
*fdp = fd;
|
||||
daemon->dhcpfd = fd;
|
||||
|
||||
if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 ||
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) ||
|
||||
setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
|
||||
die("cannot create ICMP raw socket: %s.", NULL);
|
||||
|
||||
daemon->dhcp_icmp_fd = fd;
|
||||
|
||||
#ifdef HAVE_BPF
|
||||
opt = 0;
|
||||
while (1)
|
||||
{
|
||||
char filename[50];
|
||||
sprintf(filename, "/dev/bpf%d", opt++);
|
||||
if ((fd = open(filename, O_RDWR, 0)) != -1)
|
||||
break;
|
||||
if (errno != EBUSY)
|
||||
die("cannot create DHCP BPF socket: %s", NULL);
|
||||
}
|
||||
{
|
||||
int i = 0;
|
||||
while (1)
|
||||
{
|
||||
char filename[50];
|
||||
sprintf(filename, "/dev/bpf%d", i++);
|
||||
if ((fd = open(filename, O_RDWR, 0)) != -1)
|
||||
break;
|
||||
if (errno != EBUSY)
|
||||
die("cannot create DHCP BPF socket: %s", NULL);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1)
|
||||
die("cannot create DHCP packet socket: %s", NULL);
|
||||
/* since we don't ever use the packet socket for reception,
|
||||
and it receives copies of _all_ IP packets, then that data
|
||||
will build up in kernel buffers, wasting memory. Set the
|
||||
socket receive buffer size to one to avoid that. (zero is
|
||||
rejected as non-sensical by some BSD kernels) */
|
||||
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1 ||
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1)
|
||||
die("cannot create DHCP packet socket: %s. "
|
||||
"Is CONFIG_PACKET enabled in your kernel?", NULL);
|
||||
#endif
|
||||
|
||||
*rfdp = fd;
|
||||
|
||||
daemon->dhcp_raw_fd = fd;
|
||||
|
||||
/* If the same IP appears in more than one host config, then DISCOVER
|
||||
for one of the hosts will get the address, but REQUEST will be NAKed,
|
||||
since the address is reserved by the other one -> protocol loop. */
|
||||
for (; configs; configs = configs->next)
|
||||
for (configs = daemon->dhcp_conf; configs; configs = configs->next)
|
||||
for (cp = configs->next; cp; cp = cp->next)
|
||||
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
|
||||
die("Duplicate IP address %s in dhcp-config directive.", inet_ntoa(cp->addr));
|
||||
die("duplicate IP address %s in dhcp-config directive.", inet_ntoa(cp->addr));
|
||||
|
||||
daemon->dhcp_packet = safe_malloc(sizeof(struct udp_dhcp_packet));
|
||||
/* These two each hold a DHCP option max size 256
|
||||
and get a terminating zero added */
|
||||
daemon->dhcp_buff = safe_malloc(257);
|
||||
daemon->dhcp_buff2 = safe_malloc(257);
|
||||
|
||||
}
|
||||
|
||||
void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
||||
struct dhcp_vendor *vendors,
|
||||
time_t now, char *namebuff, char *domain_suffix,
|
||||
char *dhcp_file, char *dhcp_sname,
|
||||
struct in_addr dhcp_next_server, int dhcp_fd, int raw_fd,
|
||||
struct iname *names, struct iname *addrs, struct iname *except)
|
||||
void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
{
|
||||
struct udp_dhcp_packet *rawpacket = (struct udp_dhcp_packet *)packet;
|
||||
struct dhcp_packet *mess = (struct dhcp_packet *)&rawpacket->data;
|
||||
struct udp_dhcp_packet *rawpacket = daemon->dhcp_packet;
|
||||
struct dhcp_packet *mess = &rawpacket->data;
|
||||
struct dhcp_context *context;
|
||||
struct iname *tmp;
|
||||
struct ifreq ifr;
|
||||
@@ -85,8 +106,7 @@ 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, iface_netmask, iface_addr, iface_broadcast;
|
||||
struct in_addr netmask_save, broadcast_save, router;
|
||||
struct in_addr iface_netmask, iface_addr, iface_broadcast;
|
||||
#ifdef HAVE_BPF
|
||||
unsigned char iface_hwaddr[ETHER_ADDR_LEN];
|
||||
#endif
|
||||
@@ -100,8 +120,8 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
#endif
|
||||
} control_u;
|
||||
|
||||
iov[0].iov_base = (char *)&rawpacket->data;
|
||||
iov[0].iov_len = DNSMASQ_PACKETSZ - (sizeof(struct ip) + sizeof(struct udphdr));
|
||||
iov[0].iov_base = (char *)mess;
|
||||
iov[0].iov_len = sizeof(struct dhcp_packet);
|
||||
|
||||
msg.msg_control = control_u.control;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
@@ -111,7 +131,7 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
sz = recvmsg(dhcp_fd, &msg, 0);
|
||||
sz = recvmsg(daemon->dhcpfd, &msg, 0);
|
||||
|
||||
if (sz < (int)(sizeof(*mess) - sizeof(mess->options)))
|
||||
return;
|
||||
@@ -124,7 +144,7 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
||||
|
||||
if (!(ifr.ifr_ifindex = iface_index) ||
|
||||
ioctl(dhcp_fd, SIOCGIFNAME, &ifr) == -1)
|
||||
ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) == -1)
|
||||
return;
|
||||
|
||||
#elif defined(IP_RECVIF)
|
||||
@@ -138,35 +158,37 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
return;
|
||||
|
||||
#else
|
||||
while (names->isloop)
|
||||
names = names->next;
|
||||
strcpy(ifr.ifr_name, names->name);
|
||||
{
|
||||
struct iname *name;
|
||||
for (name = daemon->if_names; names->isloop; names = names->next);
|
||||
strcpy(ifr.ifr_name, name->name);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BPF
|
||||
ifr.ifr_addr.sa_family = AF_LINK;
|
||||
if (ioctl(dhcp_fd, SIOCGIFADDR, &ifr) < 0)
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) < 0)
|
||||
return;
|
||||
memcpy(iface_hwaddr, LLADDR((struct sockaddr_dl *)&ifr.ifr_addr), ETHER_ADDR_LEN);
|
||||
#endif
|
||||
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(dhcp_fd, SIOCGIFADDR, &ifr) < 0 )
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) < 0 )
|
||||
return;
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
|
||||
/* enforce available interface configuration */
|
||||
for (tmp = except; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return;
|
||||
|
||||
if (names || addrs)
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
for (tmp = names; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
break;
|
||||
if (!tmp)
|
||||
for (tmp = addrs; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == AF_INET &&
|
||||
tmp->addr.in.sin_addr.s_addr == iface_addr.s_addr)
|
||||
break;
|
||||
@@ -174,90 +196,71 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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 (!is_same_net(source, iface_addr, iface_netmask))
|
||||
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)
|
||||
iface_netmask.s_addr = 0;
|
||||
iface_broadcast.s_addr = 0;
|
||||
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
{
|
||||
struct in_addr netmask = context->netmask.s_addr ? context->netmask : iface_netmask;
|
||||
|
||||
if (netmask.s_addr &&
|
||||
is_same_net(source, context->start, netmask) &&
|
||||
is_same_net(source, context->end, netmask))
|
||||
break;
|
||||
/* Fill in missing netmask and broadcast address values for any approriate
|
||||
dhcp-ranges which match this interface and don't have them. */
|
||||
if (!context->netmask.s_addr)
|
||||
{
|
||||
if (!iface_netmask.s_addr && ioctl(daemon->dhcpfd, SIOCGIFNETMASK, &ifr) != -1)
|
||||
iface_netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
|
||||
if (iface_netmask.s_addr &&
|
||||
is_same_net(iface_addr, context->start, iface_netmask) &&
|
||||
is_same_net(iface_addr, context->end, iface_netmask))
|
||||
context->netmask = iface_netmask;
|
||||
}
|
||||
|
||||
/* Determine "default" default routes. These are to this server or the relay agent.
|
||||
Also broadcast addresses, if not specified */
|
||||
if (context->netmask.s_addr)
|
||||
{
|
||||
if (is_same_net(iface_addr, context->start, context->netmask))
|
||||
{
|
||||
if (!context->router.s_addr)
|
||||
context->router = iface_addr;
|
||||
if (!context->broadcast.s_addr)
|
||||
{
|
||||
if (!iface_broadcast.s_addr && ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) != -1)
|
||||
iface_broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
if (iface_broadcast.s_addr)
|
||||
context->broadcast = iface_broadcast;
|
||||
else
|
||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
||||
}
|
||||
}
|
||||
else if (mess->giaddr.s_addr && is_same_net(mess->giaddr, context->start, context->netmask))
|
||||
{
|
||||
if (!context->router.s_addr)
|
||||
context->router = mess->giaddr;
|
||||
/* fill in missing broadcast addresses for relayed ranges */
|
||||
if (!context->broadcast.s_addr)
|
||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!context)
|
||||
{
|
||||
syslog(LOG_WARNING, "no address range available for DHCP request via %s", inet_ntoa(source));
|
||||
return;
|
||||
}
|
||||
|
||||
netmask_save = context->netmask;
|
||||
broadcast_save = context->broadcast;
|
||||
|
||||
if (!context->netmask.s_addr)
|
||||
context->netmask = iface_netmask;
|
||||
|
||||
if (!context->broadcast.s_addr)
|
||||
{
|
||||
if (iface_broadcast.s_addr)
|
||||
context->broadcast = iface_broadcast;
|
||||
else
|
||||
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 (is_same_net(source, iface_addr, context->netmask))
|
||||
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, vendors, domain_suffix,
|
||||
dhcp_file, dhcp_sname, dhcp_next_server, router);
|
||||
newlen = dhcp_reply(daemon, iface_addr, ifr.ifr_name, sz, now);
|
||||
lease_update_file(0, now);
|
||||
lease_update_dns();
|
||||
|
||||
context->netmask = netmask_save;
|
||||
context->broadcast = broadcast_save;
|
||||
|
||||
if (newlen == 0)
|
||||
return;
|
||||
|
||||
if (mess->giaddr.s_addr || mess->ciaddr.s_addr)
|
||||
{
|
||||
/* To send to BOOTP relay or configured client, use
|
||||
the IP packet */
|
||||
/* To send to BOOTP relay or configured client, use the IP packet */
|
||||
|
||||
struct sockaddr_in dest;
|
||||
dest.sin_family = AF_INET;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
dest.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
if (mess->giaddr.s_addr)
|
||||
{
|
||||
dest.sin_port = htons(DHCP_SERVER_PORT);
|
||||
@@ -269,7 +272,7 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
dest.sin_addr = mess->ciaddr;
|
||||
}
|
||||
|
||||
sendto(dhcp_fd, mess, newlen, 0, (struct sockaddr *)&dest, sizeof(dest));
|
||||
sendto(daemon->dhcpfd, mess, newlen, 0, (struct sockaddr *)&dest, sizeof(dest));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -333,13 +336,13 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
memcpy(header.ether_shost, iface_hwaddr, ETHER_ADDR_LEN);
|
||||
memcpy(header.ether_dhost, hwdest, ETHER_ADDR_LEN);
|
||||
|
||||
ioctl(raw_fd, BIOCSETIF, &ifr);
|
||||
ioctl(daemon->dhcp_raw_fd, BIOCSETIF, &ifr);
|
||||
|
||||
iov[0].iov_base = (char *)&header;
|
||||
iov[0].iov_len = sizeof(struct ether_header);
|
||||
iov[1].iov_base = (char *)rawpacket;
|
||||
iov[1].iov_len = ntohs(rawpacket->ip.ip_len);
|
||||
writev(raw_fd, iov, 2);
|
||||
writev(daemon->dhcp_raw_fd, iov, 2);
|
||||
#else
|
||||
struct sockaddr_ll dest;
|
||||
|
||||
@@ -348,7 +351,7 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
dest.sll_ifindex = iface_index;
|
||||
dest.sll_protocol = htons(ETHERTYPE_IP);
|
||||
memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN);
|
||||
sendto(raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len),
|
||||
sendto(daemon->dhcp_raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len),
|
||||
0, (struct sockaddr *)&dest, sizeof(dest));
|
||||
|
||||
#endif
|
||||
@@ -363,14 +366,14 @@ int address_available(struct dhcp_context *context, struct in_addr taddr)
|
||||
|
||||
unsigned int addr, start, end;
|
||||
|
||||
/* static leases only. */
|
||||
if (context->static_only)
|
||||
return 0;
|
||||
|
||||
addr = ntohl(taddr.s_addr);
|
||||
start = ntohl(context->start.s_addr);
|
||||
end = ntohl(context->end.s_addr);
|
||||
|
||||
/* static leases only. */
|
||||
if (start == end)
|
||||
return 0;
|
||||
|
||||
if (addr < start)
|
||||
return 0;
|
||||
|
||||
@@ -391,7 +394,7 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
|
||||
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
struct in_addr *addrp, unsigned char *hwaddr)
|
||||
{
|
||||
/* Find a free address: exclude anything in use and anything allocated to
|
||||
@@ -400,8 +403,8 @@ int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
|
||||
struct in_addr start, addr ;
|
||||
unsigned int i, j;
|
||||
|
||||
/* start == end means no dynamic leases. */
|
||||
if (context->end.s_addr == context->start.s_addr)
|
||||
/* check if no dynamic leases. */
|
||||
if (context->static_only)
|
||||
return 0;
|
||||
|
||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
||||
@@ -410,20 +413,28 @@ int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
|
||||
|
||||
start.s_addr = addr.s_addr =
|
||||
htonl(ntohl(context->start.s_addr) +
|
||||
(j % (ntohl(context->end.s_addr) - ntohl(context->start.s_addr))));
|
||||
|
||||
do {
|
||||
if (addr.s_addr == context->end.s_addr)
|
||||
addr = context->start;
|
||||
else
|
||||
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
|
||||
(j % (1 + ntohl(context->end.s_addr) - ntohl(context->start.s_addr))));
|
||||
|
||||
|
||||
if (!lease_find_by_addr(addr) && !config_find_by_address(configs, addr))
|
||||
do {
|
||||
if (!lease_find_by_addr(addr) &&
|
||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
||||
{
|
||||
*addrp = addr;
|
||||
return 1;
|
||||
if (icmp_ping(daemon, addr))
|
||||
/* perturb address selection so that we are
|
||||
less likely to try this address again. */
|
||||
context->addr_epoch++;
|
||||
else
|
||||
{
|
||||
*addrp = addr;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
|
||||
|
||||
if (addr.s_addr == htonl(ntohl(context->end.s_addr) + 1))
|
||||
addr = context->start;
|
||||
|
||||
} while (addr.s_addr != start.s_addr);
|
||||
|
||||
return 0;
|
||||
@@ -481,20 +492,21 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
|
||||
void dhcp_read_ethers(struct daemon *daemon)
|
||||
{
|
||||
FILE *f = fopen(ETHERSFILE, "r");
|
||||
unsigned int flags, e0, e1, e2, e3, e4, e5;
|
||||
char *buff = daemon->namebuff;
|
||||
char *ip, *cp;
|
||||
struct in_addr addr;
|
||||
unsigned char hwaddr[ETHER_ADDR_LEN];
|
||||
struct dhcp_config *config;
|
||||
struct dhcp_config *config, *configs = daemon->dhcp_conf;
|
||||
int count = 0;
|
||||
|
||||
if (!f)
|
||||
{
|
||||
syslog(LOG_ERR, "failed to read " ETHERSFILE ":%m");
|
||||
return configs;
|
||||
return;
|
||||
}
|
||||
|
||||
while (fgets(buff, MAXDNAME, f))
|
||||
@@ -586,7 +598,8 @@ struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
|
||||
fclose(f);
|
||||
|
||||
syslog(LOG_INFO, "read " ETHERSFILE " - %d addresses", count);
|
||||
return configs;
|
||||
|
||||
daemon->dhcp_conf = configs;
|
||||
}
|
||||
|
||||
void dhcp_update_configs(struct dhcp_config *configs)
|
||||
|
||||
685
src/dnsmasq.c
685
src/dnsmasq.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2003 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2004 Simon Kelley
|
||||
|
||||
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
|
||||
@@ -16,75 +16,18 @@
|
||||
|
||||
static int sigterm, sighup, sigusr1, sigalarm, num_kids, in_child;
|
||||
|
||||
static void sig_handler(int sig)
|
||||
{
|
||||
if (sig == SIGTERM)
|
||||
sigterm = 1;
|
||||
else if (sig == SIGHUP)
|
||||
sighup = 1;
|
||||
else if (sig == SIGUSR1)
|
||||
sigusr1 = 1;
|
||||
else if (sig == SIGALRM)
|
||||
{
|
||||
/* alarm is used to kill children after a fixed time. */
|
||||
if (in_child)
|
||||
exit(0);
|
||||
else
|
||||
sigalarm = 1;
|
||||
}
|
||||
else if (sig == SIGCHLD)
|
||||
{
|
||||
/* See Stevens 5.10 */
|
||||
pid_t pid;
|
||||
int stat;
|
||||
|
||||
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
|
||||
num_kids--;
|
||||
}
|
||||
}
|
||||
static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd);
|
||||
static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now);
|
||||
static void sig_handler(int sig);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int cachesize = CACHESIZ;
|
||||
int port = NAMESERVER_PORT;
|
||||
int maxleases = MAXLEASES;
|
||||
unsigned short edns_pktsz = EDNS_PKTSZ;
|
||||
int query_port = 0;
|
||||
struct daemon *daemon;
|
||||
int first_loop = 1;
|
||||
int bind_fallback = 0;
|
||||
unsigned long local_ttl = 0;
|
||||
unsigned int options, min_leasetime;
|
||||
char *runfile = RUNFILE;
|
||||
time_t resolv_changed = 0;
|
||||
time_t now, last = 0;
|
||||
struct irec *interfaces = NULL;
|
||||
struct listener *listener, *listeners = NULL;
|
||||
struct doctor *doctors = NULL;
|
||||
struct mx_record *mxnames = NULL;
|
||||
char *mxtarget = NULL;
|
||||
char *lease_file = NULL;
|
||||
char *addn_hosts = NULL;
|
||||
char *domain_suffix = NULL;
|
||||
char *username = CHUSER;
|
||||
char *groupname = CHGRP;
|
||||
struct iname *if_names = NULL;
|
||||
struct iname *if_addrs = NULL;
|
||||
struct iname *if_except = NULL;
|
||||
struct server *serv_addrs = NULL;
|
||||
char *dnamebuff, *packet;
|
||||
int uptime_fd = -1;
|
||||
struct server *servers, *last_server;
|
||||
struct resolvc default_resolv = { NULL, 1, 0, RESOLVFILE };
|
||||
struct resolvc *resolv = &default_resolv;
|
||||
struct bogus_addr *bogus_addr = NULL;
|
||||
struct serverfd *serverfdp, *sfds = NULL;
|
||||
struct dhcp_context *dhcp_tmp, *dhcp = NULL;
|
||||
struct dhcp_config *dhcp_configs = NULL;
|
||||
struct dhcp_opt *dhcp_options = NULL;
|
||||
struct dhcp_vendor *dhcp_vendors = NULL;
|
||||
char *dhcp_file = NULL, *dhcp_sname = NULL;
|
||||
struct in_addr dhcp_next_server;
|
||||
int leasefd = -1, dhcpfd = -1, dhcp_raw_fd = -1;
|
||||
struct irec *interfaces;
|
||||
struct sigaction sigact;
|
||||
sigset_t sigmask;
|
||||
|
||||
@@ -121,56 +64,45 @@ int main (int argc, char **argv)
|
||||
sigaddset(&sigact.sa_mask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
|
||||
|
||||
/* These get allocated here to avoid overflowing the small stack
|
||||
on embedded systems. dnamebuff is big enough to hold one
|
||||
maximal sixed domain name and gets passed into all the processing
|
||||
code. We manage to get away with one buffer. */
|
||||
dnamebuff = safe_malloc(MAXDNAME);
|
||||
daemon = read_opts(argc, argv);
|
||||
|
||||
dhcp_next_server.s_addr = 0;
|
||||
options = read_opts(argc, argv, dnamebuff, &resolv, &mxnames, &mxtarget, &lease_file,
|
||||
&username, &groupname, &domain_suffix, &runfile,
|
||||
&if_names, &if_addrs, &if_except, &bogus_addr,
|
||||
&serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
|
||||
&dhcp, &dhcp_configs, &dhcp_options, &dhcp_vendors,
|
||||
&dhcp_file, &dhcp_sname, &dhcp_next_server, &maxleases, &min_leasetime,
|
||||
&doctors, &edns_pktsz);
|
||||
|
||||
if (edns_pktsz < PACKETSZ)
|
||||
edns_pktsz = PACKETSZ;
|
||||
packet = safe_malloc(edns_pktsz > DNSMASQ_PACKETSZ ? edns_pktsz : DNSMASQ_PACKETSZ);
|
||||
|
||||
if (!lease_file)
|
||||
if (daemon->edns_pktsz < PACKETSZ)
|
||||
daemon->edns_pktsz = PACKETSZ;
|
||||
daemon->packet = safe_malloc(daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
|
||||
daemon->edns_pktsz : DNSMASQ_PACKETSZ);
|
||||
|
||||
if (!daemon->lease_file)
|
||||
{
|
||||
if (dhcp)
|
||||
lease_file = LEASEFILE;
|
||||
if (daemon->dhcp)
|
||||
daemon->lease_file = LEASEFILE;
|
||||
}
|
||||
#ifndef HAVE_ISC_READER
|
||||
else if (!dhcp)
|
||||
else if (!daemon->dhcp)
|
||||
die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
|
||||
#endif
|
||||
|
||||
interfaces = enumerate_interfaces(&if_names, &if_addrs, if_except, port);
|
||||
|
||||
if (!(options & OPT_NOWILD) && !(listeners = create_wildcard_listeners(port)))
|
||||
interfaces = enumerate_interfaces(daemon);
|
||||
|
||||
if (!(daemon->options & OPT_NOWILD) &&
|
||||
!(daemon->listeners = create_wildcard_listeners(daemon->port)))
|
||||
{
|
||||
bind_fallback = 1;
|
||||
options |= OPT_NOWILD;
|
||||
daemon->options |= OPT_NOWILD;
|
||||
}
|
||||
|
||||
if (options & OPT_NOWILD)
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
{
|
||||
struct iname *if_tmp;
|
||||
listeners = create_bound_listeners(interfaces, port);
|
||||
daemon->listeners = create_bound_listeners(interfaces, daemon->port);
|
||||
|
||||
for (if_tmp = if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
die("unknown interface %s", if_tmp->name);
|
||||
|
||||
for (if_tmp = if_addrs; if_tmp; if_tmp = if_tmp->next)
|
||||
for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
|
||||
if (!if_tmp->used)
|
||||
{
|
||||
char addrbuff[ADDRSTRLEN];
|
||||
char *addrbuff = daemon->namebuff;
|
||||
#ifdef HAVE_IPV6
|
||||
if (if_tmp->addr.sa.sa_family == AF_INET)
|
||||
inet_ntop(AF_INET, &if_tmp->addr.in.sin_addr,
|
||||
@@ -186,60 +118,62 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
forward_init(1);
|
||||
cache_init(cachesize, options & OPT_LOG);
|
||||
cache_init(daemon->cachesize, daemon->options & OPT_LOG);
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if ((uptime_fd = open(UPTIME, O_RDONLY)) == -1)
|
||||
if ((daemon->uptime_fd = open(UPTIME, O_RDONLY)) == -1)
|
||||
die("cannot open " UPTIME ":%s", NULL);
|
||||
#endif
|
||||
|
||||
now = dnsmasq_time(uptime_fd);
|
||||
now = dnsmasq_time(daemon->uptime_fd);
|
||||
|
||||
if (dhcp)
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
#if !defined(IP_PKTINFO) && !defined(IP_RECVIF)
|
||||
int c;
|
||||
struct iname *tmp;
|
||||
for (c = 0, tmp = if_names; tmp; tmp = tmp->next)
|
||||
for (c = 0, tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (!tmp->isloop)
|
||||
c++;
|
||||
if (c != 1)
|
||||
die("must set exactly one interface on broken systems without IP_RECVIF", NULL);
|
||||
#endif
|
||||
dhcp_init(&dhcpfd, &dhcp_raw_fd, dhcp_configs);
|
||||
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
|
||||
dhcp_init(daemon);
|
||||
lease_init(daemon, now);
|
||||
}
|
||||
|
||||
/* If query_port is set then create a socket now, before dumping root
|
||||
for use to access nameservers without more specific source addresses.
|
||||
This allows query_port to be a low port */
|
||||
if (query_port)
|
||||
if (daemon->query_port)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.in.sin_port = htons(query_port);
|
||||
addr.in.sin_port = htons(daemon->query_port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
allocate_sfd(&addr, &sfds);
|
||||
allocate_sfd(&addr, &daemon->sfds);
|
||||
#ifdef HAVE_IPV6
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(query_port);
|
||||
addr.in6.sin6_port = htons(daemon->query_port);
|
||||
addr.in6.sin6_flowinfo = htonl(0);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
allocate_sfd(&addr, &sfds);
|
||||
allocate_sfd(&addr, &daemon->sfds);
|
||||
#endif
|
||||
}
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
if (!(options & OPT_DEBUG))
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
{
|
||||
FILE *pidfile;
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
struct passwd *ent_pw;
|
||||
int i;
|
||||
|
||||
@@ -247,20 +181,23 @@ int main (int argc, char **argv)
|
||||
See Stevens section 12.4 */
|
||||
|
||||
#ifndef NO_FORK
|
||||
if (fork() != 0 )
|
||||
exit(0);
|
||||
|
||||
setsid();
|
||||
|
||||
if (fork() != 0)
|
||||
exit(0);
|
||||
if (!(daemon->options & OPT_NO_FORK))
|
||||
{
|
||||
if (fork() != 0 )
|
||||
exit(0);
|
||||
|
||||
setsid();
|
||||
|
||||
if (fork() != 0)
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
chdir("/");
|
||||
umask(022); /* make pidfile 0644 */
|
||||
|
||||
/* write pidfile _after_ forking ! */
|
||||
if (runfile && (pidfile = fopen(runfile, "w")))
|
||||
if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w")))
|
||||
{
|
||||
fprintf(pidfile, "%d\n", (int) getpid());
|
||||
fclose(pidfile);
|
||||
@@ -270,23 +207,25 @@ int main (int argc, char **argv)
|
||||
|
||||
for (i=0; i<64; i++)
|
||||
{
|
||||
for (listener = listeners; listener; listener = listener->next)
|
||||
{
|
||||
if (listener->fd == i)
|
||||
break;
|
||||
if (listener->tcpfd == i)
|
||||
break;
|
||||
}
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
if (listener->fd == i || listener->tcpfd == i)
|
||||
break;
|
||||
if (listener)
|
||||
continue;
|
||||
|
||||
if (i == leasefd ||
|
||||
i == uptime_fd ||
|
||||
i == dhcpfd ||
|
||||
i == dhcp_raw_fd)
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (i == daemon->uptime_fd)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (daemon->dhcp &&
|
||||
(i == daemon->lease_fd ||
|
||||
i == daemon->dhcpfd ||
|
||||
i == daemon->dhcp_raw_fd ||
|
||||
i == daemon->dhcp_icmp_fd))
|
||||
continue;
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (serverfdp->fd == i)
|
||||
break;
|
||||
if (serverfdp)
|
||||
@@ -296,7 +235,7 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
/* Change uid and gid for security */
|
||||
if (username && (ent_pw = getpwnam(username)))
|
||||
if (daemon->username && (ent_pw = getpwnam(daemon->username)))
|
||||
{
|
||||
gid_t dummy;
|
||||
struct group *gp;
|
||||
@@ -304,7 +243,7 @@ int main (int argc, char **argv)
|
||||
setgroups(0, &dummy);
|
||||
/* change group for /etc/ppp/resolv.conf
|
||||
otherwise get the group for "nobody" */
|
||||
if ((groupname && (gp = getgrnam(groupname))) ||
|
||||
if ((daemon->groupname && (gp = getgrnam(daemon->groupname))) ||
|
||||
(gp = getgrgid(ent_pw->pw_gid)))
|
||||
setgid(gp->gr_gid);
|
||||
/* finally drop root */
|
||||
@@ -313,88 +252,91 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
openlog("dnsmasq",
|
||||
DNSMASQ_LOG_OPT(options & OPT_DEBUG),
|
||||
DNSMASQ_LOG_FAC(options & OPT_DEBUG));
|
||||
DNSMASQ_LOG_OPT(daemon->options & OPT_DEBUG),
|
||||
DNSMASQ_LOG_FAC(daemon->options & OPT_DEBUG));
|
||||
|
||||
if (cachesize != 0)
|
||||
syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, cachesize);
|
||||
if (daemon->cachesize != 0)
|
||||
syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, daemon->cachesize);
|
||||
else
|
||||
syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
|
||||
|
||||
if (bind_fallback)
|
||||
syslog(LOG_WARNING, "setting --bind-interfaces option because of OS limitations");
|
||||
|
||||
for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
strcpy(dnamebuff, inet_ntoa(dhcp_tmp->start));
|
||||
if (dhcp_tmp->lease_time == 0)
|
||||
sprintf(packet, "infinite");
|
||||
else
|
||||
struct dhcp_context *dhcp_tmp;
|
||||
for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
||||
{
|
||||
unsigned int x, p = 0, t = (unsigned int)dhcp_tmp->lease_time;
|
||||
if ((x = t/3600))
|
||||
p += sprintf(&packet[p], "%dh", x);
|
||||
if ((x = (t/60)%60))
|
||||
p += sprintf(&packet[p], "%dm", x);
|
||||
if ((x = t%60))
|
||||
p += sprintf(&packet[p], "%ds", x);
|
||||
char *time = daemon->dhcp_buff2;
|
||||
strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
|
||||
if (dhcp_tmp->lease_time == 0)
|
||||
sprintf(time, "infinite");
|
||||
else
|
||||
{
|
||||
unsigned int x, p = 0, t = (unsigned int)dhcp_tmp->lease_time;
|
||||
if ((x = t/3600))
|
||||
p += sprintf(&time[p], "%dh", x);
|
||||
if ((x = (t/60)%60))
|
||||
p += sprintf(&time[p], "%dm", x);
|
||||
if ((x = t%60))
|
||||
p += sprintf(&time[p], "%ds", x);
|
||||
}
|
||||
syslog(LOG_INFO,
|
||||
dhcp_tmp->static_only ?
|
||||
"DHCP, static leases only on %.0s%s, lease time %s" :
|
||||
"DHCP, IP range %s -- %s, lease time %s",
|
||||
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), time);
|
||||
}
|
||||
syslog(LOG_INFO,
|
||||
dhcp_tmp->start.s_addr == dhcp_tmp->end.s_addr ?
|
||||
"DHCP, static leases only on %.0s%s, lease time %s" :
|
||||
"DHCP, IP range %s -- %s, lease time %s",
|
||||
dnamebuff, inet_ntoa(dhcp_tmp->end), packet);
|
||||
}
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (dhcp)
|
||||
syslog(LOG_INFO, "DHCP, %s will be written every %ds", lease_file, min_leasetime/3);
|
||||
if (daemon->dhcp)
|
||||
syslog(LOG_INFO, "DHCP, %s will be written every %ds", daemon->lease_file, daemon->min_leasetime/3);
|
||||
#endif
|
||||
|
||||
if (!(options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
|
||||
if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
|
||||
syslog(LOG_WARNING, "running as root");
|
||||
|
||||
servers = check_servers(serv_addrs, interfaces, &sfds);
|
||||
last_server = NULL;
|
||||
|
||||
check_servers(daemon, interfaces);
|
||||
|
||||
while (sigterm == 0)
|
||||
{
|
||||
fd_set rset;
|
||||
|
||||
if (sighup)
|
||||
{
|
||||
cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
|
||||
if (dhcp)
|
||||
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
if (options & OPT_ETHERS)
|
||||
dhcp_configs = dhcp_read_ethers(dhcp_configs, dnamebuff);
|
||||
dhcp_update_configs(dhcp_configs);
|
||||
lease_update_from_configs(dhcp_configs, domain_suffix);
|
||||
if (daemon->options & OPT_ETHERS)
|
||||
dhcp_read_ethers(daemon);
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs(daemon->dhcp_conf, daemon->domain_suffix);
|
||||
lease_update_file(0, now);
|
||||
lease_update_dns();
|
||||
}
|
||||
if (resolv && (options & OPT_NO_POLL))
|
||||
if (daemon->resolv_files && (daemon->options & OPT_NO_POLL))
|
||||
{
|
||||
servers = check_servers(reload_servers(resolv->name, dnamebuff, servers, query_port),
|
||||
interfaces, &sfds);
|
||||
last_server = NULL;
|
||||
reload_servers(daemon->resolv_files->name, daemon);
|
||||
check_servers(daemon, interfaces);
|
||||
}
|
||||
sighup = 0;
|
||||
}
|
||||
|
||||
if (sigusr1)
|
||||
{
|
||||
dump_cache(options & (OPT_DEBUG | OPT_LOG), cachesize);
|
||||
dump_cache(daemon->options & (OPT_DEBUG | OPT_LOG), daemon->cachesize);
|
||||
sigusr1 = 0;
|
||||
}
|
||||
|
||||
if (sigalarm)
|
||||
{
|
||||
if (dhcp)
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
lease_update_file(1, now);
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
alarm(min_leasetime/3);
|
||||
alarm(daemon->min_leasetime/3);
|
||||
#endif
|
||||
}
|
||||
sigalarm = 0;
|
||||
@@ -404,30 +346,13 @@ int main (int argc, char **argv)
|
||||
|
||||
if (!first_loop)
|
||||
{
|
||||
int maxfd = 0;
|
||||
|
||||
for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
int maxfd = set_dns_listeners(daemon, &rset, 0);
|
||||
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
FD_SET(serverfdp->fd, &rset);
|
||||
if (serverfdp->fd > maxfd)
|
||||
maxfd = serverfdp->fd;
|
||||
}
|
||||
|
||||
for (listener = listeners; listener; listener = listener->next)
|
||||
{
|
||||
FD_SET(listener->fd, &rset);
|
||||
if (listener->fd > maxfd)
|
||||
maxfd = listener->fd;
|
||||
FD_SET(listener->tcpfd, &rset);
|
||||
if (listener->tcpfd > maxfd)
|
||||
maxfd = listener->tcpfd;
|
||||
}
|
||||
|
||||
if (dhcp)
|
||||
{
|
||||
FD_SET(dhcpfd, &rset);
|
||||
if (dhcpfd > maxfd)
|
||||
maxfd = dhcpfd;
|
||||
FD_SET(daemon->dhcpfd, &rset);
|
||||
if (daemon->dhcpfd > maxfd)
|
||||
maxfd = daemon->dhcpfd;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PSELECT
|
||||
@@ -442,11 +367,10 @@ int main (int argc, char **argv)
|
||||
sigprocmask(SIG_SETMASK, &save_mask, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
first_loop = 0;
|
||||
now = dnsmasq_time(uptime_fd);
|
||||
now = dnsmasq_time(daemon->uptime_fd);
|
||||
|
||||
/* Check for changes to resolv files once per second max. */
|
||||
if (last == 0 || difftime(now, last) > 1.0)
|
||||
@@ -454,13 +378,13 @@ int main (int argc, char **argv)
|
||||
last = now;
|
||||
|
||||
#ifdef HAVE_ISC_READER
|
||||
if (lease_file && !dhcp)
|
||||
load_dhcp(lease_file, domain_suffix, now, dnamebuff);
|
||||
if (daemon->lease_file && !daemon->dhcp)
|
||||
load_dhcp(daemon->lease_file, daemon->domain_suffix, now, daemon->namebuff);
|
||||
#endif
|
||||
|
||||
if (!(options & OPT_NO_POLL))
|
||||
if (!(daemon->options & OPT_NO_POLL))
|
||||
{
|
||||
struct resolvc *res = resolv, *latest = NULL;
|
||||
struct resolvc *res = daemon->resolv_files, *latest = NULL;
|
||||
struct stat statbuf;
|
||||
time_t last_change = 0;
|
||||
/* There may be more than one possible file.
|
||||
@@ -489,141 +413,268 @@ int main (int argc, char **argv)
|
||||
if (latest && difftime(last_change, resolv_changed) > 0.0)
|
||||
{
|
||||
resolv_changed = last_change;
|
||||
servers = check_servers(reload_servers(latest->name, dnamebuff, servers, query_port),
|
||||
interfaces, &sfds);
|
||||
last_server = NULL;
|
||||
reload_servers(latest->name, daemon);
|
||||
check_servers(daemon, interfaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (FD_ISSET(serverfdp->fd, &rset))
|
||||
last_server = reply_query(serverfdp, options, packet, now,
|
||||
dnamebuff, servers, last_server,
|
||||
bogus_addr, doctors, edns_pktsz);
|
||||
|
||||
if (dhcp && FD_ISSET(dhcpfd, &rset))
|
||||
dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs, dhcp_vendors,
|
||||
now, dnamebuff, domain_suffix, dhcp_file,
|
||||
dhcp_sname, dhcp_next_server, dhcpfd, dhcp_raw_fd,
|
||||
if_names, if_addrs, if_except);
|
||||
check_dns_listeners(daemon, &rset, now);
|
||||
|
||||
for (listener = listeners; listener; listener = listener->next)
|
||||
{
|
||||
if (FD_ISSET(listener->fd, &rset))
|
||||
last_server = receive_query(listener, packet,
|
||||
mxnames, mxtarget, options, now, local_ttl, dnamebuff,
|
||||
if_names, if_addrs, if_except, last_server, servers, edns_pktsz);
|
||||
|
||||
if (FD_ISSET(listener->tcpfd, &rset))
|
||||
{
|
||||
int confd;
|
||||
|
||||
while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||
|
||||
if (confd != -1)
|
||||
{
|
||||
int match = 1;
|
||||
if (!(options & OPT_NOWILD))
|
||||
{
|
||||
/* Check for allowed interfaces when binding the wildcard address */
|
||||
/* Don't know how to get interface of a connection, so we have to
|
||||
check by address. This will break when interfaces change address */
|
||||
union mysockaddr tcp_addr;
|
||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||
struct iname *tmp;
|
||||
|
||||
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (tcp_addr.sa.sa_family == AF_INET6)
|
||||
tcp_addr.in6.sin6_flowinfo = htonl(0);
|
||||
#endif
|
||||
for (match = 1, tmp = if_except; tmp; tmp = tmp->next)
|
||||
if (sockaddr_isequal(&tmp->addr, &tcp_addr))
|
||||
match = 0;
|
||||
|
||||
if (match && (if_names || if_addrs))
|
||||
{
|
||||
match = 0;
|
||||
for (tmp = if_names; tmp; tmp = tmp->next)
|
||||
if (sockaddr_isequal(&tmp->addr, &tcp_addr))
|
||||
match = 1;
|
||||
for (tmp = if_addrs; tmp; tmp = tmp->next)
|
||||
if (sockaddr_isequal(&tmp->addr, &tcp_addr))
|
||||
match = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!match || (num_kids >= MAX_PROCS))
|
||||
close(confd);
|
||||
else if (!(options & OPT_DEBUG) && fork())
|
||||
{
|
||||
num_kids++;
|
||||
close(confd);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *buff;
|
||||
struct server *s;
|
||||
int flags;
|
||||
|
||||
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||
terminate the process. */
|
||||
if (!(options & OPT_DEBUG))
|
||||
{
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigaddset(&sigact.sa_mask, SIGALRM);
|
||||
sigprocmask(SIG_UNBLOCK, &sigact.sa_mask, NULL);
|
||||
alarm(CHILD_LIFETIME);
|
||||
in_child = 1;
|
||||
}
|
||||
|
||||
/* start with no upstream connections. */
|
||||
for (s = servers; s; s = s->next)
|
||||
s->tcpfd = -1;
|
||||
|
||||
/* The connected socket inherits non-blocking
|
||||
attribute from the listening socket.
|
||||
Reset that here. */
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
|
||||
buff = tcp_request(confd, mxnames, mxtarget, options, now,
|
||||
local_ttl, dnamebuff, last_server, servers,
|
||||
bogus_addr, doctors, edns_pktsz);
|
||||
|
||||
|
||||
if (!(options & OPT_DEBUG))
|
||||
exit(0);
|
||||
|
||||
close(confd);
|
||||
if (buff)
|
||||
free(buff);
|
||||
for (s = servers; s; s = s->next)
|
||||
if (s->tcpfd != -1)
|
||||
close(s->tcpfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
|
||||
dhcp_packet(daemon, now);
|
||||
}
|
||||
|
||||
syslog(LOG_INFO, "exiting on receipt of SIGTERM");
|
||||
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (dhcp)
|
||||
lease_update_file(1, now);
|
||||
lease_update_file(1, now);
|
||||
#endif
|
||||
|
||||
if (leasefd != -1)
|
||||
close(leasefd);
|
||||
close(daemon->lease_fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sig_handler(int sig)
|
||||
{
|
||||
if (sig == SIGTERM)
|
||||
sigterm = 1;
|
||||
else if (sig == SIGHUP)
|
||||
sighup = 1;
|
||||
else if (sig == SIGUSR1)
|
||||
sigusr1 = 1;
|
||||
else if (sig == SIGALRM)
|
||||
{
|
||||
/* alarm is used to kill children after a fixed time. */
|
||||
if (in_child)
|
||||
exit(0);
|
||||
else
|
||||
sigalarm = 1;
|
||||
}
|
||||
else if (sig == SIGCHLD)
|
||||
{
|
||||
/* See Stevens 5.10 */
|
||||
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0)
|
||||
num_kids--;
|
||||
}
|
||||
}
|
||||
|
||||
static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd)
|
||||
{
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
{
|
||||
FD_SET(serverfdp->fd, set);
|
||||
if (serverfdp->fd > maxfd)
|
||||
maxfd = serverfdp->fd;
|
||||
}
|
||||
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
{
|
||||
FD_SET(listener->fd, set);
|
||||
if (listener->fd > maxfd)
|
||||
maxfd = listener->fd;
|
||||
FD_SET(listener->tcpfd, set);
|
||||
if (listener->tcpfd > maxfd)
|
||||
maxfd = listener->tcpfd;
|
||||
}
|
||||
|
||||
return maxfd;
|
||||
}
|
||||
|
||||
static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now)
|
||||
{
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (FD_ISSET(serverfdp->fd, set))
|
||||
reply_query(serverfdp, daemon, now);
|
||||
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
{
|
||||
if (FD_ISSET(listener->fd, set))
|
||||
receive_query(listener, daemon, now);
|
||||
|
||||
if (FD_ISSET(listener->tcpfd, set))
|
||||
{
|
||||
int confd;
|
||||
|
||||
while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||
|
||||
if (confd != -1)
|
||||
{
|
||||
int match = 1;
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
{
|
||||
/* Check for allowed interfaces when binding the wildcard address */
|
||||
/* Don't know how to get interface of a connection, so we have to
|
||||
check by address. This will break when interfaces change address */
|
||||
union mysockaddr tcp_addr;
|
||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||
struct iname *tmp;
|
||||
|
||||
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (tcp_addr.sa.sa_family == AF_INET6)
|
||||
tcp_addr.in6.sin6_flowinfo = htonl(0);
|
||||
#endif
|
||||
for (match = 1, tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (sockaddr_isequal(&tmp->addr, &tcp_addr))
|
||||
match = 0;
|
||||
|
||||
if (match && (daemon->if_names || daemon->if_addrs))
|
||||
{
|
||||
match = 0;
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (sockaddr_isequal(&tmp->addr, &tcp_addr))
|
||||
match = 1;
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (sockaddr_isequal(&tmp->addr, &tcp_addr))
|
||||
match = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!match || (num_kids >= MAX_PROCS))
|
||||
close(confd);
|
||||
else if (!(daemon->options & OPT_DEBUG) && fork())
|
||||
{
|
||||
num_kids++;
|
||||
close(confd);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *buff;
|
||||
struct server *s;
|
||||
int flags;
|
||||
|
||||
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||
terminate the process. */
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
{
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGALRM);
|
||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||
alarm(CHILD_LIFETIME);
|
||||
in_child = 1;
|
||||
}
|
||||
|
||||
/* start with no upstream connections. */
|
||||
for (s = daemon->servers; s; s = s->next)
|
||||
s->tcpfd = -1;
|
||||
|
||||
/* The connected socket inherits non-blocking
|
||||
attribute from the listening socket.
|
||||
Reset that here. */
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
|
||||
buff = tcp_request(daemon, confd, now);
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
exit(0);
|
||||
|
||||
close(confd);
|
||||
if (buff)
|
||||
free(buff);
|
||||
for (s = daemon->servers; s; s = s->next)
|
||||
if (s->tcpfd != -1)
|
||||
close(s->tcpfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int icmp_ping(struct daemon *daemon, struct in_addr addr)
|
||||
{
|
||||
/* Try and get an ICMP echo from a machine.
|
||||
Note that we can't create the raw socket each time
|
||||
we do this, since that needs root. Therefore the socket has to hang
|
||||
around all the time. Since most of the time we won't read the
|
||||
socket, it will accumulate buffers full of ICMP messages,
|
||||
wasting memory. To avoid that we set the receive buffer
|
||||
length to zero except when we're actively pinging. */
|
||||
|
||||
/* Note that whilst in the three second wait, we check for
|
||||
(and service) events on the DNS sockets, (so doing that
|
||||
better not use any resources our caller has in use...)
|
||||
but we remain deaf to signals or further DHCP packets. */
|
||||
|
||||
struct sockaddr_in saddr;
|
||||
struct {
|
||||
struct ip ip;
|
||||
struct icmp icmp;
|
||||
} packet;
|
||||
unsigned short id = rand16();
|
||||
unsigned int i, j;
|
||||
int opt = 2000, gotreply = 0;
|
||||
time_t start, now;
|
||||
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = 0;
|
||||
saddr.sin_addr = addr;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
saddr.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
memset(&packet.icmp, 0, sizeof(packet.icmp));
|
||||
packet.icmp.icmp_type = ICMP_ECHO;
|
||||
packet.icmp.icmp_id = id;
|
||||
for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
|
||||
j += ((u16 *)&packet.icmp)[i];
|
||||
while (j>>16)
|
||||
j = (j & 0xffff) + (j >> 16);
|
||||
packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
|
||||
|
||||
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
|
||||
|
||||
if (sendto(daemon->dhcp_icmp_fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
|
||||
(struct sockaddr *)&saddr, sizeof(saddr)) == sizeof(struct icmp))
|
||||
for (now = start = dnsmasq_time(daemon->uptime_fd); difftime(now, start) < 3.0;)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set rset;
|
||||
struct sockaddr_in faddr;
|
||||
int maxfd, len = sizeof(faddr);
|
||||
|
||||
tv.tv_usec = 250000;
|
||||
tv.tv_sec = 0;
|
||||
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(daemon->dhcp_icmp_fd, &rset);
|
||||
maxfd = set_dns_listeners(daemon, &rset, daemon->dhcp_icmp_fd);
|
||||
|
||||
if (select(maxfd+1, &rset, NULL, NULL, &tv) < 0)
|
||||
FD_ZERO(&rset);
|
||||
|
||||
now = dnsmasq_time(daemon->uptime_fd);
|
||||
check_dns_listeners(daemon, &rset, now);
|
||||
|
||||
if (FD_ISSET(daemon->dhcp_icmp_fd, &rset) &&
|
||||
recvfrom(daemon->dhcp_icmp_fd, &packet, sizeof(packet), 0,
|
||||
(struct sockaddr *)&faddr, &len) == sizeof(packet) &&
|
||||
saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
|
||||
packet.icmp.icmp_type == ICMP_ECHOREPLY &&
|
||||
packet.icmp.icmp_seq == 0 &&
|
||||
packet.icmp.icmp_id == id)
|
||||
{
|
||||
gotreply = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
opt = 1;
|
||||
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
|
||||
|
||||
return gotreply;
|
||||
}
|
||||
|
||||
137
src/dnsmasq.h
137
src/dnsmasq.h
@@ -27,14 +27,13 @@
|
||||
|
||||
/* get this before config.h too. */
|
||||
#include <syslog.h>
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <arpa/nameser.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -66,6 +65,7 @@
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#ifdef HAVE_BPF
|
||||
# include <net/bpf.h>
|
||||
# include <net/if_dl.h>
|
||||
@@ -94,6 +94,7 @@
|
||||
#define OPT_NOWILD 8192
|
||||
#define OPT_ETHERS 16384
|
||||
#define OPT_RESOLV_DOMAIN 32768
|
||||
#define OPT_NO_FORK 65536
|
||||
|
||||
struct all_addr {
|
||||
union {
|
||||
@@ -289,8 +290,9 @@ struct dhcp_vendor {
|
||||
|
||||
struct dhcp_context {
|
||||
unsigned int lease_time, addr_epoch;
|
||||
struct in_addr netmask, broadcast;
|
||||
struct in_addr netmask, broadcast, router;
|
||||
struct in_addr start, end; /* range of available addresses */
|
||||
int static_only;
|
||||
struct dhcp_netid netid;
|
||||
struct dhcp_context *next;
|
||||
};
|
||||
@@ -314,12 +316,57 @@ struct udp_dhcp_packet {
|
||||
u16 secs, flags;
|
||||
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
|
||||
u8 chaddr[16], sname[64], file[128];
|
||||
u32 cookie;
|
||||
u8 options[308];
|
||||
u8 options[312];
|
||||
} data;
|
||||
};
|
||||
|
||||
|
||||
struct daemon {
|
||||
/* datastuctures representing the command-line and
|
||||
config file arguments. All set (including defaults)
|
||||
in option.c */
|
||||
|
||||
unsigned int options;
|
||||
struct resolvc default_resolv, *resolv_files;
|
||||
struct mx_record *mxnames;
|
||||
char *mxtarget;
|
||||
char *lease_file;
|
||||
char *username, *groupname;
|
||||
char *domain_suffix;
|
||||
char *runfile;
|
||||
struct iname *if_names, *if_addrs, *if_except;
|
||||
struct bogus_addr *bogus_addr;
|
||||
struct server *servers;
|
||||
int cachesize;
|
||||
int port, query_port;
|
||||
unsigned long local_ttl;
|
||||
char *addn_hosts;
|
||||
struct dhcp_context *dhcp;
|
||||
struct dhcp_config *dhcp_conf;
|
||||
struct dhcp_opt *dhcp_opts;
|
||||
struct dhcp_vendor *dhcp_vendors;
|
||||
char *dhcp_file;
|
||||
char *dhcp_sname;
|
||||
struct in_addr dhcp_next_server;
|
||||
int dhcp_max;
|
||||
unsigned int min_leasetime;
|
||||
struct doctor *doctors;
|
||||
unsigned short edns_pktsz;
|
||||
|
||||
/* globally used stuff for DNS */
|
||||
char *packet; /* packet buffer */
|
||||
char *namebuff; /* MAXDNAME size buffer */
|
||||
struct serverfd *sfds;
|
||||
struct listener *listeners;
|
||||
struct server *last_server;
|
||||
int uptime_fd;
|
||||
|
||||
/* DHCP state */
|
||||
int dhcpfd, dhcp_raw_fd, dhcp_icmp_fd, lease_fd;
|
||||
struct udp_dhcp_packet *dhcp_packet;
|
||||
char *dhcp_buff, *dhcp_buff2;
|
||||
};
|
||||
|
||||
/* cache.c */
|
||||
void cache_init(int cachesize, int log);
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr, unsigned short type);
|
||||
@@ -347,9 +394,7 @@ int setup_reply(HEADER *header, unsigned int qlen,
|
||||
void extract_addresses(HEADER *header, unsigned int qlen, char *namebuff,
|
||||
time_t now, struct doctor *doctors);
|
||||
void extract_neg_addrs(HEADER *header, unsigned int qlen, char *namebuff, time_t now);
|
||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_record *mxnames,
|
||||
char *mxtarget, unsigned int options, time_t now, unsigned long local_ttl,
|
||||
char *namebuff, unsigned short edns_pcktsz);
|
||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon *daemon, time_t now);
|
||||
int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen);
|
||||
@@ -370,73 +415,41 @@ time_t dnsmasq_time(int fd);
|
||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
||||
|
||||
/* option.c */
|
||||
unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resolv_file,
|
||||
struct mx_record **mxnames, char **mxtarget, char **lease_file,
|
||||
char **username, char **groupname,
|
||||
char **domain_suffix, char **runfile,
|
||||
struct iname **if_names, struct iname **if_addrs, struct iname **if_except,
|
||||
struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize,
|
||||
int *port, int *query_port, unsigned long *local_ttl, char **addn_hosts,
|
||||
struct dhcp_context **dhcp, struct dhcp_config **dhcp_conf,
|
||||
struct dhcp_opt **opts, struct dhcp_vendor **dhcp_vendors,
|
||||
char **dhcp_file, char **dhcp_sname, struct in_addr *dhcp_next_server,
|
||||
int *maxleases, unsigned int *min_leasetime, struct doctor **doctors,
|
||||
unsigned short *edns_pktsz);
|
||||
struct daemon *read_opts (int argc, char **argv);
|
||||
|
||||
/* forward.c */
|
||||
void forward_init(int first);
|
||||
struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
|
||||
char *dnamebuff, struct server *servers, struct server *last_server,
|
||||
struct bogus_addr *bogus_nxdomain,
|
||||
struct doctor *doctors, unsigned short edns_pcktsz);
|
||||
void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now);
|
||||
void receive_query(struct listener *listen, struct daemon *daemon, time_t now);
|
||||
char *tcp_request(struct daemon *daemon, int confd, time_t now);
|
||||
|
||||
struct server *receive_query(struct listener *listen, char *packet, struct mx_record *mxnames,
|
||||
char *mxtarget, unsigned int options, time_t now,
|
||||
unsigned long local_ttl, char *namebuff,
|
||||
struct iname *names, struct iname *addrs, struct iname *except,
|
||||
struct server *last_server, struct server *servers, unsigned short edns_pcktsz);
|
||||
|
||||
char *tcp_request(int confd, struct mx_record *mxnames,
|
||||
char *mxtarget, unsigned int options, time_t now,
|
||||
unsigned long local_ttl, char *namebuff,
|
||||
struct server *last_server, struct server *servers,
|
||||
struct bogus_addr *bogus_nxdomain, struct doctor *doctors,
|
||||
unsigned short edns_pcktsz);
|
||||
/* network.c */
|
||||
struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds);
|
||||
struct server *reload_servers(char *fname, char *buff, struct server *servers, int query_port);
|
||||
struct server *check_servers(struct server *new, struct irec *interfaces, struct serverfd **sfds);
|
||||
struct irec *enumerate_interfaces(struct iname **names,
|
||||
struct iname **addrs,
|
||||
struct iname *except,
|
||||
int port);
|
||||
void reload_servers(char *fname, struct daemon *daemon);
|
||||
void check_servers(struct daemon *daemon, struct irec *interfaces);
|
||||
struct irec *enumerate_interfaces(struct daemon *daemon);
|
||||
struct listener *create_wildcard_listeners(int port);
|
||||
struct listener *create_bound_listeners(struct irec *interfaces, int port);
|
||||
|
||||
/* dhcp.c */
|
||||
void dhcp_init(int *fdp, int* rfdp, struct dhcp_config *configs);
|
||||
void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
||||
struct dhcp_vendor *vendors,
|
||||
time_t now, char *namebuff, char *domain_suffix,
|
||||
char *dhcp_file, char *dhcp_sname,
|
||||
struct in_addr dhcp_next_server, int dhcp_fd, int raw_fd,
|
||||
struct iname *names, struct iname *addrs, struct iname *except);
|
||||
void dhcp_init(struct daemon *daemon);
|
||||
void dhcp_packet(struct daemon *daemon, time_t now);
|
||||
|
||||
int address_available(struct dhcp_context *context, struct in_addr addr);
|
||||
int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
|
||||
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
struct in_addr *addrp, unsigned char *hwaddr);
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *clid, int clid_len,
|
||||
unsigned char *hwaddr, char *hostname);
|
||||
struct dhcp_config *read_ethers(struct dhcp_config *configs, char *buff);
|
||||
void dhcp_update_configs(struct dhcp_config *configs);
|
||||
struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff);
|
||||
void dhcp_read_ethers(struct daemon *daemon);
|
||||
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
|
||||
|
||||
/* lease.c */
|
||||
void lease_update_file(int force, time_t now);
|
||||
void lease_update_dns(void);
|
||||
int lease_init(char *lease_file, char *domain, char *buff,
|
||||
char *buff2, time_t now, int maxleases);
|
||||
void lease_init(struct daemon *daemon, time_t now);
|
||||
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr);
|
||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr);
|
||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix);
|
||||
@@ -447,16 +460,10 @@ void lease_prune(struct dhcp_lease *target, time_t now);
|
||||
void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain);
|
||||
|
||||
/* rfc2131.c */
|
||||
int dhcp_reply(struct dhcp_context *context,
|
||||
struct in_addr iface_addr,
|
||||
char *iface_name,
|
||||
int iface_mtu,
|
||||
struct udp_dhcp_packet *rawpacket,
|
||||
unsigned int sz, time_t now, char *namebuff,
|
||||
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
||||
struct dhcp_vendor *vendors,
|
||||
char *domain_suffix, char *dhcp_file, char *dhcp_sname,
|
||||
struct in_addr dhcp_next_server, struct in_addr router);
|
||||
int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_name, unsigned int sz, time_t now);
|
||||
|
||||
/* dnsmasq.c */
|
||||
int icmp_ping(struct daemon *daemon, struct in_addr addr);
|
||||
|
||||
/* isc.c */
|
||||
#ifdef HAVE_ISC_READER
|
||||
|
||||
202
src/forward.c
202
src/forward.c
@@ -114,7 +114,7 @@ static void send_from(int fd, int nowild, char *packet, int len,
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short search_servers(struct server *servers, unsigned int options, struct all_addr **addrpp,
|
||||
unsigned short search_servers(struct daemon *daemon, struct all_addr **addrpp,
|
||||
unsigned short qtype, char *qdomain, int *type, char **domain)
|
||||
|
||||
{
|
||||
@@ -127,7 +127,7 @@ unsigned short search_servers(struct server *servers, unsigned int options, stru
|
||||
struct server *serv;
|
||||
unsigned short flags = 0;
|
||||
|
||||
for (serv=servers; serv; serv=serv->next)
|
||||
for (serv = daemon->servers; serv; serv=serv->next)
|
||||
/* domain matches take priority over NODOTS matches */
|
||||
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.'))
|
||||
{
|
||||
@@ -181,7 +181,7 @@ unsigned short search_servers(struct server *servers, unsigned int options, stru
|
||||
else
|
||||
log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp, 0);
|
||||
}
|
||||
else if (qtype && (options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.'))
|
||||
else if (qtype && (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.'))
|
||||
flags = F_NOERR;
|
||||
|
||||
if (flags & (F_NOERR | F_NXDOMAIN))
|
||||
@@ -191,41 +191,39 @@ unsigned short search_servers(struct server *servers, unsigned int options, stru
|
||||
}
|
||||
|
||||
/* returns new last_server */
|
||||
static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct all_addr *dst_addr, unsigned int dst_iface,
|
||||
HEADER *header, int plen, unsigned int options, char *dnamebuff,
|
||||
struct server *servers, struct server *last_server,
|
||||
time_t now, unsigned long local_ttl)
|
||||
static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *udpaddr,
|
||||
struct all_addr *dst_addr, unsigned int dst_iface,
|
||||
HEADER *header, int plen, time_t now)
|
||||
{
|
||||
struct frec *forward;
|
||||
char *domain = NULL;
|
||||
int forwardall = 0, type = 0;
|
||||
struct all_addr *addrp = NULL;
|
||||
unsigned short flags = 0;
|
||||
unsigned short gotname = extract_request(header, (unsigned int)plen, dnamebuff, NULL);
|
||||
unsigned short gotname = extract_request(header, (unsigned int)plen, daemon->namebuff, NULL);
|
||||
struct server *start = NULL;
|
||||
|
||||
/* may be recursion not speced or no servers available. */
|
||||
if (!header->rd || !servers)
|
||||
if (!header->rd || !daemon->servers)
|
||||
forward = NULL;
|
||||
else if ((forward = lookup_frec_by_sender(ntohs(header->id), udpaddr)))
|
||||
{
|
||||
/* retry on existing query, send to all available servers */
|
||||
domain = forward->sentto->domain;
|
||||
if (!(options & OPT_ORDER))
|
||||
if (!(daemon->options & OPT_ORDER))
|
||||
{
|
||||
forwardall = 1;
|
||||
last_server = NULL;
|
||||
daemon->last_server = NULL;
|
||||
}
|
||||
type = forward->sentto->flags & SERV_TYPE;
|
||||
if (!(start = forward->sentto->next))
|
||||
start = servers; /* at end of list, recycle */
|
||||
start = daemon->servers; /* at end of list, recycle */
|
||||
header->id = htons(forward->new_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gotname)
|
||||
flags = search_servers(servers, options, &addrp, gotname, dnamebuff, &type, &domain);
|
||||
flags = search_servers(daemon, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||
|
||||
if (!flags && !(forward = get_new_frec(now)))
|
||||
/* table full - server failure. */
|
||||
@@ -237,11 +235,11 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
always try servers in the order specified in resolv.conf,
|
||||
otherwise, use the one last known to work. */
|
||||
|
||||
if (type != 0 || (options & OPT_ORDER))
|
||||
start = servers;
|
||||
else if (!(start = last_server))
|
||||
if (type != 0 || (daemon->options & OPT_ORDER))
|
||||
start = daemon->servers;
|
||||
else if (!(start = daemon->last_server))
|
||||
{
|
||||
start = servers;
|
||||
start = daemon->servers;
|
||||
forwardall = 1;
|
||||
}
|
||||
|
||||
@@ -279,13 +277,13 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
sa_len(&start->addr)) != -1)
|
||||
{
|
||||
if (!gotname)
|
||||
strcpy(dnamebuff, "query");
|
||||
strcpy(daemon->namebuff, "query");
|
||||
if (start->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_SERVER | F_IPV4 | F_FORWARD, dnamebuff,
|
||||
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&start->addr.in.sin_addr, 0);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_SERVER | F_IPV6 | F_FORWARD, dnamebuff,
|
||||
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&start->addr.in6.sin6_addr, 0);
|
||||
#endif
|
||||
forwarded = 1;
|
||||
@@ -296,14 +294,14 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
|
||||
if (!(start = start->next))
|
||||
start = servers;
|
||||
start = daemon->servers;
|
||||
|
||||
if (start == firstsentto)
|
||||
break;
|
||||
}
|
||||
|
||||
if (forwarded)
|
||||
return last_server;
|
||||
return;
|
||||
|
||||
/* could not send on, prepare to return */
|
||||
header->id = htons(forward->orig_id);
|
||||
@@ -311,15 +309,14 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
|
||||
/* could not send on, return empty answer or address if known for whole domain */
|
||||
plen = setup_reply(header, (unsigned int)plen, addrp, flags, local_ttl);
|
||||
send_from(udpfd, options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
plen = setup_reply(header, (unsigned int)plen, addrp, flags, daemon->local_ttl);
|
||||
send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
|
||||
return last_server;
|
||||
return;
|
||||
}
|
||||
|
||||
static int process_reply(HEADER *header, time_t now, char *dnamebuff, struct bogus_addr *bogus_nxdomain,
|
||||
struct doctor *doctors, union mysockaddr *serveraddr,
|
||||
int n, int options, unsigned short edns_pcktsz)
|
||||
static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
union mysockaddr *serveraddr, int n)
|
||||
{
|
||||
unsigned char *pheader;
|
||||
|
||||
@@ -333,8 +330,8 @@ static int process_reply(HEADER *header, time_t now, char *dnamebuff, struct bog
|
||||
unsigned char *psave = pheader;
|
||||
|
||||
GETSHORT(udpsz, pheader);
|
||||
if (udpsz > edns_pcktsz)
|
||||
PUTSHORT(edns_pcktsz, psave);
|
||||
if (udpsz > daemon->edns_pktsz)
|
||||
PUTSHORT(daemon->edns_pktsz, psave);
|
||||
}
|
||||
|
||||
/* Complain loudly if the upstream server is non-recursive. */
|
||||
@@ -355,24 +352,22 @@ static int process_reply(HEADER *header, time_t now, char *dnamebuff, struct bog
|
||||
|
||||
if ((header->rcode == NOERROR || header->rcode == NXDOMAIN) && header->opcode == QUERY)
|
||||
{
|
||||
if (!(bogus_nxdomain &&
|
||||
if (!(daemon->bogus_addr &&
|
||||
header->rcode == NOERROR &&
|
||||
check_for_bogus_wildcard(header, (unsigned int)n, dnamebuff, bogus_nxdomain, now)))
|
||||
check_for_bogus_wildcard(header, (unsigned int)n, daemon->namebuff, daemon->bogus_addr, now)))
|
||||
{
|
||||
if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
|
||||
extract_addresses(header, (unsigned int)n, dnamebuff, now, doctors);
|
||||
else if (!(options & OPT_NO_NEG))
|
||||
extract_neg_addrs(header, (unsigned int)n, dnamebuff, now);
|
||||
extract_addresses(header, (unsigned int)n, daemon->namebuff, now, daemon->doctors);
|
||||
else if (!(daemon->options & OPT_NO_NEG))
|
||||
extract_neg_addrs(header, (unsigned int)n, daemon->namebuff, now);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* returns new last_server */
|
||||
struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
|
||||
char *dnamebuff, struct server *servers, struct server *last_server,
|
||||
struct bogus_addr *bogus_nxdomain, struct doctor *doctors, unsigned short edns_pcktsz)
|
||||
/* sets new last_server */
|
||||
void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
||||
{
|
||||
/* packet from peer server, extract data for cache, and send to
|
||||
original requester */
|
||||
@@ -380,7 +375,7 @@ struct server *reply_query(struct serverfd *sfd, int options, char *packet, time
|
||||
HEADER *header;
|
||||
union mysockaddr serveraddr;
|
||||
socklen_t addrlen = sizeof(serveraddr);
|
||||
int n = recvfrom(sfd->fd, packet, edns_pcktsz, 0, &serveraddr.sa, &addrlen);
|
||||
int n = recvfrom(sfd->fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
|
||||
|
||||
/* Determine the address of the server replying so that we can mark that as good */
|
||||
serveraddr.sa.sa_family = sfd->source_addr.sa.sa_family;
|
||||
@@ -389,43 +384,41 @@ struct server *reply_query(struct serverfd *sfd, int options, char *packet, time
|
||||
serveraddr.in6.sin6_flowinfo = htonl(0);
|
||||
#endif
|
||||
|
||||
header = (HEADER *)packet;
|
||||
header = (HEADER *)daemon->packet;
|
||||
if (n >= (int)sizeof(HEADER) && header->qr && (forward = lookup_frec(ntohs(header->id))))
|
||||
{
|
||||
/* find good server by address if possible, otherwise assume the last one we sent to */
|
||||
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
||||
{
|
||||
for (last_server = servers; last_server; last_server = last_server->next)
|
||||
struct server *last_server;
|
||||
daemon->last_server = forward->sentto;
|
||||
for (last_server = daemon->servers; last_server; last_server = last_server->next)
|
||||
if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
|
||||
sockaddr_isequal(&last_server->addr, &serveraddr))
|
||||
break;
|
||||
if (!last_server)
|
||||
last_server = forward->sentto;
|
||||
{
|
||||
daemon->last_server = last_server;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!process_reply(header, now, dnamebuff, bogus_nxdomain, doctors, &serveraddr, n, options, edns_pcktsz))
|
||||
return NULL;
|
||||
|
||||
header->id = htons(forward->orig_id);
|
||||
send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest, forward->iface);
|
||||
forward->new_id = 0; /* cancel */
|
||||
if (process_reply(daemon, header, now, &serveraddr, n))
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n,
|
||||
&forward->source, &forward->dest, forward->iface);
|
||||
forward->new_id = 0; /* cancel */
|
||||
}
|
||||
}
|
||||
|
||||
return last_server;
|
||||
}
|
||||
|
||||
struct server *receive_query(struct listener *listen, char *packet, struct mx_record *mxnames,
|
||||
char *mxtarget, unsigned int options, time_t now,
|
||||
unsigned long local_ttl, char *namebuff,
|
||||
struct iname *names, struct iname *addrs, struct iname *except,
|
||||
struct server *last_server, struct server *servers, unsigned short edns_pcktsz)
|
||||
void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
{
|
||||
HEADER *header = (HEADER *)packet;
|
||||
HEADER *header = (HEADER *)daemon->packet;
|
||||
union mysockaddr source_addr;
|
||||
unsigned short type;
|
||||
struct iname *tmp;
|
||||
struct all_addr dst_addr;
|
||||
int check_dst = !(options & OPT_NOWILD);
|
||||
int check_dst = !(daemon->options & OPT_NOWILD);
|
||||
int m, n, if_index = 0;
|
||||
struct iovec iov[1];
|
||||
struct msghdr msg;
|
||||
@@ -443,8 +436,8 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
||||
#endif
|
||||
} control_u;
|
||||
|
||||
iov[0].iov_base = packet;
|
||||
iov[0].iov_len = edns_pcktsz;
|
||||
iov[0].iov_base = daemon->packet;
|
||||
iov[0].iov_len = daemon->edns_pktsz;
|
||||
|
||||
msg.msg_control = control_u.control;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
@@ -455,7 +448,7 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
|
||||
return last_server;
|
||||
return;
|
||||
|
||||
source_addr.sa.sa_family = listen->family;
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -467,7 +460,7 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
||||
#endif
|
||||
|
||||
if (check_dst && msg.msg_controllen < sizeof(struct cmsghdr))
|
||||
return last_server;
|
||||
return;
|
||||
|
||||
#if defined(IP_PKTINFO)
|
||||
if (check_dst && listen->family == AF_INET)
|
||||
@@ -501,7 +494,7 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
||||
#endif
|
||||
|
||||
if (n < (int)sizeof(HEADER) || header->qr)
|
||||
return last_server;
|
||||
return;
|
||||
|
||||
/* enforce available interface configuration */
|
||||
if (check_dst)
|
||||
@@ -509,31 +502,31 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
||||
struct ifreq ifr;
|
||||
|
||||
if (if_index == 0)
|
||||
return last_server;
|
||||
return;
|
||||
|
||||
if (except || names)
|
||||
if (daemon->if_except || daemon->if_names)
|
||||
{
|
||||
#ifdef SIOCGIFNAME
|
||||
ifr.ifr_ifindex = if_index;
|
||||
if (ioctl(listen->fd, SIOCGIFNAME, &ifr) == -1)
|
||||
return last_server;
|
||||
return;
|
||||
#else
|
||||
if (!if_indextoname(if_index, ifr.ifr_name))
|
||||
return last_server;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (tmp = except; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
return last_server;
|
||||
return;
|
||||
|
||||
if (names || addrs)
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
for (tmp = names; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
break;
|
||||
if (!tmp)
|
||||
for (tmp = addrs; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == listen->family)
|
||||
{
|
||||
if (tmp->addr.sa.sa_family == AF_INET &&
|
||||
@@ -548,31 +541,28 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
||||
#endif
|
||||
}
|
||||
if (!tmp)
|
||||
return last_server;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (extract_request(header, (unsigned int)n, namebuff, &type))
|
||||
if (extract_request(header, (unsigned int)n, daemon->namebuff, &type))
|
||||
{
|
||||
if (listen->family == AF_INET)
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, namebuff,
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&source_addr.in.sin_addr, type);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, namebuff,
|
||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&source_addr.in6.sin6_addr, type);
|
||||
#endif
|
||||
}
|
||||
|
||||
m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n,
|
||||
mxnames, mxtarget, options, now, local_ttl, namebuff, edns_pcktsz);
|
||||
m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n, daemon, now);
|
||||
if (m >= 1)
|
||||
send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
else
|
||||
last_server = forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||
header, n, options, namebuff, servers,
|
||||
last_server, now, local_ttl);
|
||||
return last_server;
|
||||
forward_query(daemon, listen->fd, &source_addr, &dst_addr, if_index,
|
||||
header, n, now);
|
||||
}
|
||||
|
||||
static int read_write(int fd, char *packet, int size, int rw)
|
||||
@@ -612,12 +602,7 @@ static int read_write(int fd, char *packet, int size, int rw)
|
||||
blocking as neccessary, and then return. Note, need to be a bit careful
|
||||
about resources for debug mode, when the fork is suppressed: that's
|
||||
done by the caller. */
|
||||
char *tcp_request(int confd, struct mx_record *mxnames,
|
||||
char *mxtarget, unsigned int options, time_t now,
|
||||
unsigned long local_ttl, char *namebuff,
|
||||
struct server *last_server, struct server *servers,
|
||||
struct bogus_addr *bogus_nxdomain, struct doctor *doctors,
|
||||
unsigned short edns_pktsz)
|
||||
char *tcp_request(struct daemon *daemon, int confd, time_t now)
|
||||
{
|
||||
int size = 0, m;
|
||||
unsigned short qtype, gotname;
|
||||
@@ -625,7 +610,8 @@ char *tcp_request(int confd, struct mx_record *mxnames,
|
||||
/* Max TCP packet + slop */
|
||||
char *packet = malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
||||
HEADER *header;
|
||||
|
||||
struct server *last_server;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!packet ||
|
||||
@@ -639,7 +625,7 @@ char *tcp_request(int confd, struct mx_record *mxnames,
|
||||
|
||||
header = (HEADER *)packet;
|
||||
|
||||
if ((gotname = extract_request(header, (unsigned int)size, namebuff, &qtype)))
|
||||
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||
{
|
||||
union mysockaddr peer_addr;
|
||||
socklen_t peer_len = sizeof(union mysockaddr);
|
||||
@@ -647,19 +633,18 @@ char *tcp_request(int confd, struct mx_record *mxnames,
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
|
||||
{
|
||||
if (peer_addr.sa.sa_family == AF_INET)
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, namebuff,
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&peer_addr.in.sin_addr, qtype);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, namebuff,
|
||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&peer_addr.in6.sin6_addr, qtype);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* m > 0 if answered from cache */
|
||||
m = answer_request (header, ((char *) header) + 65536, (unsigned int)size,
|
||||
mxnames, mxtarget, options, now, local_ttl, namebuff, edns_pktsz);
|
||||
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size, daemon, now);
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
@@ -669,10 +654,12 @@ char *tcp_request(int confd, struct mx_record *mxnames,
|
||||
char *domain = NULL;
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(servers, options, &addrp, gotname, namebuff, &type, &domain);
|
||||
flags = search_servers(daemon, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||
|
||||
if (type != 0 || (options & OPT_ORDER) || !last_server)
|
||||
last_server = servers;
|
||||
if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server)
|
||||
last_server = daemon->servers;
|
||||
else
|
||||
last_server = daemon->last_server;
|
||||
|
||||
if (!flags && last_server)
|
||||
{
|
||||
@@ -688,7 +675,7 @@ char *tcp_request(int confd, struct mx_record *mxnames,
|
||||
else
|
||||
{
|
||||
if (!(last_server = last_server->next))
|
||||
last_server = servers;
|
||||
last_server = daemon->servers;
|
||||
|
||||
if (last_server == firstsendto)
|
||||
break;
|
||||
@@ -729,21 +716,20 @@ char *tcp_request(int confd, struct mx_record *mxnames,
|
||||
return packet;
|
||||
|
||||
if (!gotname)
|
||||
strcpy(namebuff, "query");
|
||||
strcpy(daemon->namebuff, "query");
|
||||
if (last_server->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_SERVER | F_IPV4 | F_FORWARD, namebuff,
|
||||
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&last_server->addr.in.sin_addr, 0);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_SERVER | F_IPV6 | F_FORWARD, namebuff,
|
||||
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&last_server->addr.in6.sin6_addr, 0);
|
||||
#endif
|
||||
|
||||
/* There's no point in updating the cache, since this process will exit and
|
||||
lose the information after one query. We make this call for the alias and
|
||||
bogus-nxdomain side-effects. */
|
||||
process_reply(header, now, namebuff, bogus_nxdomain, doctors,
|
||||
&last_server->addr, m, options, edns_pktsz);
|
||||
process_reply(daemon, header, now, &last_server->addr, m);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -751,7 +737,7 @@ char *tcp_request(int confd, struct mx_record *mxnames,
|
||||
|
||||
/* In case of local answer or no connections made. */
|
||||
if (m == 0)
|
||||
m = setup_reply(header, (unsigned int)size, addrp, flags, local_ttl);
|
||||
m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
|
||||
}
|
||||
|
||||
c1 = m>>8;
|
||||
|
||||
26
src/lease.c
26
src/lease.c
@@ -15,12 +15,11 @@
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct dhcp_lease *leases;
|
||||
FILE *lease_file;
|
||||
int dns_dirty, file_dirty, new_lease;
|
||||
int leases_left;
|
||||
static FILE *lease_file;
|
||||
static int dns_dirty, file_dirty, new_lease;
|
||||
static int leases_left;
|
||||
|
||||
int lease_init(char *filename, char *domain, char *buff,
|
||||
char *buff2, time_t now, int maxleases)
|
||||
void lease_init(struct daemon *daemon, time_t now)
|
||||
{
|
||||
unsigned int e0, e1, e2, e3, e4, e5, a0, a1, a2, a3;
|
||||
unsigned long ei;
|
||||
@@ -30,19 +29,22 @@ int lease_init(char *filename, char *domain, char *buff,
|
||||
struct dhcp_lease *lease;
|
||||
int clid_len = 0;
|
||||
int has_old = 0;
|
||||
|
||||
char *buff = daemon->dhcp_buff;
|
||||
char *buff2 = daemon->dhcp_buff2;
|
||||
|
||||
leases = NULL;
|
||||
leases_left = maxleases;
|
||||
leases_left = daemon->dhcp_max;
|
||||
|
||||
/* NOTE: need a+ mode to create file if it doesn't exist */
|
||||
if (!(lease_file = fopen(filename, "a+")))
|
||||
if (!(lease_file = fopen(daemon->lease_file, "a+")))
|
||||
die("cannot open or create leases file: %s", NULL);
|
||||
|
||||
/* a+ mode lease pointer at end. */
|
||||
rewind(lease_file);
|
||||
|
||||
while (fscanf(lease_file, "%lu %x:%x:%x:%x:%x:%x %d.%d.%d.%d %256s %500s",
|
||||
&ei, &e0, &e1, &e2, &e3, &e4, &e5, &a0, &a1, &a2, &a3, buff, buff2) == 13)
|
||||
while (fscanf(lease_file, "%lu %x:%x:%x:%x:%x:%x %d.%d.%d.%d %257s %257s",
|
||||
&ei, &e0, &e1, &e2, &e3, &e4, &e5, &a0, &a1, &a2, &a3,
|
||||
buff, buff2) == 13)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (ei)
|
||||
@@ -90,14 +92,14 @@ int lease_init(char *filename, char *domain, char *buff,
|
||||
memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN);
|
||||
|
||||
if (strcmp(buff, "*") != 0)
|
||||
lease_set_hostname(lease, buff, domain);
|
||||
lease_set_hostname(lease, buff, daemon->domain_suffix);
|
||||
}
|
||||
|
||||
dns_dirty = 1;
|
||||
file_dirty = has_old;
|
||||
new_lease = 0;
|
||||
|
||||
return fileno(lease_file);
|
||||
daemon->lease_fd = fileno(lease_file);
|
||||
}
|
||||
|
||||
void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain)
|
||||
|
||||
@@ -14,16 +14,14 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *addr,
|
||||
struct iname *names, struct iname *addrs,
|
||||
struct iname *except)
|
||||
static struct irec *add_iface(struct daemon *daemon, struct irec *list, char *name, union mysockaddr *addr)
|
||||
{
|
||||
struct irec *iface;
|
||||
struct iname *tmp;
|
||||
|
||||
/* check blacklist */
|
||||
if (except)
|
||||
for (tmp = except; tmp; tmp = tmp->next)
|
||||
if (daemon->if_except)
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && strcmp(tmp->name, name) == 0)
|
||||
{
|
||||
/* record address of named interfaces, for TCP access control */
|
||||
@@ -32,18 +30,18 @@ static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *a
|
||||
}
|
||||
|
||||
/* we may need to check the whitelist */
|
||||
if (names || addrs)
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
for (tmp = names; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||
{
|
||||
tmp->addr = *addr;
|
||||
found = tmp->used = 1;
|
||||
}
|
||||
|
||||
for (tmp = addrs; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (sockaddr_isequal(&tmp->addr, addr))
|
||||
found = tmp->used = 1;
|
||||
|
||||
@@ -67,10 +65,7 @@ static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *a
|
||||
}
|
||||
|
||||
|
||||
struct irec *enumerate_interfaces(struct iname **names,
|
||||
struct iname **addrs,
|
||||
struct iname *except,
|
||||
int port)
|
||||
struct irec *enumerate_interfaces(struct daemon *daemon)
|
||||
{
|
||||
struct irec *iface = NULL;
|
||||
char *buf, *ptr;
|
||||
@@ -126,7 +121,7 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
if (ifr->ifr_addr.sa_family == AF_INET)
|
||||
{
|
||||
addr.in = *((struct sockaddr_in *) &ifr->ifr_addr);
|
||||
addr.in.sin_port = htons(port);
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifr->ifr_addr.sa_family == AF_INET6)
|
||||
@@ -136,7 +131,7 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
#else
|
||||
addr.in6 = *((struct sockaddr_in6 *) &ifr->ifr_addr);
|
||||
#endif
|
||||
addr.in6.sin6_port = htons(port);
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
addr.in6.sin6_flowinfo = htonl(0);
|
||||
}
|
||||
#endif
|
||||
@@ -148,10 +143,10 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
|
||||
/* If we are restricting the set of interfaces to use, make
|
||||
sure that loopback interfaces are in that set. */
|
||||
if (*names && (ifr->ifr_flags & IFF_LOOPBACK))
|
||||
if (daemon->if_names && (ifr->ifr_flags & IFF_LOOPBACK))
|
||||
{
|
||||
struct iname *lo;
|
||||
for (lo = *names; lo; lo = lo->next)
|
||||
for (lo = daemon->if_names; lo; lo = lo->next)
|
||||
if (lo->name && strcmp(lo->name, ifr->ifr_name) == 0)
|
||||
{
|
||||
lo->isloop = 1;
|
||||
@@ -162,12 +157,12 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
lo = safe_malloc(sizeof(struct iname));
|
||||
lo->name = safe_string_alloc(ifr->ifr_name);
|
||||
lo->isloop = lo->used = 1;
|
||||
lo->next = *names;
|
||||
*names = lo;
|
||||
lo->next = daemon->if_names;
|
||||
daemon->if_names = lo;
|
||||
}
|
||||
}
|
||||
|
||||
iface = add_iface(iface, ifr->ifr_name, &addr, *names, *addrs, except);
|
||||
iface = add_iface(daemon, iface, ifr->ifr_name, &addr);
|
||||
|
||||
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
|
||||
/* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
|
||||
@@ -198,7 +193,7 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
sscanf(addrstring+i+i, "%02x", &byte);
|
||||
addr6p[i] = byte;
|
||||
}
|
||||
addr6.in6.sin6_port = htons(port);
|
||||
addr6.in6.sin6_port = htons(daemon->port);
|
||||
addr6.in6.sin6_flowinfo = htonl(0);
|
||||
addr6.in6.sin6_scope_id = htonl(scope);
|
||||
|
||||
@@ -211,7 +206,7 @@ struct irec *enumerate_interfaces(struct iname **names,
|
||||
}
|
||||
|
||||
if (found)
|
||||
iface = add_iface(iface, ifr->ifr_name, &addr6, *names, *addrs, except);
|
||||
iface = add_iface(daemon, iface, ifr->ifr_name, &addr6);
|
||||
}
|
||||
#endif /* LINUX */
|
||||
}
|
||||
@@ -423,17 +418,19 @@ struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
||||
return sfd;
|
||||
}
|
||||
|
||||
struct server *check_servers(struct server *new, struct irec *interfaces, struct serverfd **sfds)
|
||||
void check_servers(struct daemon *daemon, struct irec *interfaces)
|
||||
{
|
||||
char addrbuff[ADDRSTRLEN];
|
||||
struct irec *iface;
|
||||
struct server *tmp, *ret = NULL;
|
||||
struct server *new, *tmp, *ret = NULL;
|
||||
int port = 0;
|
||||
|
||||
/* forward table rules reference servers, so have to blow them away */
|
||||
forward_init(0);
|
||||
|
||||
for (;new; new = tmp)
|
||||
daemon->last_server = NULL;
|
||||
|
||||
for (new = daemon->servers; new; new = tmp)
|
||||
{
|
||||
tmp = new->next;
|
||||
|
||||
@@ -465,7 +462,7 @@ struct server *check_servers(struct server *new, struct irec *interfaces, struct
|
||||
}
|
||||
|
||||
/* Do we need a socket set? */
|
||||
if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, sfds)))
|
||||
if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, &daemon->sfds)))
|
||||
{
|
||||
syslog(LOG_WARNING,
|
||||
"ignoring nameserver %s - cannot make/bind socket: %m", addrbuff);
|
||||
@@ -495,15 +492,16 @@ struct server *check_servers(struct server *new, struct irec *interfaces, struct
|
||||
syslog(LOG_INFO, "using nameserver %s#%d", addrbuff, port);
|
||||
}
|
||||
|
||||
return ret;
|
||||
daemon->servers = ret;
|
||||
}
|
||||
|
||||
struct server *reload_servers(char *fname, char *buff, struct server *serv, int query_port)
|
||||
void reload_servers(char *fname, struct daemon *daemon)
|
||||
{
|
||||
FILE *f;
|
||||
char *line;
|
||||
struct server *old_servers = NULL;
|
||||
struct server *new_servers = NULL;
|
||||
struct server *serv = daemon->servers;
|
||||
|
||||
/* move old servers to free list - we can reuse the memory
|
||||
and not risk malloc if there are the same or fewer new servers.
|
||||
@@ -533,7 +531,7 @@ struct server *reload_servers(char *fname, char *buff, struct server *serv, int
|
||||
else
|
||||
{
|
||||
syslog(LOG_INFO, "reading %s", fname);
|
||||
while ((line = fgets(buff, MAXDNAME, f)))
|
||||
while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
|
||||
{
|
||||
union mysockaddr addr, source_addr;
|
||||
char *token = strtok(line, " \t\n\r");
|
||||
@@ -556,7 +554,7 @@ struct server *reload_servers(char *fname, char *buff, struct server *serv, int
|
||||
source_addr.in.sin_family = addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_port = htons(NAMESERVER_PORT);
|
||||
source_addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
source_addr.in.sin_port = htons(query_port);
|
||||
source_addr.in.sin_port = htons(daemon->query_port);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr))
|
||||
@@ -568,7 +566,7 @@ struct server *reload_servers(char *fname, char *buff, struct server *serv, int
|
||||
addr.in6.sin6_port = htons(NAMESERVER_PORT);
|
||||
source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = htonl(0);
|
||||
source_addr.in6.sin6_addr = in6addr_any;
|
||||
source_addr.in6.sin6_port = htons(query_port);
|
||||
source_addr.in6.sin6_port = htons(daemon->query_port);
|
||||
}
|
||||
#endif /* IPV6 */
|
||||
else
|
||||
@@ -604,7 +602,7 @@ struct server *reload_servers(char *fname, char *buff, struct server *serv, int
|
||||
old_servers = tmp;
|
||||
}
|
||||
|
||||
return new_servers;
|
||||
daemon->servers = new_servers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
207
src/option.c
207
src/option.c
@@ -21,7 +21,7 @@ struct myoption {
|
||||
int val;
|
||||
};
|
||||
|
||||
#define OPTSTRING "ZDNLERzowefnbvhdqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:"
|
||||
#define OPTSTRING "ZDNLERzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:"
|
||||
|
||||
static struct myoption opts[] = {
|
||||
{"version", 0, 0, 'v'},
|
||||
@@ -73,6 +73,7 @@ static struct myoption opts[] = {
|
||||
{"dhcp-vendorclass", 1, 0, 'U'},
|
||||
{"dhcp-userclass", 1, 0, 'j'},
|
||||
{"edns-packet-max", 1, 0, 'P'},
|
||||
{"keep-in-foreground", 0, 0, 'k'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -89,6 +90,7 @@ static struct optflags optmap[] = {
|
||||
{ 'h', OPT_NO_HOSTS },
|
||||
{ 'n', OPT_NO_POLL },
|
||||
{ 'd', OPT_DEBUG },
|
||||
{ 'k', OPT_NO_FORK },
|
||||
{ 'o', OPT_ORDER },
|
||||
{ 'R', OPT_NO_RESOLV },
|
||||
{ 'E', OPT_EXPAND },
|
||||
@@ -124,6 +126,7 @@ static char *usage =
|
||||
"-i, --interface=interface Specify interface(s) to listen on.\n"
|
||||
"-I, --except-interface=int Specify interface(s) NOT to listen on.\n"
|
||||
"-j, --dhcp-userclass=<id>,<class> Map DHCP user class to option set.\n"
|
||||
"-k, --keep-in-foreground Do NOT fork into the background, do NOT run in debug mode.\n"
|
||||
"-l, --dhcp-leasefile=path Specify where to store DHCP leases (defaults to " LEASEFILE ").\n"
|
||||
"-L, --localmx Return MX records for local hosts.\n"
|
||||
"-m, --mx-host=host_name Specify the MX name to reply to.\n"
|
||||
@@ -155,26 +158,33 @@ static char *usage =
|
||||
"\n";
|
||||
|
||||
|
||||
unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **resolv_files,
|
||||
struct mx_record **mxnames, char **mxtarget, char **lease_file,
|
||||
char **username, char **groupname, char **domain_suffix, char **runfile,
|
||||
struct iname **if_names, struct iname **if_addrs, struct iname **if_except,
|
||||
struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize, int *port,
|
||||
int *query_port, unsigned long *local_ttl, char **addn_hosts, struct dhcp_context **dhcp,
|
||||
struct dhcp_config **dhcp_conf, struct dhcp_opt **dhcp_opts, struct dhcp_vendor **dhcp_vendors, char **dhcp_file,
|
||||
char **dhcp_sname, struct in_addr *dhcp_next_server, int *dhcp_max,
|
||||
unsigned int *min_leasetime, struct doctor **doctors, unsigned short *edns_pktsz)
|
||||
struct daemon *read_opts (int argc, char **argv)
|
||||
{
|
||||
struct daemon *daemon = safe_malloc(sizeof(struct daemon));
|
||||
char *buff = safe_malloc(MAXDNAME);
|
||||
int option = 0, i;
|
||||
unsigned int flags = 0;
|
||||
FILE *file_save = NULL, *f = NULL;
|
||||
char *file_name_save = NULL, *conffile = CONFFILE;
|
||||
int conffile_set = 0;
|
||||
int line_save = 0, lineno = 0;
|
||||
opterr = 0;
|
||||
|
||||
*min_leasetime = UINT_MAX;
|
||||
memset(daemon, 0, sizeof(struct daemon));
|
||||
daemon->namebuff = buff;
|
||||
|
||||
/* Set defaults - everything else is zero or NULL */
|
||||
daemon->min_leasetime = UINT_MAX;
|
||||
daemon->cachesize = CACHESIZ;
|
||||
daemon->port = NAMESERVER_PORT;
|
||||
daemon->default_resolv.is_default = 1;
|
||||
daemon->default_resolv.name = RESOLVFILE;
|
||||
daemon->resolv_files = &daemon->default_resolv;
|
||||
daemon->username = CHUSER;
|
||||
daemon->groupname = CHGRP;
|
||||
daemon->runfile = RUNFILE;
|
||||
daemon->dhcp_max = MAXLEASES;
|
||||
daemon->edns_pktsz = EDNS_PKTSZ;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!f)
|
||||
@@ -274,7 +284,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
for (i=0; optmap[i].c; i++)
|
||||
if (option == optmap[i].c)
|
||||
{
|
||||
flags |= optmap[i].flag;
|
||||
daemon->options |= optmap[i].flag;
|
||||
option = 0;
|
||||
if (f && optarg)
|
||||
{
|
||||
@@ -319,13 +329,13 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
goto fileopen;
|
||||
|
||||
case 'x':
|
||||
*runfile = safe_string_alloc(optarg);
|
||||
daemon->runfile = safe_string_alloc(optarg);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
{
|
||||
char *name = safe_string_alloc(optarg);
|
||||
struct resolvc *new, *list = *resolv_files;
|
||||
struct resolvc *new, *list = daemon->resolv_files;
|
||||
if (list && list->is_default)
|
||||
{
|
||||
/* replace default resolv file - possibly with nothing */
|
||||
@@ -346,7 +356,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
new->logged = 0;
|
||||
list = new;
|
||||
}
|
||||
*resolv_files = list;
|
||||
daemon->resolv_files = list;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -360,8 +370,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
else
|
||||
{
|
||||
struct mx_record *new = safe_malloc(sizeof(struct mx_record));
|
||||
new->next = *mxnames;
|
||||
*mxnames = new;
|
||||
new->next = daemon->mxnames;
|
||||
daemon->mxnames = new;
|
||||
new->mxname = safe_string_alloc(optarg);
|
||||
new->mxtarget = safe_string_alloc(comma); /* may be NULL */
|
||||
}
|
||||
@@ -372,59 +382,59 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
if (!canonicalise(optarg))
|
||||
option = '?';
|
||||
else
|
||||
*mxtarget = safe_string_alloc(optarg);
|
||||
daemon->mxtarget = safe_string_alloc(optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
*lease_file = safe_string_alloc(optarg);
|
||||
daemon->lease_file = safe_string_alloc(optarg);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
if (*addn_hosts)
|
||||
if (daemon->addn_hosts)
|
||||
option = '?';
|
||||
else
|
||||
*addn_hosts = safe_string_alloc(optarg);
|
||||
daemon->addn_hosts = safe_string_alloc(optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (strcmp (optarg, "#") == 0)
|
||||
flags |= OPT_RESOLV_DOMAIN;
|
||||
daemon->options |= OPT_RESOLV_DOMAIN;
|
||||
else if (!canonicalise(optarg))
|
||||
option = '?';
|
||||
else
|
||||
*domain_suffix = safe_string_alloc(optarg);
|
||||
daemon->domain_suffix = safe_string_alloc(optarg);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
*username = safe_string_alloc(optarg);
|
||||
daemon->username = safe_string_alloc(optarg);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
*groupname = safe_string_alloc(optarg);
|
||||
daemon->groupname = safe_string_alloc(optarg);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
{
|
||||
struct iname *new = safe_malloc(sizeof(struct iname));
|
||||
new->next = *if_names;
|
||||
*if_names = new;
|
||||
new->next = daemon->if_names;
|
||||
daemon->if_names = new;
|
||||
/* new->name may be NULL if someone does
|
||||
"interface=" to disable all interfaces except loop. */
|
||||
new->name = safe_string_alloc(optarg);
|
||||
new->isloop = new->used = 0;
|
||||
if (strchr(optarg, ':'))
|
||||
flags |= OPT_NOWILD;
|
||||
daemon->options |= OPT_NOWILD;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'I':
|
||||
{
|
||||
struct iname *new = safe_malloc(sizeof(struct iname));
|
||||
new->next = *if_except;
|
||||
*if_except = new;
|
||||
new->next = daemon->if_except;
|
||||
daemon->if_except = new;
|
||||
new->name = safe_string_alloc(optarg);
|
||||
if (strchr(optarg, ':'))
|
||||
flags |= OPT_NOWILD;
|
||||
daemon->options |= OPT_NOWILD;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -434,8 +444,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
if ((addr.s_addr = inet_addr(optarg)) != (in_addr_t)-1)
|
||||
{
|
||||
struct bogus_addr *baddr = safe_malloc(sizeof(struct bogus_addr));
|
||||
baddr->next = *bogus_addr;
|
||||
*bogus_addr = baddr;
|
||||
baddr->next = daemon->bogus_addr;
|
||||
daemon->bogus_addr = baddr;
|
||||
baddr->addr = addr;
|
||||
}
|
||||
else
|
||||
@@ -446,7 +456,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
case 'a':
|
||||
{
|
||||
struct iname *new = safe_malloc(sizeof(struct iname));
|
||||
new->next = *if_addrs;
|
||||
new->next = daemon->if_addrs;
|
||||
#ifdef HAVE_IPV6
|
||||
if (inet_pton(AF_INET, optarg, &new->addr.in.sin_addr))
|
||||
{
|
||||
@@ -480,7 +490,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
}
|
||||
|
||||
if (new)
|
||||
*if_addrs = new;
|
||||
daemon->if_addrs = new;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -633,8 +643,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
serv->next->source_addr = serv->source_addr;
|
||||
serv = serv->next;
|
||||
}
|
||||
serv->next = *serv_addrs;
|
||||
*serv_addrs = newlist;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = newlist;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -653,13 +663,13 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
else if (size > 10000)
|
||||
size = 10000;
|
||||
|
||||
*cachesize = size;
|
||||
daemon->cachesize = size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p':
|
||||
if (!atoi_check(optarg, port))
|
||||
if (!atoi_check(optarg, &daemon->port))
|
||||
option = '?';
|
||||
break;
|
||||
|
||||
@@ -668,12 +678,12 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
int i;
|
||||
if (!atoi_check(optarg, &i))
|
||||
option = '?';
|
||||
*edns_pktsz = (unsigned short)i;
|
||||
daemon->edns_pktsz = (unsigned short)i;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Q':
|
||||
if (!atoi_check(optarg, query_port))
|
||||
if (!atoi_check(optarg, &daemon->query_port))
|
||||
option = '?';
|
||||
break;
|
||||
|
||||
@@ -683,12 +693,12 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
if (!atoi_check(optarg, &ttl))
|
||||
option = '?';
|
||||
else
|
||||
*local_ttl = (unsigned long)ttl;
|
||||
daemon->local_ttl = (unsigned long)ttl;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'X':
|
||||
if (!atoi_check(optarg, dhcp_max))
|
||||
if (!atoi_check(optarg, &daemon->dhcp_max))
|
||||
option = '?';
|
||||
break;
|
||||
|
||||
@@ -698,13 +708,14 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
char *cp, *comma, *a[5] = { NULL, NULL, NULL, NULL, NULL };
|
||||
struct dhcp_context *new = safe_malloc(sizeof(struct dhcp_context));
|
||||
|
||||
new->next = *dhcp;
|
||||
new->next = daemon->dhcp;
|
||||
new->lease_time = DEFLEASE;
|
||||
new->addr_epoch = 0;
|
||||
new->netmask.s_addr = 0;
|
||||
new->broadcast.s_addr = 0;
|
||||
new->router.s_addr = 0;
|
||||
new->netid.net = NULL;
|
||||
|
||||
new->static_only = 0;
|
||||
|
||||
for (cp = optarg; *cp; cp++)
|
||||
if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
|
||||
@@ -730,17 +741,27 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
|
||||
option = '?';
|
||||
else if (strcmp(a[1], "static") == 0)
|
||||
new->end = new->start;
|
||||
{
|
||||
new->end = new->start;
|
||||
new->static_only = 1;
|
||||
}
|
||||
else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
|
||||
option = '?';
|
||||
|
||||
if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
|
||||
{
|
||||
struct in_addr tmp = new->start;
|
||||
new->start = new->end;
|
||||
new->end = tmp;
|
||||
}
|
||||
|
||||
if (option == '?')
|
||||
{
|
||||
free(new);
|
||||
break;
|
||||
}
|
||||
else
|
||||
*dhcp = new;
|
||||
daemon->dhcp = new;
|
||||
|
||||
if (k >= 3 && strchr(a[2], '.') &&
|
||||
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
|
||||
@@ -779,8 +800,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
}
|
||||
}
|
||||
|
||||
if (new->lease_time < *min_leasetime)
|
||||
*min_leasetime = new->lease_time;
|
||||
if (new->lease_time < daemon->min_leasetime)
|
||||
daemon->min_leasetime = new->lease_time;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -792,7 +813,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
struct dhcp_config *new = safe_malloc(sizeof(struct dhcp_config));
|
||||
struct in_addr in;
|
||||
|
||||
new->next = *dhcp_conf;
|
||||
new->next = daemon->dhcp_conf;
|
||||
new->flags = 0;
|
||||
|
||||
|
||||
@@ -944,9 +965,9 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((new->flags & CONFIG_TIME) && new->lease_time < *min_leasetime)
|
||||
*min_leasetime = new->lease_time;
|
||||
*dhcp_conf = new;
|
||||
if ((new->flags & CONFIG_TIME) && new->lease_time < daemon->min_leasetime)
|
||||
daemon->min_leasetime = new->lease_time;
|
||||
daemon->dhcp_conf = new;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -957,7 +978,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
char *cp, *comma;
|
||||
int addrs, digs, is_addr, is_hex, is_dec;
|
||||
|
||||
new->next = *dhcp_opts;
|
||||
new->next = daemon->dhcp_opts;
|
||||
new->len = 0;
|
||||
new->is_addr = 0;
|
||||
new->netid = NULL;
|
||||
@@ -988,7 +1009,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
break;
|
||||
}
|
||||
|
||||
*dhcp_opts = new;
|
||||
daemon->dhcp_opts = new;
|
||||
|
||||
if (!comma)
|
||||
break;
|
||||
@@ -1045,7 +1066,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
else if (is_dec)
|
||||
{
|
||||
/* Given that we don't know the length,
|
||||
this applaing hack is the best available */
|
||||
this appaling hack is the best available */
|
||||
unsigned int val = atoi(comma+1);
|
||||
if (val < 256)
|
||||
{
|
||||
@@ -1103,14 +1124,14 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*comma = 0;
|
||||
*dhcp_file = safe_string_alloc(optarg);
|
||||
daemon->dhcp_file = safe_string_alloc(optarg);
|
||||
if (comma)
|
||||
{
|
||||
optarg = comma+1;
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*comma = 0;
|
||||
*dhcp_sname = safe_string_alloc(optarg);
|
||||
if (comma && (dhcp_next_server->s_addr = inet_addr(comma+1)) == (in_addr_t)-1)
|
||||
daemon->dhcp_sname = safe_string_alloc(optarg);
|
||||
if (comma && (daemon->dhcp_next_server.s_addr = inet_addr(comma+1)) == (in_addr_t)-1)
|
||||
option = '?';
|
||||
}
|
||||
break;
|
||||
@@ -1132,8 +1153,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
new->data = safe_malloc(new->len);
|
||||
memcpy(new->data, comma+1, new->len);
|
||||
new->is_vendor = (option == 'U');
|
||||
new->next = *dhcp_vendors;
|
||||
*dhcp_vendors = new;
|
||||
new->next = daemon->dhcp_vendors;
|
||||
daemon->dhcp_vendors = new;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1170,8 +1191,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
new->in = in;
|
||||
new->out = out;
|
||||
new->mask = mask;
|
||||
new->next = *doctors;
|
||||
*doctors = new;
|
||||
new->next = daemon->doctors;
|
||||
daemon->doctors = new;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1191,66 +1212,66 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
}
|
||||
|
||||
/* port might no be known when the address is parsed - fill in here */
|
||||
if (*serv_addrs)
|
||||
if (daemon->servers)
|
||||
{
|
||||
struct server *tmp;
|
||||
for (tmp = *serv_addrs; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->servers; tmp; tmp = tmp->next)
|
||||
if (!(tmp->flags & SERV_HAS_SOURCE))
|
||||
{
|
||||
if (tmp->source_addr.sa.sa_family == AF_INET)
|
||||
tmp->source_addr.in.sin_port = htons(*query_port);
|
||||
tmp->source_addr.in.sin_port = htons(daemon->query_port);
|
||||
#ifdef HAVE_IPV6
|
||||
else if (tmp->source_addr.sa.sa_family == AF_INET6)
|
||||
tmp->source_addr.in6.sin6_port = htons(*query_port);
|
||||
tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (*if_addrs)
|
||||
if (daemon->if_addrs)
|
||||
{
|
||||
struct iname *tmp;
|
||||
for(tmp = *if_addrs; tmp; tmp = tmp->next)
|
||||
for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == AF_INET)
|
||||
tmp->addr.in.sin_port = htons(*port);
|
||||
tmp->addr.in.sin_port = htons(daemon->port);
|
||||
#ifdef HAVE_IPV6
|
||||
else if (tmp->addr.sa.sa_family == AF_INET6)
|
||||
tmp->addr.in6.sin6_port = htons(*port);
|
||||
tmp->addr.in6.sin6_port = htons(daemon->port);
|
||||
#endif /* IPv6 */
|
||||
}
|
||||
|
||||
/* only one of these need be specified: the other defaults to the
|
||||
host-name */
|
||||
if ((flags & OPT_LOCALMX) || *mxnames || *mxtarget)
|
||||
if ((daemon->options & OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
|
||||
{
|
||||
if (gethostname(buff, MAXDNAME) == -1)
|
||||
die("cannot get host-name: %s", NULL);
|
||||
|
||||
if (!*mxnames)
|
||||
if (!daemon->mxnames)
|
||||
{
|
||||
*mxnames = safe_malloc(sizeof(struct mx_record));
|
||||
(*mxnames)->next = NULL;
|
||||
(*mxnames)->mxtarget = NULL;
|
||||
(*mxnames)->mxname = safe_string_alloc(buff);
|
||||
}
|
||||
daemon->mxnames = safe_malloc(sizeof(struct mx_record));
|
||||
daemon->mxnames->next = NULL;
|
||||
daemon->mxnames->mxtarget = NULL;
|
||||
daemon->mxnames->mxname = safe_string_alloc(buff);
|
||||
}
|
||||
|
||||
if (!*mxtarget)
|
||||
*mxtarget = safe_string_alloc(buff);
|
||||
if (!daemon->mxtarget)
|
||||
daemon->mxtarget = safe_string_alloc(buff);
|
||||
}
|
||||
|
||||
if (flags & OPT_NO_RESOLV)
|
||||
*resolv_files = 0;
|
||||
else if (*resolv_files && (*resolv_files)->next && (flags & OPT_NO_POLL))
|
||||
if (daemon->options & OPT_NO_RESOLV)
|
||||
daemon->resolv_files = 0;
|
||||
else if (daemon->resolv_files && (daemon->resolv_files)->next && (daemon->options & OPT_NO_POLL))
|
||||
die("only one resolv.conf file allowed in no-poll mode.", NULL);
|
||||
|
||||
if (flags & OPT_RESOLV_DOMAIN)
|
||||
if (daemon->options & OPT_RESOLV_DOMAIN)
|
||||
{
|
||||
char *line;
|
||||
|
||||
if (!*resolv_files || (*resolv_files)->next)
|
||||
if (!daemon->resolv_files || (daemon->resolv_files)->next)
|
||||
die("must have exactly one resolv.conf to read domain from.", NULL);
|
||||
|
||||
if (!(f = fopen((*resolv_files)->name, "r")))
|
||||
die("failed to read %s: %m", (*resolv_files)->name);
|
||||
if (!(f = fopen((daemon->resolv_files)->name, "r")))
|
||||
die("failed to read %s: %m", (daemon->resolv_files)->name);
|
||||
|
||||
while ((line = fgets(buff, MAXDNAME, f)))
|
||||
{
|
||||
@@ -1261,17 +1282,17 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
|
||||
if ((token = strtok(NULL, " \t\n\r")) &&
|
||||
canonicalise(token) &&
|
||||
(*domain_suffix = safe_string_alloc(token)))
|
||||
(daemon->domain_suffix = safe_string_alloc(token)))
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (!*domain_suffix)
|
||||
die("no search directive found in %s", (*resolv_files)->name);
|
||||
if (!daemon->domain_suffix)
|
||||
die("no search directive found in %s", (daemon->resolv_files)->name);
|
||||
}
|
||||
|
||||
return flags;
|
||||
return daemon;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ unsigned char *find_pseudoheader(HEADER *header, unsigned int plen)
|
||||
GETSHORT(rdlen, ansp);
|
||||
if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
|
||||
return NULL;
|
||||
if (type == ns_t_opt)
|
||||
if (type == T_OPT)
|
||||
return save;
|
||||
ansp += rdlen;
|
||||
}
|
||||
@@ -788,10 +788,9 @@ int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
|
||||
}
|
||||
|
||||
/* return zero if we can't answer from cache, or packet size if we can */
|
||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_record *mxnames,
|
||||
char *mxtarget, unsigned int options, time_t now,
|
||||
unsigned long local_ttl, char *name, unsigned short edns_pcktsz)
|
||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon *daemon, time_t now)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp, *pheader;
|
||||
int qtype, qclass, is_arpa;
|
||||
struct all_addr addr;
|
||||
@@ -827,8 +826,8 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec
|
||||
than we allow, trim it so that we don't get an overlarge
|
||||
response from upstream */
|
||||
|
||||
if (udpsz > edns_pcktsz)
|
||||
PUTSHORT(edns_pcktsz, psave);
|
||||
if (udpsz > daemon->edns_pktsz)
|
||||
PUTSHORT(daemon->edns_pktsz, psave);
|
||||
|
||||
dryrun = 1;
|
||||
}
|
||||
@@ -889,7 +888,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec
|
||||
}
|
||||
else if (qclass == C_IN)
|
||||
{
|
||||
if ((options & OPT_FILTER) &&
|
||||
if ((daemon->options & OPT_FILTER) &&
|
||||
(qtype == T_SOA || qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||
{
|
||||
ans = 1;
|
||||
@@ -901,7 +900,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec
|
||||
{
|
||||
if (!(crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
|
||||
{
|
||||
if (is_arpa == F_IPV4 && (options & OPT_BOGUSPRIV) && private_net(&addr))
|
||||
if (is_arpa == F_IPV4 && (daemon->options & OPT_BOGUSPRIV) && private_net(&addr))
|
||||
{
|
||||
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||
ans = 1;
|
||||
@@ -938,7 +937,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec
|
||||
/* Return 0 ttl for DHCP entries, which might change
|
||||
before the lease expires. */
|
||||
if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
||||
ttl = local_ttl;
|
||||
ttl = daemon->local_ttl;
|
||||
else
|
||||
ttl = crecp->ttd - now;
|
||||
|
||||
@@ -1004,7 +1003,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec
|
||||
unsigned long ttl;
|
||||
|
||||
if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
||||
ttl = local_ttl;
|
||||
ttl = daemon->local_ttl;
|
||||
else
|
||||
ttl = crecp->ttd - now;
|
||||
|
||||
@@ -1033,7 +1032,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec
|
||||
if (qtype == T_MX || qtype == T_ANY)
|
||||
{
|
||||
struct mx_record *mx;
|
||||
for (mx = mxnames; mx; mx = mx->next)
|
||||
for (mx = daemon->mxnames; mx; mx = mx->next)
|
||||
if (hostname_isequal(name, mx->mxname))
|
||||
break;
|
||||
if (mx)
|
||||
@@ -1041,19 +1040,19 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
ansp = add_text_record(nameoffset, ansp, local_ttl, 1, T_MX,
|
||||
mx->mxtarget ? mx->mxtarget : mxtarget);
|
||||
ansp = add_text_record(nameoffset, ansp, daemon->local_ttl, 1, T_MX,
|
||||
mx->mxtarget ? mx->mxtarget : daemon->mxtarget);
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
else if ((options & (OPT_SELFMX | OPT_LOCALMX)) &&
|
||||
else if ((daemon->options & (OPT_SELFMX | OPT_LOCALMX)) &&
|
||||
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
ansp = add_text_record(nameoffset, ansp, local_ttl, 1, T_MX,
|
||||
(options & OPT_SELFMX) ? name : mxtarget);
|
||||
ansp = add_text_record(nameoffset, ansp, daemon->local_ttl, 1, T_MX,
|
||||
(daemon->options & OPT_SELFMX) ? name : daemon->mxtarget);
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
316
src/rfc2131.c
316
src/rfc2131.c
@@ -42,6 +42,7 @@
|
||||
#define OPTION_VENDOR_ID 60
|
||||
#define OPTION_CLIENT_ID 61
|
||||
#define OPTION_USER_CLASS 77
|
||||
#define OPTION_SUBNET_SELECT 118
|
||||
#define OPTION_END 255
|
||||
|
||||
#define DHCPDISCOVER 1
|
||||
@@ -66,53 +67,47 @@ static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_ty
|
||||
static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
unsigned char *p, unsigned char *end,
|
||||
unsigned char *req_options,
|
||||
struct dhcp_opt *config_opts,
|
||||
char *domainname, char *hostname,
|
||||
struct in_addr router,
|
||||
struct daemon *daemon,
|
||||
char *hostname,
|
||||
struct in_addr iface_addr,
|
||||
int iface_mtu, struct dhcp_netid *netid);
|
||||
struct dhcp_netid *netid,
|
||||
struct in_addr subnet_addr);
|
||||
|
||||
static int have_config(struct dhcp_config *config, unsigned int mask)
|
||||
{
|
||||
return config && (config->flags & mask);
|
||||
}
|
||||
|
||||
int dhcp_reply(struct dhcp_context *context,
|
||||
struct in_addr iface_addr,
|
||||
char *iface_name,
|
||||
int iface_mtu,
|
||||
struct udp_dhcp_packet *rawpacket,
|
||||
unsigned int sz, time_t now, char *namebuff,
|
||||
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
||||
struct dhcp_vendor *vendors,
|
||||
char *domain_suffix, char *dhcp_file, char *dhcp_sname,
|
||||
struct in_addr dhcp_next_server, struct in_addr router)
|
||||
int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_name, unsigned int sz, time_t now)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
unsigned char *opt, *clid;
|
||||
struct dhcp_lease *lease, *ltmp;
|
||||
struct dhcp_vendor *vendor;
|
||||
int clid_len;
|
||||
struct dhcp_packet *mess = &rawpacket->data;
|
||||
unsigned char *p = mess->options;
|
||||
/* default max reply packet length, max be overridden */
|
||||
unsigned char *end = (unsigned char *)(rawpacket + 1);
|
||||
struct dhcp_packet *mess = &daemon->dhcp_packet->data;
|
||||
unsigned char *p = mess->options + sizeof(u32); /* skip cookie */
|
||||
unsigned char *end = (unsigned char *)(daemon->dhcp_packet + 1);
|
||||
char *hostname = NULL;
|
||||
char *req_options = NULL;
|
||||
char *message = NULL;
|
||||
unsigned int renewal_time, expires_time, def_time;
|
||||
struct dhcp_config *config;
|
||||
struct dhcp_netid *netid = NULL;
|
||||
struct in_addr addr;
|
||||
struct in_addr addr, subnet_addr;
|
||||
unsigned short fuzz = 0;
|
||||
unsigned int mess_type = 0;
|
||||
|
||||
if (mess->op != BOOTREQUEST || mess->cookie != htonl(DHCP_COOKIE))
|
||||
subnet_addr.s_addr = 0;
|
||||
|
||||
if (mess->op != BOOTREQUEST)
|
||||
return 0;
|
||||
|
||||
/* Token ring is supported when we have packet sockets
|
||||
to make the HW headers for us. We don't have the code to build
|
||||
token ring headers when using BPF. We rely on the fact that
|
||||
token ring hwaddrs are the same size as ethernet hwaddrs. */
|
||||
|
||||
|
||||
#ifdef HAVE_BPF
|
||||
if (mess->htype != ARPHRD_ETHER)
|
||||
#else
|
||||
@@ -123,23 +118,100 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
mess->htype, iface_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (mess->hlen != ETHER_ADDR_LEN)
|
||||
return 0;
|
||||
|
||||
mess->op = BOOTREPLY;
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_MAXMESSAGE)))
|
||||
|
||||
/* check for DHCP rather than BOOTP */
|
||||
if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE)))
|
||||
{
|
||||
int maxsize = (int)option_uint(opt, 2);
|
||||
if (maxsize > DNSMASQ_PACKETSZ)
|
||||
maxsize = DNSMASQ_PACKETSZ;
|
||||
if (maxsize > iface_mtu)
|
||||
maxsize = iface_mtu;
|
||||
mess_type = option_uint(opt, 1);
|
||||
|
||||
end = ((unsigned char *)rawpacket) + maxsize;
|
||||
/* only insist on a cookie for DHCP. */
|
||||
if (*((u32 *)&mess->options) != htonl(DHCP_COOKIE))
|
||||
return 0;
|
||||
|
||||
/* Some buggy clients set ciaddr when they shouldn't, so clear that here since
|
||||
it can affect the context-determination code. */
|
||||
if ((option_find(mess, sz, OPTION_REQUESTED_IP) || mess_type == DHCPDISCOVER))
|
||||
mess->ciaddr.s_addr = 0;
|
||||
|
||||
/* Check for RFC3011 subnet selector */
|
||||
if ((opt = option_find(mess, sz, OPTION_SUBNET_SELECT)))
|
||||
subnet_addr = option_addr(opt);
|
||||
}
|
||||
|
||||
|
||||
/* Determine network for this packet. If the machine has an address already, and we don't have
|
||||
have a giaddr or explicit subnet selector, use the ciaddr. This is necessary because a
|
||||
machine which got a lease via a relay won't use the relay to renew. */
|
||||
addr =
|
||||
subnet_addr.s_addr ? subnet_addr :
|
||||
(mess->giaddr.s_addr ? mess->giaddr :
|
||||
(mess->ciaddr.s_addr ? mess->ciaddr : iface_addr));
|
||||
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
if (context->netmask.s_addr &&
|
||||
is_same_net(addr, context->start, context->netmask) &&
|
||||
is_same_net(addr, context->end, context->netmask))
|
||||
break;
|
||||
|
||||
if (!context)
|
||||
{
|
||||
syslog(LOG_WARNING, "no address range available for DHCP request %s %s",
|
||||
subnet_addr.s_addr ? "with subnet selector" : "via",
|
||||
subnet_addr.s_addr ? inet_ntoa(subnet_addr) : (mess->giaddr.s_addr ? inet_ntoa(mess->giaddr) : iface_name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
mess->op = BOOTREPLY;
|
||||
|
||||
/* start to build netid chain */
|
||||
if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
}
|
||||
|
||||
if (mess_type == 0)
|
||||
{
|
||||
/* BOOTP request */
|
||||
config = find_config(daemon->dhcp_conf, context, NULL, 0, mess->chaddr, NULL);
|
||||
if (have_config(config, CONFIG_ADDR) &&
|
||||
!have_config(config, CONFIG_DISABLE) &&
|
||||
!lease_find_by_addr(config->addr))
|
||||
{
|
||||
struct dhcp_netid id;
|
||||
char save = mess->file[128];
|
||||
end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
|
||||
mess->yiaddr = config->addr;
|
||||
mess->siaddr = daemon->dhcp_next_server.s_addr ? daemon->dhcp_next_server : iface_addr;
|
||||
if (have_config(config, CONFIG_NAME))
|
||||
hostname = config->hostname;
|
||||
if (have_config(config, CONFIG_NETID))
|
||||
{
|
||||
config->netid.next = netid;
|
||||
netid = &config->netid;
|
||||
}
|
||||
/* Match incoming filename field as a netid. */
|
||||
if (mess->file[0])
|
||||
{
|
||||
mess->file[128] = 0; /* ensure zero term. */
|
||||
id.net = mess->file;
|
||||
id.next = netid;
|
||||
netid = &id;
|
||||
}
|
||||
p = do_req_options(context, p, end, NULL, daemon,
|
||||
hostname, iface_addr, netid, subnet_addr);
|
||||
/* must do this after do_req_options since it overwrites filename field. */
|
||||
bootp_option_put(mess, daemon->dhcp_file, daemon->dhcp_sname);
|
||||
p = option_end(p, end, mess);
|
||||
log_packet(NULL, &config->addr, mess->chaddr, iface_name, NULL);
|
||||
mess->file[128] = save;
|
||||
return p - (unsigned char *)mess;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If there is no client identifier option, use the hardware address */
|
||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID)))
|
||||
{
|
||||
@@ -152,16 +224,14 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
clid_len = 0;
|
||||
}
|
||||
|
||||
config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, NULL);
|
||||
config = find_config(daemon->dhcp_conf, context, clid, clid_len, mess->chaddr, NULL);
|
||||
|
||||
if (have_config(config, CONFIG_NAME))
|
||||
hostname = config->hostname;
|
||||
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME)))
|
||||
{
|
||||
int len = option_len(opt);
|
||||
/* namebuff is 1K long, use half for requested options and half for hostname */
|
||||
/* len < 256 by definition */
|
||||
hostname = namebuff + 500;
|
||||
hostname = daemon->dhcp_buff;
|
||||
memcpy(hostname, option_ptr(opt), len);
|
||||
/* May not be zero terminated */
|
||||
hostname[len] = 0;
|
||||
@@ -173,7 +243,7 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
char *dot = strchr(hostname, '.');
|
||||
if (dot)
|
||||
{
|
||||
if (!domain_suffix || !hostname_isequal(dot+1, domain_suffix))
|
||||
if (!daemon->domain_suffix || !hostname_isequal(dot+1, daemon->domain_suffix))
|
||||
{
|
||||
syslog(LOG_WARNING, "Ignoring DHCP host name %s because it has an illegal domain part", hostname);
|
||||
hostname = NULL;
|
||||
@@ -191,7 +261,7 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
to avoid impersonation by name. */
|
||||
if (!config)
|
||||
{
|
||||
struct dhcp_config *new = find_config(dhcp_configs, context, NULL, 0, mess->chaddr, hostname);
|
||||
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0, mess->chaddr, hostname);
|
||||
if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
|
||||
config = new;
|
||||
}
|
||||
@@ -200,12 +270,6 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
|
||||
def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
|
||||
|
||||
if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
}
|
||||
|
||||
if (have_config(config, CONFIG_NETID))
|
||||
{
|
||||
config->netid.next = netid;
|
||||
@@ -214,11 +278,11 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
|
||||
/* Theres a chance that carefully chosen data could match the same
|
||||
vendor/user option twice and make a loop in the netid chain. */
|
||||
for (vendor = vendors; vendor; vendor = vendor->next)
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
vendor->used = 0;
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID)))
|
||||
for (vendor = vendors; vendor; vendor = vendor->next)
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
if (vendor->is_vendor && !vendor->used)
|
||||
{
|
||||
int i;
|
||||
@@ -237,7 +301,7 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
unsigned char *ucp = option_ptr(opt);
|
||||
int j;
|
||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1)
|
||||
for (vendor = vendors; vendor; vendor = vendor->next)
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
if (!vendor->is_vendor && !vendor->used)
|
||||
{
|
||||
int i;
|
||||
@@ -284,15 +348,12 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS)))
|
||||
{
|
||||
int len = option_len(opt);
|
||||
req_options = namebuff;
|
||||
req_options = daemon->dhcp_buff2;
|
||||
memcpy(req_options, option_ptr(opt), len);
|
||||
req_options[len] = OPTION_END;
|
||||
}
|
||||
|
||||
if (!(opt = option_find(mess, sz, OPTION_MESSAGE_TYPE)))
|
||||
return 0;
|
||||
|
||||
switch (option_uint(opt, 1))
|
||||
switch (mess_type)
|
||||
{
|
||||
case DHCPDECLINE:
|
||||
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)) ||
|
||||
@@ -302,7 +363,7 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
/* sanitise any message. Paranoid? Moi? */
|
||||
if ((opt = option_find(mess, sz, OPTION_MESSAGE)))
|
||||
{
|
||||
char *p = option_ptr(opt), *q = namebuff;
|
||||
char *p = option_ptr(opt), *q = daemon->dhcp_buff;
|
||||
int i;
|
||||
|
||||
for (i = option_len(opt); i > 0; i--)
|
||||
@@ -312,7 +373,7 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
*q++ = c;
|
||||
}
|
||||
*q++ = 0; /* add terminator */
|
||||
message = namebuff;
|
||||
message = daemon->dhcp_buff;
|
||||
}
|
||||
|
||||
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
||||
@@ -353,24 +414,22 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
if (have_config(config, CONFIG_DISABLE))
|
||||
message = "ignored";
|
||||
else if (have_config(config, CONFIG_ADDR) &&
|
||||
(!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
|
||||
(!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
|
||||
mess->yiaddr = config->addr;
|
||||
else if (lease && address_available(context, lease->addr))
|
||||
mess->yiaddr = lease->addr;
|
||||
else if (opt && address_available(context, addr) && !lease_find_by_addr(addr) &&
|
||||
!config_find_by_address(dhcp_configs, addr))
|
||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
||||
mess->yiaddr = addr;
|
||||
else if (!address_allocate(context, dhcp_configs, &mess->yiaddr, mess->chaddr))
|
||||
else if (!address_allocate(context, daemon, &mess->yiaddr, mess->chaddr))
|
||||
message = "no address available";
|
||||
log_packet("DISCOVER", opt ? &addr : NULL, mess->chaddr, iface_name, message);
|
||||
|
||||
if (message)
|
||||
return 0;
|
||||
|
||||
/* ensure that we send the reply by steam even if a buggy client sets this. */
|
||||
mess->ciaddr.s_addr = 0;
|
||||
bootp_option_put(mess, dhcp_file, dhcp_sname);
|
||||
mess->siaddr = dhcp_next_server.s_addr ? dhcp_next_server : iface_addr;
|
||||
bootp_option_put(mess, daemon->dhcp_file, daemon->dhcp_sname);
|
||||
mess->siaddr = daemon->dhcp_next_server.s_addr ? daemon->dhcp_next_server : iface_addr;
|
||||
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
||||
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);
|
||||
@@ -380,8 +439,8 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
p = option_put(p, end, OPTION_T1, 4, (expires_time/2));
|
||||
p = option_put(p, end, OPTION_T2, 4, ((expires_time * 7)/8));
|
||||
}
|
||||
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
|
||||
NULL, router, iface_addr, iface_mtu, netid);
|
||||
p = do_req_options(context, p, end, req_options, daemon,
|
||||
NULL, iface_addr, netid, subnet_addr);
|
||||
p = option_end(p, end, mess);
|
||||
|
||||
log_packet("OFFER" , &mess->yiaddr, mess->chaddr, iface_name, NULL);
|
||||
@@ -394,44 +453,51 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
{
|
||||
/* SELECTING or INIT_REBOOT */
|
||||
mess->yiaddr = option_addr(opt);
|
||||
/* The RFC says that this is already zero, but there exist
|
||||
real-world counter examples. */
|
||||
mess->ciaddr.s_addr = 0;
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)) &&
|
||||
(iface_addr.s_addr != option_addr(opt).s_addr))
|
||||
return 0;
|
||||
|
||||
/* If a lease exists for this host and another address, squash it. */
|
||||
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
|
||||
if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)))
|
||||
{
|
||||
lease_prune(lease, now);
|
||||
lease = NULL;
|
||||
/* SELECTING */
|
||||
if (iface_addr.s_addr != option_addr(opt).s_addr)
|
||||
return 0;
|
||||
|
||||
/* If a lease exists for this host and another address, squash it. */
|
||||
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
|
||||
{
|
||||
lease_prune(lease, now);
|
||||
lease = NULL;
|
||||
}
|
||||
|
||||
if (!lease)
|
||||
{
|
||||
if (lease_find_by_addr(mess->yiaddr))
|
||||
message = "address in use";
|
||||
else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
|
||||
message = "no leases left";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INIT-REBOOT */
|
||||
if (!lease)
|
||||
return 0;
|
||||
|
||||
if (lease->addr.s_addr != mess->yiaddr.s_addr)
|
||||
message = "wrong address";
|
||||
}
|
||||
|
||||
if (!lease)
|
||||
{
|
||||
if (lease_find_by_addr(mess->yiaddr))
|
||||
message = "address in use";
|
||||
else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
|
||||
message = "no leases left";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* RENEWING or REBINDING */
|
||||
/* Must exist a lease for this address */
|
||||
if (!mess->ciaddr.s_addr)
|
||||
return 0;
|
||||
|
||||
mess->yiaddr = mess->ciaddr;
|
||||
if (!lease || mess->ciaddr.s_addr != lease->addr.s_addr)
|
||||
message = "lease not found";
|
||||
|
||||
/* desynchronise renewals */
|
||||
fuzz = rand16();
|
||||
while (fuzz > (renewal_time/16))
|
||||
fuzz = fuzz/2;
|
||||
fuzz = fuzz/2;
|
||||
|
||||
mess->yiaddr = mess->ciaddr;
|
||||
}
|
||||
|
||||
if (!message)
|
||||
@@ -454,7 +520,7 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
message = "static lease available";
|
||||
|
||||
/* Check to see if the address is reserved as a static address for another host */
|
||||
else if ((addr_config = config_find_by_address(dhcp_configs, mess->yiaddr)) && addr_config != config)
|
||||
else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
|
||||
message ="address reserved";
|
||||
}
|
||||
|
||||
@@ -464,8 +530,6 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
{
|
||||
log_packet("NAK", &mess->yiaddr, mess->chaddr, iface_name, message);
|
||||
|
||||
lease_prune(lease, now);
|
||||
|
||||
mess->siaddr.s_addr = mess->yiaddr.s_addr = mess->ciaddr.s_addr = 0;
|
||||
bootp_option_put(mess, NULL, NULL);
|
||||
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
|
||||
@@ -479,11 +543,11 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
|
||||
lease_set_hwaddr(lease, mess->chaddr);
|
||||
if (hostname)
|
||||
lease_set_hostname(lease, hostname, domain_suffix);
|
||||
lease_set_hostname(lease, hostname, daemon->domain_suffix);
|
||||
lease_set_expires(lease, renewal_time == 0xffffffff ? 0 : now + (time_t)renewal_time);
|
||||
|
||||
bootp_option_put(mess, dhcp_file, dhcp_sname);
|
||||
mess->siaddr = dhcp_next_server.s_addr ? dhcp_next_server : iface_addr;
|
||||
bootp_option_put(mess, daemon->dhcp_file, daemon->dhcp_sname);
|
||||
mess->siaddr = daemon->dhcp_next_server.s_addr ? daemon->dhcp_next_server : iface_addr;
|
||||
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 = option_put(p, end, OPTION_LEASE_TIME, 4, renewal_time);
|
||||
@@ -492,8 +556,8 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
p = option_put(p, end, OPTION_T1, 4, (renewal_time/2) - fuzz);
|
||||
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, router, iface_addr, iface_mtu, netid);
|
||||
p = do_req_options(context, p, end, req_options, daemon,
|
||||
hostname, iface_addr, netid, subnet_addr);
|
||||
p = option_end(p, end, mess);
|
||||
return p - (unsigned char *)mess;
|
||||
|
||||
@@ -508,8 +572,8 @@ 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, router, iface_addr, iface_mtu, netid);
|
||||
p = do_req_options(context, p, end, req_options, daemon,
|
||||
hostname, iface_addr, netid, subnet_addr);
|
||||
p = option_end(p, end, mess);
|
||||
|
||||
log_packet("ACK", &mess->ciaddr, mess->chaddr, iface_name, hostname);
|
||||
@@ -521,8 +585,9 @@ int dhcp_reply(struct dhcp_context *context,
|
||||
|
||||
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string)
|
||||
{
|
||||
syslog(LOG_INFO, "DHCP%s(%s)%s%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x%s%s",
|
||||
type,
|
||||
syslog(LOG_INFO, "%s%s(%s)%s%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x%s%s",
|
||||
type ? "DHCP" : "BOOTP",
|
||||
type ? type : "",
|
||||
interface,
|
||||
addr ? " " : "",
|
||||
addr ? inet_ntoa(*addr) : "",
|
||||
@@ -602,13 +667,16 @@ static unsigned char *option_end(unsigned char *p, unsigned char *end, struct dh
|
||||
|
||||
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string)
|
||||
{
|
||||
if (p + strlen(string) + 3 < end)
|
||||
int len = strlen(string);
|
||||
|
||||
if (p + len + 3 < end)
|
||||
{
|
||||
*(p++) = opt;
|
||||
*(p++) = strlen(string);
|
||||
memcpy(p, string, strlen(string));
|
||||
p += strlen(string);
|
||||
*(p++) = len;
|
||||
memcpy(p, string, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -653,7 +721,8 @@ static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_ty
|
||||
int overload = 0;
|
||||
unsigned char *ret;
|
||||
|
||||
ret = option_find1(&mess->options[0], ((unsigned char *)mess) + size, opt_type, &overload);
|
||||
/* skip over DHCP cookie; */
|
||||
ret = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, opt_type, &overload);
|
||||
|
||||
if (!ret && (overload & 1))
|
||||
ret = option_find1(&mess->file[0], &mess->file[128], opt_type, &overload);
|
||||
@@ -704,39 +773,46 @@ static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *
|
||||
static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
unsigned char *p, unsigned char *end,
|
||||
unsigned char *req_options,
|
||||
struct dhcp_opt *config_opts,
|
||||
char *domainname, char *hostname,
|
||||
struct in_addr router,
|
||||
struct daemon *daemon,
|
||||
char *hostname,
|
||||
struct in_addr iface_addr,
|
||||
int iface_mtu, struct dhcp_netid *netid)
|
||||
struct dhcp_netid *netid,
|
||||
struct in_addr subnet_addr)
|
||||
{
|
||||
struct dhcp_opt *opt;
|
||||
|
||||
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
||||
|
||||
if (in_list(req_options, OPTION_MAXMESSAGE))
|
||||
p = option_put(p, end, OPTION_MAXMESSAGE, 2,
|
||||
DNSMASQ_PACKETSZ > iface_mtu ?
|
||||
iface_mtu : DNSMASQ_PACKETSZ);
|
||||
p = option_put(p, end, OPTION_MAXMESSAGE, 2, end - (unsigned char *)daemon->dhcp_packet);
|
||||
|
||||
/* rfc3011 says this doesn't need to be in the requested options list. */
|
||||
if (subnet_addr.s_addr)
|
||||
p = option_put(p, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
|
||||
|
||||
if (in_list(req_options, OPTION_NETMASK) &&
|
||||
!option_find2(netid, config_opts, OPTION_NETMASK))
|
||||
p = option_put(p, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
|
||||
|
||||
if (in_list(req_options, OPTION_BROADCAST) &&
|
||||
/* May not have a "guessed" broadcast address if we got no packets via a relay
|
||||
from this net yet (ie just unicast renewals after a restart */
|
||||
if (context->broadcast.s_addr &&
|
||||
in_list(req_options, OPTION_BROADCAST) &&
|
||||
!option_find2(netid, config_opts, OPTION_BROADCAST))
|
||||
p = option_put(p, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
|
||||
|
||||
if (in_list(req_options, OPTION_ROUTER) &&
|
||||
/* Same comments as broadcast apply, and also may not be able to get a sensible
|
||||
default when using subnet select. User must configure by steam in that case. */
|
||||
if (context->router.s_addr &&
|
||||
in_list(req_options, OPTION_ROUTER) &&
|
||||
!option_find2(netid, config_opts, OPTION_ROUTER))
|
||||
p = option_put(p, end, OPTION_ROUTER, INADDRSZ,
|
||||
ntohl(router.s_addr));
|
||||
p = option_put(p, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
|
||||
|
||||
if (in_list(req_options, OPTION_DNSSERVER) &&
|
||||
!option_find2(netid, config_opts, OPTION_DNSSERVER))
|
||||
p = option_put(p, end, OPTION_DNSSERVER, INADDRSZ, ntohl(iface_addr.s_addr));
|
||||
|
||||
if (domainname && in_list(req_options, OPTION_DOMAINNAME) &&
|
||||
if (daemon->domain_suffix && in_list(req_options, OPTION_DOMAINNAME) &&
|
||||
!option_find2(netid, config_opts, OPTION_DOMAINNAME))
|
||||
p = option_put_string(p, end, OPTION_DOMAINNAME, domainname);
|
||||
p = option_put_string(p, end, OPTION_DOMAINNAME, daemon->domain_suffix);
|
||||
|
||||
/* Note that we ignore attempts to set the hostname using
|
||||
--dhcp-option=12,<name> */
|
||||
|
||||
Reference in New Issue
Block a user