--host-record support

This commit is contained in:
Simon Kelley
2012-03-16 13:18:57 +00:00
parent 40ef23b547
commit e759d426fa
5 changed files with 129 additions and 22 deletions

View File

@@ -21,6 +21,9 @@ version 2.61
Better logging of DHCPv6 options. Better logging of DHCPv6 options.
Add --host-record. Thanks to Rob Zwissler for the
suggestion.
version 2.60 version 2.60
Fix compilation problem in Mac OS X Lion. Thanks to Olaf Fix compilation problem in Mac OS X Lion. Thanks to Olaf

View File

@@ -416,6 +416,22 @@ zone files: the port, weight and priority numbers are in a different
order. More than one SRV record for a given service/domain is allowed, order. More than one SRV record for a given service/domain is allowed,
all that match are returned. all that match are returned.
.TP .TP
.B --host-record=<name>[,<name>....][<IPv4-address>],[IPv6-address]
Add A, AAAA and PTR records to the DNS. This adds one or more names to
the DNS with associated IPv4 (A) and IPv6 (AAAA) records. A name may
appear in more than one
.B host-record
and therefore be assigned more than one address. Only the first
address creates a PTR record linking the address to the name. This is
the same rule as is used reading hosts-files.
.B host-record
options are considered to be read before host-files, so a name
appearing there inhibits PTR-record creation if it appears in
hosts-file also. Unlike host-files, names are not expanded, even when
.B expand-hosts
is in effect. Short and long names may appear in the same
.B host-record, eg. --host-record=laptop,laptop.thekelleys.org,192.168.0.1,1234::100
.TP
.B \-Y, --txt-record=<name>[[,<text>],<text>] .B \-Y, --txt-record=<name>[[,<text>],<text>]
Return a TXT DNS record. The value of TXT record is a set of strings, Return a TXT DNS record. The value of TXT record is a set of strings,
so any number may be included, delimited by commas; use quotes to put so any number may be included, delimited by commas; use quotes to put

View File

@@ -634,10 +634,11 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
return NULL; return NULL;
} }
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen, static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
unsigned short flags, int index, struct crec **rhash, int hashsz) int index, struct crec **rhash, int hashsz)
{ {
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6)); struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
int i, nameexists = 0; int i, nameexists = 0;
struct cname *a; struct cname *a;
unsigned int j; unsigned int j;
@@ -670,10 +671,10 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
j = (j*2 +((unsigned char *)addr)[i]) % hashsz; j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
for (lookup = rhash[j]; lookup; lookup = lookup->next) for (lookup = rhash[j]; lookup; lookup = lookup->next)
if ((lookup->flags & flags & (F_IPV4 | F_IPV6)) && if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0) memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{ {
flags &= ~F_REVERSE; cache->flags &= ~F_REVERSE;
break; break;
} }
@@ -684,7 +685,6 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
rhash[j] = cache; rhash[j] = cache;
} }
cache->flags = flags;
cache->uid = index; cache->uid = index;
memcpy(&cache->addr.addr, addr, addrlen); memcpy(&cache->addr.addr, addr, addrlen);
cache_hash(cache); cache_hash(cache);
@@ -692,7 +692,7 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
/* don't need to do alias stuff for second and subsequent addresses. */ /* don't need to do alias stuff for second and subsequent addresses. */
if (!nameexists) if (!nameexists)
for (a = daemon->cnames; a; a = a->next) for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(cache->name.sname, a->target) && if (hostname_isequal(cache_get_name(cache), a->target) &&
(lookup = whine_malloc(sizeof(struct crec)))) (lookup = whine_malloc(sizeof(struct crec))))
{ {
lookup->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME; lookup->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;
@@ -771,26 +771,19 @@ static int read_hostsfile(char *filename, int index, int cache_size, struct crec
{ {
lineno++; lineno++;
#ifdef HAVE_IPV6
if (inet_pton(AF_INET, token, &addr) > 0) if (inet_pton(AF_INET, token, &addr) > 0)
{ {
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4; flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ; addrlen = INADDRSZ;
domain_suffix = get_domain(addr.addr.addr4); domain_suffix = get_domain(addr.addr.addr4);
} }
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, token, &addr) > 0) else if (inet_pton(AF_INET6, token, &addr) > 0)
{ {
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6; flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
addrlen = IN6ADDRSZ; addrlen = IN6ADDRSZ;
domain_suffix = get_domain6(&addr.addr.addr6); domain_suffix = get_domain6(&addr.addr.addr6);
} }
#else
if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ;
domain_suffix = get_domain(addr.addr.addr4);
}
#endif #endif
else else
{ {
@@ -830,13 +823,15 @@ static int read_hostsfile(char *filename, int index, int cache_size, struct crec
strcpy(cache->name.sname, canon); strcpy(cache->name.sname, canon);
strcat(cache->name.sname, "."); strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix); strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags, index, rhash, hashsz); cache->flags = flags;
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
name_count++; name_count++;
} }
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME))) if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
{ {
strcpy(cache->name.sname, canon); strcpy(cache->name.sname, canon);
add_hosts_entry(cache, &addr, addrlen, flags, index, rhash, hashsz); cache->flags = flags;
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
name_count++; name_count++;
} }
free(canon); free(canon);
@@ -860,6 +855,8 @@ void cache_reload(void)
struct crec *cache, **up, *tmp; struct crec *cache, **up, *tmp;
int revhashsz, i, total_size = daemon->cachesize; int revhashsz, i, total_size = daemon->cachesize;
struct hostsfile *ah; struct hostsfile *ah;
struct host_record *hr;
struct name_list *nl;
cache_inserted = cache_live_freed = 0; cache_inserted = cache_live_freed = 0;
@@ -886,6 +883,34 @@ void cache_reload(void)
up = &cache->hash_next; up = &cache->hash_next;
} }
/* borrow the packet buffer for a temporary by-address hash */
memset(daemon->packet, 0, daemon->packet_buff_sz);
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
/* we overwrote the buffer... */
daemon->srv_save = NULL;
/* Do host_records in config. */
for (hr = daemon->host_records; hr; hr = hr->next)
for (nl = hr->names; nl; nl = nl->next)
{
if (hr->addr.s_addr != 0 &&
(cache = whine_malloc(sizeof(struct crec))))
{
cache->name.namep = nl->name;
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
}
#ifdef HAVE_IPV6
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
(cache = whine_malloc(sizeof(struct crec))))
{
cache->name.namep = nl->name;
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
}
#endif
}
if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts) if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
{ {
if (daemon->cachesize > 0) if (daemon->cachesize > 0)
@@ -893,12 +918,6 @@ void cache_reload(void)
return; return;
} }
/* borrow the packet buffer for a temporary by-address hash */
memset(daemon->packet, 0, daemon->packet_buff_sz);
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
/* we overwrote the buffer... */
daemon->srv_save = NULL;
if (!option_bool(OPT_NO_HOSTS)) if (!option_bool(OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz); total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);

View File

@@ -274,6 +274,18 @@ struct cname {
struct cname *next; struct cname *next;
}; };
struct host_record {
struct name_list {
char *name;
struct name_list *next;
} *names;
struct in_addr addr;
#ifdef HAVE_IPV6
struct in6_addr addr6;
#endif
struct host_record *next;
};
struct interface_name { struct interface_name {
char *name; /* domain name */ char *name; /* domain name */
char *intr; /* interface name */ char *intr; /* interface name */
@@ -695,6 +707,7 @@ extern struct daemon {
struct naptr *naptr; struct naptr *naptr;
struct txt_record *txt; struct txt_record *txt;
struct ptr_record *ptr; struct ptr_record *ptr;
struct host_record *host_records, *host_records_tail;
struct cname *cnames; struct cname *cnames;
struct interface_name *int_names; struct interface_name *int_names;
char *mxtarget; char *mxtarget;

View File

@@ -116,6 +116,7 @@ struct myoption {
#define LOPT_LUASCRIPT 305 #define LOPT_LUASCRIPT 305
#define LOPT_RA 306 #define LOPT_RA 306
#define LOPT_DUID 307 #define LOPT_DUID 307
#define LOPT_HOST_REC 308
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
@@ -237,6 +238,7 @@ static const struct myoption opts[] =
{ "dhcp-luascript", 1, 0, LOPT_LUASCRIPT }, { "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
{ "enable-ra", 0, 0, LOPT_RA }, { "enable-ra", 0, 0, LOPT_RA },
{ "dhcp-duid", 1, 0, LOPT_DUID }, { "dhcp-duid", 1, 0, LOPT_DUID },
{ "host-record", 1, 0, LOPT_HOST_REC },
{ NULL, 0, 0, 0 } { NULL, 0, 0, 0 }
}; };
@@ -365,6 +367,7 @@ static struct {
{ LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL }, { LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL }, { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL }, { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
{ 0, 0, NULL, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
@@ -3030,6 +3033,59 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
break; break;
} }
case LOPT_HOST_REC: /* --host-record */
{
struct host_record *new = opt_malloc(sizeof(struct host_record));
memset(new, 0, sizeof(struct host_record));
if (!arg || !(comma = split(arg)))
problem = _("Bad host-record");
else
while (arg)
{
struct all_addr addr;
if (inet_pton(AF_INET, arg, &addr))
new->addr = addr.addr.addr4;
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &addr))
new->addr6 = addr.addr.addr6;
#endif
else
{
int nomem;
char *canon = canonicalise(arg, &nomem);
struct name_list *nl = opt_malloc(sizeof(struct name_list));
if (!canon)
{
problem = _("Bad name in host-record");
break;
}
nl->name = canon;
/* keep order, so that PTR record goes to first name */
nl->next = NULL;
if (!new->names)
new->names = nl;
else
{
struct name_list *tmp;
for (tmp = new->names; tmp->next; tmp = tmp->next);
tmp->next = nl;
}
}
arg = comma;
comma = split(arg);
}
/* Keep list order */
if (!daemon->host_records_tail)
daemon->host_records = new;
else
daemon->host_records_tail->next = new;
new->next = NULL;
daemon->host_records_tail = new;
break;
}
default: default:
return _("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)"); return _("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)");