Compare commits

...
12 Commits
13 changed files with 231 additions and 125 deletions

No files matched your search

+13 -3
View File
@@ -4,8 +4,12 @@ version 2.61
and allows us to find the prefix length for IPv6
addresses.
Add ra-names DHCPv6 keyword which adds AAAA records
for dual-stack hosts which get IPv6 addresses via SLAAC.
Add ra-names, ra-stateless and slaac keywords for DHCPv6.
Dnsmasq can now synthesise AAAA records for dual-stack
hosts which get IPv6 addresses via SLAAC. It is also now
possible to use SLAAC and stateless DHCPv6, and to
tell clients to use SLAAC addresses as well as DHCP ones.
Thanks to Dave Taht for help with this.
Add --dhcp-duid to allow DUID-EN uids to be used.
@@ -65,9 +69,15 @@ version 2.61
Fix bug in address6_available() which caused DHCPv6 lease
aquistion to fail of more than one dhcp-range in use.
Provide RDNSS and DNSSL data in router advertisements,
using the settings provided for DHCP options
option6:domain-search and option6:dns-server.
Tweak logo/favicon.ico to add some transparency. Thanks to
SamLT for work on this.
version 2.60
Fix compilation problem in Mac OS X Lion. Thanks to Olaf
Flebbe for the patch.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

+4
View File
@@ -1343,6 +1343,10 @@ the machine running dnsmasq. By default, he "managed address" bits are set, and
the "use SLAAC" bit is reset. This can be changed for individual
subnets with the mode keywords described in
.B --dhcp-range.
RFC6106 DNS parameters are included in the advertisements. By default,
the relevant link-local address of the machine running dnsmasq is sent
as recursive DNS server. If provided, the DHCPv6 options dns-server and
domain-search are used for RDNSS and DNSSL.
.TP
.B --enable-tftp[=<interface>]
Enable the TFTP server function. This is deliberately limited to that
+2 -1
View File
@@ -1128,9 +1128,10 @@ msgstr "DHCP, Proxy im Subnetz %.0s%s%.0s"
msgid "DHCP, IP range %s -- %s, lease time %s"
msgstr "DHCP, IP-Bereich %s - %s, Lease-Zeit %s "
# FIXME: this and the next few must be full strings to be translatable - do not assemble in code"
#: dnsmasq.c:588
msgid "root is "
msgstr "FIXME: this and the next few must be full strings to be translatable - do not assemble in code"
msgstr ""
#: dnsmasq.c:588
msgid "enabled"
+7
View File
@@ -111,6 +111,13 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
last_tag->next = tags;
tagif = run_tag_if(context_tags);
/* reset stuff with tag:!<tag> which now matches. */
for (opt = opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
(opt->flags & DHOPT_TAGOK) &&
!match_netid(opt->netid, tagif, 0))
opt->flags &= ~DHOPT_TAGOK;
for (opt = opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
match_netid(opt->netid, tagif, 0))
+1
View File
@@ -54,6 +54,7 @@
#define OPTION6_RECONFIGURE_MSG 19
#define OPTION6_RECONF_ACCEPT 20
#define OPTION6_DNS_SERVER 23
#define OPTION6_DOMAIN_SEARCH 24
#define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39
+2 -2
View File
@@ -33,12 +33,12 @@ void dhcp6_init(void)
{
int fd;
struct sockaddr_in6 saddr;
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
int class = IPTOS_CLASS_CS6;
#endif
if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
#endif
!fix_fd(fd) ||
+4 -1
View File
@@ -373,7 +373,10 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
{
slaac_ping_reply(sender, packet, interface, leases);
/* We may be doing RA but not DHCPv4, in which case the lease
database may not exist and we have nothing to do anyway */
if (daemon->dhcp)
slaac_ping_reply(sender, packet, interface, leases);
}
#endif
+25 -13
View File
@@ -1000,6 +1000,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
while (arg && *arg)
{
u16 len = strlen(arg);
unhide_metas(arg);
PUTSHORT(len, p);
memcpy(p, arg, len);
p += len;
@@ -1013,29 +1014,40 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
else if (comma && (opt_len & OT_RFC1035_NAME))
{
int i, commas = 1;
unsigned char *p, *newp;
for (i = 0; comma[i]; i++)
if (comma[i] == ',')
commas++;
newp = opt_malloc(strlen(comma)+(2*commas));
p = newp;
unsigned char *p = NULL, *newp, *end;
int len = 0;
arg = comma;
comma = split(arg);
while (arg && *arg)
{
p = do_rfc1035_name(p, arg);
*p++ = 0;
char *dom = canonicalise_opt(arg);
if (!dom)
{
problem = _("bad domain in dhcp-option");
break;
}
newp = opt_malloc(len + strlen(dom) + 2);
if (p)
{
memcpy(newp, p, len);
free(p);
}
p = newp;
end = do_rfc1035_name(p + len, dom);
*end++ = 0;
len = end - p;
free(dom);
arg = comma;
comma = split(arg);
}
new->val = newp;
new->len = p - newp;
new->val = p;
new->len = len;
}
#endif
else
+1
View File
@@ -43,6 +43,7 @@ struct prefix_opt {
#define ICMP6_OPT_PREFIX 3
#define ICMP6_OPT_MTU 5
#define ICMP6_OPT_RDNSS 25
#define ICMP6_OPT_DNSSL 31
+138 -74
View File
@@ -29,6 +29,7 @@
struct ra_param {
int ind, managed, other, found_context, first;
char *if_name;
struct dhcp_netid *tags;
struct in6_addr link_local;
};
@@ -50,7 +51,7 @@ void ra_init(time_t now)
{
struct icmp6_filter filter;
int fd;
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
int class = IPTOS_CLASS_CS6;
#endif
int val = 255; /* radvd uses this value */
@@ -72,7 +73,7 @@ void ra_init(time_t now)
if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
#endif
!fix_fd(fd) ||
@@ -116,8 +117,7 @@ void icmp6_packet(void)
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
} control_u;
struct sockaddr_in6 from;
unsigned char *p;
char *mac = "";
unsigned char *packet;
struct iname *tmp;
struct dhcp_context *context;
@@ -132,6 +132,8 @@ void icmp6_packet(void)
if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
return;
packet = (unsigned char *)daemon->outpacket.iov_base;
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
@@ -160,36 +162,25 @@ void icmp6_packet(void)
if (!context->interface || strcmp(context->interface, interface) == 0)
break;
if (!context)
if (!context || packet[1] != 0)
return;
p = (unsigned char *)daemon->outpacket.iov_base;
if (p[1] != 0)
return;
if (p[0] == ICMP6_ECHO_REPLY)
if (packet[0] == ICMP6_ECHO_REPLY)
lease_ping_reply(&from.sin6_addr, packet, interface);
else if (packet[0] == ND_ROUTER_SOLICIT)
{
/* We may be doing RA but not DHCPv4, in which case the lease
database may not exist and we have nothing to do anyway */
if (daemon->dhcp)
lease_ping_reply(&from.sin6_addr, p, interface);
return;
char *mac = "";
/* look for link-layer address option for logging */
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
{
print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
mac = daemon->namebuff;
}
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
send_ra(if_index, interface, &from.sin6_addr);
}
if (p[0] != ND_ROUTER_SOLICIT)
return;
/* look for link-layer address option for logging */
if (sz >= 16 && p[8] == ICMP6_OPT_SOURCE_MAC && (p[9] * 8) + 8 <= sz)
{
print_mac(daemon->namebuff, &p[10], (p[9] * 8) - 2);
mac = daemon->namebuff;
}
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
send_ra(if_index, interface, &from.sin6_addr);
}
static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
@@ -199,7 +190,10 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
struct ifreq ifr;
struct sockaddr_in6 addr;
struct dhcp_context *context;
struct dhcp_netid iface_id;
struct dhcp_opt *opt_cfg;
int done_dns = 0;
save_counter(0);
ra = expand(sizeof(struct ra_packet));
@@ -218,9 +212,17 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
parm.if_name = iface_name;
parm.first = 1;
for (context = daemon->ra_contexts; context; context = context->next)
context->flags &= ~CONTEXT_RA_DONE;
/* set tag with name == interface */
iface_id.net = iface_name;
iface_id.next = NULL;
parm.tags = &iface_id;
for (context = daemon->ra_contexts; context; context = context->next)
{
context->flags &= ~CONTEXT_RA_DONE;
context->netid.next = &context->netid;
}
if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
!parm.found_context)
return;
@@ -236,14 +238,63 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
}
iface_enumerate(AF_LOCAL, &iface, add_lla);
/* RDNSS, RFC 6106, use relevant DHCP6 options */
(void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
/* RDNSS, RFC 6106 */
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char(3);
put_opt6_short(0);
put_opt6_long(1800); /* lifetime - twice RA retransmit */
put_opt6(&parm.link_local, IN6ADDRSZ);
for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
{
int i;
/* netids match and not encapsulated? */
if (!(opt_cfg->flags & DHOPT_TAGOK))
continue;
if (opt_cfg->opt == OPTION6_DNS_SERVER)
{
struct in6_addr *a = (struct in6_addr *)opt_cfg->val;
done_dns = 1;
if (opt_cfg->len == 0)
continue;
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char((opt_cfg->len/8) + 1);
put_opt6_short(0);
put_opt6_long(1800); /* lifetime - twice RA retransmit */
/* zero means "self" */
for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
if (IN6_IS_ADDR_UNSPECIFIED(a))
put_opt6(&parm.link_local, IN6ADDRSZ);
else
put_opt6(a, IN6ADDRSZ);
}
if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
{
int len = ((opt_cfg->len+7)/8);
put_opt6_char(ICMP6_OPT_DNSSL);
put_opt6_char(len + 1);
put_opt6_short(0);
put_opt6_long(1800); /* lifetime - twice RA retransmit */
put_opt6(opt_cfg->val, opt_cfg->len);
/* pad */
for (i = opt_cfg->len; i < len * 8; i++)
put_opt6_char(0);
}
}
if (!done_dns)
{
/* default == us. */
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char(3);
put_opt6_short(0);
put_opt6_long(1800); /* lifetime - twice RA retransmit */
put_opt6(&parm.link_local, IN6ADDRSZ);
}
/* set managed bits unless we're providing only RA on this link */
if (parm.managed)
@@ -276,7 +327,6 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_context *context;
struct ra_param *param = vparam;
(void)scope; /* warning */
@@ -290,12 +340,12 @@ static int add_prefixes(struct in6_addr *local, int prefix,
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
int do_prefix = 0;
int do_slaac = 0;
int deprecate = 0;
unsigned int time = 0xffffffff;
struct in6_addr *addr = NULL;
struct prefix_opt *opt;
struct dhcp_context *context;
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
@@ -305,8 +355,12 @@ static int add_prefixes(struct in6_addr *local, int prefix,
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
{
do_slaac = 1;
if (context->flags & CONTEXT_RA_STATELESS)
param->other = 1;
if (context->flags & CONTEXT_DHCP)
{
param->other = 1;
if (!(context->flags & CONTEXT_RA_STATELESS))
param->managed = 1;
}
}
else
{
@@ -330,37 +384,47 @@ static int add_prefixes(struct in6_addr *local, int prefix,
context->ra_time = 0;
param->first = 0;
param->found_context = 1;
if (context->flags & CONTEXT_RA_DONE)
continue;
context->flags |= CONTEXT_RA_DONE;
addr = &context->start6;
/* collect dhcp-range tags */
if (context->netid.next == &context->netid && context->netid.net)
{
context->netid.next = param->tags;
param->tags = &context->netid;
}
if (!(context->flags & CONTEXT_RA_DONE))
{
context->flags |= CONTEXT_RA_DONE;
do_prefix = 1;
}
}
if (addr && (opt = expand(sizeof(struct prefix_opt))))
if (do_prefix)
{
u64 addrpart = addr6part(addr);
u64 mask = (prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU;
/* lifetimes must be min 2 hrs, by RFC 2462 */
if (time < 7200)
time = 7200;
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = prefix;
/* autonomous only is we're not doing dhcp */
opt->flags = do_slaac ? 0x40 : 0x00;
opt->valid_lifetime = htonl(time);
opt->preferred_lifetime = htonl(deprecate ? 0 : time);
opt->reserved = 0;
opt->prefix = *addr;
setaddr6part(&opt->prefix, addrpart & ~mask);
inet_ntop(AF_INET6, &opt->prefix, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
struct prefix_opt *opt;
if ((opt = expand(sizeof(struct prefix_opt))))
{
/* zero net part of address */
setaddr6part(local, addr6part(local) & ~((prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU));
/* lifetimes must be min 2 hrs, by RFC 2462 */
if (time < 7200)
time = 7200;
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = prefix;
/* autonomous only if we're not doing dhcp */
opt->flags = do_slaac ? 0x40 : 0x00;
opt->valid_lifetime = htonl(time);
opt->preferred_lifetime = htonl(deprecate ? 0 : time);
opt->reserved = 0;
opt->prefix = *local;
inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
}
}
}
}
+22 -22
View File
@@ -349,28 +349,28 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (len != 0 && len < 255)
{
unsigned char *pp, *op = opt6_ptr(opt, 1);
char *pq = daemon->dhcp_buff;
pp = op;
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
{
memcpy(pq, op+1, *op);
pq += *op;
op += (*op)+1;
*(pq++) = '.';
}
if (pq != daemon->dhcp_buff)
pq--;
*pq = 0;
if (legal_hostname(daemon->dhcp_buff))
{
client_hostname = daemon->dhcp_buff;
if (option_bool(OPT_LOG_OPTS))
my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), xid, client_hostname);
}
unsigned char *pp, *op = opt6_ptr(opt, 1);
char *pq = daemon->dhcp_buff;
pp = op;
while (*op != 0 && ((op + (*op)) - pp) < len)
{
memcpy(pq, op+1, *op);
pq += *op;
op += (*op)+1;
*(pq++) = '.';
}
if (pq != daemon->dhcp_buff)
pq--;
*pq = 0;
if (legal_hostname(daemon->dhcp_buff))
{
client_hostname = daemon->dhcp_buff;
if (option_bool(OPT_LOG_OPTS))
my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), xid, client_hostname);
}
}
}
+12 -9
View File
@@ -108,8 +108,8 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
{
struct dhcp_context *context;
struct dhcp_lease *lease;
struct slaac_address *slaac;
time_t next_event = 0;
struct slaac_address *slaac;
time_t next_event = 0;
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
@@ -139,8 +139,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
{
struct ping_packet *ping;
struct sockaddr_in6 addr;
int err;
save_counter(0);
ping = expand(sizeof(struct ping_packet));
ping->type = ICMP6_ECHO_REQUEST;
@@ -156,9 +155,15 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
addr.sin6_port = htons(IPPROTO_ICMPV6);
addr.sin6_addr = slaac->addr;
if (send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
(union mysockaddr *)&addr, (struct all_addr *)&slaac->local,
lease->last_interface, &err))
if (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0,
(struct sockaddr *)&addr, sizeof(addr)) == -1 &&
errno == EHOSTUNREACH)
{
slaac->ping_time = 0; /* Give up */
inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "SLAAC-HOSTUNREACH %s", daemon->addrbuff);
}
else
{
slaac->ping_time += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */
if (slaac->backoff > 4)
@@ -166,8 +171,6 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
if (slaac->backoff < 12)
slaac->backoff++;
}
else if (err == EHOSTUNREACH)
slaac->ping_time = 0; /* Give up */
}
if (slaac->ping_time != 0 &&