mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.20.tar.gz
This commit is contained in:
78
src/cache.c
78
src/cache.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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
|
||||
@@ -156,32 +156,52 @@ static int is_outdated_cname_pointer(struct crec *crecp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
|
||||
static int is_expired(time_t now, struct crec *crecp)
|
||||
{
|
||||
if (crecp->flags & F_IMMORTAL)
|
||||
return 0;
|
||||
|
||||
if (difftime(now, crecp->ttd) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
|
||||
{
|
||||
/* Scan and remove old entries.
|
||||
If (flags & F_FORWARD) then remove any forward entries for name and any expired
|
||||
entries but only in the same hash bucket as name.
|
||||
If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
|
||||
entries in the whole cache.
|
||||
If (flags == 0) remove any expired entries in the whole cache. */
|
||||
If (flags == 0) remove any expired entries in the whole cache.
|
||||
|
||||
In the flags & F_FORWARD case, the return code is valid, and returns zero if the
|
||||
name exists in the cache as a HOSTS or DHCP entry (these are never deleted) */
|
||||
|
||||
#define F_CACHESTATUS (F_HOSTS | F_DHCP | F_FORWARD | F_REVERSE | F_IPV4 | F_IPV6 | F_CNAME)
|
||||
struct crec *crecp, **up;
|
||||
flags &= (F_FORWARD | F_REVERSE | F_IPV6 | F_IPV4 | F_CNAME);
|
||||
|
||||
if (flags & F_FORWARD)
|
||||
{
|
||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
|
||||
if ((!(crecp->flags & F_IMMORTAL) && difftime(now, crecp->ttd) > 0) ||
|
||||
is_outdated_cname_pointer(crecp) ||
|
||||
((flags == (crecp->flags & F_CACHESTATUS)) && hostname_isequal(cache_get_name(crecp), name)))
|
||||
{
|
||||
if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
{
|
||||
{
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
}
|
||||
else if ((crecp->flags & F_FORWARD) &&
|
||||
((flags & crecp->flags & (F_IPV4 | F_IPV6)) || (crecp->flags & F_CNAME)) &&
|
||||
hostname_isequal(cache_get_name(crecp), name))
|
||||
{
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP))
|
||||
return 0;
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
else
|
||||
up = &crecp->hash_next;
|
||||
@@ -196,8 +216,7 @@ static void cache_scan_free(char *name, struct all_addr *addr, time_t now, unsig
|
||||
#endif
|
||||
for (i = 0; i < hash_size; i++)
|
||||
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
|
||||
if ((!(crecp->flags & F_IMMORTAL) && difftime(now, crecp->ttd) > 0) ||
|
||||
((flags == (crecp->flags & F_CACHESTATUS)) && memcmp(&crecp->addr.addr, addr, addrlen) == 0))
|
||||
if (is_expired(now, crecp))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
@@ -206,9 +225,20 @@ static void cache_scan_free(char *name, struct all_addr *addr, time_t now, unsig
|
||||
cache_free(crecp);
|
||||
}
|
||||
}
|
||||
else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&
|
||||
(flags & crecp->flags & F_REVERSE) &&
|
||||
(flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
|
||||
memcmp(&crecp->addr.addr, addr, addrlen) == 0)
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
else
|
||||
up = &crecp->hash_next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Note: The normal calling sequence is
|
||||
@@ -260,8 +290,13 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
return NULL;
|
||||
|
||||
/* First remove any expired entries and entries for the name/address we
|
||||
are currently inserting. */
|
||||
cache_scan_free(name, addr, now, flags);
|
||||
are currently inserting. Fail is we attempt to delete a name from
|
||||
/etc/hosts or DHCP. */
|
||||
if (!cache_scan_free(name, addr, now, flags))
|
||||
{
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Now get a cache entry from the end of the LRU list */
|
||||
while (1) {
|
||||
@@ -376,8 +411,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
{
|
||||
next = crecp->hash_next;
|
||||
|
||||
if (!is_outdated_cname_pointer(crecp) &&
|
||||
((crecp->flags & F_IMMORTAL) || difftime(now, crecp->ttd) < 0))
|
||||
if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
|
||||
{
|
||||
if ((crecp->flags & F_FORWARD) &&
|
||||
(crecp->flags & prot) &&
|
||||
@@ -458,7 +492,7 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
||||
|
||||
for(i=0; i<hash_size; i++)
|
||||
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
|
||||
if ((crecp->flags & F_IMMORTAL) || difftime(now, crecp->ttd) < 0)
|
||||
if (!is_expired(now, crecp))
|
||||
{
|
||||
if ((crecp->flags & F_REVERSE) &&
|
||||
(crecp->flags & prot) &&
|
||||
@@ -835,7 +869,15 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||
strcat(addrbuff, "-IPv6");
|
||||
}
|
||||
else if (flags & F_CNAME)
|
||||
strcpy(addrbuff, "<CNAME>");
|
||||
{
|
||||
/* nasty abuse of IPV4 and IPV6 flags */
|
||||
if (flags & F_IPV4)
|
||||
strcpy(addrbuff, "<MX>");
|
||||
else if (flags & F_IPV6)
|
||||
strcpy(addrbuff, "<SRV>");
|
||||
else
|
||||
strcpy(addrbuff, "<CNAME>");
|
||||
}
|
||||
else
|
||||
#ifdef HAVE_IPV6
|
||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2004 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#define VERSION "2.19"
|
||||
#define VERSION "2.20"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
@@ -278,7 +278,6 @@ typedef unsigned long in_addr_t;
|
||||
#define HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_PSELECT
|
||||
#define HAVE_BPF
|
||||
#define BIND_8_COMPAT
|
||||
/* Define before sys/socket.h is included so we get socklen_t */
|
||||
#define _BSD_SOCKLEN_T_
|
||||
/* This is not defined in Mac OS X arpa/nameserv.h */
|
||||
|
||||
52
src/dhcp.c
52
src/dhcp.c
@@ -34,6 +34,13 @@ void dhcp_init(struct daemon *daemon)
|
||||
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
|
||||
die("failed to set options on DHCP socket: %s", NULL);
|
||||
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
instance binding port 67. That's Ok if they serve different networks.
|
||||
Need to set REUSEADDR to make this posible. */
|
||||
if ((daemon->options & OPT_NOWILD) &&
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt)) == -1)
|
||||
die("failed to set SO_REUSEADDR on DHCP socket: %s", NULL);
|
||||
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(DHCP_SERVER_PORT);
|
||||
saddr.sin_addr.s_addr = INADDR_ANY;
|
||||
@@ -429,17 +436,52 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Is every member of check matched by a member of pool? */
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||
{
|
||||
struct dhcp_netid *tmp1;
|
||||
|
||||
if (!check)
|
||||
return 0;
|
||||
|
||||
for (; check; check = check->next)
|
||||
{
|
||||
if (check->net[0] != '#')
|
||||
{
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp(check->net, tmp1->net) == 0)
|
||||
break;
|
||||
if (!tmp1)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp((check->net)+1, tmp1->net) == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
struct in_addr *addrp, unsigned char *hwaddr)
|
||||
struct in_addr *addrp, unsigned char *hwaddr, struct dhcp_netid *netids)
|
||||
{
|
||||
/* Find a free address: exclude anything in use and anything allocated to
|
||||
a particular hwaddr/clientid/hostname in our configuration */
|
||||
a particular hwaddr/clientid/hostname in our configuration.
|
||||
Try to return from contexts which mathc netis first. */
|
||||
|
||||
struct in_addr start, addr ;
|
||||
unsigned int i, j;
|
||||
|
||||
for (; context; context = context->current)
|
||||
if (!context->static_only)
|
||||
if (context->static_only)
|
||||
continue;
|
||||
else if (netids && !context->filter_netid)
|
||||
continue;
|
||||
else if (!netids && context->filter_netid)
|
||||
continue;
|
||||
else if (netids && context->filter_netid && !match_netid(&context->netid, netids))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
/* 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++)
|
||||
@@ -471,6 +513,10 @@ int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
|
||||
} while (addr.s_addr != start.s_addr);
|
||||
}
|
||||
|
||||
if (netids)
|
||||
return address_allocate(context, daemon, addrp, hwaddr, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2004 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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
|
||||
@@ -82,8 +82,9 @@ int main (int argc, char **argv)
|
||||
die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
|
||||
#endif
|
||||
|
||||
interfaces = enumerate_interfaces(daemon);
|
||||
|
||||
if (!enumerate_interfaces(daemon, &interfaces, NULL, NULL))
|
||||
die("failed to find list of interfaces: %s", NULL);
|
||||
|
||||
if (!(daemon->options & OPT_NOWILD) &&
|
||||
!(daemon->listeners = create_wildcard_listeners(daemon->port)))
|
||||
{
|
||||
@@ -509,45 +510,25 @@ static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now)
|
||||
if (FD_ISSET(listener->tcpfd, set))
|
||||
{
|
||||
int confd;
|
||||
struct in_addr netmask, dst_addr_4;
|
||||
|
||||
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))
|
||||
union mysockaddr tcp_addr;
|
||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
interface too, for localisation. */
|
||||
|
||||
if ((num_kids >= MAX_PROCS) ||
|
||||
(!(daemon->options & OPT_NOWILD) &&
|
||||
(getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1 ||
|
||||
!enumerate_interfaces(daemon, NULL, &tcp_addr, &netmask))))
|
||||
close(confd);
|
||||
#ifndef NO_FORK
|
||||
else if (!(daemon->options & OPT_DEBUG) && fork())
|
||||
@@ -584,7 +565,21 @@ static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now)
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
|
||||
buff = tcp_request(daemon, confd, now);
|
||||
if (listener->family == AF_INET)
|
||||
{
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
{
|
||||
netmask = listener->iface->netmask;
|
||||
dst_addr_4 = listener->iface->addr.in.sin_addr;
|
||||
}
|
||||
else
|
||||
/* netmask already set by enumerate_interfaces */
|
||||
dst_addr_4 = tcp_addr.in.sin_addr;
|
||||
}
|
||||
else
|
||||
dst_addr_4.s_addr = 0;
|
||||
|
||||
buff = tcp_request(daemon, confd, now, dst_addr_4, netmask);
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
exit(0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2003 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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
|
||||
@@ -12,11 +12,11 @@
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#define COPYRIGHT "Copyright (C) 2000-2004 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (C) 2000-2005 Simon Kelley"
|
||||
|
||||
#ifdef __linux__
|
||||
/* for pselect.... */
|
||||
#define _XOPEN_SOURCE 600
|
||||
# define _XOPEN_SOURCE 600
|
||||
/* but then DNS headers don't compile without.... */
|
||||
#define _BSD_SOURCE
|
||||
#endif
|
||||
@@ -27,6 +27,10 @@
|
||||
|
||||
/* get this before config.h too. */
|
||||
#include <syslog.h>
|
||||
#ifdef __APPLE__
|
||||
/* need this before arpa/nameser.h */
|
||||
# define BIND_8_COMPAT
|
||||
#endif
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
/* and this. */
|
||||
@@ -57,6 +61,7 @@
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <stdarg.h>
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
# include <netinet/if_ether.h>
|
||||
#else
|
||||
@@ -96,6 +101,7 @@
|
||||
#define OPT_RESOLV_DOMAIN 32768
|
||||
#define OPT_NO_FORK 65536
|
||||
#define OPT_AUTHORITATIVE 131072
|
||||
#define OPT_LOCALISE 262144
|
||||
|
||||
struct all_addr {
|
||||
union {
|
||||
@@ -119,9 +125,16 @@ struct doctor {
|
||||
|
||||
struct mx_record {
|
||||
char *mxname, *mxtarget;
|
||||
int preference;
|
||||
struct mx_record *next;
|
||||
};
|
||||
|
||||
struct srv_record {
|
||||
char *srvname, *srvtarget;
|
||||
int srvport, priority, weight;
|
||||
struct srv_record *next;
|
||||
};
|
||||
|
||||
union bigname {
|
||||
char name[MAXDNAME];
|
||||
union bigname *next; /* freelist */
|
||||
@@ -211,11 +224,13 @@ struct server {
|
||||
|
||||
struct irec {
|
||||
union mysockaddr addr;
|
||||
struct in_addr netmask; /* only valid for IPv4 */
|
||||
struct irec *next;
|
||||
};
|
||||
|
||||
struct listener {
|
||||
int fd, tcpfd, family;
|
||||
struct irec *iface; /* only valid for non-wildcard */
|
||||
struct listener *next;
|
||||
};
|
||||
|
||||
@@ -319,7 +334,7 @@ struct dhcp_context {
|
||||
unsigned int lease_time, addr_epoch;
|
||||
struct in_addr netmask, broadcast, router;
|
||||
struct in_addr start, end; /* range of available addresses */
|
||||
int static_only;
|
||||
int static_only, filter_netid;
|
||||
struct dhcp_netid netid;
|
||||
struct dhcp_context *next, *current;
|
||||
};
|
||||
@@ -360,6 +375,7 @@ struct daemon {
|
||||
char *lease_file;
|
||||
char *username, *groupname;
|
||||
char *domain_suffix;
|
||||
struct srv_record *srvnames;
|
||||
char *runfile;
|
||||
struct iname *if_names, *if_addrs, *if_except;
|
||||
struct bogus_addr *bogus_addr;
|
||||
@@ -420,12 +436,13 @@ 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 daemon *daemon);
|
||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon *daemon, time_t now);
|
||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon *daemon,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, 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 int *len, unsigned char **p);
|
||||
int check_for_local_domain(char *name, time_t now, struct mx_record *mx);
|
||||
int check_for_local_domain(char *name, time_t now, struct daemon *daemon);
|
||||
unsigned int questions_crc(HEADER *header, unsigned int plen);
|
||||
int resize_packet(HEADER *header, unsigned int plen,
|
||||
unsigned char *pheader, unsigned int hlen);
|
||||
@@ -453,13 +470,15 @@ struct daemon *read_opts (int argc, char **argv);
|
||||
void forward_init(int first);
|
||||
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);
|
||||
char *tcp_request(struct daemon *daemon, int confd, time_t now,
|
||||
struct in_addr local_addr, struct in_addr netmask);
|
||||
|
||||
/* network.c */
|
||||
struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds);
|
||||
void reload_servers(char *fname, struct daemon *daemon);
|
||||
void check_servers(struct daemon *daemon, struct irec *interfaces);
|
||||
struct irec *enumerate_interfaces(struct daemon *daemon);
|
||||
int enumerate_interfaces(struct daemon *daemon, struct irec **chainp,
|
||||
union mysockaddr *test_addrp, struct in_addr *netmaskp);
|
||||
struct listener *create_wildcard_listeners(int port);
|
||||
struct listener *create_bound_listeners(struct irec *interfaces, int port);
|
||||
|
||||
@@ -469,8 +488,10 @@ void dhcp_packet(struct daemon *daemon, time_t now);
|
||||
|
||||
struct dhcp_context *address_available(struct dhcp_context *context, struct in_addr addr);
|
||||
struct dhcp_context *narrow_context(struct dhcp_context *context, struct in_addr taddr);
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool);
|
||||
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
||||
struct in_addr *addrp, unsigned char *hwaddr);
|
||||
struct in_addr *addrp, unsigned char *hwaddr,
|
||||
struct dhcp_netid *netids);
|
||||
struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *clid, int clid_len,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2003 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000 - 2005 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
|
||||
@@ -197,7 +197,7 @@ static unsigned short search_servers(struct daemon *daemon, time_t now, struct a
|
||||
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))
|
||||
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now, daemon))
|
||||
flags = F_NOERR;
|
||||
|
||||
if (flags == F_NXDOMAIN || flags == F_NOERR)
|
||||
@@ -390,7 +390,7 @@ static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||
{
|
||||
if (header->rcode == NXDOMAIN &&
|
||||
extract_request(header, n, daemon->namebuff, NULL) &&
|
||||
check_for_local_domain(daemon->namebuff, now, daemon->mxnames))
|
||||
check_for_local_domain(daemon->namebuff, now, daemon))
|
||||
{
|
||||
/* 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,
|
||||
@@ -474,6 +474,7 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
unsigned short type;
|
||||
struct iname *tmp;
|
||||
struct all_addr dst_addr;
|
||||
struct in_addr netmask, dst_addr_4;
|
||||
int m, n, if_index = 0;
|
||||
struct iovec iov[1];
|
||||
struct msghdr msg;
|
||||
@@ -491,6 +492,14 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
#endif
|
||||
} control_u;
|
||||
|
||||
if (listen->family == AF_INET && (daemon->options & OPT_NOWILD))
|
||||
{
|
||||
dst_addr_4 = listen->iface->addr.in.sin_addr;
|
||||
netmask = listen->iface->netmask;
|
||||
}
|
||||
else
|
||||
dst_addr_4.s_addr = 0;
|
||||
|
||||
iov[0].iov_base = daemon->packet;
|
||||
iov[0].iov_len = daemon->edns_pktsz;
|
||||
|
||||
@@ -526,7 +535,7 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
|
||||
dst_addr_4 = dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
|
||||
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
||||
}
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
@@ -534,7 +543,7 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
|
||||
dst_addr_4 = dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||
}
|
||||
@@ -557,7 +566,7 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
if (if_index == 0)
|
||||
return;
|
||||
|
||||
if (daemon->if_except || daemon->if_names)
|
||||
if (daemon->if_except || daemon->if_names || (daemon->options & OPT_LOCALISE))
|
||||
{
|
||||
#ifdef SIOCGIFNAME
|
||||
ifr.ifr_ifindex = if_index;
|
||||
@@ -567,6 +576,13 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
if (!if_indextoname(if_index, ifr.ifr_name))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (listen->family == AF_INET &&
|
||||
(daemon->options & OPT_LOCALISE) &&
|
||||
ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1)
|
||||
return;
|
||||
|
||||
netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
}
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
@@ -610,7 +626,8 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
#endif
|
||||
}
|
||||
|
||||
m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n, daemon, now);
|
||||
m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n, daemon,
|
||||
dst_addr_4, netmask, now);
|
||||
if (m >= 1)
|
||||
send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
else
|
||||
@@ -647,7 +664,8 @@ 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(struct daemon *daemon, int confd, time_t now)
|
||||
char *tcp_request(struct daemon *daemon, int confd, time_t now,
|
||||
struct in_addr local_addr, struct in_addr netmask)
|
||||
{
|
||||
int size = 0, m;
|
||||
unsigned short qtype, gotname;
|
||||
@@ -689,7 +707,8 @@ char *tcp_request(struct daemon *daemon, int confd, time_t now)
|
||||
}
|
||||
|
||||
/* m > 0 if answered from cache */
|
||||
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size, daemon, now);
|
||||
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size, daemon,
|
||||
local_addr, netmask, now);
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2004 by Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000 - 2005 by 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2003 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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
|
||||
|
||||
113
src/network.c
113
src/network.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2003 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000 - 2005 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
|
||||
@@ -14,10 +14,9 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct irec *add_iface(struct daemon *daemon, struct irec *list,
|
||||
char *name, int is_loopback, union mysockaddr *addr)
|
||||
static int iface_allowed(struct daemon *daemon, struct irec *iface,
|
||||
char *name, int is_loopback, union mysockaddr *addr)
|
||||
{
|
||||
struct irec *iface;
|
||||
struct iname *tmp;
|
||||
|
||||
/* If we are restricting the set of interfaces to use, make
|
||||
@@ -45,12 +44,8 @@ static struct irec *add_iface(struct daemon *daemon, struct irec *list,
|
||||
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 */
|
||||
tmp->addr = *addr;
|
||||
return list;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/* we may need to check the whitelist */
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
@@ -58,36 +53,39 @@ static struct irec *add_iface(struct daemon *daemon, struct irec *list,
|
||||
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||
{
|
||||
tmp->addr = *addr;
|
||||
found = tmp->used = 1;
|
||||
}
|
||||
|
||||
found = tmp->used = 1;
|
||||
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (sockaddr_isequal(&tmp->addr, addr))
|
||||
found = tmp->used = 1;
|
||||
|
||||
if (!found)
|
||||
return list;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check whether the interface IP has been added already
|
||||
it is possible to have multiple interfaces with the same address */
|
||||
for (iface = list; iface; iface = iface->next)
|
||||
for (; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, addr))
|
||||
break;
|
||||
if (iface)
|
||||
return list;
|
||||
return 0;
|
||||
|
||||
/* If OK, add it to the head of the list */
|
||||
iface = safe_malloc(sizeof(struct irec));
|
||||
iface->addr = *addr;
|
||||
iface->next = list;
|
||||
return iface;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This does two different jobs: if chainp is non-NULL, it puts
|
||||
a list of all the interfaces allowed by config into *chainp.
|
||||
If chainp is NULL, it returns 1 if addr is an address of an interface
|
||||
allowed by config and if that address is IPv4, it fills in the
|
||||
netmask of the interface.
|
||||
|
||||
If chainp is non-NULL, a zero return indicates a fatal error.
|
||||
|
||||
struct irec *enumerate_interfaces(struct daemon *daemon)
|
||||
If chainp is NULL, errors result in a match failure and zero return.
|
||||
*/
|
||||
int enumerate_interfaces(struct daemon *daemon, struct irec **chainp,
|
||||
union mysockaddr *test_addrp, struct in_addr *netmaskp)
|
||||
{
|
||||
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
|
||||
FILE *f;
|
||||
@@ -100,9 +98,16 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
|
||||
int lastlen = 0;
|
||||
int len = 20 * sizeof(struct ifreq);
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
struct in_addr netmask;
|
||||
int ret = 0;
|
||||
|
||||
if (fd == -1)
|
||||
die ("cannot create socket to enumerate interfaces: %s", NULL);
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (test_addrp && test_addrp->sa.sa_family == AF_INET6)
|
||||
test_addrp->in6.sin6_flowinfo = htonl(0);
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -113,7 +118,7 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
|
||||
{
|
||||
if (errno != EINVAL || lastlen != 0)
|
||||
die ("ioctl error while enumerating interfaces: %s", NULL);
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -133,7 +138,7 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
|
||||
unaligned accesses. */
|
||||
int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
|
||||
if (!(ifr = realloc(ifr, ifr_len)))
|
||||
die("cannot allocate buffer", NULL);
|
||||
goto exit;
|
||||
|
||||
memcpy(ifr, ptr, ifr_len);
|
||||
ptr += ifr_len;
|
||||
@@ -147,6 +152,9 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
|
||||
{
|
||||
addr.in = *((struct sockaddr_in *) &ifr->ifr_addr);
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
||||
goto exit;
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifr->ifr_addr.sa_family == AF_INET6)
|
||||
@@ -164,9 +172,25 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
|
||||
continue; /* unknown address family */
|
||||
|
||||
if (ioctl(fd, SIOCGIFFLAGS, ifr) < 0)
|
||||
die("ioctl error getting interface flags: %m", NULL);
|
||||
goto exit;
|
||||
|
||||
iface = add_iface(daemon, iface, ifr->ifr_name, ifr->ifr_flags & IFF_LOOPBACK, &addr);
|
||||
if (iface_allowed(daemon, iface, ifr->ifr_name, ifr->ifr_flags & IFF_LOOPBACK, &addr))
|
||||
{
|
||||
if (chainp)
|
||||
{
|
||||
struct irec *new = safe_malloc(sizeof(struct irec));
|
||||
new->addr = addr;
|
||||
new->netmask = netmask;
|
||||
new->next = iface;
|
||||
iface = new;
|
||||
}
|
||||
else if (sockaddr_isequal(&addr, test_addrp))
|
||||
{
|
||||
*netmaskp = netmask;
|
||||
ret = 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
|
||||
@@ -198,13 +222,35 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
|
||||
|
||||
strncpy(sifr.ifr_name, devname, IF_NAMESIZE);
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &sifr) < 0)
|
||||
die("ioctl error getting interface flags: %m", NULL);
|
||||
iface = add_iface(daemon, iface, sifr.ifr_name, sifr.ifr_flags & IFF_LOOPBACK, &addr);
|
||||
goto exit;
|
||||
|
||||
if (iface_allowed(daemon, iface, sifr.ifr_name, sifr.ifr_flags & IFF_LOOPBACK, &addr))
|
||||
{
|
||||
if (chainp)
|
||||
{
|
||||
struct irec *new = safe_malloc(sizeof(struct irec));
|
||||
new->addr = addr;
|
||||
new->next = iface;
|
||||
iface = new;
|
||||
}
|
||||
else if (sockaddr_isequal(&addr, test_addrp))
|
||||
{
|
||||
ret = 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
#endif /* LINUX */
|
||||
|
||||
|
||||
if (chainp)
|
||||
{
|
||||
*chainp = iface;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (buf)
|
||||
free(buf);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
@@ -213,7 +259,7 @@ struct irec *enumerate_interfaces(struct daemon *daemon)
|
||||
#endif
|
||||
close(fd);
|
||||
|
||||
return iface;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -354,6 +400,7 @@ struct listener *create_bound_listeners(struct irec *interfaces, int port)
|
||||
{
|
||||
struct listener *new = safe_malloc(sizeof(struct listener));
|
||||
new->family = iface->addr.sa.sa_family;
|
||||
new->iface = iface;
|
||||
new->next = listeners;
|
||||
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
|
||||
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
|
||||
|
||||
162
src/option.c
162
src/option.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2004 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000 - 2005 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
|
||||
@@ -21,7 +21,7 @@ struct myoption {
|
||||
int val;
|
||||
};
|
||||
|
||||
#define OPTSTRING "ZDNLERKzowefnbvhdkqr: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:J:"
|
||||
#define OPTSTRING "yZDNLERKzowefnbvhdkqr: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:J:W:"
|
||||
|
||||
static struct myoption opts[] = {
|
||||
{"version", 0, 0, 'v'},
|
||||
@@ -76,6 +76,8 @@ static struct myoption opts[] = {
|
||||
{"edns-packet-max", 1, 0, 'P'},
|
||||
{"keep-in-foreground", 0, 0, 'k'},
|
||||
{"dhcp-authoritative", 0, 0, 'K'},
|
||||
{"srv-host", 1, 0, 'W'},
|
||||
{"localise-queries", 0, 0, 'y'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -102,6 +104,7 @@ static struct optflags optmap[] = {
|
||||
{ 'D', OPT_NODOTS_LOCAL },
|
||||
{ 'z', OPT_NOWILD },
|
||||
{ 'Z', OPT_ETHERS },
|
||||
{ 'y', OPT_LOCALISE },
|
||||
{ 'v', 0},
|
||||
{ 'w', 0},
|
||||
{ 0, 0 }
|
||||
@@ -137,7 +140,7 @@ static char *usage =
|
||||
"-K, --dhcp-authoritative Assume we are the only DHCP server on the local network.\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"
|
||||
"-m, --mx-host=host_name,target,pref Specify an MX record.\n"
|
||||
"-M, --dhcp-boot=<bootp opts> Specify BOOTP options to DHCP server.\n"
|
||||
"-n, --no-poll Do NOT poll " RESOLVFILE " file, reload only on SIGHUP.\n"
|
||||
"-N, --no-negcache Do NOT cache failed search results.\n"
|
||||
@@ -152,15 +155,17 @@ static char *usage =
|
||||
"-S, --server=/domain/ipaddr Specify address(es) of upstream servers with optional domains.\n"
|
||||
" --local=/domain/ Never forward queries to specified domains.\n"
|
||||
"-s, --domain=domain Specify the domain to be assigned in DHCP leases.\n"
|
||||
"-t, --mx-target=host_name Specify the host in an MX reply.\n"
|
||||
"-t, --mx-target=host_name Specify default target in an MX record.\n"
|
||||
"-T, --local-ttl=time Specify time-to-live in seconds for replies from /etc/hosts.\n"
|
||||
"-u, --user=username Change to this user after startup. (defaults to " CHUSER ").\n"
|
||||
"-U, --dhcp-vendorclass=<id>,<class> Map DHCP vendor class to option set.\n"
|
||||
"-v, --version Display dnsmasq version and copyright information.\n"
|
||||
"-V, --alias=addr,addr,mask Translate IPv4 addresses from upstream servers.\n"
|
||||
"-W, --srv-host=name,port,pri,weight Specify a SRV record.\n"
|
||||
"-w, --help Display this message.\n"
|
||||
"-x, --pid-file=path Specify path of PID file. (defaults to " RUNFILE ").\n"
|
||||
"-X, --dhcp-lease-max=number Specify maximum number of DHCP leases (defaults to %d).\n"
|
||||
"-y, --localise-queries Answer DNS queries based on the interface a query was sent to."
|
||||
"-z, --bind-interfaces Bind only to interfaces in use.\n"
|
||||
"-Z, --read-ethers Read DHCP static host information from " ETHERSFILE ".\n"
|
||||
"\n";
|
||||
@@ -372,24 +377,41 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
|
||||
case 'm':
|
||||
{
|
||||
int pref = 1;
|
||||
struct mx_record *new;
|
||||
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*(comma++) = 0;
|
||||
{
|
||||
char *prefstr;
|
||||
*(comma++) = 0;
|
||||
if ((prefstr=strchr(comma, ',')))
|
||||
{
|
||||
*(prefstr++) = 0;
|
||||
if (!atoi_check(prefstr, &pref))
|
||||
{
|
||||
option = '?';
|
||||
problem = "bad MX preference";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!canonicalise(optarg) || (comma && !canonicalise(comma)))
|
||||
{
|
||||
option = '?';
|
||||
problem = "bad MX name";
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct mx_record *new = safe_malloc(sizeof(struct mx_record));
|
||||
new->next = daemon->mxnames;
|
||||
daemon->mxnames = new;
|
||||
new->mxname = safe_string_alloc(optarg);
|
||||
new->mxtarget = safe_string_alloc(comma); /* may be NULL */
|
||||
}
|
||||
|
||||
new = safe_malloc(sizeof(struct mx_record));
|
||||
new->next = daemon->mxnames;
|
||||
daemon->mxnames = new;
|
||||
new->mxname = safe_string_alloc(optarg);
|
||||
new->mxtarget = safe_string_alloc(comma); /* may be NULL */
|
||||
new->preference = pref;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 't':
|
||||
if (!canonicalise(optarg))
|
||||
{
|
||||
@@ -747,7 +769,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
new->broadcast.s_addr = 0;
|
||||
new->router.s_addr = 0;
|
||||
new->netid.net = NULL;
|
||||
new->static_only = 0;
|
||||
new->static_only = new->filter_netid = 0;
|
||||
|
||||
problem = "bad dhcp-range";
|
||||
|
||||
@@ -758,7 +780,14 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
if (*cp != ',' && (comma = strchr(optarg, ',')))
|
||||
{
|
||||
*comma = 0;
|
||||
new->netid.net = safe_string_alloc(optarg);
|
||||
if (strstr(optarg, "net:") == optarg)
|
||||
{
|
||||
new->netid.net = safe_string_alloc(optarg+4);
|
||||
new->netid.next = NULL;
|
||||
new->filter_netid = 1;
|
||||
}
|
||||
else
|
||||
new->netid.net = safe_string_alloc(optarg);
|
||||
a[0] = comma + 1;
|
||||
}
|
||||
else
|
||||
@@ -1363,6 +1392,84 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'W':
|
||||
{
|
||||
int port = 1, priority = 0, weight = 0;
|
||||
char *name, *target = NULL;
|
||||
struct srv_record *new;
|
||||
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*(comma++) = 0;
|
||||
|
||||
if (!canonicalise(optarg))
|
||||
{
|
||||
option = '?';
|
||||
problem = "bad SRV record";
|
||||
break;
|
||||
}
|
||||
name = safe_string_alloc(optarg);
|
||||
|
||||
if (comma)
|
||||
{
|
||||
optarg = comma;
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*(comma++) = 0;
|
||||
if (!canonicalise(optarg))
|
||||
{
|
||||
option = '?';
|
||||
problem = "bad SRV target";
|
||||
break;
|
||||
}
|
||||
target = safe_string_alloc(optarg);
|
||||
if (comma)
|
||||
{
|
||||
optarg = comma;
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*(comma++) = 0;
|
||||
if (!atoi_check(optarg, &port))
|
||||
{
|
||||
option = '?';
|
||||
problem = "invalid port number";
|
||||
break;
|
||||
}
|
||||
if (comma)
|
||||
{
|
||||
optarg = comma;
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*(comma++) = 0;
|
||||
if (!atoi_check(optarg, &priority))
|
||||
{
|
||||
option = '?';
|
||||
problem = "invalid priority";
|
||||
break;
|
||||
}
|
||||
if (comma)
|
||||
{
|
||||
optarg = comma;
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*(comma++) = 0;
|
||||
if (!atoi_check(optarg, &weight))
|
||||
{
|
||||
option = '?';
|
||||
problem = "invalid weight";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new = safe_malloc(sizeof(struct srv_record));
|
||||
new->next = daemon->srvnames;
|
||||
daemon->srvnames = new;
|
||||
new->srvname = name;
|
||||
new->srvtarget = target;
|
||||
new->srvport = port;
|
||||
new->priority = priority;
|
||||
new->weight = weight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1411,24 +1518,39 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
#endif /* IPv6 */
|
||||
}
|
||||
|
||||
/* only one of these need be specified: the other defaults to the
|
||||
host-name */
|
||||
/* only one of these need be specified: the other defaults to the host-name */
|
||||
if ((daemon->options & OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
|
||||
{
|
||||
if (gethostname(buff, MAXDNAME) == -1)
|
||||
die("cannot get host-name: %s", NULL);
|
||||
|
||||
|
||||
if (!daemon->mxnames)
|
||||
{
|
||||
daemon->mxnames = safe_malloc(sizeof(struct mx_record));
|
||||
daemon->mxnames->next = NULL;
|
||||
daemon->mxnames->mxtarget = NULL;
|
||||
daemon->mxnames->mxname = safe_string_alloc(buff);
|
||||
}
|
||||
}
|
||||
|
||||
if (!daemon->mxtarget)
|
||||
daemon->mxtarget = safe_string_alloc(buff);
|
||||
}
|
||||
|
||||
if (daemon->domain_suffix)
|
||||
{
|
||||
/* add domain for any srv record without one. */
|
||||
struct srv_record *srv;
|
||||
|
||||
for (srv = daemon->srvnames; srv; srv = srv->next)
|
||||
if (strchr(srv->srvname, '.') && strchr(srv->srvname, '.') == strrchr(srv->srvname, '.'))
|
||||
{
|
||||
strcpy(buff, srv->srvname);
|
||||
strcat(buff, ".");
|
||||
strcat(buff, daemon->domain_suffix);
|
||||
free(srv->srvname);
|
||||
srv->srvname = safe_string_alloc(buff);
|
||||
}
|
||||
}
|
||||
|
||||
if (daemon->options & OPT_NO_RESOLV)
|
||||
daemon->resolv_files = 0;
|
||||
|
||||
520
src/rfc1035.c
520
src/rfc1035.c
@@ -12,6 +12,11 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static int add_resource_record(HEADER *header, char *limit, int *truncp,
|
||||
unsigned int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, int *offset, unsigned short type,
|
||||
unsigned short class, char *format, ...);
|
||||
|
||||
static int extract_name(HEADER *header, unsigned int plen, unsigned char **pp,
|
||||
unsigned char *name, int isExtract)
|
||||
{
|
||||
@@ -19,6 +24,9 @@ static int extract_name(HEADER *header, unsigned int plen, unsigned char **pp,
|
||||
unsigned int j, l, hops = 0;
|
||||
int retvalue = 1;
|
||||
|
||||
if (isExtract)
|
||||
*cp = 0;
|
||||
|
||||
while ((l = *p++))
|
||||
{
|
||||
unsigned int label_type = l & 0xc0;
|
||||
@@ -117,9 +125,8 @@ static int extract_name(HEADER *header, unsigned int plen, unsigned char **pp,
|
||||
|
||||
if (isExtract)
|
||||
*cp++ = '.';
|
||||
else
|
||||
if (*cp != 0 && *cp++ != '.')
|
||||
retvalue = 2;
|
||||
else if (*cp != 0 && *cp++ != '.')
|
||||
retvalue = 2;
|
||||
}
|
||||
|
||||
if ((unsigned int)(p - (unsigned char *)header) >= plen)
|
||||
@@ -128,7 +135,9 @@ static int extract_name(HEADER *header, unsigned int plen, unsigned char **pp,
|
||||
|
||||
if (isExtract)
|
||||
*--cp = 0; /* terminate: lose final period */
|
||||
|
||||
else if (*cp != 0)
|
||||
retvalue = 2;
|
||||
|
||||
if (p1) /* we jumped via compression */
|
||||
*pp = p1;
|
||||
else
|
||||
@@ -420,43 +429,6 @@ static int private_net(struct all_addr *addrp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *add_text_record(HEADER *header, unsigned int nameoffset, unsigned char *p,
|
||||
unsigned long ttl, unsigned short pref,
|
||||
unsigned short type, char *name, int *offset)
|
||||
{
|
||||
unsigned char *sav, *cp;
|
||||
int j;
|
||||
|
||||
PUTSHORT(nameoffset | 0xc000, p);
|
||||
PUTSHORT(type, p);
|
||||
PUTSHORT(C_IN, p);
|
||||
PUTLONG(ttl, p); /* TTL */
|
||||
|
||||
sav = p;
|
||||
PUTSHORT(0, p); /* dummy RDLENGTH */
|
||||
|
||||
if (pref)
|
||||
PUTSHORT(pref, p);
|
||||
|
||||
while (*name)
|
||||
{
|
||||
cp = p++;
|
||||
for (j=0; *name && (*name != '.'); name++, j++)
|
||||
*p++ = *name;
|
||||
*cp = j;
|
||||
if (*name)
|
||||
name++;
|
||||
}
|
||||
*p++ = 0;
|
||||
j = p - sav - 2;
|
||||
PUTSHORT(j, sav); /* Real RDLENGTH */
|
||||
|
||||
if (offset)
|
||||
*offset = sav - (unsigned char *)header;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void dns_doctor(HEADER *header, struct doctor *doctor, struct in_addr *addr)
|
||||
{
|
||||
for (; doctor; doctor = doctor->next)
|
||||
@@ -773,13 +745,7 @@ int setup_reply(HEADER *header, unsigned int qlen,
|
||||
header->rcode = NOERROR;
|
||||
header->ancount = htons(1);
|
||||
header->aa = 1;
|
||||
PUTSHORT (sizeof(HEADER) | 0xc000, p);
|
||||
PUTSHORT(T_A, p);
|
||||
PUTSHORT(C_IN, p);
|
||||
PUTLONG(ttl, p); /* TTL */
|
||||
PUTSHORT(INADDRSZ, p);
|
||||
memcpy(p, addrp, INADDRSZ);
|
||||
p += INADDRSZ;
|
||||
add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (p && flags == F_IPV6)
|
||||
@@ -787,13 +753,7 @@ int setup_reply(HEADER *header, unsigned int qlen,
|
||||
header->rcode = NOERROR;
|
||||
header->ancount = htons(1);
|
||||
header->aa = 1;
|
||||
PUTSHORT (sizeof(HEADER) | 0xc000, p);
|
||||
PUTSHORT(T_AAAA, p);
|
||||
PUTSHORT(C_IN, p);
|
||||
PUTLONG(ttl, p); /* TTL */
|
||||
PUTSHORT(IN6ADDRSZ, p);
|
||||
memcpy(p, addrp, IN6ADDRSZ);
|
||||
p += IN6ADDRSZ;
|
||||
add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
|
||||
}
|
||||
#endif
|
||||
else /* nowhere to forward to */
|
||||
@@ -803,18 +763,24 @@ int setup_reply(HEADER *header, unsigned int qlen,
|
||||
}
|
||||
|
||||
/* 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)
|
||||
int check_for_local_domain(char *name, time_t now, struct daemon *daemon)
|
||||
{
|
||||
struct crec *crecp;
|
||||
struct mx_record *mx;
|
||||
struct srv_record *srv;
|
||||
|
||||
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)
|
||||
for (mx = daemon->mxnames; mx; mx = mx->next)
|
||||
if (hostname_isequal(name, mx->mxname))
|
||||
return 1;
|
||||
|
||||
|
||||
for (srv = daemon->srvnames; srv; srv = srv->next)
|
||||
if (hostname_isequal(name, srv->srvname))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -862,8 +828,103 @@ int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
unsigned char *sav, *p = *pp;
|
||||
int j;
|
||||
unsigned short usval;
|
||||
long lval;
|
||||
char *sval;
|
||||
|
||||
if (truncp && *truncp)
|
||||
return 0;
|
||||
|
||||
PUTSHORT(nameoffset | 0xc000, p);
|
||||
PUTSHORT(type, p);
|
||||
PUTSHORT(class, p);
|
||||
PUTLONG(ttl, p); /* TTL */
|
||||
|
||||
sav = p; /* Save pointer to RDLength field */
|
||||
PUTSHORT(0, p); /* Placeholder RDLength */
|
||||
|
||||
va_start(ap, format); /* make ap point to 1st unamed argument */
|
||||
|
||||
for (; *format; format++)
|
||||
switch (*format)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
case '6':
|
||||
sval = va_arg(ap, char *);
|
||||
memcpy(p, sval, IN6ADDRSZ);
|
||||
p += IN6ADDRSZ;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case '4':
|
||||
sval = va_arg(ap, char *);
|
||||
memcpy(p, sval, INADDRSZ);
|
||||
p += INADDRSZ;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
usval = va_arg(ap, int);
|
||||
PUTSHORT(usval, p);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
lval = va_arg(ap, long);
|
||||
PUTLONG(lval, p);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
/* get domain-name answer arg and store it in RDATA field */
|
||||
sval = va_arg(ap, char *);
|
||||
while (sval && *sval)
|
||||
{
|
||||
unsigned char *cp = p++;
|
||||
for (j = 0; *sval && (*sval != '.'); sval++, j++)
|
||||
*p++ = *sval;
|
||||
*cp = j;
|
||||
if (*sval)
|
||||
sval++;
|
||||
}
|
||||
*p++ = 0;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
sval = va_arg(ap, char *);
|
||||
j = strlen(sval);
|
||||
*p++ = j;
|
||||
memcpy(p, sval, j);
|
||||
p += j;
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap); /* clean up variable argument pointer */
|
||||
|
||||
j = p - sav - 2;
|
||||
PUTSHORT(j, sav); /* Now, store real RDLength */
|
||||
|
||||
if (offset)
|
||||
*offset = sav - (unsigned char *)header;
|
||||
|
||||
/* check for overflow of buffer */
|
||||
if (limit && ((unsigned char *)limit - p) < 0)
|
||||
{
|
||||
if (truncp)
|
||||
*truncp = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pp = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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 daemon *daemon, time_t now)
|
||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon *daemon,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp, *pheader;
|
||||
@@ -872,10 +933,10 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
||||
unsigned int nameoffset;
|
||||
unsigned short flag;
|
||||
int qdcount = ntohs(header->qdcount);
|
||||
int q, ans, anscount;
|
||||
int q, ans, anscount = 0;
|
||||
int dryrun = 0, sec_reqd = 0;
|
||||
struct crec *crecp;
|
||||
int nxdomain, auth;
|
||||
int nxdomain = 0, auth = 1, trunc = 0;
|
||||
|
||||
if (!qdcount || header->opcode != QUERY )
|
||||
return 0;
|
||||
@@ -914,7 +975,6 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
||||
|
||||
/* now process each question, answers go in RRs after the question */
|
||||
p = (unsigned char *)(header+1);
|
||||
nxdomain = 0, auth = 1, anscount = 0;
|
||||
|
||||
for (q=0; q<qdcount; q++)
|
||||
{
|
||||
@@ -940,7 +1000,6 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
int len;
|
||||
if (hostname_isequal(name, "version.bind"))
|
||||
sprintf(name, "dnsmasq-%s", VERSION);
|
||||
else if (hostname_isequal(name, "authors.bind"))
|
||||
@@ -949,112 +1008,104 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
||||
sprintf(name, COPYRIGHT);
|
||||
else
|
||||
*name = 0;
|
||||
len = strlen(name);
|
||||
PUTSHORT(nameoffset | 0xc000, ansp);
|
||||
PUTSHORT(T_TXT, ansp);
|
||||
PUTSHORT(C_CHAOS, ansp);
|
||||
PUTLONG(0, ansp);
|
||||
PUTSHORT(len+1, ansp);
|
||||
*ansp++ = len;
|
||||
memcpy(ansp, name, len);
|
||||
ansp += len;
|
||||
anscount++;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 0, NULL,
|
||||
T_TXT, C_CHAOS, "t", name))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
else if (qclass == C_IN)
|
||||
{
|
||||
if ((daemon->options & OPT_FILTER) &&
|
||||
(qtype == T_SOA || qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||
if (qtype == T_PTR || qtype == T_ANY)
|
||||
{
|
||||
ans = 1;
|
||||
log_query(F_CONFIG | F_NEG, name, &addr, 0, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (qtype == T_PTR || qtype == T_ANY)
|
||||
{
|
||||
if (!(crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
|
||||
{
|
||||
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;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, name, &addr, 0, NULL, 0);
|
||||
nxdomain = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else do
|
||||
{
|
||||
/* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
|
||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
continue;
|
||||
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, 0, NULL, 0);
|
||||
auth = 0;
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
}
|
||||
}
|
||||
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned long ttl;
|
||||
/* Return 0 ttl for DHCP entries, which might change
|
||||
before the lease expires. */
|
||||
if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
||||
ttl = daemon->local_ttl;
|
||||
else
|
||||
ttl = crecp->ttd - now;
|
||||
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
auth = 0;
|
||||
|
||||
ansp = add_text_record(header, nameoffset, ansp, ttl, 0, T_PTR,
|
||||
cache_get_name(crecp), NULL);
|
||||
|
||||
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
|
||||
0, daemon->addn_hosts, crecp->uid);
|
||||
anscount++;
|
||||
|
||||
/* if last answer exceeded packet size, give up */
|
||||
if (((unsigned char *)limit - ansp) < 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
|
||||
}
|
||||
|
||||
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
|
||||
{
|
||||
unsigned short type = T_A;
|
||||
int addrsz = INADDRSZ;
|
||||
|
||||
if (flag == F_IPV6)
|
||||
if (!(crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
|
||||
{
|
||||
if (is_arpa == F_IPV4 && (daemon->options & OPT_BOGUSPRIV) && private_net(&addr))
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
type = T_AAAA;
|
||||
addrsz = IN6ADDRSZ;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||
ans = 1;
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, name, &addr, 0, NULL, 0);
|
||||
}
|
||||
|
||||
if (qtype != type && qtype != T_ANY)
|
||||
}
|
||||
else do
|
||||
{
|
||||
/* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
|
||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
continue;
|
||||
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
ans = 1;
|
||||
auth = 0;
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, 0, NULL, 0);
|
||||
}
|
||||
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
|
||||
{
|
||||
ans = 1;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
auth = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned long ttl;
|
||||
/* Return 0 ttl for DHCP entries, which might change
|
||||
before the lease expires. */
|
||||
if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
||||
ttl = daemon->local_ttl;
|
||||
else
|
||||
ttl = crecp->ttd - now;
|
||||
|
||||
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
|
||||
0, daemon->addn_hosts, crecp->uid);
|
||||
|
||||
cname_restart:
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)))
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL,
|
||||
T_PTR, C_IN, "d", cache_get_name(crecp)))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
|
||||
}
|
||||
|
||||
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
|
||||
{
|
||||
unsigned short type = T_A;
|
||||
|
||||
if (flag == F_IPV6)
|
||||
#ifdef HAVE_IPV6
|
||||
type = T_AAAA;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
|
||||
if (qtype != type && qtype != T_ANY)
|
||||
continue;
|
||||
|
||||
cname_restart:
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
|
||||
{
|
||||
int localise = 0;
|
||||
|
||||
/* See if a putative address is on the network from which we recieved
|
||||
the query, is so we'll filter other answers. */
|
||||
if (local_addr.s_addr != 0 && (daemon->options & OPT_LOCALISE) && flag == F_IPV4)
|
||||
{
|
||||
struct crec *save = crecp;
|
||||
do {
|
||||
if ((crecp->flags & F_HOSTS) &&
|
||||
is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
|
||||
{
|
||||
localise = 1;
|
||||
break;
|
||||
}
|
||||
} while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
|
||||
crecp = save;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
/* don't answer wildcard queries with data not from /etc/hosts
|
||||
or DHCP leases */
|
||||
@@ -1065,29 +1116,37 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
||||
{
|
||||
if (!dryrun)
|
||||
{
|
||||
ansp = add_text_record(header, nameoffset, ansp, crecp->ttd - now, 0, T_CNAME,
|
||||
cache_get_name(crecp->addr.cname.cache), &nameoffset);
|
||||
anscount++;
|
||||
log_query(crecp->flags, name, NULL, 0, daemon->addn_hosts, crecp->uid);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crecp->ttd - now, &nameoffset,
|
||||
T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
|
||||
strcpy(name, cache_get_name(crecp->addr.cname.cache));
|
||||
goto cname_restart;
|
||||
}
|
||||
|
||||
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
ans = 1;
|
||||
auth = 0;
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(crecp->flags, name, NULL, 0, NULL, 0);
|
||||
auth = 0;
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
}
|
||||
log_query(crecp->flags, name, NULL, 0, NULL, 0);
|
||||
}
|
||||
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
|
||||
{
|
||||
/* If we are returning local answers depending on network,
|
||||
filter here. */
|
||||
if (localise &&
|
||||
(crecp->flags & F_HOSTS) &&
|
||||
!is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
|
||||
continue;
|
||||
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
auth = 0;
|
||||
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
@@ -1098,68 +1157,93 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
||||
else
|
||||
ttl = crecp->ttd - now;
|
||||
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
auth = 0;
|
||||
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
|
||||
0, daemon->addn_hosts, crecp->uid);
|
||||
|
||||
/* copy question as first part of answer (use compression) */
|
||||
PUTSHORT(nameoffset | 0xc000, ansp);
|
||||
PUTSHORT(type, ansp);
|
||||
PUTSHORT(C_IN, ansp);
|
||||
PUTLONG(ttl, ansp); /* TTL */
|
||||
|
||||
PUTSHORT(addrsz, ansp);
|
||||
memcpy(ansp, &crecp->addr, addrsz);
|
||||
ansp += addrsz;
|
||||
anscount++;
|
||||
|
||||
if (((unsigned char *)limit - ansp) < 0)
|
||||
return 0;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, type, C_IN,
|
||||
type == T_A ? "4" : "6", &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
|
||||
}
|
||||
|
||||
if (qtype == T_MX || qtype == T_ANY)
|
||||
{
|
||||
struct mx_record *mx;
|
||||
for (mx = daemon->mxnames; mx; mx = mx->next)
|
||||
if (hostname_isequal(name, mx->mxname))
|
||||
break;
|
||||
if (mx)
|
||||
}
|
||||
|
||||
if (qtype == T_MX || qtype == T_ANY)
|
||||
{
|
||||
int found = 0;
|
||||
struct mx_record *mx;
|
||||
for (mx = daemon->mxnames; mx; mx = mx->next)
|
||||
if (hostname_isequal(name, mx->mxname))
|
||||
{
|
||||
ans = found = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
ansp = add_text_record(header, nameoffset, ansp, daemon->local_ttl, 1, T_MX,
|
||||
mx->mxtarget ? mx->mxtarget : daemon->mxtarget, NULL);
|
||||
anscount++;
|
||||
}
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
|
||||
T_MX, C_IN, "sd", mx->preference,
|
||||
mx->mxtarget ? mx->mxtarget : daemon->mxtarget))
|
||||
anscount++;
|
||||
}
|
||||
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(header, nameoffset, ansp, daemon->local_ttl, 1, T_MX,
|
||||
(daemon->options & OPT_SELFMX) ? name : daemon->mxtarget, NULL);
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && (daemon->options & (OPT_SELFMX | OPT_LOCALMX)) &&
|
||||
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
|
||||
T_MX, C_IN, "sd", 1,
|
||||
(daemon->options & OPT_SELFMX) ? name : daemon->mxtarget))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (qtype == T_SRV || qtype == T_ANY)
|
||||
{
|
||||
int found = 0;
|
||||
struct srv_record *srv;
|
||||
|
||||
if (qtype == T_MAILB)
|
||||
ans = 1, nxdomain = 1;
|
||||
for (srv = daemon->srvnames; srv; srv = srv->next)
|
||||
if (hostname_isequal(name, srv->srvname))
|
||||
{
|
||||
found = ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV6, name, NULL, 0, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
NULL, T_SRV, C_IN, "sssd",
|
||||
srv->priority, srv->weight, srv->srvport, srv->srvtarget))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && (daemon->options & OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_NEG, name, NULL, 0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (qtype == T_MAILB)
|
||||
ans = 1, nxdomain = 1;
|
||||
|
||||
if (qtype == T_SOA && (daemon->options & OPT_FILTER))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_NEG, name, &addr, 0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ans || ((unsigned char *)limit - ansp) < 0)
|
||||
|
||||
if (!ans)
|
||||
return 0; /* failed to answer a question */
|
||||
}
|
||||
|
||||
|
||||
if (dryrun)
|
||||
{
|
||||
dryrun = 0;
|
||||
@@ -1170,7 +1254,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
||||
header->qr = 1; /* response */
|
||||
header->aa = auth; /* authoritive - only hosts and DHCP derived names. */
|
||||
header->ra = 1; /* recursion if available */
|
||||
header->tc = 0; /* truncation */
|
||||
header->tc = trunc; /* truncation */
|
||||
if (anscount == 0 && nxdomain)
|
||||
header->rcode = NXDOMAIN;
|
||||
else
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2003 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2005 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
|
||||
@@ -59,13 +59,12 @@ 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);
|
||||
static void bootp_option_put(struct dhcp_packet *mess,
|
||||
struct dhcp_boot *boot_opts, struct dhcp_netid *netids);
|
||||
static unsigned int option_len(unsigned char *opt);
|
||||
static int option_len(unsigned char *opt);
|
||||
static void *option_ptr(unsigned char *opt);
|
||||
static struct in_addr option_addr(unsigned char *opt);
|
||||
static unsigned int option_uint(unsigned char *opt, int size);
|
||||
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string);
|
||||
static int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool);
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type, unsigned int minsize);
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type, int minsize);
|
||||
static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
unsigned char *p, unsigned char *end,
|
||||
unsigned char *req_options,
|
||||
@@ -211,7 +210,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
if (have_config(config, CONFIG_NAME))
|
||||
hostname = config->hostname;
|
||||
|
||||
if (context->netid.net)
|
||||
if (context->netid.net && !context->filter_netid)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
@@ -255,7 +254,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
hostname = config->hostname;
|
||||
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
|
||||
{
|
||||
unsigned int len = option_len(opt);
|
||||
int len = option_len(opt);
|
||||
hostname = daemon->dhcp_buff;
|
||||
memcpy(hostname, option_ptr(opt), len);
|
||||
/* May not be zero terminated */
|
||||
@@ -291,7 +290,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
unsigned char *ucp = option_ptr(opt);
|
||||
unsigned int tmp, j;
|
||||
int tmp, j;
|
||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
||||
if (j == option_len(opt))
|
||||
for (j = 0; j < option_len(opt); j = tmp)
|
||||
@@ -304,7 +303,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
if ((opt = option_find(mess, sz, vendor->is_vendor ? OPTION_VENDOR_ID : OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
unsigned int i;
|
||||
int i;
|
||||
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
||||
if (memcmp(vendor->data, option_ptr(opt)+i, vendor->len) == 0)
|
||||
{
|
||||
@@ -407,7 +406,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
else if (opt && address_available(context, addr) && !lease_find_by_addr(addr) &&
|
||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
||||
mess->yiaddr = addr;
|
||||
else if (!address_allocate(context, daemon, &mess->yiaddr, mess->chaddr))
|
||||
else if (!address_allocate(context, daemon, &mess->yiaddr, mess->chaddr, netid))
|
||||
message = "no address available";
|
||||
log_packet("DISCOVER", opt ? &addr : NULL, mess->chaddr, iface_name, message);
|
||||
|
||||
@@ -415,7 +414,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
return 0;
|
||||
|
||||
context = narrow_context(context, mess->yiaddr);
|
||||
if (context->netid.net)
|
||||
if (context->netid.net && !context->filter_netid)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
@@ -542,7 +541,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
log_packet("ACK", &mess->yiaddr, mess->chaddr, iface_name, hostname);
|
||||
|
||||
context = narrow_context(context, mess->yiaddr);
|
||||
if (context->netid.net)
|
||||
if (context->netid.net && !context->filter_netid)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
@@ -628,7 +627,7 @@ static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr,
|
||||
string ? string : "");
|
||||
}
|
||||
|
||||
static unsigned int option_len(unsigned char *opt)
|
||||
static int option_len(unsigned char *opt)
|
||||
{
|
||||
return opt[1];
|
||||
}
|
||||
@@ -769,7 +768,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type, unsigned int minsize)
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type, int minsize)
|
||||
{
|
||||
int overload = 0;
|
||||
unsigned char *ret;
|
||||
@@ -805,32 +804,6 @@ static int in_list(unsigned char *list, int opt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is every member of check matched by a member of pool? */
|
||||
static int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||
{
|
||||
struct dhcp_netid *tmp1;
|
||||
|
||||
if (!check)
|
||||
return 0;
|
||||
|
||||
for (; check; check = check->next)
|
||||
{
|
||||
if (check->net[0] != '#')
|
||||
{
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp(check->net, tmp1->net) == 0)
|
||||
break;
|
||||
if (!tmp1)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp((check->net)+1, tmp1->net) == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
|
||||
{
|
||||
struct dhcp_opt *tmp;
|
||||
|
||||
12
src/util.c
12
src/util.c
@@ -113,20 +113,22 @@ int legal_char(char c)
|
||||
int canonicalise(char *s)
|
||||
{
|
||||
/* check for legal chars and remove trailing .
|
||||
also fail empty string. */
|
||||
int l = strlen(s);
|
||||
also fail empty string and label > 63 chars */
|
||||
int dotgap = 0, l = strlen(s);
|
||||
char c;
|
||||
|
||||
if (l == 0) return 0;
|
||||
if (l == 0 || l > MAXDNAME) return 0;
|
||||
|
||||
if (s[l-1] == '.')
|
||||
{
|
||||
if (l == 1) return 0;
|
||||
s[l-1] = 0;
|
||||
}
|
||||
|
||||
|
||||
while ((c = *s++))
|
||||
if (c != '.' && !legal_char(c))
|
||||
if (c == '.')
|
||||
dotgap = 0;
|
||||
else if (!legal_char(c) || (++dotgap > MAXLABEL))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user