mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
Don't extract MAC address from ND table when DHCPv6 request is from a relay.
This commit is contained in:
102
src/dhcp6.c
102
src/dhcp6.c
@@ -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.
|
||||
|
||||
if (state->link_address)
|
||||
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)
|
||||
get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type);
|
||||
else
|
||||
{
|
||||
struct dhcp_context *c;
|
||||
state->context = NULL;
|
||||
@@ -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,8 +1976,11 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user