diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 6f01dac593..9750902661 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1015,6 +1015,19 @@ + + Type= + + The Type identifier for special route types, which can be + unicast route to a destination network address which describes the path to the destination, + blackhole packets are discarded silently, + unreachable packets are discarded and the ICMP message host unreachable is generated, + prohibit packets are discarded and the ICMP message communication administratively + prohibited is generated. Defaults to unicast. + + + + diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index 586d94f624..d6c52b5b43 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -155,6 +155,35 @@ int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family) { return 0; } +int sd_rtnl_message_route_get_type(sd_netlink_message *m, unsigned char *type) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(type, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *type = rtm->rtm_type; + + return 0; +} + +int sd_rtnl_message_route_set_type(sd_netlink_message *m, unsigned char type) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + rtm->rtm_type = type; + + return 0; +} + int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) { struct rtmsg *rtm; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 82b9663019..b9cf42d72f 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -296,7 +296,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo Link *link = NULL; uint16_t type; uint32_t ifindex, priority = 0; - unsigned char protocol, scope, tos, table; + unsigned char protocol, scope, tos, table, rt_type; int family; unsigned char dst_prefixlen, src_prefixlen; union in_addr_union dst = {}, gw = {}, src = {}, prefsrc = {}; @@ -441,6 +441,12 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo return 0; } + r = sd_rtnl_message_route_get_type(message, &rt_type); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received route with invalid type, ignoring: %m"); + return 0; + } + r = sd_rtnl_message_route_get_table(message, &table); if (r < 0) { log_link_warning_errno(link, r, "rtnl: received route with invalid table, ignoring: %m"); @@ -464,7 +470,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo return 0; } - route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, protocol); + route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, rt_type, protocol); break; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 274d2a8bbe..5947f6dc15 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -100,6 +100,7 @@ Route.Table, config_parse_route_table, Route.GatewayOnlink, config_parse_gateway_onlink, 0, 0 Route.IPv6Preference, config_parse_ipv6_route_preference, 0, 0 Route.Protocol, config_parse_route_protocol, 0, 0 +Route.Type, config_parse_route_type, 0, 0 DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns) DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_use_ntp) diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index e5d61ce8cc..5b4874795a 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -70,6 +70,7 @@ int route_new(Route **ret) { route->family = AF_UNSPEC; route->scope = RT_SCOPE_UNIVERSE; route->protocol = RTPROT_UNSPEC; + route->type = RTN_UNICAST; route->table = RT_TABLE_MAIN; route->lifetime = USEC_INFINITY; @@ -372,7 +373,8 @@ int route_update(Route *route, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, - unsigned char protocol) { + unsigned char protocol, + unsigned char type) { assert(route); assert(src); @@ -385,6 +387,7 @@ int route_update(Route *route, route->prefsrc = *prefsrc; route->scope = scope; route->protocol = protocol; + route->type = type; return 0; } @@ -458,9 +461,15 @@ int route_remove(Route *route, Link *link, if (r < 0) return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m"); - r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex); + r = sd_rtnl_message_route_set_type(req, route->type); if (r < 0) - return log_error_errno(r, "Could not append RTA_OIF attribute: %m"); + return log_error_errno(r, "Could not set route type: %m"); + + if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE)) { + r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex); + if (r < 0) + return log_error_errno(r, "Could not append RTA_OIF attribute: %m"); + } r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL); if (r < 0) @@ -612,9 +621,15 @@ int route_configure( if (r < 0) return log_error_errno(r, "Could not append RTA_PREF attribute: %m"); - r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex); + r = sd_rtnl_message_route_set_type(req, route->type); if (r < 0) - return log_error_errno(r, "Could not append RTA_OIF attribute: %m"); + return log_error_errno(r, "Could not set route type: %m"); + + if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE)) { + r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex); + if (r < 0) + return log_error_errno(r, "Could not append RTA_OIF attribute: %m"); + } r = sd_netlink_message_open_container(req, RTA_METRICS); if (r < 0) @@ -1023,3 +1038,39 @@ int config_parse_route_protocol(const char *unit, return 0; } + +int config_parse_route_type(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 = userdata; + _cleanup_route_free_ Route *n = NULL; + int r; + + r = route_new_static(network, filename, section_line, &n); + if (r < 0) + return r; + + if (streq(rvalue, "unicast")) + n->type = RTN_UNICAST; + else if (streq(rvalue, "blackhole")) + n->type = RTN_BLACKHOLE; + else if (streq(rvalue, "unreachable")) + n->type = RTN_UNREACHABLE; + else if (streq(rvalue, "prohibit")) + n->type = RTN_PROHIBIT; + else { + log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route type \"%s\", ignoring assignment: %m", rvalue); + return 0; + } + + n = NULL; + + return 0; +} diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 3f389489da..89d32e9214 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -35,6 +35,7 @@ struct Route { unsigned char src_prefixlen; unsigned char scope; unsigned char protocol; /* RTPROT_* */ + unsigned char type; /* RTN_* */ unsigned char tos; uint32_t priority; /* note that ip(8) calls this 'metric' */ uint32_t table; @@ -62,7 +63,7 @@ int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback int route_get(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret); int route_add(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret); int route_add_foreign(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret); -int route_update(Route *route, const union in_addr_union *src, unsigned char src_prefixlen, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol); +int route_update(Route *route, const union in_addr_union *src, unsigned char src_prefixlen, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol, unsigned char type); int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata); @@ -78,3 +79,4 @@ int config_parse_route_table(const char *unit, const char *filename, unsigned li int config_parse_gateway_onlink(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); int config_parse_ipv6_route_preference(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); int config_parse_route_protocol(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); +int config_parse_route_type(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); diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 2289269eef..b28fc0da00 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -138,6 +138,7 @@ int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope); int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags); int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table); +int sd_rtnl_message_route_set_type(sd_netlink_message *m, unsigned char type); int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags); int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family); int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family); @@ -147,6 +148,7 @@ int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos); int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table); int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len); int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len); +int sd_rtnl_message_route_get_type(sd_netlink_message *m, unsigned char *type); int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags); int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state);