LCOV - code coverage report
Current view: top level - network - networkd-routing-policy-rule.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 171 787 21.7 %
Date: 2019-08-22 15:41:25 Functions: 7 32 21.9 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <net/if.h>
       4             : #include <linux/fib_rules.h>
       5             : 
       6             : #include "af-list.h"
       7             : #include "alloc-util.h"
       8             : #include "conf-parser.h"
       9             : #include "fileio.h"
      10             : #include "ip-protocol-list.h"
      11             : #include "networkd-routing-policy-rule.h"
      12             : #include "netlink-util.h"
      13             : #include "networkd-manager.h"
      14             : #include "networkd-util.h"
      15             : #include "parse-util.h"
      16             : #include "socket-util.h"
      17             : #include "string-util.h"
      18             : #include "strv.h"
      19             : 
      20           7 : int routing_policy_rule_new(RoutingPolicyRule **ret) {
      21             :         RoutingPolicyRule *rule;
      22             : 
      23           7 :         rule = new(RoutingPolicyRule, 1);
      24           7 :         if (!rule)
      25           0 :                 return -ENOMEM;
      26             : 
      27           7 :         *rule = (RoutingPolicyRule) {
      28             :                 .table = RT_TABLE_MAIN,
      29             :         };
      30             : 
      31           7 :         *ret = rule;
      32           7 :         return 0;
      33             : }
      34             : 
      35           7 : void routing_policy_rule_free(RoutingPolicyRule *rule) {
      36             : 
      37           7 :         if (!rule)
      38           0 :                 return;
      39             : 
      40           7 :         if (rule->network) {
      41           0 :                 LIST_REMOVE(rules, rule->network->rules, rule);
      42           0 :                 assert(rule->network->n_rules > 0);
      43           0 :                 rule->network->n_rules--;
      44             : 
      45           0 :                 if (rule->section)
      46           0 :                         hashmap_remove(rule->network->rules_by_section, rule->section);
      47             :         }
      48             : 
      49           7 :         if (rule->manager) {
      50           0 :                 if (set_get(rule->manager->rules, rule) == rule)
      51           0 :                         set_remove(rule->manager->rules, rule);
      52           0 :                 if (set_get(rule->manager->rules_foreign, rule) == rule)
      53           0 :                         set_remove(rule->manager->rules_foreign, rule);
      54             :         }
      55             : 
      56           7 :         network_config_section_free(rule->section);
      57           7 :         free(rule->iif);
      58           7 :         free(rule->oif);
      59           7 :         free(rule);
      60             : }
      61             : 
      62           0 : static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *src) {
      63           0 :         _cleanup_free_ char *iif = NULL, *oif = NULL;
      64             : 
      65           0 :         assert(dest);
      66           0 :         assert(src);
      67             : 
      68           0 :         if (src->iif) {
      69           0 :                 iif = strdup(src->iif);
      70           0 :                 if (!iif)
      71           0 :                         return -ENOMEM;
      72             :         }
      73             : 
      74           0 :         if (src->oif) {
      75           0 :                 oif = strdup(src->oif);
      76           0 :                 if (!oif)
      77           0 :                         return -ENOMEM;
      78             :         }
      79             : 
      80           0 :         dest->family = src->family;
      81           0 :         dest->from = src->from;
      82           0 :         dest->from_prefixlen = src->from_prefixlen;
      83           0 :         dest->to = src->to;
      84           0 :         dest->to_prefixlen = src->to_prefixlen;
      85           0 :         dest->invert_rule = src->invert_rule;
      86           0 :         dest->tos = src->tos;
      87           0 :         dest->fwmark = src->fwmark;
      88           0 :         dest->fwmask = src->fwmask;
      89           0 :         dest->priority = src->priority;
      90           0 :         dest->table = src->table;
      91           0 :         dest->iif = TAKE_PTR(iif);
      92           0 :         dest->oif = TAKE_PTR(oif);
      93           0 :         dest->protocol = src->protocol;
      94           0 :         dest->sport = src->sport;
      95           0 :         dest->dport = src->dport;
      96             : 
      97           0 :         return 0;
      98             : }
      99             : 
     100           7 : static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
     101           7 :         assert(rule);
     102             : 
     103           7 :         siphash24_compress(&rule->family, sizeof(rule->family), state);
     104             : 
     105           7 :         switch (rule->family) {
     106           7 :         case AF_INET:
     107             :         case AF_INET6:
     108             : 
     109           7 :                 siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
     110           7 :                 siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
     111             : 
     112           7 :                 siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
     113           7 :                 siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
     114             : 
     115           7 :                 siphash24_compress_boolean(rule->invert_rule, state);
     116             : 
     117           7 :                 siphash24_compress(&rule->tos, sizeof(rule->tos), state);
     118           7 :                 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
     119           7 :                 siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
     120           7 :                 siphash24_compress(&rule->priority, sizeof(rule->priority), state);
     121           7 :                 siphash24_compress(&rule->table, sizeof(rule->table), state);
     122             : 
     123           7 :                 siphash24_compress(&rule->protocol, sizeof(rule->protocol), state);
     124           7 :                 siphash24_compress(&rule->sport, sizeof(rule->sport), state);
     125           7 :                 siphash24_compress(&rule->dport, sizeof(rule->dport), state);
     126             : 
     127           7 :                 if (rule->iif)
     128           2 :                         siphash24_compress(rule->iif, strlen(rule->iif), state);
     129             : 
     130           7 :                 if (rule->oif)
     131           2 :                         siphash24_compress(rule->oif, strlen(rule->oif), state);
     132             : 
     133           7 :                 break;
     134           0 :         default:
     135             :                 /* treat any other address family as AF_UNSPEC */
     136           0 :                 break;
     137             :         }
     138           7 : }
     139             : 
     140           0 : static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
     141             :         int r;
     142             : 
     143           0 :         r = CMP(a->family, b->family);
     144           0 :         if (r != 0)
     145           0 :                 return r;
     146             : 
     147           0 :         switch (a->family) {
     148           0 :         case AF_INET:
     149             :         case AF_INET6:
     150           0 :                 r = CMP(a->from_prefixlen, b->from_prefixlen);
     151           0 :                 if (r != 0)
     152           0 :                         return r;
     153             : 
     154           0 :                 r = CMP(a->to_prefixlen, b->to_prefixlen);
     155           0 :                 if (r != 0)
     156           0 :                         return r;
     157             : 
     158           0 :                 r = CMP(a->invert_rule, b->invert_rule);
     159           0 :                 if (r != 0)
     160           0 :                         return r;
     161             : 
     162           0 :                 r = CMP(a->tos, b->tos);
     163           0 :                 if (r != 0)
     164           0 :                         return r;
     165             : 
     166           0 :                 r = CMP(a->fwmark, b->fwmark);
     167           0 :                 if (r != 0)
     168           0 :                         return r;
     169             : 
     170           0 :                 r = CMP(a->fwmask, b->fwmask);
     171           0 :                 if (r != 0)
     172           0 :                         return r;
     173             : 
     174           0 :                 r = CMP(a->priority, b->priority);
     175           0 :                 if (r != 0)
     176           0 :                         return r;
     177             : 
     178           0 :                 r = CMP(a->table, b->table);
     179           0 :                 if (r != 0)
     180           0 :                         return r;
     181             : 
     182           0 :                 r = strcmp_ptr(a->iif, b->iif);
     183           0 :                 if (!r)
     184           0 :                         return r;
     185             : 
     186           0 :                 r = strcmp_ptr(a->oif, b->oif);
     187           0 :                 if (!r)
     188           0 :                         return r;
     189             : 
     190           0 :                 r = CMP(a->protocol, b->protocol);
     191           0 :                 if (r != 0)
     192           0 :                         return r;
     193             : 
     194           0 :                 r = memcmp(&a->sport, &b->sport, sizeof(a->sport));
     195           0 :                 if (r != 0)
     196           0 :                         return r;
     197             : 
     198           0 :                 r = memcmp(&a->dport, &b->dport, sizeof(a->dport));
     199           0 :                 if (r != 0)
     200           0 :                         return r;
     201             : 
     202           0 :                 r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
     203           0 :                 if (r != 0)
     204           0 :                         return r;
     205             : 
     206           0 :                 return memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
     207             : 
     208           0 :         default:
     209             :                 /* treat any other address family as AF_UNSPEC */
     210           0 :                 return 0;
     211             :         }
     212             : }
     213             : 
     214             : DEFINE_PRIVATE_HASH_OPS(routing_policy_rule_hash_ops, RoutingPolicyRule, routing_policy_rule_hash_func, routing_policy_rule_compare_func);
     215             : 
     216           0 : int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
     217             : 
     218             :         RoutingPolicyRule *existing;
     219             : 
     220           0 :         assert(m);
     221             : 
     222           0 :         existing = set_get(m->rules, rule);
     223           0 :         if (existing) {
     224           0 :                 if (ret)
     225           0 :                         *ret = existing;
     226           0 :                 return 1;
     227             :         }
     228             : 
     229           0 :         existing = set_get(m->rules_foreign, rule);
     230           0 :         if (existing) {
     231           0 :                 if (ret)
     232           0 :                         *ret = existing;
     233           0 :                 return 0;
     234             :         }
     235             : 
     236           0 :         return -ENOENT;
     237             : }
     238             : 
     239           0 : int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) {
     240             :         int r;
     241             : 
     242           0 :         assert(m);
     243             : 
     244           0 :         if (set_contains(m->rules_foreign, rule)) {
     245           0 :                 set_remove(m->rules_foreign, rule);
     246             : 
     247           0 :                 r = set_ensure_allocated(&m->rules, &routing_policy_rule_hash_ops);
     248           0 :                 if (r < 0)
     249           0 :                         return r;
     250             : 
     251           0 :                 r = set_put(m->rules, rule);
     252           0 :                 if (r < 0)
     253           0 :                         return r;
     254           0 :                 if (r == 0)
     255           0 :                         routing_policy_rule_free(rule);
     256             :         }
     257             : 
     258           0 :         return -ENOENT;
     259             : }
     260             : 
     261           0 : static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPolicyRule *in, RoutingPolicyRule **ret) {
     262           0 :         _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
     263             :         int r;
     264             : 
     265           0 :         assert(m);
     266           0 :         assert(rules);
     267           0 :         assert(in);
     268             : 
     269           0 :         r = routing_policy_rule_new(&rule);
     270           0 :         if (r < 0)
     271           0 :                 return r;
     272             : 
     273           0 :         rule->manager = m;
     274             : 
     275           0 :         r = routing_policy_rule_copy(rule, in);
     276           0 :         if (r < 0)
     277           0 :                 return r;
     278             : 
     279           0 :         r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
     280           0 :         if (r < 0)
     281           0 :                 return r;
     282             : 
     283           0 :         r = set_put(*rules, rule);
     284           0 :         if (r < 0)
     285           0 :                 return r;
     286           0 :         if (r == 0)
     287           0 :                 return -EEXIST;
     288             : 
     289           0 :         if (ret)
     290           0 :                 *ret = rule;
     291             : 
     292           0 :         TAKE_PTR(rule);
     293           0 :         return 0;
     294             : }
     295             : 
     296           0 : static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
     297           0 :         return routing_policy_rule_add_internal(m, &m->rules, rule, ret);
     298             : }
     299             : 
     300           0 : int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
     301           0 :         return routing_policy_rule_add_internal(m, &m->rules_foreign, rule, ret);
     302             : }
     303             : 
     304           0 : static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
     305             :         int r;
     306             : 
     307           0 :         assert(m);
     308           0 :         assert(link);
     309           0 :         assert(link->ifname);
     310             : 
     311           0 :         link->routing_policy_rule_remove_messages--;
     312             : 
     313           0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
     314           0 :                 return 1;
     315             : 
     316           0 :         r = sd_netlink_message_get_errno(m);
     317           0 :         if (r < 0)
     318           0 :                 log_link_warning_errno(link, r, "Could not drop routing policy rule: %m");
     319             : 
     320           0 :         return 1;
     321             : }
     322             : 
     323           0 : int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback) {
     324           0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
     325             :         int r;
     326             : 
     327           0 :         assert(routing_policy_rule);
     328           0 :         assert(link);
     329           0 :         assert(link->manager);
     330           0 :         assert(link->manager->rtnl);
     331           0 :         assert(link->ifindex > 0);
     332           0 :         assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6));
     333             : 
     334           0 :         r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family);
     335           0 :         if (r < 0)
     336           0 :                 return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
     337             : 
     338           0 :         if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from) == 0) {
     339           0 :                 r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from);
     340           0 :                 if (r < 0)
     341           0 :                         return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
     342             : 
     343           0 :                 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
     344           0 :                 if (r < 0)
     345           0 :                         return log_error_errno(r, "Could not set source prefix length: %m");
     346             :         }
     347             : 
     348           0 :         if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) {
     349           0 :                 r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to);
     350           0 :                 if (r < 0)
     351           0 :                         return log_error_errno(r, "Could not append FRA_DST attribute: %m");
     352             : 
     353           0 :                 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
     354           0 :                 if (r < 0)
     355           0 :                         return log_error_errno(r, "Could not set destination prefix length: %m");
     356             :         }
     357             : 
     358           0 :         r = netlink_call_async(link->manager->rtnl, NULL, m,
     359             :                                callback ?: routing_policy_rule_remove_handler,
     360             :                                link_netlink_destroy_callback, link);
     361           0 :         if (r < 0)
     362           0 :                 return log_error_errno(r, "Could not send rtnetlink message: %m");
     363             : 
     364           0 :         link_ref(link);
     365             : 
     366           0 :         return 0;
     367             : }
     368             : 
     369           0 : static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
     370           0 :         _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
     371           0 :         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
     372             :         int r;
     373             : 
     374           0 :         assert(network);
     375           0 :         assert(ret);
     376           0 :         assert(!!filename == (section_line > 0));
     377             : 
     378           0 :         if (filename) {
     379           0 :                 r = network_config_section_new(filename, section_line, &n);
     380           0 :                 if (r < 0)
     381           0 :                         return r;
     382             : 
     383           0 :                 rule = hashmap_get(network->rules_by_section, n);
     384           0 :                 if (rule) {
     385           0 :                         *ret = TAKE_PTR(rule);
     386             : 
     387           0 :                         return 0;
     388             :                 }
     389             :         }
     390             : 
     391           0 :         r = routing_policy_rule_new(&rule);
     392           0 :         if (r < 0)
     393           0 :                 return r;
     394             : 
     395           0 :         rule->network = network;
     396           0 :         LIST_APPEND(rules, network->rules, rule);
     397           0 :         network->n_rules++;
     398             : 
     399           0 :         if (filename) {
     400           0 :                 rule->section = TAKE_PTR(n);
     401             : 
     402           0 :                 r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
     403           0 :                 if (r < 0)
     404           0 :                         return r;
     405             : 
     406           0 :                 r = hashmap_put(network->rules_by_section, rule->section, rule);
     407           0 :                 if (r < 0)
     408           0 :                         return r;
     409             :         }
     410             : 
     411           0 :         *ret = TAKE_PTR(rule);
     412             : 
     413           0 :         return 0;
     414             : }
     415             : 
     416           0 : static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
     417             :         int r;
     418             : 
     419           0 :         assert(rtnl);
     420           0 :         assert(m);
     421           0 :         assert(link);
     422           0 :         assert(link->ifname);
     423           0 :         assert(link->routing_policy_rule_messages > 0);
     424             : 
     425           0 :         link->routing_policy_rule_messages--;
     426             : 
     427           0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
     428           0 :                 return 1;
     429             : 
     430           0 :         r = sd_netlink_message_get_errno(m);
     431           0 :         if (r < 0 && r != -EEXIST) {
     432           0 :                 log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
     433           0 :                 link_enter_failed(link);
     434           0 :                 return 1;
     435             :         }
     436             : 
     437           0 :         if (link->routing_policy_rule_messages == 0) {
     438           0 :                 log_link_debug(link, "Routing policy rule configured");
     439           0 :                 link->routing_policy_rules_configured = true;
     440           0 :                 link_check_ready(link);
     441             :         }
     442             : 
     443           0 :         return 1;
     444             : }
     445             : 
     446           0 : int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback) {
     447           0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
     448             :         int r;
     449             : 
     450           0 :         assert(rule);
     451           0 :         assert(link);
     452           0 :         assert(link->ifindex > 0);
     453           0 :         assert(link->manager);
     454           0 :         assert(link->manager->rtnl);
     455             : 
     456           0 :         if (rule->family == AF_INET6 && link_sysctl_ipv6_enabled(link) == 0) {
     457           0 :                 log_link_warning(link, "An IPv6 routing policy rule is requested, but IPv6 is disabled by sysctl, ignoring.");
     458           0 :                 return 0;
     459             :         }
     460             : 
     461           0 :         r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
     462           0 :         if (r < 0)
     463           0 :                 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
     464             : 
     465           0 :         if (in_addr_is_null(rule->family, &rule->from) == 0) {
     466           0 :                 r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
     467           0 :                 if (r < 0)
     468           0 :                         return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
     469             : 
     470           0 :                 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
     471           0 :                 if (r < 0)
     472           0 :                         return log_error_errno(r, "Could not set source prefix length: %m");
     473             :         }
     474             : 
     475           0 :         if (in_addr_is_null(rule->family, &rule->to) == 0) {
     476           0 :                 r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
     477           0 :                 if (r < 0)
     478           0 :                         return log_error_errno(r, "Could not append FRA_DST attribute: %m");
     479             : 
     480           0 :                 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
     481           0 :                 if (r < 0)
     482           0 :                         return log_error_errno(r, "Could not set destination prefix length: %m");
     483             :         }
     484             : 
     485           0 :         r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
     486           0 :         if (r < 0)
     487           0 :                 return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
     488             : 
     489           0 :         if (rule->tos > 0) {
     490           0 :                 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
     491           0 :                 if (r < 0)
     492           0 :                         return log_error_errno(r, "Could not set ip rule tos: %m");
     493             :         }
     494             : 
     495           0 :         if (rule->table < 256) {
     496           0 :                 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
     497           0 :                 if (r < 0)
     498           0 :                         return log_error_errno(r, "Could not set ip rule table: %m");
     499             :         } else {
     500           0 :                 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
     501           0 :                 if (r < 0)
     502           0 :                         return log_error_errno(r, "Could not set ip rule table: %m");
     503             : 
     504           0 :                 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
     505           0 :                 if (r < 0)
     506           0 :                         return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
     507             :         }
     508             : 
     509           0 :         if (rule->fwmark > 0) {
     510           0 :                 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
     511           0 :                 if (r < 0)
     512           0 :                         return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
     513             :         }
     514             : 
     515           0 :         if (rule->fwmask > 0) {
     516           0 :                 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
     517           0 :                 if (r < 0)
     518           0 :                         return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
     519             :         }
     520             : 
     521           0 :         if (rule->iif) {
     522           0 :                 r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
     523           0 :                 if (r < 0)
     524           0 :                         return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m");
     525             :         }
     526             : 
     527           0 :         if (rule->oif) {
     528           0 :                 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
     529           0 :                 if (r < 0)
     530           0 :                         return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m");
     531             :         }
     532             : 
     533           0 :         r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
     534           0 :         if (r < 0)
     535           0 :                 return log_error_errno(r, "Could not append FRA_IP_PROTO attribute: %m");
     536             : 
     537           0 :         if (rule->sport.start != 0 || rule->sport.end != 0) {
     538           0 :                 r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
     539           0 :                 if (r < 0)
     540           0 :                         return log_error_errno(r, "Could not append FRA_SPORT_RANGE attribute: %m");
     541             :         }
     542             : 
     543           0 :         if (rule->dport.start != 0 || rule->dport.end != 0) {
     544           0 :                 r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
     545           0 :                 if (r < 0)
     546           0 :                         return log_error_errno(r, "Could not append FRA_DPORT_RANGE attribute: %m");
     547             :         }
     548             : 
     549           0 :         if (rule->invert_rule) {
     550           0 :                 r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
     551           0 :                 if (r < 0)
     552           0 :                         return log_error_errno(r, "Could not append FIB_RULE_INVERT attribute: %m");
     553             :         }
     554             : 
     555           0 :         rule->link = link;
     556             : 
     557           0 :         r = netlink_call_async(link->manager->rtnl, NULL, m,
     558             :                                callback ?: routing_policy_rule_handler,
     559             :                                link_netlink_destroy_callback, link);
     560           0 :         if (r < 0)
     561           0 :                 return log_error_errno(r, "Could not send rtnetlink message: %m");
     562             : 
     563           0 :         link_ref(link);
     564             : 
     565           0 :         r = routing_policy_rule_add(link->manager, rule, NULL);
     566           0 :         if (r < 0)
     567           0 :                 return log_error_errno(r, "Could not add rule: %m");
     568             : 
     569           0 :         return 1;
     570             : }
     571             : 
     572           0 : int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
     573             :         int r;
     574             : 
     575           0 :         if (section_is_invalid(rule->section))
     576           0 :                 return -EINVAL;
     577             : 
     578           0 :         if ((rule->family == AF_INET && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) ||
     579           0 :             (rule->family == AF_INET6 && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)))
     580           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     581             :                                 "%s: address family specified by Family= conflicts with the address "
     582             :                                 "specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.",
     583             :                                 rule->section->filename, rule->section->line);
     584             : 
     585           0 :         if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6)) {
     586           0 :                 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule6 = NULL;
     587             : 
     588           0 :                 assert(rule->family == AF_UNSPEC);
     589             : 
     590             :                 /* When Family=both, we need to copy the section, AF_INET and AF_INET6. */
     591             : 
     592           0 :                 r = routing_policy_rule_new_static(rule->network, NULL, 0, &rule6);
     593           0 :                 if (r < 0)
     594           0 :                         return r;
     595             : 
     596           0 :                 r = routing_policy_rule_copy(rule6, rule);
     597           0 :                 if (r < 0)
     598           0 :                         return r;
     599             : 
     600           0 :                 rule->family = AF_INET;
     601           0 :                 rule6->family = AF_INET6;
     602             : 
     603           0 :                 TAKE_PTR(rule6);
     604             :         }
     605             : 
     606           0 :         if (rule->family == AF_UNSPEC) {
     607           0 :                 if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6))
     608           0 :                         rule->family = AF_INET6;
     609             :                 else
     610           0 :                         rule->family = AF_INET;
     611             :         }
     612             : 
     613           0 :         return 0;
     614             : }
     615             : 
     616           3 : static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
     617           3 :         _cleanup_free_ char *f = NULL;
     618             :         char *p;
     619             :         int r;
     620             : 
     621           3 :         assert(s);
     622             : 
     623           3 :         f = strdup(s);
     624           3 :         if (!f)
     625           0 :                 return -ENOMEM;
     626             : 
     627           3 :         p = strchr(f, '/');
     628           3 :         if (p)
     629           1 :                 *p++ = '\0';
     630             : 
     631           3 :         r = safe_atou32(f, fwmark);
     632           3 :         if (r < 0)
     633           0 :                 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
     634             : 
     635           3 :         if (p) {
     636           1 :                 r = safe_atou32(p, fwmask);
     637           1 :                 if (r < 0)
     638           0 :                         return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
     639             :         }
     640             : 
     641           3 :         return 0;
     642             : }
     643             : 
     644           0 : int config_parse_routing_policy_rule_tos(
     645             :                 const char *unit,
     646             :                 const char *filename,
     647             :                 unsigned line,
     648             :                 const char *section,
     649             :                 unsigned section_line,
     650             :                 const char *lvalue,
     651             :                 int ltype,
     652             :                 const char *rvalue,
     653             :                 void *data,
     654             :                 void *userdata) {
     655             : 
     656           0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     657           0 :         Network *network = userdata;
     658             :         int r;
     659             : 
     660           0 :         assert(filename);
     661           0 :         assert(section);
     662           0 :         assert(lvalue);
     663           0 :         assert(rvalue);
     664           0 :         assert(data);
     665             : 
     666           0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     667           0 :         if (r < 0)
     668           0 :                 return r;
     669             : 
     670           0 :         r = safe_atou8(rvalue, &n->tos);
     671           0 :         if (r < 0) {
     672           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
     673           0 :                 return 0;
     674             :         }
     675             : 
     676           0 :         n = NULL;
     677             : 
     678           0 :         return 0;
     679             : }
     680             : 
     681           0 : int config_parse_routing_policy_rule_priority(
     682             :                 const char *unit,
     683             :                 const char *filename,
     684             :                 unsigned line,
     685             :                 const char *section,
     686             :                 unsigned section_line,
     687             :                 const char *lvalue,
     688             :                 int ltype,
     689             :                 const char *rvalue,
     690             :                 void *data,
     691             :                 void *userdata) {
     692             : 
     693           0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     694           0 :         Network *network = userdata;
     695             :         int r;
     696             : 
     697           0 :         assert(filename);
     698           0 :         assert(section);
     699           0 :         assert(lvalue);
     700           0 :         assert(rvalue);
     701           0 :         assert(data);
     702             : 
     703           0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     704           0 :         if (r < 0)
     705           0 :                 return r;
     706             : 
     707           0 :         r = safe_atou32(rvalue, &n->priority);
     708           0 :         if (r < 0) {
     709           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
     710           0 :                 return 0;
     711             :         }
     712             : 
     713           0 :         n = NULL;
     714             : 
     715           0 :         return 0;
     716             : }
     717             : 
     718           0 : int config_parse_routing_policy_rule_table(
     719             :                 const char *unit,
     720             :                 const char *filename,
     721             :                 unsigned line,
     722             :                 const char *section,
     723             :                 unsigned section_line,
     724             :                 const char *lvalue,
     725             :                 int ltype,
     726             :                 const char *rvalue,
     727             :                 void *data,
     728             :                 void *userdata) {
     729             : 
     730           0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     731           0 :         Network *network = userdata;
     732             :         int r;
     733             : 
     734           0 :         assert(filename);
     735           0 :         assert(section);
     736           0 :         assert(lvalue);
     737           0 :         assert(rvalue);
     738           0 :         assert(data);
     739             : 
     740           0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     741           0 :         if (r < 0)
     742           0 :                 return r;
     743             : 
     744           0 :         r = safe_atou32(rvalue, &n->table);
     745           0 :         if (r < 0) {
     746           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
     747           0 :                 return 0;
     748             :         }
     749             : 
     750           0 :         n = NULL;
     751             : 
     752           0 :         return 0;
     753             : }
     754             : 
     755           0 : int config_parse_routing_policy_rule_fwmark_mask(
     756             :                 const char *unit,
     757             :                 const char *filename,
     758             :                 unsigned line,
     759             :                 const char *section,
     760             :                 unsigned section_line,
     761             :                 const char *lvalue,
     762             :                 int ltype,
     763             :                 const char *rvalue,
     764             :                 void *data,
     765             :                 void *userdata) {
     766             : 
     767           0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     768           0 :         Network *network = userdata;
     769             :         int r;
     770             : 
     771           0 :         assert(filename);
     772           0 :         assert(section);
     773           0 :         assert(lvalue);
     774           0 :         assert(rvalue);
     775           0 :         assert(data);
     776             : 
     777           0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     778           0 :         if (r < 0)
     779           0 :                 return r;
     780             : 
     781           0 :         r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
     782           0 :         if (r < 0) {
     783           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
     784           0 :                 return 0;
     785             :         }
     786             : 
     787           0 :         n = NULL;
     788             : 
     789           0 :         return 0;
     790             : }
     791             : 
     792           0 : int config_parse_routing_policy_rule_prefix(
     793             :                 const char *unit,
     794             :                 const char *filename,
     795             :                 unsigned line,
     796             :                 const char *section,
     797             :                 unsigned section_line,
     798             :                 const char *lvalue,
     799             :                 int ltype,
     800             :                 const char *rvalue,
     801             :                 void *data,
     802             :                 void *userdata) {
     803             : 
     804           0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     805           0 :         Network *network = userdata;
     806             :         union in_addr_union *buffer;
     807             :         uint8_t *prefixlen;
     808             :         int r;
     809             : 
     810           0 :         assert(filename);
     811           0 :         assert(section);
     812           0 :         assert(lvalue);
     813           0 :         assert(rvalue);
     814           0 :         assert(data);
     815             : 
     816           0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     817           0 :         if (r < 0)
     818           0 :                 return r;
     819             : 
     820           0 :         if (streq(lvalue, "To")) {
     821           0 :                 buffer = &n->to;
     822           0 :                 prefixlen = &n->to_prefixlen;
     823             :         } else {
     824           0 :                 buffer = &n->from;
     825           0 :                 prefixlen = &n->from_prefixlen;
     826             :         }
     827             : 
     828           0 :         if (n->family == AF_UNSPEC)
     829           0 :                 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
     830             :         else
     831           0 :                 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
     832           0 :         if (r < 0) {
     833           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
     834           0 :                 return 0;
     835             :         }
     836             : 
     837           0 :         n = NULL;
     838             : 
     839           0 :         return 0;
     840             : }
     841             : 
     842           0 : int config_parse_routing_policy_rule_device(
     843             :                 const char *unit,
     844             :                 const char *filename,
     845             :                 unsigned line,
     846             :                 const char *section,
     847             :                 unsigned section_line,
     848             :                 const char *lvalue,
     849             :                 int ltype,
     850             :                 const char *rvalue,
     851             :                 void *data,
     852             :                 void *userdata) {
     853             : 
     854           0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     855           0 :         Network *network = userdata;
     856             :         int r;
     857             : 
     858           0 :         assert(filename);
     859           0 :         assert(section);
     860           0 :         assert(lvalue);
     861           0 :         assert(rvalue);
     862           0 :         assert(data);
     863             : 
     864           0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     865           0 :         if (r < 0)
     866           0 :                 return r;
     867             : 
     868           0 :         if (!ifname_valid(rvalue)) {
     869           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
     870           0 :                 return 0;
     871             :         }
     872             : 
     873           0 :         if (streq(lvalue, "IncomingInterface")) {
     874           0 :                 r = free_and_strdup(&n->iif, rvalue);
     875           0 :                 if (r < 0)
     876           0 :                         return log_oom();
     877             :         } else {
     878           0 :                 r = free_and_strdup(&n->oif, rvalue);
     879           0 :                 if (r < 0)
     880           0 :                         return log_oom();
     881             :         }
     882             : 
     883           0 :         n = NULL;
     884             : 
     885           0 :         return 0;
     886             : }
     887             : 
     888           0 : int config_parse_routing_policy_rule_port_range(
     889             :                 const char *unit,
     890             :                 const char *filename,
     891             :                 unsigned line,
     892             :                 const char *section,
     893             :                 unsigned section_line,
     894             :                 const char *lvalue,
     895             :                 int ltype,
     896             :                 const char *rvalue,
     897             :                 void *data,
     898             :                 void *userdata) {
     899           0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     900           0 :         Network *network = userdata;
     901             :         uint16_t low, high;
     902             :         int r;
     903             : 
     904           0 :         assert(filename);
     905           0 :         assert(section);
     906           0 :         assert(lvalue);
     907           0 :         assert(rvalue);
     908           0 :         assert(data);
     909             : 
     910           0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     911           0 :         if (r < 0)
     912           0 :                 return r;
     913             : 
     914           0 :         r = parse_ip_port_range(rvalue, &low, &high);
     915           0 :         if (r < 0) {
     916           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
     917           0 :                 return 0;
     918             :         }
     919             : 
     920           0 :         if (streq(lvalue, "SourcePort")) {
     921           0 :                 n->sport.start = low;
     922           0 :                 n->sport.end = high;
     923             :         } else {
     924           0 :                 n->dport.start = low;
     925           0 :                 n->dport.end = high;
     926             :         }
     927             : 
     928           0 :         n = NULL;
     929             : 
     930           0 :         return 0;
     931             : }
     932             : 
     933           0 : int config_parse_routing_policy_rule_ip_protocol(
     934             :                 const char *unit,
     935             :                 const char *filename,
     936             :                 unsigned line,
     937             :                 const char *section,
     938             :                 unsigned section_line,
     939             :                 const char *lvalue,
     940             :                 int ltype,
     941             :                 const char *rvalue,
     942             :                 void *data,
     943             :                 void *userdata) {
     944             : 
     945           0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     946           0 :         Network *network = userdata;
     947             :         int r;
     948             : 
     949           0 :         assert(filename);
     950           0 :         assert(section);
     951           0 :         assert(lvalue);
     952           0 :         assert(rvalue);
     953           0 :         assert(data);
     954             : 
     955           0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     956           0 :         if (r < 0)
     957           0 :                 return r;
     958             : 
     959           0 :         r = parse_ip_protocol(rvalue);
     960           0 :         if (r < 0) {
     961           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
     962           0 :                 return 0;
     963             :         }
     964             : 
     965           0 :         n->protocol = r;
     966             : 
     967           0 :         n = NULL;
     968             : 
     969           0 :         return 0;
     970             : }
     971             : 
     972           0 : int config_parse_routing_policy_rule_invert(
     973             :                 const char *unit,
     974             :                 const char *filename,
     975             :                 unsigned line,
     976             :                 const char *section,
     977             :                 unsigned section_line,
     978             :                 const char *lvalue,
     979             :                 int ltype,
     980             :                 const char *rvalue,
     981             :                 void *data,
     982             :                 void *userdata) {
     983             : 
     984           0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     985           0 :         Network *network = userdata;
     986             :         int r;
     987             : 
     988           0 :         assert(filename);
     989           0 :         assert(section);
     990           0 :         assert(lvalue);
     991           0 :         assert(rvalue);
     992           0 :         assert(data);
     993             : 
     994           0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     995           0 :         if (r < 0)
     996           0 :                 return r;
     997             : 
     998           0 :         r = parse_boolean(rvalue);
     999           0 :         if (r < 0) {
    1000           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
    1001           0 :                 return 0;
    1002             :         }
    1003             : 
    1004           0 :         n->invert_rule = r;
    1005             : 
    1006           0 :         n = NULL;
    1007             : 
    1008           0 :         return 0;
    1009             : }
    1010             : 
    1011           0 : int config_parse_routing_policy_rule_family(
    1012             :                 const char *unit,
    1013             :                 const char *filename,
    1014             :                 unsigned line,
    1015             :                 const char *section,
    1016             :                 unsigned section_line,
    1017             :                 const char *lvalue,
    1018             :                 int ltype,
    1019             :                 const char *rvalue,
    1020             :                 void *data,
    1021             :                 void *userdata) {
    1022             : 
    1023           0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
    1024           0 :         Network *network = userdata;
    1025             :         AddressFamily a;
    1026             :         int r;
    1027             : 
    1028           0 :         assert(filename);
    1029           0 :         assert(section);
    1030           0 :         assert(lvalue);
    1031           0 :         assert(rvalue);
    1032           0 :         assert(data);
    1033             : 
    1034           0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
    1035           0 :         if (r < 0)
    1036           0 :                 return r;
    1037             : 
    1038           0 :         a = routing_policy_rule_address_family_from_string(rvalue);
    1039           0 :         if (a < 0) {
    1040           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0,
    1041             :                            "Invalid address family '%s', ignoring.", rvalue);
    1042           0 :                 return 0;
    1043             :         }
    1044             : 
    1045           0 :         n->address_family = a;
    1046           0 :         n = NULL;
    1047             : 
    1048           0 :         return 0;
    1049             : }
    1050             : 
    1051           8 : static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
    1052           8 :         _cleanup_free_ char *s = NULL;
    1053             :         size_t size;
    1054             :         int r;
    1055             : 
    1056           8 :         assert(state_file);
    1057             : 
    1058           8 :         r = read_full_file(state_file, &s, &size);
    1059           8 :         if (r == -ENOENT)
    1060           1 :                 return -ENODATA;
    1061           7 :         if (r < 0)
    1062           0 :                 return r;
    1063           7 :         if (size <= 0)
    1064           0 :                 return -ENODATA;
    1065             : 
    1066           7 :         *ret = TAKE_PTR(s);
    1067             : 
    1068           7 :         return size;
    1069             : }
    1070             : 
    1071           7 : int routing_policy_serialize_rules(Set *rules, FILE *f) {
    1072           7 :         RoutingPolicyRule *rule = NULL;
    1073             :         Iterator i;
    1074             :         int r;
    1075             : 
    1076           7 :         assert(f);
    1077             : 
    1078          14 :         SET_FOREACH(rule, rules, i) {
    1079           7 :                 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
    1080           7 :                 bool space = false;
    1081             :                 const char *family_str;
    1082             : 
    1083           7 :                 fputs("RULE=", f);
    1084             : 
    1085           7 :                 if (!in_addr_is_null(rule->family, &rule->from)) {
    1086           7 :                         r = in_addr_to_string(rule->family, &rule->from, &from_str);
    1087           7 :                         if (r < 0)
    1088           0 :                                 return r;
    1089             : 
    1090           7 :                         fprintf(f, "from=%s/%hhu",
    1091           7 :                                 from_str, rule->from_prefixlen);
    1092           7 :                         space = true;
    1093             :                 }
    1094             : 
    1095           7 :                 if (!in_addr_is_null(rule->family, &rule->to)) {
    1096           7 :                         r = in_addr_to_string(rule->family, &rule->to, &to_str);
    1097           7 :                         if (r < 0)
    1098           0 :                                 return r;
    1099             : 
    1100           7 :                         fprintf(f, "%sto=%s/%hhu",
    1101             :                                 space ? " " : "",
    1102           7 :                                 to_str, rule->to_prefixlen);
    1103           7 :                         space = true;
    1104             :                 }
    1105             : 
    1106           7 :                 family_str = af_to_name(rule->family);
    1107           7 :                 if (family_str)
    1108           7 :                 fprintf(f, "%sfamily=%s",
    1109             :                         space ? " " : "",
    1110             :                         family_str);
    1111             : 
    1112           7 :                 if (rule->tos != 0) {
    1113           2 :                         fprintf(f, "%stos=%hhu",
    1114             :                                 space ? " " : "",
    1115           2 :                                 rule->tos);
    1116           2 :                         space = true;
    1117             :                 }
    1118             : 
    1119           7 :                 fprintf(f, "%spriority=%"PRIu32,
    1120             :                         space ? " " : "",
    1121           7 :                         rule->priority);
    1122             : 
    1123           7 :                 if (rule->fwmark != 0) {
    1124           2 :                         fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
    1125             :                                 space ? " " : "",
    1126           2 :                                 rule->fwmark, rule->fwmask);
    1127           2 :                         space = true;
    1128             :                 }
    1129             : 
    1130           7 :                 if (rule->iif) {
    1131           2 :                         fprintf(f, "%siif=%s",
    1132             :                                 space ? " " : "",
    1133           2 :                                 rule->iif);
    1134           2 :                         space = true;
    1135             :                 }
    1136             : 
    1137           7 :                 if (rule->oif) {
    1138           2 :                         fprintf(f, "%soif=%s",
    1139             :                                 space ? " " : "",
    1140           2 :                                 rule->oif);
    1141           2 :                         space = true;
    1142             :                 }
    1143             : 
    1144           7 :                 if (rule->protocol != 0) {
    1145           0 :                         fprintf(f, "%sprotocol=%hhu",
    1146             :                                 space ? " " : "",
    1147           0 :                                 rule->protocol);
    1148           0 :                         space = true;
    1149             :                 }
    1150             : 
    1151           7 :                 if (rule->sport.start != 0 || rule->sport.end != 0) {
    1152           0 :                         fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16,
    1153             :                                 space ? " " : "",
    1154           0 :                                 rule->sport.start, rule->sport.end);
    1155           0 :                         space = true;
    1156             :                 }
    1157             : 
    1158           7 :                 if (rule->dport.start != 0 || rule->dport.end != 0) {
    1159           0 :                         fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16,
    1160             :                                 space ? " " : "",
    1161           0 :                                 rule->dport.start, rule->dport.end);
    1162           0 :                         space = true;
    1163             :                 }
    1164             : 
    1165           7 :                 fprintf(f, "%stable=%"PRIu32 "\n",
    1166             :                         space ? " " : "",
    1167           7 :                         rule->table);
    1168             :         }
    1169             : 
    1170           7 :         return 0;
    1171             : }
    1172             : 
    1173           8 : int routing_policy_load_rules(const char *state_file, Set **rules) {
    1174           8 :         _cleanup_strv_free_ char **l = NULL;
    1175           8 :         _cleanup_free_ char *data = NULL;
    1176           8 :         uint16_t low = 0, high = 0;
    1177             :         const char *p;
    1178             :         char **i;
    1179             :         int r;
    1180             : 
    1181           8 :         assert(state_file);
    1182           8 :         assert(rules);
    1183             : 
    1184           8 :         r = routing_policy_rule_read_full_file(state_file, &data);
    1185           8 :         if (r <= 0)
    1186           1 :                 return r;
    1187             : 
    1188           7 :         l = strv_split_newlines(data);
    1189           7 :         if (!l)
    1190           0 :                 return -ENOMEM;
    1191             : 
    1192           7 :         r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
    1193           7 :         if (r < 0)
    1194           0 :                 return r;
    1195             : 
    1196          14 :         STRV_FOREACH(i, l) {
    1197           7 :                 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
    1198             : 
    1199           7 :                 p = startswith(*i, "RULE=");
    1200           7 :                 if (!p)
    1201           0 :                         continue;
    1202             : 
    1203           7 :                 r = routing_policy_rule_new(&rule);
    1204           7 :                 if (r < 0)
    1205           0 :                         return r;
    1206             : 
    1207          42 :                 for (;;) {
    1208          63 :                         _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
    1209             : 
    1210          49 :                         r = extract_first_word(&p, &word, NULL, 0);
    1211          49 :                         if (r < 0)
    1212           0 :                                 return r;
    1213          49 :                         if (r == 0)
    1214           7 :                                 break;
    1215             : 
    1216          42 :                         r = split_pair(word, "=", &a, &b);
    1217          42 :                         if (r < 0)
    1218           0 :                                 continue;
    1219             : 
    1220          42 :                         if (STR_IN_SET(a, "from", "to")) {
    1221             :                                 union in_addr_union *buffer;
    1222             :                                 uint8_t *prefixlen;
    1223             : 
    1224          16 :                                 if (streq(a, "to")) {
    1225           8 :                                         buffer = &rule->to;
    1226           8 :                                         prefixlen = &rule->to_prefixlen;
    1227             :                                 } else {
    1228           8 :                                         buffer = &rule->from;
    1229           8 :                                         prefixlen = &rule->from_prefixlen;
    1230             :                                 }
    1231             : 
    1232          16 :                                 r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
    1233          16 :                                 if (r < 0) {
    1234           0 :                                         log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
    1235           0 :                                         continue;
    1236             :                                 }
    1237             : 
    1238          26 :                         } else if (streq(a, "family")) {
    1239           4 :                                 r = af_from_name(b);
    1240           4 :                                 if (r < 0) {
    1241           0 :                                         log_error_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b);
    1242           0 :                                         continue;
    1243             :                                 }
    1244           4 :                                 rule->family = r;
    1245          22 :                         } else if (streq(a, "tos")) {
    1246           2 :                                 r = safe_atou8(b, &rule->tos);
    1247           2 :                                 if (r < 0) {
    1248           0 :                                         log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
    1249           0 :                                         continue;
    1250             :                                 }
    1251          20 :                         } else if (streq(a, "table")) {
    1252           7 :                                 r = safe_atou32(b, &rule->table);
    1253           7 :                                 if (r < 0) {
    1254           0 :                                         log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
    1255           0 :                                         continue;
    1256             :                                 }
    1257          13 :                         } else if (streq(a, "priority")) {
    1258           3 :                                 r = safe_atou32(b, &rule->priority);
    1259           3 :                                 if (r < 0) {
    1260           0 :                                         log_error_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b);
    1261           0 :                                         continue;
    1262             :                                 }
    1263          10 :                         } else if (streq(a, "fwmark")) {
    1264             : 
    1265           3 :                                 r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
    1266           3 :                                 if (r < 0) {
    1267           0 :                                         log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
    1268           0 :                                         continue;
    1269             :                                 }
    1270           7 :                         } else if (streq(a, "iif")) {
    1271             : 
    1272           3 :                                 if (free_and_strdup(&rule->iif, b) < 0)
    1273           0 :                                         return log_oom();
    1274             : 
    1275           4 :                         } else if (streq(a, "oif")) {
    1276             : 
    1277           3 :                                 if (free_and_strdup(&rule->oif, b) < 0)
    1278           0 :                                         return log_oom();
    1279           1 :                         } else if (streq(a, "protocol")) {
    1280           0 :                                 r = safe_atou8(b, &rule->protocol);
    1281           0 :                                 if (r < 0) {
    1282           0 :                                         log_error_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
    1283           0 :                                         continue;
    1284             :                                 }
    1285           1 :                         } else if (streq(a, "sourceport")) {
    1286             : 
    1287           0 :                                 r = parse_ip_port_range(b, &low, &high);
    1288           0 :                                 if (r < 0) {
    1289           0 :                                         log_error_errno(r, "Invalid routing policy rule source port range, ignoring assignment:'%s'", b);
    1290           0 :                                         continue;
    1291             :                                 }
    1292             : 
    1293           0 :                                 rule->sport.start = low;
    1294           0 :                                 rule->sport.end = high;
    1295             : 
    1296           1 :                         } else if (streq(a, "destinationport")) {
    1297             : 
    1298           0 :                                 r = parse_ip_port_range(b, &low, &high);
    1299           0 :                                 if (r < 0) {
    1300           0 :                                         log_error_errno(r, "Invalid routing policy rule destination port range, ignoring assignment:'%s'", b);
    1301           0 :                                         continue;
    1302             :                                 }
    1303             : 
    1304           0 :                                 rule->dport.start = low;
    1305           0 :                                 rule->dport.end = high;
    1306             :                         }
    1307             :                 }
    1308             : 
    1309           7 :                 r = set_put(*rules, rule);
    1310           7 :                 if (r < 0) {
    1311           0 :                         log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
    1312           0 :                         continue;
    1313             :                 }
    1314           7 :                 if (r > 0)
    1315           7 :                         rule = NULL;
    1316             :         }
    1317             : 
    1318           7 :         return 0;
    1319             : }
    1320             : 
    1321           0 : static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
    1322             :         RoutingPolicyRule *link_rule;
    1323             :         Iterator i;
    1324             :         Link *link;
    1325             : 
    1326           0 :         assert(m);
    1327           0 :         assert(rule);
    1328             : 
    1329           0 :         HASHMAP_FOREACH(link, m->links, i) {
    1330           0 :                 if (!link->network)
    1331           0 :                         continue;
    1332             : 
    1333           0 :                 LIST_FOREACH(rules, link_rule, link->network->rules)
    1334           0 :                         if (routing_policy_rule_compare_func(link_rule, rule) == 0)
    1335           0 :                                 return true;
    1336             :         }
    1337             : 
    1338           0 :         return false;
    1339             : }
    1340             : 
    1341           0 : void routing_policy_rule_purge(Manager *m, Link *link) {
    1342             :         RoutingPolicyRule *rule, *existing;
    1343             :         Iterator i;
    1344             :         int r;
    1345             : 
    1346           0 :         assert(m);
    1347           0 :         assert(link);
    1348             : 
    1349           0 :         SET_FOREACH(rule, m->rules_saved, i) {
    1350           0 :                 existing = set_get(m->rules_foreign, rule);
    1351           0 :                 if (!existing)
    1352           0 :                         continue; /* Saved rule does not exist anymore. */
    1353             : 
    1354           0 :                 if (manager_links_have_routing_policy_rule(m, existing))
    1355           0 :                         continue; /* Existing links have the saved rule. */
    1356             : 
    1357             :                 /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
    1358             :                  * later when it is requested. */
    1359             : 
    1360           0 :                 r = routing_policy_rule_remove(existing, link, NULL);
    1361           0 :                 if (r < 0) {
    1362           0 :                         log_warning_errno(r, "Could not remove routing policy rules: %m");
    1363           0 :                         continue;
    1364             :                 }
    1365             : 
    1366           0 :                 link->routing_policy_rule_remove_messages++;
    1367             : 
    1368           0 :                 assert_se(set_remove(m->rules_foreign, existing) == existing);
    1369           0 :                 routing_policy_rule_free(existing);
    1370             :         }
    1371           0 : }

Generated by: LCOV version 1.14