]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-ndisc.c
hibernate-resume: add resumeflags= kernel option
[thirdparty/systemd.git] / src / network / networkd-ndisc.c
index e5b8d115551b71f2edb57eb5978087fc1d778544..3016f3448bddc9644767010f21f0246ae62e71d4 100644 (file)
@@ -39,7 +39,7 @@ static int ndisc_netlink_message_handler(sd_netlink *rtnl, sd_netlink_message *m
 
 static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
         _cleanup_(route_freep) Route *route = NULL;
-        struct in6_addr gateway;
+        union in_addr_union gateway;
         uint16_t lifetime;
         unsigned preference;
         uint32_t mtu;
@@ -58,31 +58,35 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
         if (lifetime == 0) /* not a default router */
                 return 0;
 
-        r = sd_ndisc_router_get_address(rt, &gateway);
+        r = sd_ndisc_router_get_address(rt, &gateway.in6);
         if (r < 0)
                 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
 
-        SET_FOREACH(address, link->addresses, i)
-                if (!memcmp(&gateway, &address->in_addr.in6, sizeof(address->in_addr.in6))) {
-                        char buffer[INET6_ADDRSTRLEN];
+        SET_FOREACH(address, link->addresses, i) {
+                if (address->family != AF_INET6)
+                        continue;
+                if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
+                        _cleanup_free_ char *buffer = NULL;
 
+                        (void) in_addr_to_string(AF_INET6, &address->in_addr, &buffer);
                         log_link_debug(link, "No NDisc route added, gateway %s matches local address",
-                                       inet_ntop(AF_INET6,
-                                                 &address->in_addr.in6,
-                                                 buffer, sizeof(buffer)));
+                                       strnull(buffer));
                         return 0;
                 }
+        }
 
-        SET_FOREACH(address, link->addresses_foreign, i)
-                if (!memcmp(&gateway, &address->in_addr.in6, sizeof(address->in_addr.in6))) {
-                        char buffer[INET6_ADDRSTRLEN];
+        SET_FOREACH(address, link->addresses_foreign, i) {
+                if (address->family != AF_INET6)
+                        continue;
+                if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
+                        _cleanup_free_ char *buffer = NULL;
 
+                        (void) in_addr_to_string(AF_INET6, &address->in_addr, &buffer);
                         log_link_debug(link, "No NDisc route added, gateway %s matches local address",
-                                       inet_ntop(AF_INET6,
-                                                 &address->in_addr.in6,
-                                                 buffer, sizeof(buffer)));
+                                       strnull(buffer));
                         return 0;
                 }
+        }
 
         r = sd_ndisc_router_get_preference(rt, &preference);
         if (r < 0)
@@ -103,11 +107,11 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
                 return log_link_error_errno(link, r, "Could not allocate route: %m");
 
         route->family = AF_INET6;
-        route->table = link->network->ipv6_accept_ra_route_table;
+        route->table = link_get_ipv6_accept_ra_route_table(link);
         route->priority = link->network->dhcp_route_metric;
         route->protocol = RTPROT_RA;
         route->pref = preference;
-        route->gw.in6 = gateway;
+        route->gw = gateway;
         route->lifetime = time_now + lifetime * USEC_PER_SEC;
         route->mtu = mtu;
 
@@ -238,7 +242,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
                 return log_link_error_errno(link, r, "Could not allocate route: %m");
 
         route->family = AF_INET6;
-        route->table = link->network->ipv6_accept_ra_route_table;
+        route->table = link_get_ipv6_accept_ra_route_table(link);
         route->priority = link->network->dhcp_route_metric;
         route->protocol = RTPROT_RA;
         route->flags = RTM_F_PREFIX;
@@ -299,7 +303,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
                 return log_link_error_errno(link, r, "Could not allocate route: %m");
 
         route->family = AF_INET6;
-        route->table = link->network->ipv6_accept_ra_route_table;
+        route->table = link_get_ipv6_accept_ra_route_table(link);
         route->protocol = RTPROT_RA;
         route->pref = preference;
         route->gw.in6 = gateway;
@@ -493,7 +497,7 @@ static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
         }
 }
 
-static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
+static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
         int r;
 
         assert(link);
@@ -503,18 +507,14 @@ static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
         for (;;) {
                 uint8_t type;
 
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "Failed to iterate through options: %m");
-                        return;
-                }
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
                 if (r == 0) /* EOF */
                         break;
 
                 r = sd_ndisc_router_option_get_type(rt, &type);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "Failed to get RA option type: %m");
-                        return;
-                }
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
 
                 switch (type) {
 
@@ -522,14 +522,15 @@ static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
                         uint8_t flags;
 
                         r = sd_ndisc_router_prefix_get_flags(rt, &flags);
-                        if (r < 0) {
-                                log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
-                                return;
-                        }
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
 
-                        if (flags & ND_OPT_PI_FLAG_ONLINK)
+                        if (link->network->ipv6_accept_ra_use_onlink_prefix &&
+                            FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK))
                                 (void) ndisc_router_process_onlink_prefix(link, rt);
-                        if (flags & ND_OPT_PI_FLAG_AUTO)
+
+                        if (link->network->ipv6_accept_ra_use_autonomous_prefix &&
+                            FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO))
                                 (void) ndisc_router_process_autonomous_prefix(link, rt);
 
                         break;
@@ -552,11 +553,53 @@ static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
 
                 r = sd_ndisc_router_option_next(rt);
         }
+
+        return 0;
+}
+
+static int ndisc_prefix_is_black_listed(Link *link, sd_ndisc_router *rt) {
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(rt);
+
+        for (r = sd_ndisc_router_option_rewind(rt); ; r = sd_ndisc_router_option_next(rt)) {
+                union in_addr_union a;
+                uint8_t type;
+
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
+                if (r == 0) /* EOF */
+                        return false;
+
+                r = sd_ndisc_router_option_get_type(rt, &type);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
+
+                if (type != SD_NDISC_OPTION_PREFIX_INFORMATION)
+                        continue;
+
+                r = sd_ndisc_router_prefix_get_address(rt, &a.in6);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Failed to get prefix address: %m");
+
+                if (set_contains(link->network->ndisc_black_listed_prefix, &a.in6)) {
+                        if (DEBUG_LOGGING) {
+                                _cleanup_free_ char *b = NULL;
+
+                                (void) in_addr_to_string(AF_INET6, &a, &b);
+                                log_link_debug(link, "Prefix '%s' is black listed, ignoring", strna(b));
+                        }
+
+                        return true;
+                }
+        }
 }
 
 static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
         uint64_t flags;
-        int r = 0;
+        int r;
 
         assert(link);
         assert(link->network);
@@ -578,8 +621,10 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
                 }
         }
 
-        ndisc_router_process_default(link, rt);
-        ndisc_router_process_options(link, rt);
+        if (ndisc_prefix_is_black_listed(link, rt) == 0) {
+                (void) ndisc_router_process_default(link, rt);
+                (void) ndisc_router_process_options(link, rt);
+        }
 
         return r;
 }
@@ -669,3 +714,76 @@ void ndisc_flush(Link *link) {
         link->ndisc_rdnss = set_free_free(link->ndisc_rdnss);
         link->ndisc_dnssl = set_free_free(link->ndisc_dnssl);
 }
+
+int config_parse_ndisc_black_listed_prefix(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Network *network = data;
+        const char *p;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (isempty(rvalue)) {
+                network->ndisc_black_listed_prefix = set_free_free(network->ndisc_black_listed_prefix);
+                return 0;
+        }
+
+        for (p = rvalue;;) {
+                _cleanup_free_ char *n = NULL;
+                _cleanup_free_ struct in6_addr *a = NULL;
+                union in_addr_union ip;
+
+                r = extract_first_word(&p, &n, NULL, 0);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to parse NDISC black listed prefix, ignoring assignment: %s",
+                                   rvalue);
+                        return 0;
+                }
+                if (r == 0)
+                        return 0;
+
+                r = in_addr_from_string(AF_INET6, n, &ip);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "NDISC black listed prefix is invalid, ignoring assignment: %s", n);
+                        continue;
+                }
+
+                r = set_ensure_allocated(&network->ndisc_black_listed_prefix, &in6_addr_hash_ops);
+                if (r < 0)
+                        return log_oom();
+
+                a = newdup(struct in6_addr, &ip.in6, 1);
+                if (!a)
+                        return log_oom();
+
+                r = set_put(network->ndisc_black_listed_prefix, a);
+                if (r < 0) {
+                        if (r == -EEXIST)
+                                log_syntax(unit, LOG_WARNING, filename, line, r,
+                                           "NDISC black listed prefixs is duplicated, ignoring assignment: %s", n);
+                        else
+                                log_syntax(unit, LOG_ERR, filename, line, r,
+                                           "Failed to store NDISC black listed prefix '%s', ignoring assignment: %m", n);
+                        continue;
+                }
+
+                TAKE_PTR(a);
+        }
+
+        return 0;
+}