Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patches to add flexibility to odhcpd's Route Info Option handling #33

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ ra_management integer 1 RA management mode
ra_offlink bool 0 Announce prefixes off-link
ra_preference string medium Route(r) preference
[medium|high|low]
ra_unreachable bool 1 Announce router's unreachable
routes via Route Info Option
ra_route list <IPv6/bits [low|medium|high]> Announce manually
configured routes via the RA
Route Info Option
ndproxy_routing bool 1 Learn routes from NDP
ndproxy_slave bool 0 NDProxy external slave

Expand Down
94 changes: 93 additions & 1 deletion src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
#include <signal.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#include <uci.h>
#include <uci_blob.h>

#include "odhcpd.h"
#include "router.h"

static struct blob_buf b;
static int reload_pipe[2];
Expand Down Expand Up @@ -40,6 +43,8 @@ enum {
IFACE_ATTR_RA_OFFLINK,
IFACE_ATTR_RA_PREFERENCE,
IFACE_ATTR_RA_ADVROUTER,
IFACE_ATTR_RA_UNREACHABLE,
IFACE_ATTR_RA_ROUTE,
IFACE_ATTR_PD_MANAGER,
IFACE_ATTR_PD_CER,
IFACE_ATTR_NDPROXY_ROUTING,
Expand Down Expand Up @@ -74,6 +79,8 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
[IFACE_ATTR_RA_OFFLINK] = { .name = "ra_offlink", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_RA_PREFERENCE] = { .name = "ra_preference", .type = BLOBMSG_TYPE_STRING },
[IFACE_ATTR_RA_ADVROUTER] = { .name = "ra_advrouter", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_RA_UNREACHABLE] = { .name = "ra_unreachable", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_RA_ROUTE] = { .name = "ra_route", .type = BLOBMSG_TYPE_ARRAY },
[IFACE_ATTR_NDPROXY_ROUTING] = { .name = "ndproxy_routing", .type = BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL },
};
Expand Down Expand Up @@ -275,6 +282,47 @@ static int set_lease(struct uci_section *s)
}


int config_parse_ra_route(struct in6_addr *addr, uint8_t *bits, int *pref,
char *src)
{
int n;
char *p, *sep = " \t/";

*pref = 0;
for(n = 0, p = strtok(src, sep); p; n++, p = strtok(NULL, sep)) {
switch(n) {
case 0: /* IPv6 address */
if (inet_pton(AF_INET6, p, addr) <= 0) return 0;
break;

case 1: /* Network bits */
*bits = strtol(p, (char **)NULL, 10);
if (((*bits) == 0 && errno != 0) || (*bits) > 128)
return 0;
break;

case 2: /* Preference */
if (!strcasecmp(p, "low")) {
*pref = -1;
} else if (!strcasecmp(p, "medium")) {
*pref = 0;
} else if (!strcasecmp(p, "high")) {
*pref = 1;
} else {
return 0; /* Uknown preference name, report error */
}
break;

default:
return 0; /* Unexpected tokens found, report error */
}
}
if (n < 2) return 0; /* Not all required tokens found, report error */

return 1;
}


int config_parse_interface(void *data, size_t len, const char *name, bool overwrite)
{
struct blob_attr *tb[IFACE_ATTR_MAX], *c;
Expand Down Expand Up @@ -528,6 +576,51 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
goto err;
}

if ((c = tb[IFACE_ATTR_RA_UNREACHABLE]))
iface->no_ra_unreachable = !blobmsg_get_bool(c);

if ((c = tb[IFACE_ATTR_RA_ROUTE])) {
int pref, i, j;
unsigned rem;
uint8_t bits;
uint32_t mask;
struct blob_attr *cur;
struct in6_addr addr;
struct ra_route *dst;

blobmsg_for_each_attr(cur, c, rem) {
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING
|| !blobmsg_check_attr(cur, NULL))
continue;

if (config_parse_ra_route(&addr, &bits, &pref,
blobmsg_get_string(cur))) {
iface->ra_routes = realloc(iface->ra_routes,
(++iface->ra_routes_cnt) * sizeof(*iface->ra_routes));
if (!iface->ra_routes) goto err;

dst = &iface->ra_routes[iface->ra_routes_cnt - 1];
dst->type = ND_OPT_ROUTE_INFO;
dst->len = sizeof(struct ra_route) / 8;
dst->prefix = bits;
dst->flags = 0;
if (pref < 0) dst->flags |= ND_RA_PREF_LOW;
if (pref > 0) dst->flags |= ND_RA_PREF_HIGH;

i = 3;
memcpy(dst->addr, addr.s6_addr32, 4 * sizeof(dst->addr[0]));
if (bits <= 96) dst->addr[i--] = 0;
if (bits <= 64) dst->addr[i--] = 0;
if (bits <= 32) dst->addr[i--] = 0;
for(j = 0, mask = 0; j < (bits - i * 32); j++)
mask |= 1 << (31 - j);
dst->addr[i] &= htonl(mask);
} else {
goto err;
}
}
}

if ((c = tb[IFACE_ATTR_PD_MANAGER]))
strncpy(iface->dhcpv6_pd_manager, blobmsg_get_string(c),
sizeof(iface->dhcpv6_pd_manager) - 1);
Expand Down Expand Up @@ -721,4 +814,3 @@ void odhcpd_run(void)
while (!list_empty(&interfaces))
close_interface(list_first_entry(&interfaces, struct interface, head));
}

13 changes: 13 additions & 0 deletions src/odhcpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ struct lease {
};


struct ra_route {
uint8_t type;
uint8_t len;
uint8_t prefix;
uint8_t flags;
uint32_t lifetime;
uint32_t addr[4];
};


struct interface {
struct list_head head;

Expand Down Expand Up @@ -139,6 +149,9 @@ struct interface {
bool always_rewrite_dns;
bool ra_not_onlink;
bool ra_advrouter;
bool no_ra_unreachable;
struct ra_route *ra_routes;
size_t ra_routes_cnt;
bool no_dynamic_dhcp;

int learn_routes;
Expand Down
16 changes: 7 additions & 9 deletions src/router.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,16 +375,9 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add


size_t routes_cnt = 0;
struct {
uint8_t type;
uint8_t len;
uint8_t prefix;
uint8_t flags;
uint32_t lifetime;
uint32_t addr[4];
} routes[RELAYD_MAX_PREFIXES];
struct ra_route routes[RELAYD_MAX_PREFIXES];

for (ssize_t i = 0; i < ipcnt; ++i) {
for (ssize_t i = 0; !iface->no_ra_unreachable && i < ipcnt; ++i) {
struct odhcpd_ipaddr *addr = &addrs[i];
if (addr->dprefix > 64 || addr->dprefix == 0 ||
(addr->dprefix == 64 && addr->prefix == 64)) {
Expand Down Expand Up @@ -413,6 +406,10 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
++routes_cnt;
}

// Update lifetime in routes obtained from configuration
for (size_t i = 0; i < iface->ra_routes_cnt; ++i)
iface->ra_routes[i].lifetime = htonl(MaxValidTime);

// Calculate periodic transmit
int msecs = 0;
uint32_t maxival = MaxRtrAdvInterval * 1000;
Expand Down Expand Up @@ -440,6 +437,7 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add

struct iovec iov[] = {{&adv, (uint8_t*)&adv.prefix[cnt] - (uint8_t*)&adv},
{&routes, routes_cnt * sizeof(*routes)},
{iface->ra_routes, iface->ra_routes_cnt * sizeof(iface->ra_routes[0])},
{&dns, (dns_cnt) ? sizeof(dns) : 0},
{dns_addr, dns_cnt * sizeof(*dns_addr)},
{search, search->len * 8},
Expand Down