+int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
+ uint8_t tos = 0, to_prefixlen = 0, from_prefixlen = 0;
+ RoutingPolicyRule *rule = NULL;
+ union in_addr_union to, from;
+ uint32_t fwmark = 0, table = 0;
+ Manager *m = userdata;
+ uint16_t type;
+ int family;
+ int r;
+
+ assert(rtnl);
+ assert(message);
+ assert(m);
+
+ if (sd_netlink_message_is_error(message)) {
+ r = sd_netlink_message_get_errno(message);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to receive rule: %m");
+
+ return 0;
+ }
+
+ r = sd_netlink_message_get_type(message, &type);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get message type: %m");
+ return 0;
+ } else if (!IN_SET(type, RTM_NEWRULE, RTM_DELRULE)) {
+ log_warning("rtnl: received unexpected message type '%u' when processing rule.", type);
+ return 0;
+ }
+
+ r = sd_rtnl_message_get_family(message, &family);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get rule family: %m");
+ return 0;
+ } else if (!IN_SET(family, AF_INET, AF_INET6)) {
+ log_debug("rtnl: received address with invalid family %u, ignoring.", family);
+ return 0;
+ }
+
+ switch (family) {
+ case AF_INET:
+ r = sd_netlink_message_read_in_addr(message, FRA_SRC, &from.in);
+ if (r >= 0) {
+ r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to retrive rule from prefix length: %m");
+ }
+
+ r = sd_netlink_message_read_in_addr(message, FRA_DST, &to.in);
+ if (r >= 0) {
+ r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to retrive rule to prefix length: %m");
+ }
+
+ break;
+
+ case AF_INET6:
+ r = sd_netlink_message_read_in6_addr(message, FRA_SRC, &from.in6);
+ if (r >= 0) {
+ r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to retrive rule from prefix length: %m");
+ }
+
+ r = sd_netlink_message_read_in6_addr(message, FRA_DST, &to.in6);
+ if (r >= 0) {
+ r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to retrive rule to prefix length: %m");
+ }
+
+ break;
+
+ default:
+ assert_not_reached("Received unsupported address family");
+ }
+
+ if (from_prefixlen == 0 && to_prefixlen == 0)
+ return 0;
+
+ (void) sd_netlink_message_read_u32(message, FRA_FWMARK, &fwmark);
+ (void) sd_netlink_message_read_u32(message, FRA_TABLE, &table);
+ (void) sd_rtnl_message_routing_policy_rule_get_tos(message, &tos);
+
+ (void) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, &rule);
+
+ switch (type) {
+ case RTM_NEWRULE:
+ if(!rule) {
+ r = routing_policy_rule_add_foreign(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, &rule);
+ if (r < 0) {
+ log_warning_errno(r, "Could not add rule: %m");
+ return 0;
+ }
+ }
+ break;
+ case RTM_DELRULE:
+ routing_policy_rule_free(rule);
+
+ break;
+
+ default:
+ assert_not_reached("Received invalid RTNL message type");
+ }
+
+ return 1;
+}
+