Skip to content

Commit 4fec3c8

Browse files
committed
config: refactor parsing of static RA routes
Adds comments and makes static RA routes parser easier to read and maintain. Also logs concrete values in case some routes are invalid. Fixes memory leak in case of invalid RA route (line 395 in the original `config.c`). Signed-off-by: Dávid Benko <[email protected]>
1 parent f1ee9c6 commit 4fec3c8

File tree

1 file changed

+70
-37
lines changed

1 file changed

+70
-37
lines changed

src/config.c

+70-37
Original file line numberDiff line numberDiff line change
@@ -372,45 +372,52 @@ static int parse_ra_flags(uint8_t *flags, struct blob_attr *attr)
372372

373373
/* Returns 0 on success, -1 on invalid value, -2 on memory error
374374
(`routes` is unmodified in that case) */
375-
static int parse_ra_staticroute(struct blob_attr *attr, struct odhcpd_ip6prefix **routes,
376-
size_t *routes_cnt)
375+
static int parse_append_ra_staticroute(struct blob_attr *attr,
376+
struct odhcpd_ip6prefix **routes, size_t *routes_cnt)
377377
{
378378
if (blobmsg_type(attr) != BLOBMSG_TYPE_STRING ||
379-
!blobmsg_check_attr(attr, false))
379+
!blobmsg_check_attr(attr, false)) {
380380
return -1;
381+
}
381382

382383
const char *str = blobmsg_get_string(attr);
383-
char *astr = malloc(strlen(str) + 1);
384-
char *delim;
385-
int l;
386384
struct odhcpd_ip6prefix prefix;
387385

388-
if (!astr || !strcpy(astr, str))
389-
return -2;
386+
/* Parse the address and prefix length */
387+
if (odhcpd_parse_addr6_prefix(str, &prefix.addr, &prefix.len) < 0) {
388+
return -1;
389+
}
390390

391-
if ((delim = strchr(astr, '/')) == NULL || (*(delim++) = 0) ||
392-
sscanf(delim, "%i", &l) == 0 || l < 1 || l > 128 ||
393-
inet_pton(AF_INET6, astr, &prefix.addr) == 0 ||
394-
IN6_IS_ADDR_UNSPECIFIED(&prefix.addr)) {
391+
/*
392+
* Validate prefix length
393+
* Default route (::/0) is managed elsewhere.
394+
*/
395+
if (prefix.len == 0 || prefix.len > 128) {
395396
return -1;
396-
} else {
397-
prefix.len = l;
398-
399-
struct odhcpd_ip6prefix *tmp = realloc(*routes, (*routes_cnt + 1) *
400-
sizeof(**routes));
401-
if (!tmp) {
402-
if (astr)
403-
free(astr);
404-
return -2;
405-
}
397+
}
406398

407-
*routes = tmp;
408-
(*routes)[*routes_cnt] = prefix;
409-
++(*routes_cnt);
399+
/*
400+
* Validate address
401+
* Zero-address (::) specifies default route and is managed elsewhere,
402+
* loopback and link-local addresses are not routable.
403+
*/
404+
if (IN6_IS_ADDR_UNSPECIFIED(&prefix.addr) ||
405+
IN6_IS_ADDR_LOOPBACK(&prefix.addr) ||
406+
IN6_IS_ADDR_LINKLOCAL(&prefix.addr)) {
407+
return -1;
410408
}
411409

412-
if (astr)
413-
free(astr);
410+
/* Append the prefix to the list */
411+
struct odhcpd_ip6prefix *tmp = realloc(*routes, (*routes_cnt + 1) *
412+
sizeof(**routes));
413+
if (!tmp) {
414+
return -2;
415+
}
416+
417+
*routes = tmp;
418+
(*routes)[*routes_cnt] = prefix;
419+
++(*routes_cnt);
420+
414421
return 0;
415422
}
416423

@@ -461,15 +468,28 @@ static void set_config(struct uci_section *s)
461468
unsigned rem;
462469

463470
blobmsg_for_each_attr(cur, c, rem) {
464-
int ec = parse_ra_staticroute(cur, &(config.ra_static_routes),
471+
/* Parse and append the route */
472+
int ec = parse_append_ra_staticroute(
473+
cur, &(config.ra_static_routes),
465474
&(config.ra_static_routes_cnt));
466475

467476
if (ec == -1) {
468-
syslog(LOG_ERR, "Invalid %s value",
469-
odhcpd_attrs[ODHCPD_ATTR_RA_STATICROUTE].name);
477+
/* Invalid value */
478+
char default_str[] = "?";
479+
char *str = default_str;
480+
if (blobmsg_type(cur) == BLOBMSG_TYPE_STRING &&
481+
blobmsg_check_attr(cur, false)) {
482+
str = blobmsg_get_string(cur);
483+
}
484+
syslog(LOG_WARNING, "Invalid %s value (%s), "
485+
"ignoring this route",
486+
odhcpd_attrs[ODHCPD_ATTR_RA_STATICROUTE].name,
487+
str);
470488
} else if (ec == -2) {
489+
/* Memory error */
471490
syslog(LOG_ERR, "Memory allocation failed for %s",
472-
odhcpd_attrs[ODHCPD_ATTR_RA_STATICROUTE].name);
491+
odhcpd_attrs[ODHCPD_ATTR_RA_STATICROUTE].name);
492+
break;
473493
}
474494
}
475495
}
@@ -1388,21 +1408,34 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
13881408

13891409
if ((c = tb[IFACE_ATTR_RA_DNS]))
13901410
iface->ra_dns = blobmsg_get_bool(c);
1391-
1411+
13921412
if ((c = tb[IFACE_ATTR_RA_STATICROUTE])) {
13931413
struct blob_attr *cur;
13941414
unsigned rem;
13951415

13961416
blobmsg_for_each_attr(cur, c, rem) {
1397-
int ec = parse_ra_staticroute(cur, &(iface->ra_static_routes),
1417+
/* Parse and append the route */
1418+
int ec = parse_append_ra_staticroute(
1419+
cur, &(iface->ra_static_routes),
13981420
&(iface->ra_static_routes_cnt));
13991421

14001422
if (ec == -1) {
1401-
syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
1402-
iface_attrs[IFACE_ATTR_RA_STATICROUTE].name, iface->name);
1423+
/* Invalid value */
1424+
char default_str[] = "?";
1425+
char *str = default_str;
1426+
if (blobmsg_type(cur) == BLOBMSG_TYPE_STRING &&
1427+
blobmsg_check_attr(cur, false)) {
1428+
str = blobmsg_get_string(cur);
1429+
}
1430+
syslog(LOG_WARNING, "Invalid %s value (%s) for "
1431+
"interface '%s', ignoring this route",
1432+
odhcpd_attrs[ODHCPD_ATTR_RA_STATICROUTE].name,
1433+
str, iface->name);
14031434
} else if (ec == -2) {
1404-
syslog(LOG_ERR, "Memory allocation failed for %s on interface '%s'",
1405-
iface_attrs[IFACE_ATTR_RA_STATICROUTE].name, iface->name);
1435+
/* Memory error */
1436+
syslog(LOG_ERR, "Memory allocation failed for %s",
1437+
odhcpd_attrs[ODHCPD_ATTR_RA_STATICROUTE].name);
1438+
break;
14061439
}
14071440
}
14081441
}

0 commit comments

Comments
 (0)