165ff3638SAlexander V. Chernikov /*- 265ff3638SAlexander V. Chernikov * Copyright (c) 2015 365ff3638SAlexander V. Chernikov * Alexander V. Chernikov <melifaro@FreeBSD.org> 465ff3638SAlexander V. Chernikov * 565ff3638SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 665ff3638SAlexander V. Chernikov * modification, are permitted provided that the following conditions 765ff3638SAlexander V. Chernikov * are met: 865ff3638SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 965ff3638SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 1065ff3638SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 1165ff3638SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 1265ff3638SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 13fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 1465ff3638SAlexander V. Chernikov * may be used to endorse or promote products derived from this software 1565ff3638SAlexander V. Chernikov * without specific prior written permission. 1665ff3638SAlexander V. Chernikov * 1765ff3638SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1865ff3638SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1965ff3638SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2065ff3638SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2165ff3638SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2265ff3638SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2365ff3638SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2465ff3638SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2565ff3638SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2665ff3638SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2765ff3638SAlexander V. Chernikov * SUCH DAMAGE. 2865ff3638SAlexander V. Chernikov */ 2965ff3638SAlexander V. Chernikov 3065ff3638SAlexander V. Chernikov #include <sys/cdefs.h> 3165ff3638SAlexander V. Chernikov __FBSDID("$FreeBSD$"); 3265ff3638SAlexander V. Chernikov 3365ff3638SAlexander V. Chernikov #include "opt_inet.h" 3465ff3638SAlexander V. Chernikov #include "opt_route.h" 3565ff3638SAlexander V. Chernikov 3665ff3638SAlexander V. Chernikov #include <sys/param.h> 3765ff3638SAlexander V. Chernikov #include <sys/systm.h> 3865ff3638SAlexander V. Chernikov #include <sys/lock.h> 3920efcfc6SAndrey V. Elsukov #include <sys/rmlock.h> 4065ff3638SAlexander V. Chernikov #include <sys/malloc.h> 4165ff3638SAlexander V. Chernikov #include <sys/mbuf.h> 4265ff3638SAlexander V. Chernikov #include <sys/socket.h> 4365ff3638SAlexander V. Chernikov #include <sys/sysctl.h> 4465ff3638SAlexander V. Chernikov #include <sys/kernel.h> 4565ff3638SAlexander V. Chernikov 4665ff3638SAlexander V. Chernikov #include <net/if.h> 4765ff3638SAlexander V. Chernikov #include <net/if_var.h> 4865ff3638SAlexander V. Chernikov #include <net/if_dl.h> 4965ff3638SAlexander V. Chernikov #include <net/route.h> 50*fedeb08bSAlexander V. Chernikov #include <net/route/route_ctl.h> 51e7d8af4fSAlexander V. Chernikov #include <net/route/route_var.h> 52a6663252SAlexander V. Chernikov #include <net/route/nhop.h> 5365ff3638SAlexander V. Chernikov #include <net/vnet.h> 5465ff3638SAlexander V. Chernikov 5565ff3638SAlexander V. Chernikov #include <netinet/in.h> 5665ff3638SAlexander V. Chernikov #include <netinet/in_var.h> 5765ff3638SAlexander V. Chernikov #include <netinet/in_fib.h> 5865ff3638SAlexander V. Chernikov 5965ff3638SAlexander V. Chernikov #ifdef INET 60983066f0SAlexander V. Chernikov 61983066f0SAlexander V. Chernikov /* Verify struct route compatiblity */ 62983066f0SAlexander V. Chernikov /* Assert 'struct route_in' is compatible with 'struct route' */ 63983066f0SAlexander V. Chernikov CHK_STRUCT_ROUTE_COMPAT(struct route_in, ro_dst4); 6465ff3638SAlexander V. Chernikov 65a6663252SAlexander V. Chernikov /* 66a6663252SAlexander V. Chernikov * Looks up path in fib @fibnum specified by @dst. 67a6663252SAlexander V. Chernikov * Returns path nexthop on success. Nexthop is safe to use 68a6663252SAlexander V. Chernikov * within the current network epoch. If longer lifetime is required, 69a6663252SAlexander V. Chernikov * one needs to pass NHR_REF as a flag. This will return referenced 70a6663252SAlexander V. Chernikov * nexthop. 71a6663252SAlexander V. Chernikov */ 72a6663252SAlexander V. Chernikov struct nhop_object * 73a6663252SAlexander V. Chernikov fib4_lookup(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, 74a6663252SAlexander V. Chernikov uint32_t flags, uint32_t flowid) 75a6663252SAlexander V. Chernikov { 76a6663252SAlexander V. Chernikov RIB_RLOCK_TRACKER; 77a6663252SAlexander V. Chernikov struct rib_head *rh; 78a6663252SAlexander V. Chernikov struct radix_node *rn; 79a6663252SAlexander V. Chernikov struct nhop_object *nh; 80a6663252SAlexander V. Chernikov 81a6663252SAlexander V. Chernikov KASSERT((fibnum < rt_numfibs), ("fib4_lookup: bad fibnum")); 82a6663252SAlexander V. Chernikov rh = rt_tables_get_rnh(fibnum, AF_INET); 83a6663252SAlexander V. Chernikov if (rh == NULL) 84a6663252SAlexander V. Chernikov return (NULL); 85a6663252SAlexander V. Chernikov 86a6663252SAlexander V. Chernikov /* Prepare lookup key */ 87a6663252SAlexander V. Chernikov struct sockaddr_in sin4; 88a6663252SAlexander V. Chernikov memset(&sin4, 0, sizeof(sin4)); 89a6663252SAlexander V. Chernikov sin4.sin_family = AF_INET; 90a6663252SAlexander V. Chernikov sin4.sin_len = sizeof(struct sockaddr_in); 91a6663252SAlexander V. Chernikov sin4.sin_addr = dst; 92a6663252SAlexander V. Chernikov 93a6663252SAlexander V. Chernikov nh = NULL; 94a6663252SAlexander V. Chernikov RIB_RLOCK(rh); 95a6663252SAlexander V. Chernikov rn = rh->rnh_matchaddr((void *)&sin4, &rh->head); 96a6663252SAlexander V. Chernikov if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { 97*fedeb08bSAlexander V. Chernikov nh = nhop_select((RNTORT(rn))->rt_nhop, flowid); 98a6663252SAlexander V. Chernikov /* Ensure route & ifp is UP */ 99a6663252SAlexander V. Chernikov if (RT_LINK_IS_UP(nh->nh_ifp)) { 100a6663252SAlexander V. Chernikov if (flags & NHR_REF) 101a6663252SAlexander V. Chernikov nhop_ref_object(nh); 102a6663252SAlexander V. Chernikov RIB_RUNLOCK(rh); 103a6663252SAlexander V. Chernikov return (nh); 104a6663252SAlexander V. Chernikov } 105a6663252SAlexander V. Chernikov } 106a6663252SAlexander V. Chernikov RIB_RUNLOCK(rh); 107a6663252SAlexander V. Chernikov 108a6663252SAlexander V. Chernikov RTSTAT_INC(rts_unreach); 109a6663252SAlexander V. Chernikov return (NULL); 110a6663252SAlexander V. Chernikov } 111a6663252SAlexander V. Chernikov 112a6663252SAlexander V. Chernikov inline static int 113*fedeb08bSAlexander V. Chernikov check_urpf_nhop(const struct nhop_object *nh, uint32_t flags, 114a6663252SAlexander V. Chernikov const struct ifnet *src_if) 115a6663252SAlexander V. Chernikov { 116a6663252SAlexander V. Chernikov 117a6663252SAlexander V. Chernikov if (src_if != NULL && nh->nh_aifp == src_if) { 118a6663252SAlexander V. Chernikov return (1); 119a6663252SAlexander V. Chernikov } 120a6663252SAlexander V. Chernikov if (src_if == NULL) { 121a6663252SAlexander V. Chernikov if ((flags & NHR_NODEFAULT) == 0) 122a6663252SAlexander V. Chernikov return (1); 123a6663252SAlexander V. Chernikov else if ((nh->nh_flags & NHF_DEFAULT) == 0) 124a6663252SAlexander V. Chernikov return (1); 125a6663252SAlexander V. Chernikov } 126a6663252SAlexander V. Chernikov 127a6663252SAlexander V. Chernikov return (0); 128a6663252SAlexander V. Chernikov } 129a6663252SAlexander V. Chernikov 130*fedeb08bSAlexander V. Chernikov static int 131*fedeb08bSAlexander V. Chernikov check_urpf(struct nhop_object *nh, uint32_t flags, 132a6663252SAlexander V. Chernikov const struct ifnet *src_if) 133a6663252SAlexander V. Chernikov { 134*fedeb08bSAlexander V. Chernikov #ifdef ROUTE_MPATH 135*fedeb08bSAlexander V. Chernikov if (NH_IS_NHGRP(nh)) { 136*fedeb08bSAlexander V. Chernikov struct weightened_nhop *wn; 137*fedeb08bSAlexander V. Chernikov uint32_t num_nhops; 138*fedeb08bSAlexander V. Chernikov wn = nhgrp_get_nhops((struct nhgrp_object *)nh, &num_nhops); 139*fedeb08bSAlexander V. Chernikov for (int i = 0; i < num_nhops; i++) { 140*fedeb08bSAlexander V. Chernikov if (check_urpf_nhop(wn[i].nh, flags, src_if) != 0) 141a6663252SAlexander V. Chernikov return (1); 142a6663252SAlexander V. Chernikov } 143a6663252SAlexander V. Chernikov return (0); 144*fedeb08bSAlexander V. Chernikov } else 145a6663252SAlexander V. Chernikov #endif 146*fedeb08bSAlexander V. Chernikov return (check_urpf_nhop(nh, flags, src_if)); 147*fedeb08bSAlexander V. Chernikov } 148a6663252SAlexander V. Chernikov 149a6663252SAlexander V. Chernikov /* 150a6663252SAlexander V. Chernikov * Performs reverse path forwarding lookup. 151a6663252SAlexander V. Chernikov * If @src_if is non-zero, verifies that at least 1 path goes via 152a6663252SAlexander V. Chernikov * this interface. 153a6663252SAlexander V. Chernikov * If @src_if is zero, verifies that route exist. 154a6663252SAlexander V. Chernikov * if @flags contains NHR_NOTDEFAULT, do not consider default route. 155a6663252SAlexander V. Chernikov * 156a6663252SAlexander V. Chernikov * Returns 1 if route matching conditions is found, 0 otherwise. 157a6663252SAlexander V. Chernikov */ 158a6663252SAlexander V. Chernikov int 159a6663252SAlexander V. Chernikov fib4_check_urpf(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, 160a6663252SAlexander V. Chernikov uint32_t flags, const struct ifnet *src_if) 161a6663252SAlexander V. Chernikov { 162a6663252SAlexander V. Chernikov RIB_RLOCK_TRACKER; 163a6663252SAlexander V. Chernikov struct rib_head *rh; 164a6663252SAlexander V. Chernikov struct radix_node *rn; 165a6663252SAlexander V. Chernikov int ret; 166a6663252SAlexander V. Chernikov 167a6663252SAlexander V. Chernikov KASSERT((fibnum < rt_numfibs), ("fib4_check_urpf: bad fibnum")); 168a6663252SAlexander V. Chernikov rh = rt_tables_get_rnh(fibnum, AF_INET); 169a6663252SAlexander V. Chernikov if (rh == NULL) 170a6663252SAlexander V. Chernikov return (0); 171a6663252SAlexander V. Chernikov 172a6663252SAlexander V. Chernikov /* Prepare lookup key */ 173a6663252SAlexander V. Chernikov struct sockaddr_in sin4; 174a6663252SAlexander V. Chernikov memset(&sin4, 0, sizeof(sin4)); 175a6663252SAlexander V. Chernikov sin4.sin_len = sizeof(struct sockaddr_in); 176a6663252SAlexander V. Chernikov sin4.sin_addr = dst; 177a6663252SAlexander V. Chernikov 178a6663252SAlexander V. Chernikov RIB_RLOCK(rh); 179a6663252SAlexander V. Chernikov rn = rh->rnh_matchaddr((void *)&sin4, &rh->head); 180a6663252SAlexander V. Chernikov if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { 181*fedeb08bSAlexander V. Chernikov ret = check_urpf(RNTORT(rn)->rt_nhop, flags, src_if); 182a6663252SAlexander V. Chernikov RIB_RUNLOCK(rh); 183a6663252SAlexander V. Chernikov return (ret); 184a6663252SAlexander V. Chernikov } 185a6663252SAlexander V. Chernikov RIB_RUNLOCK(rh); 186a6663252SAlexander V. Chernikov 187a6663252SAlexander V. Chernikov return (0); 188a6663252SAlexander V. Chernikov } 189a6663252SAlexander V. Chernikov 19055f57ca9SAlexander V. Chernikov struct nhop_object * 19155f57ca9SAlexander V. Chernikov fib4_lookup_debugnet(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, 19255f57ca9SAlexander V. Chernikov uint32_t flags) 19355f57ca9SAlexander V. Chernikov { 19455f57ca9SAlexander V. Chernikov struct rib_head *rh; 19555f57ca9SAlexander V. Chernikov struct radix_node *rn; 19655f57ca9SAlexander V. Chernikov struct nhop_object *nh; 19755f57ca9SAlexander V. Chernikov 19855f57ca9SAlexander V. Chernikov KASSERT((fibnum < rt_numfibs), ("fib4_lookup_debugnet: bad fibnum")); 19955f57ca9SAlexander V. Chernikov rh = rt_tables_get_rnh(fibnum, AF_INET); 20055f57ca9SAlexander V. Chernikov if (rh == NULL) 20155f57ca9SAlexander V. Chernikov return (NULL); 20255f57ca9SAlexander V. Chernikov 20355f57ca9SAlexander V. Chernikov /* Prepare lookup key */ 20455f57ca9SAlexander V. Chernikov struct sockaddr_in sin4; 20555f57ca9SAlexander V. Chernikov memset(&sin4, 0, sizeof(sin4)); 20655f57ca9SAlexander V. Chernikov sin4.sin_family = AF_INET; 20755f57ca9SAlexander V. Chernikov sin4.sin_len = sizeof(struct sockaddr_in); 20855f57ca9SAlexander V. Chernikov sin4.sin_addr = dst; 20955f57ca9SAlexander V. Chernikov 21055f57ca9SAlexander V. Chernikov nh = NULL; 21155f57ca9SAlexander V. Chernikov /* unlocked lookup */ 21255f57ca9SAlexander V. Chernikov rn = rh->rnh_matchaddr((void *)&sin4, &rh->head); 21355f57ca9SAlexander V. Chernikov if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { 214*fedeb08bSAlexander V. Chernikov nh = nhop_select((RNTORT(rn))->rt_nhop, 0); 21555f57ca9SAlexander V. Chernikov /* Ensure route & ifp is UP */ 21655f57ca9SAlexander V. Chernikov if (RT_LINK_IS_UP(nh->nh_ifp)) { 21755f57ca9SAlexander V. Chernikov if (flags & NHR_REF) 21855f57ca9SAlexander V. Chernikov nhop_ref_object(nh); 21955f57ca9SAlexander V. Chernikov return (nh); 22055f57ca9SAlexander V. Chernikov } 22155f57ca9SAlexander V. Chernikov } 22255f57ca9SAlexander V. Chernikov 22355f57ca9SAlexander V. Chernikov return (NULL); 22455f57ca9SAlexander V. Chernikov } 22555f57ca9SAlexander V. Chernikov 22665ff3638SAlexander V. Chernikov #endif 227