Add --dynamic-host option.

A and AAAA records which take their
network part from the network of a local interface. Useful
for routers with dynamically prefixes.
This commit is contained in:
Simon Kelley committed 2021-03-11 23:39:33 +00:00
1 parent 14e3f6ba19
commit b7cf754f6f
5 files changed
+170 -44

No files matched your search

+8 -1
View File
@@ -423,10 +423,17 @@ struct host_record {
struct host_record *next;
};
#define IN4 1
#define IN6 2
#define INP4 4
#define INP6 8
struct interface_name {
char *name; /* domain name */
char *intr; /* interface name */
int family; /* AF_INET, AF_INET6 or zero for both */
int flags;
struct in_addr proto4;
struct in6_addr proto6;
struct addrlist *addr;
struct interface_name *next;
};
+95 -22
View File
@@ -348,36 +348,109 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
/* Update addresses from interface_names. These are a set independent
of the set we're listening on. */
for (int_name = daemon->int_names; int_name; int_name = int_name->next)
if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0 &&
(addr->sa.sa_family == int_name->family || int_name->family == 0))
if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0)
{
if (param->spare)
struct addrlist *lp;
al = NULL;
if (addr->sa.sa_family == AF_INET && (int_name->flags & (IN4 | INP4)))
{
al = param->spare;
param->spare = al->next;
struct in_addr newaddr = addr->in.sin_addr;
if (int_name->flags & INP4)
{
if (netmask.s_addr == 0xffff)
continue;
newaddr.s_addr = (addr->in.sin_addr.s_addr & netmask.s_addr) |
(int_name->proto4.s_addr & ~netmask.s_addr);
}
/* check for duplicates. */
for (lp = int_name->addr; lp; lp = lp->next)
if (lp->flags == 0 && lp->addr.addr4.s_addr == newaddr.s_addr)
break;
if (!lp)
{
if (param->spare)
{
al = param->spare;
param->spare = al->next;
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
al->flags = 0;
al->addr.addr4 = newaddr;
}
}
}
if (addr->sa.sa_family == AF_INET6 && (int_name->flags & (IN6 | INP6)))
{
struct in6_addr newaddr = addr->in6.sin6_addr;
if (int_name->flags & INP6)
{
int i;
/* No sense in doing /128. */
if (prefixlen == 128)
continue;
for (i = 0; i < 16; i++)
{
int bits = ((i+1)*8) - prefixlen;
if (bits >= 8)
newaddr.s6_addr[i] = int_name->proto6.s6_addr[i];
else if (bits >= 0)
{
unsigned char mask = 0xff << bits;
newaddr.s6_addr[i] =
(addr->in6.sin6_addr.s6_addr[i] & mask) |
(int_name->proto6.s6_addr[i] & ~mask);
}
}
}
/* check for duplicates. */
for (lp = int_name->addr; lp; lp = lp->next)
if ((lp->flags & ADDRLIST_IPV6) &&
IN6_ARE_ADDR_EQUAL(&lp->addr.addr6, &newaddr))
break;
if (!lp)
{
if (param->spare)
{
al = param->spare;
param->spare = al->next;
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
al->flags = ADDRLIST_IPV6;
al->addr.addr6 = newaddr;
/* Privacy addresses and addresses still undergoing DAD and deprecated addresses
don't appear in forward queries, but will in reverse ones. */
if (!(iface_flags & IFACE_PERMANENT) || (iface_flags & (IFACE_DEPRECATED | IFACE_TENTATIVE)))
al->flags |= ADDRLIST_REVONLY;
}
}
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
al->next = int_name->addr;
int_name->addr = al;
if (addr->sa.sa_family == AF_INET)
{
al->addr.addr4 = addr->in.sin_addr;
al->flags = 0;
}
else
{
al->addr.addr6 = addr->in6.sin6_addr;
al->flags = ADDRLIST_IPV6;
/* Privacy addresses and addresses still undergoing DAD and deprecated addresses
don't appear in forward queries, but will in reverse ones. */
if (!(iface_flags & IFACE_PERMANENT) || (iface_flags & (IFACE_DEPRECATED | IFACE_TENTATIVE)))
al->flags |= ADDRLIST_REVONLY;
}
}
}
}
+50 -17
View File
@@ -168,6 +168,7 @@ struct myoption {
#define LOPT_SINGLE_PORT 359
#define LOPT_SCRIPT_TIME 360
#define LOPT_PXE_VENDOR 361
#define LOPT_DYNHOST 362
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -341,6 +342,7 @@ static const struct myoption opts[] =
{ "dumpfile", 1, 0, LOPT_DUMPFILE },
{ "dumpmask", 1, 0, LOPT_DUMPMASK },
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID },
{ "dynamic-host", 1, 0, LOPT_DYNHOST },
{ NULL, 0, 0, 0 }
};
@@ -491,6 +493,7 @@ static struct {
{ 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_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
{ LOPT_DYNHOST, ARG_DUP, "<name>,[<IPv4>][,<IPv6>],<interface-name>", gettext_noop("Specify host record in interface subnet"), NULL },
{ LOPT_CAA, ARG_DUP, "<name>,<flags>,<tag>,<value>", gettext_noop("Specify certification authority authorization record"), NULL },
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
@@ -4075,36 +4078,66 @@ err:
}
case LOPT_INTNAME: /* --interface-name */
case LOPT_DYNHOST: /* --dynamic-host */
{
struct interface_name *new, **up;
char *domain = NULL;
comma = split(arg);
char *domain = arg;
if (!comma || !(domain = canonicalise_opt(arg)))
ret_err(_("bad interface name"));
arg = split(arg);
new = opt_malloc(sizeof(struct interface_name));
new->next = NULL;
new->addr = NULL;
memset(new, 0, sizeof(struct interface_name));
new->flags = IN4 | IN6;
/* Add to the end of the list, so that first name
of an interface is used for PTR lookups. */
for (up = &daemon->int_names; *up; up = &((*up)->next));
*up = new;
new->name = domain;
new->family = 0;
arg = split_chr(comma, '/');
if (arg)
while ((comma = split(arg)))
{
if (strcmp(arg, "4") == 0)
new->family = AF_INET;
else if (strcmp(arg, "6") == 0)
new->family = AF_INET6;
if (inet_pton(AF_INET, arg, &new->proto4))
new->flags |= INP4;
else if (inet_pton(AF_INET6, arg, &new->proto6))
new->flags |= INP6;
else
break;
arg = comma;
}
if ((comma = split_chr(arg, '/')))
{
if (strcmp(comma, "4") == 0)
new->flags &= ~IN6;
else if (strcmp(comma, "6") == 0)
new->flags &= ~IN4;
else
ret_err_free(gen_err, new);
}
new->intr = opt_string_alloc(comma);
}
new->intr = opt_string_alloc(arg);
if (option == LOPT_DYNHOST)
{
if (!(new->flags & (INP4 | INP6)))
ret_err(_("missing address in dynamic host"));
if (!(new->flags & IN4) || !(new->flags & IN6))
arg = NULL; /* provoke error below */
new->flags &= ~(IN4 | IN6);
}
else
{
if (new->flags & (INP4 | INP6))
arg = NULL; /* provoke error below */
}
if (!domain || !arg || !(new->name = canonicalise_opt(domain)))
ret_err(option == LOPT_DYNHOST ?
_("bad dynamic host") : _("bad interface name"));
break;
}