version 1.1.1.3, 2016/11/02 09:57:01
|
version 1.1.1.5, 2023/09/27 11:02:07
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
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 |
it under the terms of the GNU General Public License as published by |
Line 82 void ra_init(time_t now)
|
Line 82 void ra_init(time_t now)
|
/* ensure this is around even if we're not doing DHCPv6 */ |
/* ensure this is around even if we're not doing DHCPv6 */ |
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet)); |
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet)); |
|
|
/* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */ | /* See if we're guessing SLAAC addresses, if so we need to receive ping replies */ |
for (context = daemon->dhcp6; context; context = context->next) |
for (context = daemon->dhcp6; context; context = context->next) |
if ((context->flags & CONTEXT_RA_NAME)) |
if ((context->flags & CONTEXT_RA_NAME)) |
break; |
break; |
Line 112 void ra_init(time_t now)
|
Line 112 void ra_init(time_t now)
|
daemon->icmp6fd = fd; |
daemon->icmp6fd = fd; |
|
|
if (daemon->doing_ra) |
if (daemon->doing_ra) |
ra_start_unsolicted(now, NULL); | ra_start_unsolicited(now, NULL); |
} |
} |
|
|
void ra_start_unsolicted(time_t now, struct dhcp_context *context) | void ra_start_unsolicited(time_t now, struct dhcp_context *context) |
{ |
{ |
/* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed |
/* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed |
if it's not appropriate to advertise those contexts. |
if it's not appropriate to advertise those contexts. |
Line 123 void ra_start_unsolicted(time_t now, struct dhcp_conte
|
Line 123 void ra_start_unsolicted(time_t now, struct dhcp_conte
|
and pick up new interfaces */ |
and pick up new interfaces */ |
|
|
if (context) |
if (context) |
context->ra_short_period_start = context->ra_time = now; | { |
| context->ra_short_period_start = now; |
| /* start after 1 second to get logging right at startup. */ |
| context->ra_time = now + 1; |
| } |
else |
else |
for (context = daemon->dhcp6; context; context = context->next) |
for (context = daemon->dhcp6; context; context = context->next) |
if (!(context->flags & CONTEXT_TEMPLATE)) |
if (!(context->flags & CONTEXT_TEMPLATE)) |
Line 162 void icmp6_packet(time_t now)
|
Line 166 void icmp6_packet(time_t now)
|
return; |
return; |
|
|
packet = (unsigned char *)daemon->outpacket.iov_base; |
packet = (unsigned char *)daemon->outpacket.iov_base; |
| |
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) |
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) |
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo) |
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo) |
{ |
{ |
Line 187 void icmp6_packet(time_t now)
|
Line 191 void icmp6_packet(time_t now)
|
|
|
if (packet[1] != 0) |
if (packet[1] != 0) |
return; |
return; |
| |
if (packet[0] == ICMP6_ECHO_REPLY) |
if (packet[0] == ICMP6_ECHO_REPLY) |
lease_ping_reply(&from.sin6_addr, packet, interface); |
lease_ping_reply(&from.sin6_addr, packet, interface); |
else if (packet[0] == ND_ROUTER_SOLICIT) |
else if (packet[0] == ND_ROUTER_SOLICIT) |
{ |
{ |
char *mac = ""; |
char *mac = ""; |
struct dhcp_bridge *bridge, *alias; |
struct dhcp_bridge *bridge, *alias; |
|
ssize_t rem; |
|
unsigned char *p; |
|
int opt_sz; |
|
|
|
#ifdef HAVE_DUMPFILE |
|
dump_packet_icmp(DUMP_RA, (void *)packet, sz, (union mysockaddr *)&from, NULL); |
|
#endif |
|
|
/* look for link-layer address option for logging */ |
/* look for link-layer address option for logging */ |
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz) | for (rem = sz - 8, p = &packet[8]; rem >= 2; rem -= opt_sz, p += opt_sz) |
{ |
{ |
print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2); | opt_sz = p[1] * 8; |
mac = daemon->namebuff; | |
| if (opt_sz == 0 || opt_sz > rem) |
| return; /* Bad packet */ |
| |
| if (p[0] == ICMP6_OPT_SOURCE_MAC && ((opt_sz - 2) * 3 - 1 < MAXDNAME)) |
| { |
| print_mac(daemon->namebuff, &p[2], opt_sz - 2); |
| mac = daemon->namebuff; |
| } |
} |
} |
| |
if (!option_bool(OPT_QUIET_RA)) |
if (!option_bool(OPT_QUIET_RA)) |
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac); |
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac); |
|
|
Line 243 static void send_ra_alias(time_t now, int iface, char
|
Line 262 static void send_ra_alias(time_t now, int iface, char
|
struct dhcp_netid iface_id; |
struct dhcp_netid iface_id; |
struct dhcp_opt *opt_cfg; |
struct dhcp_opt *opt_cfg; |
struct ra_interface *ra_param = find_iface_param(iface_name); |
struct ra_interface *ra_param = find_iface_param(iface_name); |
int done_dns = 0, old_prefix = 0; | int done_dns = 0, old_prefix = 0, mtu = 0; |
unsigned int min_pref_time; |
unsigned int min_pref_time; |
#ifdef HAVE_LINUX_NETWORK |
#ifdef HAVE_LINUX_NETWORK |
FILE *f; |
FILE *f; |
Line 261 static void send_ra_alias(time_t now, int iface, char
|
Line 280 static void send_ra_alias(time_t now, int iface, char
|
parm.adv_interval = calc_interval(ra_param); |
parm.adv_interval = calc_interval(ra_param); |
parm.prio = calc_prio(ra_param); |
parm.prio = calc_prio(ra_param); |
|
|
save_counter(0); | reset_counter(); |
ra = expand(sizeof(struct ra_packet)); | |
|
|
|
if (!(ra = expand(sizeof(struct ra_packet)))) |
|
return; |
|
|
ra->type = ND_ROUTER_ADVERT; |
ra->type = ND_ROUTER_ADVERT; |
ra->code = 0; |
ra->code = 0; |
ra->hop_limit = hop_limit; |
ra->hop_limit = hop_limit; |
Line 283 static void send_ra_alias(time_t now, int iface, char
|
Line 304 static void send_ra_alias(time_t now, int iface, char
|
context->netid.next = &context->netid; |
context->netid.next = &context->netid; |
} |
} |
|
|
if (!iface_enumerate(AF_INET6, &parm, add_prefixes)) | /* If no link-local address then we can't advertise since source address of |
| advertisement must be link local address: RFC 4861 para 6.1.2. */ |
| if (!iface_enumerate(AF_INET6, &parm, add_prefixes) || |
| parm.link_pref_time == 0) |
return; |
return; |
|
|
/* Find smallest preferred time within address classes, |
/* Find smallest preferred time within address classes, |
Line 397 static void send_ra_alias(time_t now, int iface, char
|
Line 421 static void send_ra_alias(time_t now, int iface, char
|
put_opt6_long(1000 * calc_interval(find_iface_param(iface_name))); |
put_opt6_long(1000 * calc_interval(find_iface_param(iface_name))); |
} |
} |
|
|
|
/* Set the MTU from ra_param if any, an MTU of 0 mean automatic for linux, */ |
|
/* an MTU of -1 prevents the option from being sent. */ |
|
if (ra_param) |
|
mtu = ra_param->mtu; |
#ifdef HAVE_LINUX_NETWORK |
#ifdef HAVE_LINUX_NETWORK |
/* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU | /* Note that IPv6 MTU is not necessarily the same as the IPv4 MTU |
available from SIOCGIFMTU */ |
available from SIOCGIFMTU */ |
sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name); | if (mtu == 0) |
if ((f = fopen(daemon->namebuff, "r"))) | |
{ |
{ |
if (fgets(daemon->namebuff, MAXDNAME, f)) | char *mtu_name = ra_param ? ra_param->mtu_name : NULL; |
{ | sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", mtu_name ? mtu_name : iface_name); |
put_opt6_char(ICMP6_OPT_MTU); | if ((f = fopen(daemon->namebuff, "r"))) |
put_opt6_char(1); | { |
put_opt6_short(0); | if (fgets(daemon->namebuff, MAXDNAME, f)) |
put_opt6_long(atoi(daemon->namebuff)); | mtu = atoi(daemon->namebuff); |
} | fclose(f); |
fclose(f); | } |
} |
} |
#endif |
#endif |
|
if (mtu > 0) |
|
{ |
|
put_opt6_char(ICMP6_OPT_MTU); |
|
put_opt6_char(1); |
|
put_opt6_short(0); |
|
put_opt6_long(mtu); |
|
} |
|
|
iface_enumerate(AF_LOCAL, &send_iface, add_lla); |
iface_enumerate(AF_LOCAL, &send_iface, add_lla); |
|
|
Line 525 static void send_ra_alias(time_t now, int iface, char
|
Line 559 static void send_ra_alias(time_t now, int iface, char
|
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &send_iface, sizeof(send_iface)); |
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &send_iface, sizeof(send_iface)); |
} |
} |
|
|
|
#ifdef HAVE_DUMPFILE |
|
{ |
|
struct sockaddr_in6 src; |
|
src.sin6_family = AF_INET6; |
|
src.sin6_addr = parm.link_local; |
|
|
|
dump_packet_icmp(DUMP_RA, (void *)daemon->outpacket.iov_base, save_counter(-1), (union mysockaddr *)&src, (union mysockaddr *)&addr); |
|
} |
|
#endif |
|
|
while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base, |
while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base, |
save_counter(0), 0, (struct sockaddr *)&addr, | save_counter(-1), 0, (struct sockaddr *)&addr, |
sizeof(addr)))); |
sizeof(addr)))); |
|
|
} |
} |
Line 608 static int add_prefixes(struct in6_addr *local, int p
|
Line 652 static int add_prefixes(struct in6_addr *local, int p
|
real_prefix = context->prefix; |
real_prefix = context->prefix; |
} |
} |
|
|
/* find floor time, don't reduce below 3 * RA interval. */ | /* find floor time, don't reduce below 3 * RA interval. |
if (time > context->lease_time) | If the lease time has been left as default, don't |
| use that as a floor. */ |
| if ((context->flags & CONTEXT_SETLEASE) && |
| time > context->lease_time) |
{ |
{ |
time = context->lease_time; |
time = context->lease_time; |
if (time < ((unsigned int)(3 * param->adv_interval))) |
if (time < ((unsigned int)(3 * param->adv_interval))) |
Line 725 static int add_lla(int index, unsigned int type, char
|
Line 772 static int add_lla(int index, unsigned int type, char
|
add 7 to round up */ |
add 7 to round up */ |
int len = (maclen + 9) >> 3; |
int len = (maclen + 9) >> 3; |
unsigned char *p = expand(len << 3); |
unsigned char *p = expand(len << 3); |
|
if (!p) |
|
return 1; |
memset(p, 0, len << 3); |
memset(p, 0, len << 3); |
*p++ = ICMP6_OPT_SOURCE_MAC; |
*p++ = ICMP6_OPT_SOURCE_MAC; |
*p++ = len; |
*p++ = len; |
Line 778 time_t periodic_ra(time_t now)
|
Line 827 time_t periodic_ra(time_t now)
|
associated with it, because it's for a subnet we dont |
associated with it, because it's for a subnet we dont |
have an interface on. Probably we're doing DHCP on |
have an interface on. Probably we're doing DHCP on |
a remote subnet via a relay. Zero the timer, since we won't |
a remote subnet via a relay. Zero the timer, since we won't |
ever be able to send ra's and satistfy it. */ | ever be able to send ra's and satisfy it. */ |
context->ra_time = 0; |
context->ra_time = 0; |
|
|
if (param.iface != 0 && |
if (param.iface != 0 && |
Line 873 static int iface_search(struct in6_addr *local, int p
|
Line 922 static int iface_search(struct in6_addr *local, int p
|
{ |
{ |
struct search_param *param = vparam; |
struct search_param *param = vparam; |
struct dhcp_context *context; |
struct dhcp_context *context; |
| struct iname *tmp; |
| |
(void)scope; |
(void)scope; |
(void)preferred; |
(void)preferred; |
(void)valid; |
(void)valid; |
| |
| /* ignore interfaces we're not doing DHCP on. */ |
| if (!indextoname(daemon->icmp6fd, if_index, param->name) || |
| !iface_check(AF_LOCAL, NULL, param->name, NULL)) |
| return 1; |
| |
| for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) |
| if (tmp->name && wildcard_match(tmp->name, param->name)) |
| return 1; |
| |
for (context = daemon->dhcp6; context; context = context->next) |
for (context = daemon->dhcp6; context; context = context->next) |
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) && |
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) && |
prefix <= context->prefix && |
prefix <= context->prefix && |
Line 889 static int iface_search(struct in6_addr *local, int p
|
Line 948 static int iface_search(struct in6_addr *local, int p
|
/* found an interface that's overdue for RA determine new |
/* found an interface that's overdue for RA determine new |
timeout value and arrange for RA to be sent unless interface is |
timeout value and arrange for RA to be sent unless interface is |
still doing DAD.*/ |
still doing DAD.*/ |
|
|
if (!(flags & IFACE_TENTATIVE)) |
if (!(flags & IFACE_TENTATIVE)) |
param->iface = if_index; |
param->iface = if_index; |
|
|
/* should never fail */ |
|
if (!indextoname(daemon->icmp6fd, if_index, param->name)) |
|
{ |
|
param->iface = 0; |
|
return 0; |
|
} |
|
|
|
new_timeout(context, param->name, param->now); |
new_timeout(context, param->name, param->now); |
|
|