diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2012-12-03 14:05:59 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2012-12-03 14:05:59 +0000 |
commit | 29d28dda95d77250197a4cd3e199540e13317441 (patch) | |
tree | 5242d44ce0745698fc97b4423ce213010862cf32 | |
parent | 421594f83ddcfcb2ac4fc91eb8b06f7596bb4e44 (diff) | |
download | dnsmasq-29d28dda95d77250197a4cd3e199540e13317441.tar.gz |
-rw-r--r-- | CHANGELOG | 9 | ||||
-rw-r--r-- | src/forward.c | 21 | ||||
-rw-r--r-- | src/radv.c | 20 |
3 files changed, 32 insertions, 18 deletions
@@ -58,6 +58,15 @@ version 2.64 Check interface for outgoing unsolicited router advertisements, rather than relying on interface address configuration. Thanks to Gene Czarinski for the patch. + + Handle better attempts to transmit on interfaces which are + still doing DAD, and specifically do not just transmit + without setting source address and interface, since this + can cause very puzzling effects when a router + advertisement goes astray. Thanks again to Gene Czarinski. + + Get RA timers right when there is more than one + dhcp-range on a subnet. version 2.63 diff --git a/src/forward.c b/src/forward.c index f672194..4afc25a 100644 --- a/src/forward.c +++ b/src/forward.c @@ -95,26 +95,19 @@ int send_from(int fd, int nowild, char *packet, size_t len, #endif } - retry: - if (sendmsg(fd, &msg, 0) == -1) + while (sendmsg(fd, &msg, 0) == -1) { - /* certain Linux kernels seem to object to setting the source address in the IPv6 stack - by returning EINVAL from sendmsg. In that case, try again without setting the - source address, since it will nearly alway be correct anyway. IPv6 stinks. */ - if (errno == EINVAL && msg.msg_controllen) - { - msg.msg_controllen = 0; - goto retry; - } - if (retry_send()) - goto retry; + continue; - my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno)); + /* If interface is still in DAD, EINVAL results - ignore that. */ + if (errno == EINVAL) + break; + my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno)); return 0; } - + return 1; } @@ -457,6 +457,7 @@ time_t periodic_ra(time_t now) char interface[IF_NAMESIZE+1]; param.now = now; + param.iface = 0; while (1) { @@ -482,7 +483,8 @@ time_t periodic_ra(time_t now) ever be able to send ra's and satistfy it. */ if (iface_enumerate(AF_INET6, ¶m, iface_search)) context->ra_time = 0; - else if (indextoname(daemon->icmp6fd, param.iface, interface) && + else if (param.iface != 0 && + indextoname(daemon->icmp6fd, param.iface, interface) && iface_check(AF_LOCAL, NULL, interface)) { struct iname *tmp; @@ -512,9 +514,11 @@ static int iface_search(struct in6_addr *local, int prefix, if (context->ra_time != 0 && difftime(context->ra_time, param->now) <= 0.0) { /* found an interface that's overdue for RA determine new - timeout value and zap other contexts on the same interface - so they don't timeout independently .*/ - param->iface = if_index; + timeout value and arrange for RA to be sent unless interface is + still doing DAD.*/ + + if (!dad) + param->iface = if_index; if (difftime(param->now, ra_short_period_start) < 60.0) /* range 5 - 20 */ @@ -523,6 +527,14 @@ static int iface_search(struct in6_addr *local, int prefix, /* range 450 - 600 */ context->ra_time = param->now + 450 + (rand16()/440); + /* zero timers for other contexts on the same subnet, so they don't timeout + independently */ + for (context = context->next; context; context = context->next) + if (prefix == context->prefix && + is_same_net6(local, &context->start6, prefix) && + is_same_net6(local, &context->end6, prefix)) + context->ra_time = 0; + return 0; /* found, abort */ } |