diff --git a/src/dnsmasq.h b/src/dnsmasq.h index f2a6f36..4364e38 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -911,9 +911,9 @@ unsigned char *tcp_request(int confd, time_t now, union mysockaddr *local_addr, struct in_addr netmask); void server_gone(struct server *server); struct frec *get_new_frec(time_t now, int *wait); -void send_from(int fd, int nowild, char *packet, size_t len, +int send_from(int fd, int nowild, char *packet, size_t len, union mysockaddr *to, struct all_addr *source, - unsigned int iface); + unsigned int iface, int *errp); /* network.c */ int indextoname(int fd, int index, char *name); diff --git a/src/forward.c b/src/forward.c index e3bf7d7..35921fb 100644 --- a/src/forward.c +++ b/src/forward.c @@ -26,9 +26,9 @@ static struct randfd *allocate_rfd(int family); /* Send a UDP packet with its source address set as "source" unless nowild is true, when we just send it with the kernel default */ -void send_from(int fd, int nowild, char *packet, size_t len, - union mysockaddr *to, struct all_addr *source, - unsigned int iface) +int send_from(int fd, int nowild, char *packet, size_t len, + union mysockaddr *to, struct all_addr *source, + unsigned int iface, int *errp) { struct msghdr msg; struct iovec iov[1]; @@ -110,8 +110,15 @@ void send_from(int fd, int nowild, char *packet, size_t len, if (retry_send()) goto retry; - my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno)); + if (errp) + *errp = errno; + else + my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno)); + + return 0; } + + return 1; } static unsigned int search_servers(time_t now, struct all_addr **addrpp, @@ -432,7 +439,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, if (udpfd != -1) { plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl); - send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface); + send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface, NULL); } return 0; @@ -621,7 +628,7 @@ void reply_query(int fd, int family, time_t now) header->id = htons(forward->orig_id); header->hb4 |= HB4_RA; /* recursion if available */ send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn, - &forward->source, &forward->dest, forward->iface); + &forward->source, &forward->dest, forward->iface, NULL); } free_frec(forward); /* cancel */ } @@ -816,7 +823,7 @@ void receive_query(struct listener *listen, time_t now) if (m >= 1) { send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header, - m, &source_addr, &dst_addr, if_index); + m, &source_addr, &dst_addr, if_index, NULL); daemon->local_answer++; } else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index, diff --git a/src/radv.c b/src/radv.c index ab15b68..ea8f905 100644 --- a/src/radv.c +++ b/src/radv.c @@ -199,7 +199,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest) struct ifreq ifr; struct sockaddr_in6 addr; struct dhcp_context *context; - + save_counter(0); ra = expand(sizeof(struct ra_packet)); @@ -266,7 +266,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest) inet_pton(AF_INET6, ALL_HOSTS, &addr.sin6_addr); send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0), - (union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface); + (union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface, NULL); } diff --git a/src/slaac.c b/src/slaac.c index fbb21a1..7eb69f9 100644 --- a/src/slaac.c +++ b/src/slaac.c @@ -131,14 +131,15 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases) for (lease = leases; lease; lease = lease->next) for (slaac = lease->slaac_address; slaac; slaac = slaac->next) { - /* confirmed? */ - if (slaac->backoff == 0) + /* confirmed or given up? */ + if (slaac->backoff == 0 || slaac->ping_time == 0) continue; if (difftime(slaac->ping_time, now) <= 0.0) { struct ping_packet *ping; struct sockaddr_in6 addr; + int err; save_counter(0); ping = expand(sizeof(struct ping_packet)); @@ -155,16 +156,22 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases) addr.sin6_port = htons(IPPROTO_ICMPV6); addr.sin6_addr = slaac->addr; - send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0), - (union mysockaddr *)&addr, (struct all_addr *)&slaac->local, lease->last_interface); - - slaac->ping_time += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */ - if (slaac->backoff > 4) - slaac->ping_time += rand16()/4000; /* 0 - 15 */ - slaac->backoff++; + 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)) + { + slaac->ping_time += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */ + if (slaac->backoff > 4) + slaac->ping_time += rand16()/4000; /* 0 - 15 */ + if (slaac->backoff < 12) + slaac->backoff++; + } + else if (err == EHOSTUNREACH) + slaac->ping_time = 0; /* Give up */ } - if (next_event == 0 || difftime(next_event, slaac->ping_time) >= 0.0) + if (slaac->ping_time != 0 && + (next_event == 0 || difftime(next_event, slaac->ping_time) >= 0.0)) next_event = slaac->ping_time; }