From 04473969ef07c953415d8ce7964f1e9664e96a6c Mon Sep 17 00:00:00 2001 From: Patrik Flykt Date: Fri, 12 May 2017 16:48:27 +0300 Subject: [PATCH] sd-radv: Add Router Advertisement prefix handling Define Router Advertisement prefix structure. Add the Prefix Information ICMPv6 option defined in RFC 4861 to the prefix information structure, as it will simplify sending a Prefix Information option later on. In order to handle endianness correctly, the structure is redefined here instead of using the one in netinet/icmp6.h. Add functions to create and modify prefix information and set default values as defined in RFC 4861, Section 6.2.1. --- Makefile.am | 3 + src/libsystemd-network/radv-internal.h | 48 ++++++++++++ src/libsystemd-network/sd-radv.c | 136 +++++++++++++++++++++++++++++++++ src/systemd/sd-radv.h | 56 ++++++++++++++ 4 files changed, 243 insertions(+) create mode 100644 src/libsystemd-network/radv-internal.h create mode 100644 src/libsystemd-network/sd-radv.c create mode 100644 src/systemd/sd-radv.h diff --git a/Makefile.am b/Makefile.am index b62166c..29fa71d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3637,6 +3637,7 @@ libsystemd_network_la_SOURCES = \ src/systemd/sd-ipv4ll.h \ src/systemd/sd-ipv4acd.h \ src/systemd/sd-ndisc.h \ + src/systemd/sd-radv.h \ src/systemd/sd-dhcp6-client.h \ src/systemd/sd-dhcp6-lease.h \ src/systemd/sd-lldp.h \ @@ -3660,6 +3661,8 @@ libsystemd_network_la_SOURCES = \ src/libsystemd-network/ndisc-internal.h \ src/libsystemd-network/ndisc-router.h \ src/libsystemd-network/ndisc-router.c \ + src/libsystemd-network/sd-radv.c \ + src/libsystemd-network/radv-internal.h \ src/libsystemd-network/icmp6-util.h \ src/libsystemd-network/icmp6-util.c \ src/libsystemd-network/sd-dhcp6-client.c \ diff --git a/src/libsystemd-network/radv-internal.h b/src/libsystemd-network/radv-internal.h new file mode 100644 index 0000000..0f92c8b --- /dev/null +++ b/src/libsystemd-network/radv-internal.h @@ -0,0 +1,48 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2017 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-radv.h" + +#include "log.h" +#include "list.h" +#include "sparse-endian.h" + +struct sd_radv_prefix { + unsigned n_ref; + + struct { + uint8_t type; + uint8_t length; + uint8_t prefixlen; + uint8_t flags; + be32_t valid_lifetime; + be32_t preferred_lifetime; + uint32_t reserved; + struct in6_addr in6_addr; + } _packed_ opt; + + LIST_FIELDS(struct sd_radv_prefix, prefix); +}; + +#define log_radv_full(level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "RADV: " fmt, ##__VA_ARGS__) +#define log_radv_errno(error, fmt, ...) log_radv_full(LOG_DEBUG, error, fmt, ##__VA_ARGS__) +#define log_radv_warning_errno(error, fmt, ...) log_radv_full(LOG_WARNING, error, fmt, ##__VA_ARGS__) +#define log_radv(fmt, ...) log_radv_errno(0, fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c new file mode 100644 index 0000000..54f126e --- /dev/null +++ b/src/libsystemd-network/sd-radv.c @@ -0,0 +1,136 @@ +/*** + This file is part of systemd. + + Copyright (C) 2017 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "sd-radv.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "icmp6-util.h" +#include "in-addr-util.h" +#include "radv-internal.h" +#include "socket-util.h" +#include "string-util.h" +#include "util.h" + +_public_ int sd_radv_prefix_new(sd_radv_prefix **ret) { + _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL; + + assert_return(ret, -EINVAL); + + p = new0(sd_radv_prefix, 1); + if (!p) + return -ENOMEM; + + p->n_ref = 1; + + p->opt.type = ND_OPT_PREFIX_INFORMATION; + p->opt.length = (sizeof(p->opt) - 1) /8 + 1; + + p->opt.prefixlen = 64; + + /* RFC 4861, Section 6.2.1 */ + SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, true); + SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, true); + p->opt.preferred_lifetime = htobe32(604800); + p->opt.valid_lifetime = htobe32(2592000); + + *ret = p; + p = NULL; + + return 0; +} + +_public_ sd_radv_prefix *sd_radv_prefix_ref(sd_radv_prefix *p) { + if (!p) + return NULL; + + assert(p->n_ref > 0); + p->n_ref++; + + return p; +} + +_public_ sd_radv_prefix *sd_radv_prefix_unref(sd_radv_prefix *p) { + if (!p) + return NULL; + + assert(p->n_ref > 0); + p->n_ref--; + + if (p->n_ref > 0) + return NULL; + + return mfree(p); +} + +_public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, struct in6_addr *in6_addr, + unsigned char prefixlen) { + assert_return(p, -EINVAL); + assert_return(in6_addr, -EINVAL); + + if (prefixlen < 3 || prefixlen > 128) + return -EINVAL; + + if (prefixlen > 64) + /* unusual but allowed, log it */ + log_radv("Unusual prefix length %d greater than 64", prefixlen); + + p->opt.in6_addr = *in6_addr; + p->opt.prefixlen = prefixlen; + + return 0; +} + +_public_ int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) { + assert_return(p, -EINVAL); + + SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, onlink); + + return 0; +} + +_public_ int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p, + int address_autoconfiguration) { + assert_return(p, -EINVAL); + + SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, address_autoconfiguration); + + return 0; +} + +_public_ int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p, + uint32_t valid_lifetime) { + assert_return(p, -EINVAL); + + p->opt.valid_lifetime = htobe32(valid_lifetime); + + return 0; +} + +_public_ int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p, + uint32_t preferred_lifetime) { + assert_return(p, -EINVAL); + + p->opt.preferred_lifetime = htobe32(preferred_lifetime); + + return 0; +} diff --git a/src/systemd/sd-radv.h b/src/systemd/sd-radv.h new file mode 100644 index 0000000..c993367 --- /dev/null +++ b/src/systemd/sd-radv.h @@ -0,0 +1,56 @@ +#ifndef foosdradvfoo +#define foosdradvfoo + +/*** + This file is part of systemd. + + Copyright (C) 2017 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "sd-event.h" + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +typedef struct sd_radv_prefix sd_radv_prefix; + +/* Advertised prefixes */ +int sd_radv_prefix_new(sd_radv_prefix **ret); +sd_radv_prefix *sd_radv_prefix_ref(sd_radv_prefix *ra); +sd_radv_prefix *sd_radv_prefix_unref(sd_radv_prefix *ra); + +int sd_radv_prefix_set_prefix(sd_radv_prefix *p, struct in6_addr *in6_addr, + unsigned char prefixlen); +int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink); +int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p, + int address_autoconfiguration); +int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p, + uint32_t valid_lifetime); +int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p, + uint32_t preferred_lifetime); + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv, sd_radv_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv_prefix, sd_radv_prefix_unref); + +_SD_END_DECLARATIONS; + +#endif -- 2.7.4