Commit ab308385 authored by Joanne Hugé's avatar Joanne Hugé

Support router solicitation without SLLA option

Many clients don't include SLLA option in router solicitations:
https://github.com/radvd-project/radvd/issues/63#issuecomment-287172252
Answer these router solicitations by triggering a neighbour
solicitation when SLLA is not included, and then waiting for the
neighbour advertisment.
parent b5ce1263
......@@ -9,6 +9,7 @@
#include <netlink/msg.h>
#include <netlink/attr.h>
#include <netlink/route/addr.h>
#include <netlink/route/neighbour.h>
#include <netlink/route/route.h>
#include <netlink/errno.h>
......@@ -71,6 +72,51 @@ static int family_handler(struct nl_msg *msg, void *arg)
return NL_SKIP;
}
struct nl_sock *rtnl_sock = NULL;
int nl_get_mac(int ifindex, unsigned char * dst, unsigned char * mac)
{
struct nl_cache * cache = NULL;
struct rtnl_neigh * neigh = NULL;
struct nl_addr *dst_addr = NULL;
struct nl_addr *mac_addr = NULL;
int rc;
if(rtnl_sock == NULL) {
rtnl_sock = nl_socket_alloc();
if(rtnl_sock == NULL)
return -NLE_NOMEM;
rc = nl_connect(rtnl_sock, NETLINK_ROUTE);
if(rc < 0) {
nl_socket_free(rtnl_sock);
rtnl_sock = NULL;
return rc;
}
}
rc = rtnl_neigh_alloc_cache(rtnl_sock, &cache);
if(rc)
return rc;
dst_addr = nl_addr_build(AF_INET6, dst, 16);
neigh = rtnl_neigh_get(cache, ifindex, dst_addr);
if(neigh == NULL) {
nl_cache_free(cache);
return 1;
}
mac_addr = rtnl_neigh_get_lladdr(neigh);
if(mac_addr == NULL) {
nl_cache_free(cache);
return 1;
}
memcpy(mac, nl_addr_get_binary_addr(mac_addr), 6);
rtnl_neigh_put(neigh);
nl_cache_free(cache);
return 0;
}
int nl_get_multicast_id(struct nl_sock *sock,
const char *family, const char *group)
{
......@@ -281,7 +327,6 @@ netlink_disassociate(int ifindex, const unsigned char *mac,
return -1;
}
struct nl_sock *rtnl_sock = NULL;
int
netlink_route(int ifindex, int add, int ipv6, const unsigned char *dst, int dlen)
......
......@@ -8,3 +8,4 @@ int netlink_disassociate(int ifindex, const unsigned char *mac,
const unsigned char *mymac);
int netlink_route(int ifindex, int add, int ipv6,
const unsigned char *dst, int dlen);
int nl_get_mac(int ifindex, unsigned char * dst, unsigned char * mac);
......@@ -13,6 +13,7 @@
#include "flood.h"
#include "util.h"
#include "ra.h"
#include "netlink.h"
unsigned char dnsv6[16][16];
int numdnsv6 = 0;
......@@ -163,6 +164,7 @@ receive_rs()
int buflen = 1500, rc;
unsigned char buf[buflen];
unsigned char *mac;
unsigned char mac_cache[6];
struct sockaddr_in6 from;
struct interface *interface;
struct iovec iov[1];
......@@ -231,7 +233,14 @@ receive_rs()
}
if(mac == NULL) {
debugf("No source address option in router solicitation.\n");
return -1;
rc = nl_get_mac(interface->ifindex, from.sin6_addr.s6_addr, mac_cache);
if(rc < 0)
return rc;
if (rc) {
send_ns(interface, from.sin6_addr.s6_addr);
return -1;
}
mac = mac_cache;
}
debugf("<- RS %s\n", interface->ifname);
......@@ -300,6 +309,37 @@ send_gratuitous_na(struct interface *interface)
return sendto(ra_socket, buf, i, 0, (struct sockaddr*)&to, sizeof(to));
}
int
send_ns(struct interface *interface, unsigned char * ipv6)
{
int buflen = 1024;
unsigned char buf[buflen];
struct sockaddr_in6 to;
int i = 0;
memset(&to, 0, sizeof(to));
to.sin6_family = AF_INET6;
memcpy(&to.sin6_addr, all_nodes, 16);
to.sin6_scope_id = interface->ifindex;
CHECK(24);
BYTE(135);
BYTE(0);
SHORT(0);
LONG(0);
BYTES(ipv6, 16);
if(memcmp(interface->mac, zeroes, 6) != 0) {
CHECK(8);
BYTE(1);
BYTE(1);
BYTES(interface->mac, 6);
}
sendit:
debugf("-> Neighbour Solicitation\n");
return sendto(ra_socket, buf, i, 0, (struct sockaddr*)&to, sizeof(to));
}
int
ra_setup()
......
......@@ -35,5 +35,6 @@ int send_ra(const unsigned char *prefix, int tm,
const struct sockaddr_in6 *to, struct interface *interface);
int receive_rs(void);
int send_gratuitous_na(struct interface *interface);
int send_ns(struct interface *interface, unsigned char * ipv6);
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