diff options
author | Alexander V. Chernikov <melifaro@FreeBSD.org> | 2021-02-08 23:29:05 +0000 |
---|---|---|
committer | Alexander V. Chernikov <melifaro@FreeBSD.org> | 2021-03-28 20:40:48 +0000 |
commit | 367fcd5bce34bcd9aff540443a0d2e7fa5dbe90a (patch) | |
tree | 248d76eff61c4aafa466dd4fa709267e2ef841a9 | |
parent | d6616e3dbaeeb0cf336dda3eec1c5fa7faf8a5c5 (diff) | |
download | src-367fcd5bce34bcd9aff540443a0d2e7fa5dbe90a.tar.gz src-367fcd5bce34bcd9aff540443a0d2e7fa5dbe90a.zip |
Fix blackhole/reject routes.
Traditionally *BSD routing stack required to supply some
interface data for blackhole/reject routes. This lead to
varieties of hacks in routing daemons when inserting such routes.
With the recent routeing stack changes, gateway sockaddr without
RTF_GATEWAY started to be treated differently, purely as link
identifier.
This change broke net/bird, which installs blackhole routes with
127.0.0.1 gateway without RTF_GATEWAY flags.
Fix this by automatically constructing necessary gateway data at
rtsock level if RTF_REJECT/RTF_BLACKHOLE is set.
Reported by: Marek Zarychta <zarychtam at plan-b.pwste.edu.pl>
Reviewed by: donner
Approved by: re (gjb)
(cherry picked from commit 3489286a5f368e7fcf11a9691f9bb5df77abe9a3)
-rw-r--r-- | sys/net/rtsock.c | 62 |
1 files changed, 60 insertions, 2 deletions
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index d9294441b2bc..f13c3189ba26 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -564,6 +564,54 @@ rtm_get_jailed(struct rt_addrinfo *info, struct ifnet *ifp, return (0); } +static int +fill_blackholeinfo(struct rt_addrinfo *info, union sockaddr_union *saun) +{ + struct ifaddr *ifa; + sa_family_t saf; + + if (V_loif == NULL) { + printf("Unable to add blackhole/reject nhop without loopback"); + return (ENOTSUP); + } + info->rti_ifp = V_loif; + + saf = info->rti_info[RTAX_DST]->sa_family; + + CK_STAILQ_FOREACH(ifa, &info->rti_ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr->sa_family == saf) { + info->rti_ifa = ifa; + break; + } + } + if (info->rti_ifa == NULL) + return (ENOTSUP); + + bzero(saun, sizeof(union sockaddr_union)); + switch (saf) { +#ifdef INET + case AF_INET: + saun->sin.sin_family = AF_INET; + saun->sin.sin_len = sizeof(struct sockaddr_in); + saun->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + break; +#endif +#ifdef INET6 + case AF_INET6: + saun->sin6.sin6_family = AF_INET6; + saun->sin6.sin6_len = sizeof(struct sockaddr_in6); + saun->sin6.sin6_addr = in6addr_loopback; + break; +#endif + default: + return (ENOTSUP); + } + info->rti_info[RTAX_GATEWAY] = &saun->sa; + info->rti_flags |= RTF_GATEWAY; + + return (0); +} + /* * Fills in @info based on userland-provided @rtm message. * @@ -951,7 +999,6 @@ route_output(struct mbuf *m, struct socket *so, ...) #endif int alloc_len = 0, len, error = 0, fibnum; sa_family_t saf = AF_UNSPEC; - struct walkarg w; struct rib_cmd_info rc; struct nhop_object *nh; @@ -979,7 +1026,6 @@ route_output(struct mbuf *m, struct socket *so, ...) m_copydata(m, 0, len, (caddr_t)rtm); bzero(&info, sizeof(info)); - bzero(&w, sizeof(w)); nh = NULL; if (rtm->rtm_version != RTM_VERSION) { @@ -1011,6 +1057,18 @@ route_output(struct mbuf *m, struct socket *so, ...) goto flush; } + union sockaddr_union gw_saun; + int blackhole_flags = rtm->rtm_flags & (RTF_BLACKHOLE|RTF_REJECT); + if (blackhole_flags != 0) { + if (blackhole_flags != (RTF_BLACKHOLE | RTF_REJECT)) + error = fill_blackholeinfo(&info, &gw_saun); + else + error = EINVAL; + if (error != 0) + senderr(error); + /* TODO: rebuild rtm from scratch */ + } + switch (rtm->rtm_type) { case RTM_ADD: case RTM_CHANGE: |