mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.15.tar.gz
This commit is contained in:
24
CHANGELOG
24
CHANGELOG
@@ -1190,3 +1190,27 @@ version 2.14
|
||||
|
||||
Added "keep-in-foreground" option. Thanks to Sean
|
||||
MacLennan for the patch.
|
||||
|
||||
version 2.15
|
||||
Fixed NXDOMAIN/NODATA confusion for locally known
|
||||
names. We now return a NODATA reponse for names which are
|
||||
locally known. Now a query for (eg AAAA or MX) for a name
|
||||
with an IPv4 address in /etc/hosts which fails upstream
|
||||
will generate a NODATA response. Note that the query
|
||||
is still tried upstream, but a NXDOMAIN reply gets
|
||||
converted to NODATA. Thanks to Eric de Thouars, Eric
|
||||
Spakman and Mike Mestnik for bug reports/testing.
|
||||
|
||||
Allow multiple dhcp-ranges within the same network. The
|
||||
original intention was that there would be a dhcp-range
|
||||
option for each network served, but there's no real reason
|
||||
not to allow discontinuous ranges within a network so this
|
||||
release adds support for that.
|
||||
|
||||
Check for dhcp-ranges which are inconsistent with their
|
||||
netmask, and generate errors or warnings.
|
||||
|
||||
Improve error messages when there are problems with
|
||||
configuration.
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.14
|
||||
Version: 2.15
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: System Environment/Daemons
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.14
|
||||
Version: 2.15
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Productivity/Networking/DNS/Servers
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#define VERSION "2.14"
|
||||
#define VERSION "2.15"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
|
||||
111
src/dhcp.c
111
src/dhcp.c
@@ -209,9 +209,19 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
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;
|
||||
(is_same_net(iface_addr, context->start, iface_netmask) ||
|
||||
is_same_net(iface_addr, context->end, iface_netmask)))
|
||||
{
|
||||
context->netmask = iface_netmask;
|
||||
if (!(is_same_net(iface_addr, context->start, iface_netmask) &&
|
||||
is_same_net(iface_addr, context->end, iface_netmask)))
|
||||
{
|
||||
strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
|
||||
strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
|
||||
syslog(LOG_WARNING, "DHCP range %s -- %s is not consistent with netmask %s",
|
||||
daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(iface_netmask));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine "default" default routes. These are to this server or the relay agent.
|
||||
@@ -226,7 +236,8 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
{
|
||||
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)
|
||||
if (iface_broadcast.s_addr &&
|
||||
is_same_net(iface_broadcast, context->start, context->netmask))
|
||||
context->broadcast = iface_broadcast;
|
||||
else
|
||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
||||
@@ -361,26 +372,23 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
|
||||
int address_available(struct dhcp_context *context, struct in_addr taddr)
|
||||
{
|
||||
/* Check is an address is OK for this network, ie
|
||||
within allowable range and not in an existing lease */
|
||||
/* Check is an address is OK for this network, check all
|
||||
possible ranges. */
|
||||
|
||||
unsigned int addr, start, end;
|
||||
unsigned int start, end, addr = ntohl(taddr.s_addr);
|
||||
|
||||
/* static leases only. */
|
||||
if (context->static_only)
|
||||
return 0;
|
||||
for (; context; context = context->current)
|
||||
{
|
||||
start = ntohl(context->start.s_addr);
|
||||
end = ntohl(context->end.s_addr);
|
||||
|
||||
addr = ntohl(taddr.s_addr);
|
||||
start = ntohl(context->start.s_addr);
|
||||
end = ntohl(context->end.s_addr);
|
||||
if (!context->static_only &&
|
||||
addr >= start &&
|
||||
addr <= end)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (addr < start)
|
||||
return 0;
|
||||
|
||||
if (addr > end)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
|
||||
@@ -402,41 +410,40 @@ int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
|
||||
struct in_addr start, addr ;
|
||||
unsigned int i, j;
|
||||
|
||||
/* 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. */
|
||||
for (j = context->addr_epoch, i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
|
||||
|
||||
start.s_addr = addr.s_addr =
|
||||
htonl(ntohl(context->start.s_addr) +
|
||||
(j % (1 + ntohl(context->end.s_addr) - ntohl(context->start.s_addr))));
|
||||
|
||||
do {
|
||||
if (!lease_find_by_addr(addr) &&
|
||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
||||
for (; context; context = context->current)
|
||||
if (!context->static_only)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
||||
for (j = context->addr_epoch, i = 0; i < ETHER_ADDR_LEN; i++)
|
||||
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
|
||||
|
||||
start.s_addr = addr.s_addr =
|
||||
htonl(ntohl(context->start.s_addr) +
|
||||
(j % (1 + ntohl(context->end.s_addr) - ntohl(context->start.s_addr))));
|
||||
|
||||
do {
|
||||
if (!lease_find_by_addr(addr) &&
|
||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
||||
{
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -294,7 +294,7 @@ struct dhcp_context {
|
||||
struct in_addr start, end; /* range of available addresses */
|
||||
int static_only;
|
||||
struct dhcp_netid netid;
|
||||
struct dhcp_context *next;
|
||||
struct dhcp_context *next, *current;
|
||||
};
|
||||
|
||||
typedef unsigned char u8;
|
||||
@@ -393,11 +393,15 @@ int setup_reply(HEADER *header, unsigned int qlen,
|
||||
unsigned long local_ttl);
|
||||
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);
|
||||
void extract_neg_addrs(HEADER *header, unsigned int qlen, char *namebuff, time_t now, unsigned short flags);
|
||||
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);
|
||||
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen,
|
||||
unsigned int *len, unsigned char **p);
|
||||
int check_for_local_domain(char *name, time_t now, struct mx_record *mx);
|
||||
int resize_packet(HEADER *header, unsigned int plen,
|
||||
unsigned char *pheader, unsigned int hlen);
|
||||
|
||||
/* util.c */
|
||||
unsigned short rand16(void);
|
||||
|
||||
124
src/forward.c
124
src/forward.c
@@ -114,8 +114,8 @@ static void send_from(int fd, int nowild, char *packet, int len,
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short search_servers(struct daemon *daemon, struct all_addr **addrpp,
|
||||
unsigned short qtype, char *qdomain, int *type, char **domain)
|
||||
static unsigned short search_servers(struct daemon *daemon, time_t now, struct all_addr **addrpp,
|
||||
unsigned short qtype, char *qdomain, int *type, char **domain)
|
||||
|
||||
{
|
||||
/* If the query ends in the domain in one of our servers, set
|
||||
@@ -133,19 +133,23 @@ unsigned short search_servers(struct daemon *daemon, struct all_addr **addrpp,
|
||||
{
|
||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
*type = SERV_FOR_NODOTS;
|
||||
flags = 0;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
else if ((serv->flags & SERV_LITERAL_ADDRESS) && (sflag & qtype))
|
||||
{
|
||||
flags = sflag;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||
flags = F_NXDOMAIN;
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
if (sflag & qtype)
|
||||
{
|
||||
flags = sflag;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
else
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (!flags)
|
||||
flags = F_NOERR;
|
||||
}
|
||||
}
|
||||
else if (serv->flags & SERV_HAS_DOMAIN)
|
||||
{
|
||||
@@ -158,23 +162,27 @@ unsigned short search_servers(struct daemon *daemon, struct all_addr **addrpp,
|
||||
*type = SERV_HAS_DOMAIN;
|
||||
*domain = serv->domain;
|
||||
matchlen = domainlen;
|
||||
flags = 0;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
else if ((serv->flags & SERV_LITERAL_ADDRESS) && ((sflag | F_QUERY ) & qtype))
|
||||
flags = F_NXDOMAIN;
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
flags = qtype;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||
if ((sflag | F_QUERY ) & qtype)
|
||||
{
|
||||
flags = qtype;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
else
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
#endif
|
||||
}
|
||||
else if (!flags)
|
||||
flags = F_NOERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & ~F_NXDOMAIN) /* flags set here means a literal found */
|
||||
if (flags & ~(F_NOERR | F_NXDOMAIN)) /* flags set here means a literal found */
|
||||
{
|
||||
if (flags & F_QUERY)
|
||||
log_query(F_CONFIG | F_FORWARD | F_NEG, qdomain, NULL, 0);
|
||||
@@ -182,9 +190,12 @@ unsigned short search_servers(struct daemon *daemon, struct all_addr **addrpp,
|
||||
log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp, 0);
|
||||
}
|
||||
else if (qtype && (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.'))
|
||||
flags = F_NXDOMAIN;
|
||||
|
||||
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now, daemon->mxnames))
|
||||
flags = F_NOERR;
|
||||
|
||||
if (flags & (F_NOERR | F_NXDOMAIN))
|
||||
if (flags == F_NXDOMAIN || flags == F_NOERR)
|
||||
log_query(F_CONFIG | F_FORWARD | F_NEG | qtype | (flags & F_NXDOMAIN), qdomain, NULL, 0);
|
||||
|
||||
return flags;
|
||||
@@ -223,7 +234,7 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
|
||||
else
|
||||
{
|
||||
if (gotname)
|
||||
flags = search_servers(daemon, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||
flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||
|
||||
if (!flags && !(forward = get_new_frec(now)))
|
||||
/* table full - server failure. */
|
||||
@@ -316,20 +327,21 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
|
||||
}
|
||||
|
||||
static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
union mysockaddr *serveraddr, int n)
|
||||
union mysockaddr *serveraddr, unsigned int n)
|
||||
{
|
||||
unsigned char *pheader;
|
||||
unsigned char *pheader, *sizep;
|
||||
unsigned int plen;
|
||||
|
||||
/* If upstream is advertising a larger UDP packet size
|
||||
than we allow, trim it so that we don't get overlarge
|
||||
requests for the client. */
|
||||
|
||||
if ((pheader = find_pseudoheader(header, n)))
|
||||
if ((pheader = find_pseudoheader(header, n, &plen, &sizep)))
|
||||
{
|
||||
unsigned short udpsz;
|
||||
unsigned char *psave = pheader;
|
||||
unsigned char *psave = sizep;
|
||||
|
||||
GETSHORT(udpsz, pheader);
|
||||
GETSHORT(udpsz, sizep);
|
||||
if (udpsz > daemon->edns_pktsz)
|
||||
PUTSHORT(daemon->edns_pktsz, psave);
|
||||
}
|
||||
@@ -350,20 +362,52 @@ static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((header->rcode == NOERROR || header->rcode == NXDOMAIN) && header->opcode == QUERY)
|
||||
if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
|
||||
return n;
|
||||
|
||||
if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
|
||||
{
|
||||
if (!(daemon->bogus_addr &&
|
||||
header->rcode == NOERROR &&
|
||||
check_for_bogus_wildcard(header, (unsigned int)n, daemon->namebuff, daemon->bogus_addr, now)))
|
||||
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now)))
|
||||
extract_addresses(header, n, daemon->namebuff, now, daemon->doctors);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned short flags = F_NEG;
|
||||
int munged = 0;
|
||||
|
||||
if (header->rcode == NXDOMAIN)
|
||||
{
|
||||
if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
|
||||
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);
|
||||
/* if we forwarded a query for a locally known name (because it was for
|
||||
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
|
||||
since we know that the domain exists, even if upstream doesn't */
|
||||
if (extract_request(header, n, daemon->namebuff, NULL) &&
|
||||
check_for_local_domain(daemon->namebuff, now, daemon->mxnames))
|
||||
{
|
||||
munged = 1;
|
||||
header->rcode = NOERROR;
|
||||
}
|
||||
else
|
||||
flags |= F_NXDOMAIN;
|
||||
}
|
||||
|
||||
if (!(daemon->options & OPT_NO_NEG))
|
||||
extract_neg_addrs(header, n, daemon->namebuff, now, flags);
|
||||
|
||||
/* do this after extract_neg_addrs. Ensure NODATA reply and remove
|
||||
nameserver info. */
|
||||
if (munged)
|
||||
{
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
/* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
|
||||
sections of the packet. Find the new length here and put back pseudoheader
|
||||
if it was removed. */
|
||||
return resize_packet(header, n, pheader, plen);
|
||||
}
|
||||
|
||||
/* sets new last_server */
|
||||
@@ -401,7 +445,7 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
if (process_reply(daemon, header, now, &serveraddr, n))
|
||||
if ((n = process_reply(daemon, header, now, &serveraddr, (unsigned int)n)))
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n,
|
||||
@@ -654,7 +698,7 @@ char *tcp_request(struct daemon *daemon, int confd, time_t now)
|
||||
char *domain = NULL;
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(daemon, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||
flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||
|
||||
if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server)
|
||||
last_server = daemon->servers;
|
||||
@@ -729,7 +773,7 @@ char *tcp_request(struct daemon *daemon, int confd, time_t now)
|
||||
/* 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(daemon, header, now, &last_server->addr, m);
|
||||
m = process_reply(daemon, header, now, &last_server->addr, (unsigned int)m);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
57
src/option.c
57
src/option.c
@@ -161,7 +161,7 @@ static char *usage =
|
||||
struct daemon *read_opts (int argc, char **argv)
|
||||
{
|
||||
struct daemon *daemon = safe_malloc(sizeof(struct daemon));
|
||||
char *buff = safe_malloc(MAXDNAME);
|
||||
char *problem = NULL, *buff = safe_malloc(MAXDNAME);
|
||||
int option = 0, i;
|
||||
FILE *file_save = NULL, *f = NULL;
|
||||
char *file_name_save = NULL, *conffile = CONFFILE;
|
||||
@@ -187,6 +187,8 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
|
||||
while (1)
|
||||
{
|
||||
problem = NULL;
|
||||
|
||||
if (!f)
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
option = getopt_long(argc, argv, OPTSTRING, (struct option *)opts, NULL);
|
||||
@@ -302,7 +304,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
complain(buff, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
switch (option)
|
||||
{
|
||||
case 'C':
|
||||
@@ -366,7 +368,10 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
if (comma)
|
||||
*(comma++) = 0;
|
||||
if (!canonicalise(optarg) || (comma && !canonicalise(comma)))
|
||||
option = '?';
|
||||
{
|
||||
option = '?';
|
||||
problem = "bad MX name";
|
||||
}
|
||||
else
|
||||
{
|
||||
struct mx_record *new = safe_malloc(sizeof(struct mx_record));
|
||||
@@ -380,7 +385,10 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
|
||||
case 't':
|
||||
if (!canonicalise(optarg))
|
||||
option = '?';
|
||||
{
|
||||
option = '?';
|
||||
problem = "bad MX target";
|
||||
}
|
||||
else
|
||||
daemon->mxtarget = safe_string_alloc(optarg);
|
||||
break;
|
||||
@@ -391,7 +399,10 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
|
||||
case 'H':
|
||||
if (daemon->addn_hosts)
|
||||
option = '?';
|
||||
{
|
||||
option = '?';
|
||||
problem = "only one addn hosts file allowed";
|
||||
}
|
||||
else
|
||||
daemon->addn_hosts = safe_string_alloc(optarg);
|
||||
break;
|
||||
@@ -563,7 +574,10 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
{
|
||||
*portno = 0;
|
||||
if (!atoi_check(portno+1, &source_port))
|
||||
option = '?';
|
||||
{
|
||||
option = '?';
|
||||
problem = "bad port";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,7 +585,10 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
{
|
||||
*portno = 0;
|
||||
if (!atoi_check(portno+1, &serv_port))
|
||||
option = '?';
|
||||
{
|
||||
option = '?';
|
||||
problem = "bad port";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -717,6 +734,8 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
new->netid.net = NULL;
|
||||
new->static_only = 0;
|
||||
|
||||
problem = "bad dhcp-range";
|
||||
|
||||
for (cp = optarg; *cp; cp++)
|
||||
if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
|
||||
break;
|
||||
@@ -755,6 +774,17 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
new->end = tmp;
|
||||
}
|
||||
|
||||
if (option != '?' && k >= 3 && strchr(a[2], '.') &&
|
||||
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
|
||||
{
|
||||
leasepos = 3;
|
||||
if (!is_same_net(new->start, new->end, new->netmask))
|
||||
{
|
||||
problem = "inconsistent DHCP range";
|
||||
option = '?';
|
||||
}
|
||||
}
|
||||
|
||||
if (option == '?')
|
||||
{
|
||||
free(new);
|
||||
@@ -762,11 +792,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
}
|
||||
else
|
||||
daemon->dhcp = new;
|
||||
|
||||
if (k >= 3 && strchr(a[2], '.') &&
|
||||
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
|
||||
leasepos = 3;
|
||||
|
||||
|
||||
if (k >= 4 && strchr(a[3], '.') &&
|
||||
((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
|
||||
leasepos = 4;
|
||||
@@ -955,6 +981,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
|
||||
if (option == '?')
|
||||
{
|
||||
problem = "bad dhcp-host";
|
||||
if (new->flags & CONFIG_NAME)
|
||||
free(new->hostname);
|
||||
if (new->flags & CONFIG_CLID)
|
||||
@@ -1003,6 +1030,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
if ((new->opt = atoi(optarg)) == 0)
|
||||
{
|
||||
option = '?';
|
||||
problem = "bad dhcp-opt";
|
||||
if (new->netid)
|
||||
free(new->netid);
|
||||
free(new);
|
||||
@@ -1203,11 +1231,12 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
{
|
||||
if (f)
|
||||
{
|
||||
sprintf(buff, "error at line %d of %s ", lineno, conffile);
|
||||
sprintf(buff, "%s at line %d of %s ",
|
||||
problem ? problem : "error", lineno, conffile);
|
||||
complain(buff, NULL);
|
||||
}
|
||||
else
|
||||
die("bad command line options: try --help.", NULL);
|
||||
die("bad command line options: %s.", problem ? problem : "try --help");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -306,9 +306,44 @@ static unsigned char *skip_questions(HEADER *header, unsigned int plen)
|
||||
return ansp;
|
||||
}
|
||||
|
||||
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen)
|
||||
int resize_packet(HEADER *header, unsigned int plen, unsigned char *pheader, unsigned int hlen)
|
||||
{
|
||||
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it. */
|
||||
int i;
|
||||
unsigned char *ansp = skip_questions(header, plen);
|
||||
unsigned short rdlen;
|
||||
|
||||
if (!ansp)
|
||||
return 0;
|
||||
|
||||
for (i = 0;
|
||||
i < (ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount));
|
||||
i++)
|
||||
{
|
||||
if (!(ansp = skip_name(ansp, header, plen)))
|
||||
return 0;
|
||||
ansp += 8; /* type, class, TTL */
|
||||
GETSHORT(rdlen, ansp);
|
||||
if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
|
||||
return 0;
|
||||
ansp += rdlen;
|
||||
}
|
||||
|
||||
/* restore pseudoheader */
|
||||
if (pheader && ntohs(header->arcount) == 0)
|
||||
{
|
||||
/* must use memmove, may overlap */
|
||||
memmove(ansp, pheader, hlen);
|
||||
header->arcount = htons(1);
|
||||
ansp += hlen;
|
||||
}
|
||||
|
||||
return ansp - (unsigned char *)header;
|
||||
}
|
||||
|
||||
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen, unsigned int *len, unsigned char **p)
|
||||
{
|
||||
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
|
||||
also return length of pseudoheader in *len and pointer to the UDP size in *p */
|
||||
|
||||
int i, arcount = ntohs(header->arcount);
|
||||
unsigned char *ansp;
|
||||
@@ -330,7 +365,7 @@ unsigned char *find_pseudoheader(HEADER *header, unsigned int plen)
|
||||
|
||||
for (i = 0; i < arcount; i++)
|
||||
{
|
||||
unsigned char *save;
|
||||
unsigned char *save, *start = ansp;
|
||||
if (!(ansp = skip_name(ansp, header, plen)))
|
||||
return NULL;
|
||||
|
||||
@@ -340,9 +375,15 @@ 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 == T_OPT)
|
||||
return save;
|
||||
ansp += rdlen;
|
||||
ansp += rdlen;
|
||||
if (type == T_OPT)
|
||||
{
|
||||
if (len)
|
||||
*len = ansp - start;
|
||||
if (p)
|
||||
*p = save;
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -397,17 +438,13 @@ static unsigned char *add_text_record(unsigned int nameoffset, unsigned char *p,
|
||||
|
||||
/* On receiving an NXDOMAIN or NODATA reply, determine which names are known
|
||||
not to exist for negative caching. name if a working buffer passed in. */
|
||||
void extract_neg_addrs(HEADER *header, unsigned int qlen, char *name, time_t now)
|
||||
void extract_neg_addrs(HEADER *header, unsigned int qlen, char *name, time_t now, unsigned short flags)
|
||||
{
|
||||
unsigned char *p;
|
||||
int i, found_soa = 0;
|
||||
int qtype, qclass, rdlen;
|
||||
unsigned long ttl, minttl = 0;
|
||||
unsigned short flags = F_NEG;
|
||||
|
||||
if (header->rcode == NXDOMAIN)
|
||||
flags |= F_NXDOMAIN;
|
||||
|
||||
|
||||
/* there may be more than one question with some questions
|
||||
answered. We don't generate negative entries from those. */
|
||||
if (ntohs(header->ancount) != 0)
|
||||
@@ -555,7 +592,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name,
|
||||
#endif
|
||||
else if (qtype == T_PTR)
|
||||
{
|
||||
/* PTR record */
|
||||
/* PTR record */
|
||||
struct all_addr addr;
|
||||
int name_encoding = in_arpa_name_2_addr(name, &addr);
|
||||
if (name_encoding)
|
||||
@@ -735,7 +772,22 @@ int setup_reply(HEADER *header, unsigned int qlen,
|
||||
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
|
||||
|
||||
/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
|
||||
int check_for_local_domain(char *name, time_t now, struct mx_record *mx)
|
||||
{
|
||||
struct crec *crecp;
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4|F_IPV6)) &&
|
||||
(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
return 1;
|
||||
|
||||
for (; mx; mx = mx->next)
|
||||
if (hostname_isequal(name, mx->mxname))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is the packet a reply with the answer address equal to addr?
|
||||
If so mung is into an NXDOMAIN reply and also put that information
|
||||
@@ -811,7 +863,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
||||
forward rather than answering from the cache, which doesn't include
|
||||
security information. */
|
||||
|
||||
if ((pheader = find_pseudoheader(header, qlen)))
|
||||
if (find_pseudoheader(header, qlen, NULL, &pheader))
|
||||
{
|
||||
unsigned short udpsz, ext_rcode, flags;
|
||||
unsigned char *psave = pheader;
|
||||
|
||||
@@ -80,7 +80,7 @@ static int have_config(struct dhcp_config *config, unsigned int mask)
|
||||
|
||||
int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_name, unsigned int sz, time_t now)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_context *context, *context_tmp;
|
||||
unsigned char *opt, *clid;
|
||||
struct dhcp_lease *lease, *ltmp;
|
||||
struct dhcp_vendor *vendor;
|
||||
@@ -148,12 +148,25 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
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;
|
||||
|
||||
/* More than one context may match, we build a chain of them all on ->current
|
||||
Note that if netmasks, netid or lease times don't match, odd things may happen. */
|
||||
|
||||
for (context = NULL, context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
|
||||
if (context_tmp->netmask.s_addr &&
|
||||
is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
|
||||
is_same_net(addr, context_tmp->end, context_tmp->netmask))
|
||||
{
|
||||
context_tmp->current = context;
|
||||
context = context_tmp;
|
||||
|
||||
/* start to build netid chain */
|
||||
if (context_tmp->netid.net)
|
||||
{
|
||||
context_tmp->netid.next = netid;
|
||||
netid = &context_tmp->netid;
|
||||
}
|
||||
}
|
||||
|
||||
if (!context)
|
||||
{
|
||||
@@ -164,14 +177,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
}
|
||||
|
||||
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 */
|
||||
@@ -268,14 +274,12 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
}
|
||||
}
|
||||
|
||||
def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
|
||||
|
||||
if (have_config(config, CONFIG_NETID))
|
||||
{
|
||||
config->netid.next = netid;
|
||||
netid = &config->netid;
|
||||
}
|
||||
|
||||
|
||||
/* 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 = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
@@ -326,10 +330,12 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
/* do we have a lease in store? */
|
||||
lease = lease_find_by_client(clid, clid_len);
|
||||
|
||||
def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
|
||||
{
|
||||
unsigned int req_time = option_uint(opt, 4);
|
||||
|
||||
|
||||
if (def_time == 0xffffffff ||
|
||||
(req_time != 0xffffffff && req_time < def_time))
|
||||
expires_time = renewal_time = req_time;
|
||||
@@ -392,7 +398,8 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
}
|
||||
else
|
||||
/* make sure this host gets a different address next time. */
|
||||
context->addr_epoch++;
|
||||
for (; context; context = context->current)
|
||||
context->addr_epoch++;
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user