Handle errors when sending ICMP6 pings better.

This commit is contained in:
Simon Kelley
2012-03-22 14:01:00 +00:00
parent a953096485
commit 29689cfa5a
4 changed files with 35 additions and 21 deletions

View File

@@ -911,9 +911,9 @@ unsigned char *tcp_request(int confd, time_t now,
union mysockaddr *local_addr, struct in_addr netmask); union mysockaddr *local_addr, struct in_addr netmask);
void server_gone(struct server *server); void server_gone(struct server *server);
struct frec *get_new_frec(time_t now, int *wait); 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, union mysockaddr *to, struct all_addr *source,
unsigned int iface); unsigned int iface, int *errp);
/* network.c */ /* network.c */
int indextoname(int fd, int index, char *name); int indextoname(int fd, int index, char *name);

View File

@@ -26,9 +26,9 @@ static struct randfd *allocate_rfd(int family);
/* Send a UDP packet with its source address set as "source" /* Send a UDP packet with its source address set as "source"
unless nowild is true, when we just send it with the kernel default */ 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, int send_from(int fd, int nowild, char *packet, size_t len,
union mysockaddr *to, struct all_addr *source, union mysockaddr *to, struct all_addr *source,
unsigned int iface) unsigned int iface, int *errp)
{ {
struct msghdr msg; struct msghdr msg;
struct iovec iov[1]; struct iovec iov[1];
@@ -110,8 +110,15 @@ void send_from(int fd, int nowild, char *packet, size_t len,
if (retry_send()) if (retry_send())
goto retry; 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, 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) if (udpfd != -1)
{ {
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl); 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; return 0;
@@ -621,7 +628,7 @@ void reply_query(int fd, int family, time_t now)
header->id = htons(forward->orig_id); header->id = htons(forward->orig_id);
header->hb4 |= HB4_RA; /* recursion if available */ header->hb4 |= HB4_RA; /* recursion if available */
send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn, 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 */ free_frec(forward); /* cancel */
} }
@@ -816,7 +823,7 @@ void receive_query(struct listener *listen, time_t now)
if (m >= 1) if (m >= 1)
{ {
send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header, 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++; daemon->local_answer++;
} }
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index, else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,

View File

@@ -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); inet_pton(AF_INET6, ALL_HOSTS, &addr.sin6_addr);
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0), 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);
} }

View File

@@ -131,14 +131,15 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
for (slaac = lease->slaac_address; slaac; slaac = slaac->next) for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
{ {
/* confirmed? */ /* confirmed or given up? */
if (slaac->backoff == 0) if (slaac->backoff == 0 || slaac->ping_time == 0)
continue; continue;
if (difftime(slaac->ping_time, now) <= 0.0) if (difftime(slaac->ping_time, now) <= 0.0)
{ {
struct ping_packet *ping; struct ping_packet *ping;
struct sockaddr_in6 addr; struct sockaddr_in6 addr;
int err;
save_counter(0); save_counter(0);
ping = expand(sizeof(struct ping_packet)); 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_port = htons(IPPROTO_ICMPV6);
addr.sin6_addr = slaac->addr; addr.sin6_addr = slaac->addr;
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0), if (send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
(union mysockaddr *)&addr, (struct all_addr *)&slaac->local, lease->last_interface); (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 += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */
slaac->ping_time += rand16()/4000; /* 0 - 15 */ if (slaac->backoff > 4)
slaac->backoff++; 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; next_event = slaac->ping_time;
} }