From d81b42d0674d161934a060bea5de1a44a8238376 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Mon, 23 Sep 2013 12:26:34 +0100 Subject: [PATCH] Prod neighbour discovery with ARP instead of PING. --- src/dhcp6.c | 17 +++++++++-------- src/radv-protocol.h | 7 +++++++ src/rfc3315.c | 34 ++++++++++++++++------------------ 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/dhcp6.c b/src/dhcp6.c index 9ad8912..5e151d6 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -183,13 +183,13 @@ void dhcp6_packet(time_t now) return; /* Recieving a packet from a host does not populate the neighbour - cache, so we send a ping to prompt neighbour discovery if we can't + cache, so we send a neighbour discovery request if we can't find the sender. Repeat a few times in case of packet loss. */ for (i = 0; i < 5; i++) { struct timespec ts; - struct ping_packet *ping; + struct neigh_packet *neigh; struct sockaddr_in6 addr; mac_param.target = &from.sin6_addr; @@ -201,12 +201,12 @@ void dhcp6_packet(time_t now) break; save_counter(0); - ping = expand(sizeof(struct ping_packet)); - ping->type = ICMP6_ECHO_REQUEST; - ping->code = 0; - ping->identifier = 1; - ping->sequence_no = 1; - + neigh = expand(sizeof(struct neigh_packet)); + neigh->type = ND_NEIGHBOR_SOLICIT; + neigh->code = 0; + neigh->reserved = 0; + neigh->target = from.sin6_addr; + memset(&addr, 0, sizeof(addr)); #ifdef HAVE_SOCKADDR_SA_LEN addr.sin6_len = sizeof(struct sockaddr_in6); @@ -214,6 +214,7 @@ void dhcp6_packet(time_t now) addr.sin6_family = AF_INET6; addr.sin6_port = htons(IPPROTO_ICMPV6); addr.sin6_addr = from.sin6_addr; + addr.sin6_scope_id = from.sin6_scope_id; sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0, (struct sockaddr *)&addr, sizeof(addr)); diff --git a/src/radv-protocol.h b/src/radv-protocol.h index 1f0f88a..8d5b153 100644 --- a/src/radv-protocol.h +++ b/src/radv-protocol.h @@ -33,6 +33,13 @@ struct ra_packet { u32 retrans_time; }; +struct neigh_packet { + u8 type, code; + u16 checksum; + u16 reserved; + struct in6_addr target; +}; + struct prefix_opt { u8 type, len, prefix_len, flags; u32 valid_lifetime, preferred_lifetime, reserved; diff --git a/src/rfc3315.c b/src/rfc3315.c index ee06353..26dca71 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -419,14 +419,22 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh } if (mac_len != 0) - for (mac_opt = daemon->dhcp_macs; mac_opt; mac_opt = mac_opt->next) - if ((unsigned)mac_opt->hwaddr_len == mac_len && - ((unsigned)mac_opt->hwaddr_type == mac_type || mac_opt->hwaddr_type == 0) && - memcmp_masked(mac_opt->hwaddr, mac, mac_len, mac_opt->mask)) + { + if (option_bool(OPT_LOG_OPTS)) { - mac_opt->netid.next = state.tags; - state.tags = &mac_opt->netid; + print_mac(daemon->dhcp_buff, mac, mac_len); + my_syslog(MS_DHCP | LOG_INFO, _("%u client MAC address: %s"), state.xid, daemon->dhcp_buff); } + + for (mac_opt = daemon->dhcp_macs; mac_opt; mac_opt = mac_opt->next) + if ((unsigned)mac_opt->hwaddr_len == mac_len && + ((unsigned)mac_opt->hwaddr_type == mac_type || mac_opt->hwaddr_type == 0) && + memcmp_masked(mac_opt->hwaddr, mac, mac_len, mac_opt->mask)) + { + mac_opt->netid.next = state.tags; + state.tags = &mac_opt->netid; + } + } if ((opt = opt6_find(state.packet_options, state.end, OPTION6_FQDN, 1))) { @@ -1225,18 +1233,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh } log_tags(tagif, state.xid); + log6_opts(0, state.xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1)); - if (option_bool(OPT_LOG_OPTS)) - { - if (mac_len != 0) - { - print_mac(daemon->dhcp_buff, mac, mac_len); - my_syslog(MS_DHCP | LOG_INFO, _("%u client MAC address: %s"), state.xid, daemon->dhcp_buff); - } - - log6_opts(0, state.xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1)); - } - return 1; } @@ -1824,7 +1822,7 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op void *opt; char *desc = nest ? "nest" : "sent"; - if (start_opts == end_opts) + if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts) return; for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))