Commit 8939c95f authored by Simon Kelley's avatar Simon Kelley

Don't extract MAC address from ND table when DHCPv6 request is from a relay.

parent 408c368f
......@@ -29,7 +29,7 @@ struct iface_param {
struct mac_param {
struct in6_addr *target;
unsigned char mac[DHCP_CHADDR_MAX];
unsigned char *mac;
unsigned int maclen;
};
......@@ -99,7 +99,6 @@ void dhcp6_packet(time_t now)
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param parm;
struct mac_param mac_param;
struct cmsghdr *cmptr;
struct msghdr msg;
int if_index = 0;
......@@ -145,8 +144,6 @@ void dhcp6_packet(time_t now)
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
{
int i;
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
......@@ -182,48 +179,6 @@ void dhcp6_packet(time_t now)
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return;
/* Recieving a packet from a host does not populate the neighbour
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 neigh_packet *neigh;
struct sockaddr_in6 addr;
mac_param.target = &from.sin6_addr;
mac_param.maclen = 0;
iface_enumerate(AF_UNSPEC, &mac_param, find_mac);
if (mac_param.maclen != 0)
break;
save_counter(0);
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);
#endif
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));
ts.tv_sec = 0;
ts.tv_nsec = 100000000; /* 100ms */
nanosleep(&ts, NULL);
}
if (daemon->if_names || daemon->if_addrs)
{
......@@ -244,8 +199,7 @@ void dhcp6_packet(time_t now)
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id,
mac_param.maclen == 0 ? NULL : &mac_param.mac[0], mac_param.maclen, ARPHRD_ETHER);
relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id);
return;
}
......@@ -256,8 +210,7 @@ void dhcp6_packet(time_t now)
lease_prune(NULL, now); /* lose any expired leases */
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now,
mac_param.maclen == 0 ? NULL : &mac_param.mac[0], mac_param.maclen, ARPHRD_ETHER);
sz, &from.sin6_addr, now);
lease_update_file(now);
lease_update_dns(0);
......@@ -276,6 +229,55 @@ void dhcp6_packet(time_t now)
}
}
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep)
{
/* Recieving a packet from a host does not populate the neighbour
cache, so we send a neighbour discovery request if we can't
find the sender. Repeat a few times in case of packet loss. */
struct neigh_packet neigh;
struct sockaddr_in6 addr;
struct mac_param mac_param;
int i;
neigh.type = ND_NEIGHBOR_SOLICIT;
neigh.code = 0;
neigh.reserved = 0;
neigh.target = *client;
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
addr.sin6_len = sizeof(struct sockaddr_in6);
#endif
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(IPPROTO_ICMPV6);
addr.sin6_addr = *client;
addr.sin6_scope_id = iface;
mac_param.target = client;
mac_param.maclen = 0;
mac_param.mac = mac;
for (i = 0; i < 5; i++)
{
struct timespec ts;
iface_enumerate(AF_UNSPEC, &mac_param, find_mac);
if (mac_param.maclen != 0)
break;
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)&addr, sizeof(addr));
ts.tv_sec = 0;
ts.tv_nsec = 100000000; /* 100ms */
nanosleep(&ts, NULL);
}
*maclenp = mac_param.maclen;
*mactypep = ARPHRD_ETHER;
}
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
{
struct mac_param *parm = parmv;
......
......@@ -1212,15 +1212,15 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
int prefix, u64 addr);
void make_duid(time_t now);
void dhcp_construct_contexts(time_t now);
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
unsigned int *maclenp, unsigned int *mactypep);
#endif
/* rfc3315.c */
#ifdef HAVE_DHCP6
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
struct in6_addr *fallback, size_t sz, int is_multicast, time_t now,
unsigned char *mac, unsigned int mac_len, unsigned int mac_type);
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id,
unsigned char *mac, unsigned int mac_len, unsigned int mac_type);
struct in6_addr *fallback, size_t sz, struct in6_addr *client_addr, time_t now);
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id);
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
#endif
......
......@@ -29,14 +29,15 @@ struct state {
char *iface_name;
void *packet_options, *end;
struct dhcp_netid *tags, *context_tags;
unsigned char *mac;
unsigned char mac[DHCP_CHADDR_MAX];
unsigned int mac_len, mac_type;
#ifdef OPTION6_PREFIX_CLASS
struct prefix_class *send_prefix_class;
#endif
};
static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, int is_unicast, time_t now);
static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
struct in6_addr *client_addr, int is_unicast, time_t now);
static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now);
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
......@@ -67,8 +68,7 @@ static void calculate_times(struct dhcp_context *context, unsigned int *min_time
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
struct in6_addr *fallback, size_t sz, int is_unicast, time_t now,
unsigned char *mac, unsigned int mac_len, unsigned int mac_type)
struct in6_addr *fallback, size_t sz, struct in6_addr *client_addr, time_t now)
{
struct dhcp_vendor *vendor;
int msg_type;
......@@ -88,20 +88,20 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if
state.interface = interface;
state.iface_name = iface_name;
state.fallback = fallback;
state.mac = mac;
state.mac_len = mac_len;
state.mac_type = mac_type;
state.mac_len = 0;
state.tags = NULL;
state.link_address = NULL;
if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, is_unicast, now))
if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr,
IN6_IS_ADDR_MULTICAST(client_addr), now))
return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
return 0;
}
/* This cost me blood to write, it will probably cost you blood to understand - srk. */
static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, int is_unicast, time_t now)
static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
struct in6_addr *client_addr, int is_unicast, time_t now)
{
void *end = inbuff + sz;
void *opts = inbuff + 34;
......@@ -116,9 +116,14 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, int i
/* if link_address != NULL if points to the link address field of the
innermost nested RELAYFORW message, which is where we find the
address of the network on which we can allocate an address.
Recalculate the available contexts using that information. */
Recalculate the available contexts using that information.
link_address == NULL means there's no relay in use, so we try and find the client's
MAC address from the local ND cache. */
if (state->link_address)
if (!state->link_address)
get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type);
else
{
struct dhcp_context *c;
state->context = NULL;
......@@ -146,7 +151,7 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, int i
return 0;
}
}
if (!state->context)
{
my_syslog(MS_DHCP | LOG_WARNING,
......@@ -193,9 +198,9 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, int i
/* RFC-6939 */
if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
{
state->mac = opt6_ptr(opt, 2);
state->mac_type = opt6_uint(opt, 0, 2);
state->mac_len = opt6_len(opt) - 2;
memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
}
for (opt = opts; opt; opt = opt6_next(opt, end))
......@@ -209,7 +214,7 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, int i
state->link_address = &align;
/* zero is_unicast since that is now known to refer to the
relayed packet, not the original sent by the client */
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), 0, now))
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
return 0;
}
else if (opt6_type(opt) != OPTION6_CLIENT_MAC)
......@@ -1961,8 +1966,7 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
return ret;
}
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id,
unsigned char *mac, unsigned int mac_len, unsigned int mac_type )
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id)
{
/* ->local is same value for all relays on ->current chain */
......@@ -1972,9 +1976,12 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer
int msg_type = *inbuff;
int hopcount;
struct in6_addr multicast;
unsigned int maclen, mactype;
unsigned char mac[DHCP_CHADDR_MAX];
inet_pton(AF_INET6, ALL_SERVERS, &multicast);
get_client_mac(peer_address, scope_id, mac, &maclen, &mactype);
/* source address == relay address */
from.addr.addr6 = relay->local.addr.addr6;
......@@ -2000,11 +2007,11 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer
memcpy(&header[18], peer_address, IN6ADDRSZ);
/* RFC-6939 */
if (mac)
if (maclen != 0)
{
o = new_opt6(OPTION6_CLIENT_MAC);
put_opt6_short(mac_type);
put_opt6(mac, mac_len);
put_opt6_short(mactype);
put_opt6(mac, maclen);
end_opt6(o);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment