Commit 2bb73af7 authored by Simon Kelley's avatar Simon Kelley

Add --synth-domain

parent 86e92f99
...@@ -15,6 +15,9 @@ version 2.67 ...@@ -15,6 +15,9 @@ version 2.67
Fix --dhcp-match, --dhcp-vendorclass and --dhcp-userclass Fix --dhcp-match, --dhcp-vendorclass and --dhcp-userclass
to work with BOOTP and well as DHCP. Thanks to Peter to work with BOOTP and well as DHCP. Thanks to Peter
Korsgaard for spotting the problem. Korsgaard for spotting the problem.
Add --synth-domain. Thanks to Vishvananda Ishaya for
suggesting this.
version 2.66 version 2.66
......
...@@ -65,7 +65,7 @@ version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"' ...@@ -65,7 +65,7 @@ version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
objs = cache.o rfc1035.o util.o option.o forward.o network.o \ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \ dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \ helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o domain.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h dns-protocol.h radv-protocol.h
......
...@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \ ...@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
netlink.c network.c option.c rfc1035.c \ netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c \ rfc2131.c tftp.c util.c conntrack.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \ dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c auth.c ipset.c radv.c slaac.c auth.c ipset.c domain.c
LOCAL_MODULE := dnsmasq LOCAL_MODULE := dnsmasq
......
...@@ -519,6 +519,21 @@ the name. More than one name may be associated with an interface ...@@ -519,6 +519,21 @@ the name. More than one name may be associated with an interface
address by repeating the flag; in that case the first instance is used address by repeating the flag; in that case the first instance is used
for the reverse address-to-name mapping. for the reverse address-to-name mapping.
.TP .TP
.B --synth-domain=<domain>,<address range>
Create artificial A/AAAA and PTR records for an address range. The
records use the address, with periods (or colons for IPv6) replaced
with dashes.
An example should make this clearer.
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24
will result in a query for 192-168-0-56.thekelleys.org.uk returning
192.168.0.56 and a reverse query vice versa. The same applies to IPv6, but IPv6 addresses may start with '::'
but DNS labels may not start with '-' so in this case a zero is added
in front of the label. ::1 becomes 0--1.
The address range can be of the form
<ip address>,<ip address> or <ip address>/<netmask>
.TP
.B --add-mac .B --add-mac
Add the MAC address of the requestor to DNS queries which are Add the MAC address of the requestor to DNS queries which are
forwarded upstream. This may be used to DNS filtering by the upstream forwarded upstream. This may be used to DNS filtering by the upstream
......
...@@ -971,38 +971,6 @@ void cache_reload(void) ...@@ -971,38 +971,6 @@ void cache_reload(void)
total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz); total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
} }
char *get_domain(struct in_addr addr)
{
struct cond_domain *c;
for (c = daemon->cond_domain; c; c = c->next)
if (!c->is6 &&
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return c->domain;
return daemon->domain_suffix;
}
#ifdef HAVE_IPV6
char *get_domain6(struct in6_addr *addr)
{
struct cond_domain *c;
u64 addrpart = addr6part(addr);
for (c = daemon->cond_domain; c; c = c->next)
if (c->is6 &&
is_same_net6(addr, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
return c->domain;
return daemon->domain_suffix;
}
#endif
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
struct in_addr a_record_from_hosts(char *name, time_t now) struct in_addr a_record_from_hosts(char *name, time_t now)
{ {
......
...@@ -789,7 +789,7 @@ extern struct daemon { ...@@ -789,7 +789,7 @@ extern struct daemon {
struct name_list *secondary_forward_server; struct name_list *secondary_forward_server;
int group_set, osport; int group_set, osport;
char *domain_suffix; char *domain_suffix;
struct cond_domain *cond_domain; struct cond_domain *cond_domain, *synth_domains;
char *runfile; char *runfile;
char *lease_change_command; char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers; struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers;
...@@ -907,15 +907,19 @@ void cache_unhash_dhcp(void); ...@@ -907,15 +907,19 @@ void cache_unhash_dhcp(void);
void dump_cache(time_t now); void dump_cache(time_t now);
char *cache_get_name(struct crec *crecp); char *cache_get_name(struct crec *crecp);
struct crec *cache_enumerate(int init); struct crec *cache_enumerate(int init);
char *get_domain(struct in_addr addr);
#ifdef HAVE_IPV6
char *get_domain6(struct in6_addr *addr);
#endif
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
struct keydata *keydata_alloc(char *data, size_t len); struct keydata *keydata_alloc(char *data, size_t len);
void keydata_free(struct keydata *blocks); void keydata_free(struct keydata *blocks);
#endif #endif
/* domain.c */
char *get_domain(struct in_addr addr);
#ifdef HAVE_IPV6
char *get_domain6(struct in6_addr *addr);
#endif
int is_name_synthetic(int flags, char *name, struct all_addr *addr);
int is_rev_synth(int flag, struct all_addr *addr, char *name);
/* rfc1035.c */ /* rfc1035.c */
unsigned int extract_request(struct dns_header *header, size_t qlen, unsigned int extract_request(struct dns_header *header, size_t qlen,
char *name, unsigned short *typep); char *name, unsigned short *typep);
......
/* dnsmasq is Copyright (c) 2000-2013 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
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c);
#ifdef HAVE_IPV6
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
#endif
int is_name_synthetic(int flags, char *name, struct all_addr *addr)
{
char *p;
struct cond_domain *c = NULL;
int prot = AF_INET;
#ifdef HAVE_IPV6
if (flags & F_IPV6)
prot = AF_INET6;
#endif
/* NB, must not alter name if we return zero */
for (p = name; *p; p++)
{
char c = *p;
if ((c >='0' && c <= '9') || c == '-')
continue;
#ifdef HAVE_IPV6
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
continue;
#endif
break;
}
if (*p != '.')
return 0;
*p = 0;
for (p = name; *p; p++)
if (*p == '-')
{
if (prot == AF_INET)
*p = '.';
#ifdef HAVE_IPV6
else
*p = ':';
#endif
}
if (inet_pton(prot, name, addr))
for (c = daemon->synth_domains; c; c = c->next)
if (hostname_isequal(c->domain, p+1))
{
if (prot == AF_INET)
{
if (!c->is6 &&
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
break;
}
#ifdef HAVE_IPV6
else
{
u64 addrpart = addr6part(&addr->addr.addr6);
if (c->is6 &&
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
break;
}
#endif
}
/* restore name */
for (p = name; *p; p++)
if (*p == '.' || *p == ':')
*p = '-';
*p = '.';
return (c != NULL);
}
int is_rev_synth(int flag, struct all_addr *addr, char *name)
{
struct cond_domain *c;
if (flag & F_IPV4 && (c = search_domain(addr->addr.addr4, daemon->synth_domains)))
{
char *p;
inet_ntop(AF_INET, &addr->addr.addr4, name, ADDRSTRLEN);
for (p = name; *p; p++)
if (*p == '.')
*p = '-';
strncat(name, ".", MAXDNAME);
strncat(name, c->domain, MAXDNAME);
return 1;
}
#ifdef HAVE_IPV6
if (flag & F_IPV6 && (c = search_domain6(&addr->addr.addr6, daemon->synth_domains)))
{
char *p;
inet_ntop(AF_INET6, &addr->addr.addr6, name, ADDRSTRLEN);
/* IPv6 presentation address can start with ":", but valid domain names
cannot start with "-" so prepend a zero in that case. */
if (*name == ':')
{
*name = '0';
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
}
for (p = name; *p; p++)
if (*p == ':')
*p = '-';
strncat(name, ".", MAXDNAME);
strncat(name, c->domain, MAXDNAME);
return 1;
}
#endif
return 0;
}
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
{
for (; c; c = c->next)
if (!c->is6 &&
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return c;
return NULL;
}
char *get_domain(struct in_addr addr)
{
struct cond_domain *c;
if ((c = search_domain(addr, daemon->cond_domain)))
return c->domain;
return daemon->domain_suffix;
}
#ifdef HAVE_IPV6
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
{
u64 addrpart = addr6part(addr);
for (; c; c = c->next)
if (c->is6 &&
is_same_net6(addr, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
return c;
return NULL;
}
char *get_domain6(struct in6_addr *addr)
{
struct cond_domain *c;
if ((c = search_domain6(addr, daemon->cond_domain)))
return c->domain;
return daemon->domain_suffix;
}
#endif
...@@ -128,8 +128,9 @@ struct myoption { ...@@ -128,8 +128,9 @@ struct myoption {
#define LOPT_AUTHSFS 317 #define LOPT_AUTHSFS 317
#define LOPT_AUTHPEER 318 #define LOPT_AUTHPEER 318
#define LOPT_IPSET 319 #define LOPT_IPSET 319
#define LOPT_SYNTH 320
#ifdef OPTION6_PREFIX_CLASS #ifdef OPTION6_PREFIX_CLASS
#define LOPT_PREF_CLSS 320 #define LOPT_PREF_CLSS 321
#endif #endif
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
...@@ -264,6 +265,7 @@ static const struct myoption opts[] = ...@@ -264,6 +265,7 @@ static const struct myoption opts[] =
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS }, { "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
{ "auth-peer", 1, 0, LOPT_AUTHPEER }, { "auth-peer", 1, 0, LOPT_AUTHPEER },
{ "ipset", 1, 0, LOPT_IPSET }, { "ipset", 1, 0, LOPT_IPSET },
{ "synth-domain", 1, 0, LOPT_SYNTH },
#ifdef OPTION6_PREFIX_CLASS #ifdef OPTION6_PREFIX_CLASS
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS }, { "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
#endif #endif
...@@ -406,6 +408,7 @@ static struct { ...@@ -406,6 +408,7 @@ static struct {
{ LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL }, { LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
{ LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL }, { LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
{ LOPT_IPSET, ARG_DUP, "/<domain>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL }, { LOPT_IPSET, ARG_DUP, "/<domain>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>", gettext_noop("Specify a domain and address range for sythesised names"), NULL },
#ifdef OPTION6_PREFIX_CLASS #ifdef OPTION6_PREFIX_CLASS
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL }, { LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
#endif #endif
...@@ -1687,7 +1690,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -1687,7 +1690,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break; break;
case 's': /* --domain */ case 's': /* --domain */
case LOPT_SYNTH: /* --synth-domain */
if (strcmp (arg, "#") == 0) if (strcmp (arg, "#") == 0)
set_option_bool(OPT_RESOLV_DOMAIN); set_option_bool(OPT_RESOLV_DOMAIN);
else else
...@@ -1702,7 +1706,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -1702,7 +1706,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{ {
struct cond_domain *new = opt_malloc(sizeof(struct cond_domain)); struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
char *netpart; char *netpart;
unhide_metas(comma); unhide_metas(comma);
if ((netpart = split_chr(comma, '/'))) if ((netpart = split_chr(comma, '/')))
{ {
...@@ -1723,7 +1727,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -1723,7 +1727,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
local=/<domain>/ local=/<domain>/
local=/xxx.yyy.zzz.in-addr.arpa/ */ local=/xxx.yyy.zzz.in-addr.arpa/ */
if (strcmp(arg, "local") != 0 || if (strcmp(arg, "local") != 0 ||
option != 's' ||
(msize != 8 && msize != 16 && msize != 24)) (msize != 8 && msize != 16 && msize != 24))
ret_err(gen_err); ret_err(gen_err);
else else
...@@ -1779,7 +1784,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -1779,7 +1784,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
local=/<domain>/ local=/<domain>/
local=/xxx.yyy.zzz.ip6.arpa/ */ local=/xxx.yyy.zzz.ip6.arpa/ */
if (strcmp(arg, "local") != 0 || ((msize & 4) != 0)) if (strcmp(arg, "local") != 0 ||
option != 's' ||
((msize & 4) != 0))
ret_err(gen_err); ret_err(gen_err);
else else
{ {
...@@ -1813,7 +1820,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -1813,7 +1820,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
else else
ret_err(gen_err); ret_err(gen_err);
} }
else else
{ {
arg = split(comma); arg = split(comma);
if (inet_pton(AF_INET, comma, &new->start)) if (inet_pton(AF_INET, comma, &new->start))
...@@ -1839,11 +1846,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -1839,11 +1846,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
new->domain = d; new->domain = d;
new->next = daemon->cond_domain; if (option == 's')
daemon->cond_domain = new; {
new->next = daemon->cond_domain;
daemon->cond_domain = new;
}
else
{
new->next = daemon->synth_domains;
daemon->synth_domains = new;
}
} }
else else if (option == 's')
daemon->domain_suffix = d; daemon->domain_suffix = d;
else
ret_err(gen_err);
} }
} }
break; break;
......
...@@ -1517,6 +1517,19 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1517,6 +1517,19 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
} }
} }
} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa))); } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
else if (is_rev_synth(is_arpa, &addr, name))
{
ans = 1;
if (!dryrun)
{
log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL,
T_PTR, C_IN, "d", name))
anscount++;
}
}
else if (is_arpa == F_IPV4 && else if (is_arpa == F_IPV4 &&
option_bool(OPT_BOGUSPRIV) && option_bool(OPT_BOGUSPRIV) &&
private_net(addr.addr.addr4, 1)) private_net(addr.addr.addr4, 1))
...@@ -1687,6 +1700,17 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1687,6 +1700,17 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
} }
} while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME))); } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
} }
else if (is_name_synthetic(flag, name, &addr))
{
ans = 1;
if (!dryrun)
{
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
anscount++;
}
}
} }
if (qtype == T_CNAME || qtype == T_ANY) if (qtype == T_CNAME || qtype == T_ANY)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment