1 /*        $NetBSD: rtsock.c,v 1.256 2022/08/27 08:36:41 skrll Exp $   */
2 
3 /*
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1988, 1991, 1993
34  *        The Regents of the University of California.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. Neither the name of the University nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  *
60  *        @(#)rtsock.c        8.7 (Berkeley) 10/12/95
61  */
62 
63 #include <sys/cdefs.h>
64 __KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.256 2022/08/27 08:36:41 skrll Exp $");
65 
66 #ifdef _KERNEL_OPT
67 #include "opt_inet.h"
68 #include "opt_compat_netbsd.h"
69 #endif
70 
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/proc.h>
74 #include <sys/socket.h>
75 #include <sys/socketvar.h>
76 #include <sys/domain.h>
77 #include <sys/protosw.h>
78 #include <sys/sysctl.h>
79 #include <sys/kauth.h>
80 #include <sys/kmem.h>
81 #include <sys/intr.h>
82 #include <sys/condvar.h>
83 #include <sys/compat_stub.h>
84 
85 #include <net/if.h>
86 #include <net/if_llatbl.h>
87 #include <net/if_types.h>
88 #include <net/route.h>
89 #include <net/raw_cb.h>
90 
91 #include <netinet/in_var.h>
92 #include <netinet/if_inarp.h>
93 
94 #include <netmpls/mpls.h>
95 
96 #include <compat/net/if.h>
97 #include <compat/net/route.h>
98 
99 #ifdef COMPAT_RTSOCK
100 #undef COMPAT_RTSOCK
101 #endif
102 
103 static int if_addrflags(struct ifaddr *);
104 
105 #include <net/rtsock_shared.c>
106 
107 /*
108  * XXX avoid using void * once msghdr compat disappears.
109  */
110 void
rt_setmetrics(void * in,struct rtentry * out)111 rt_setmetrics(void *in, struct rtentry *out)
112 {
113           const struct rt_xmsghdr *rtm = in;
114 
115           _rt_setmetrics(rtm->rtm_inits, rtm, out);
116 }
117 
118 int
rt_msg3(int type,struct rt_addrinfo * rtinfo,void * cpv,struct rt_walkarg * w,int * lenp)119 rt_msg3(int type, struct rt_addrinfo *rtinfo, void *cpv, struct rt_walkarg *w,
120           int *lenp)
121 {
122           return rt_msg2(type, rtinfo, cpv, w, lenp);
123 }
124 
125 static int
if_addrflags(struct ifaddr * ifa)126 if_addrflags(struct ifaddr *ifa)
127 {
128 
129           switch (ifa->ifa_addr->sa_family) {
130 #ifdef INET
131           case AF_INET:
132                     return ifatoia(ifa)->ia4_flags;
133 #endif
134 #ifdef INET6
135           case AF_INET6:
136                     return ifatoia6(ifa)->ia6_flags;
137 #endif
138           default:
139                     return 0;
140           }
141 }
142 
143 
144 /*
145  * Send a routing message as mimicing that a cloned route is added.
146  */
147 void
rt_clonedmsg(int type,const struct sockaddr * src,const struct sockaddr * dst,const uint8_t * lladdr,const struct ifnet * ifp)148 rt_clonedmsg(int type, const struct sockaddr *src, const struct sockaddr *dst,
149     const uint8_t *lladdr, const struct ifnet *ifp)
150 {
151           struct rt_addrinfo info;
152           /* Mimic flags exactly */
153 #define RTF_LLINFO  0x400
154 #define RTF_CLONED  0x2000
155           int flags = RTF_DONE;
156           union {
157                     struct sockaddr sa;
158                     struct sockaddr_storage ss;
159                     struct sockaddr_dl sdl;
160           } u;
161 
162           if (type != RTM_MISS)
163                     flags |= RTF_HOST | RTF_CLONED | RTF_LLINFO;
164           if (type == RTM_ADD || type == RTM_CHANGE)
165                     flags |= RTF_UP;
166           memset(&info, 0, sizeof(info));
167           info.rti_info[RTAX_AUTHOR] = src;
168           info.rti_info[RTAX_DST] = dst;
169           sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type,
170               NULL, 0, lladdr, ifp->if_addrlen);
171           info.rti_info[RTAX_GATEWAY] = &u.sa;
172 
173           rt_missmsg(type, &info, flags, 0);
174 #undef RTF_LLINFO
175 #undef RTF_CLONED
176 }
177 
178 
179 /*
180  * The remaining code implements the routing-table sysctl node.  It is
181  * compiled only for the non-COMPAT case.
182  */
183 
184 /*
185  * This is used in dumping the kernel table via sysctl().
186  */
187 static int
sysctl_dumpentry(struct rtentry * rt,void * v)188 sysctl_dumpentry(struct rtentry *rt, void *v)
189 {
190           struct rt_walkarg *w = v;
191           int error = 0, size;
192           struct rt_addrinfo info;
193 
194           if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
195                     return 0;
196           memset(&info, 0, sizeof(info));
197           info.rti_info[RTAX_DST] = rt_getkey(rt);
198           info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
199           info.rti_info[RTAX_NETMASK] = rt_mask(rt);
200           info.rti_info[RTAX_TAG] = rt_gettag(rt);
201           if (rt->rt_ifp) {
202                     const struct ifaddr *rtifa;
203                     info.rti_info[RTAX_IFP] = rt->rt_ifp->if_dl->ifa_addr;
204                     /* rtifa used to be simply rt->rt_ifa.  If rt->rt_ifa != NULL,
205                      * then rt_get_ifa() != NULL.  So this ought to still be safe.
206                      * --dyoung
207                      */
208                     rtifa = rt_get_ifa(rt);
209                     info.rti_info[RTAX_IFA] = rtifa->ifa_addr;
210                     if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
211                               info.rti_info[RTAX_BRD] = rtifa->ifa_dstaddr;
212           }
213           if ((error = rt_msg2(RTM_GET, &info, 0, w, &size)))
214                     return error;
215           if (w->w_where && w->w_tmem && w->w_needed <= 0) {
216                     struct rt_xmsghdr *rtm = (struct rt_xmsghdr *)w->w_tmem;
217 
218                     rtm->rtm_flags = rt->rt_flags;
219                     rtm->rtm_use = rt->rt_use;
220                     rtm_setmetrics(rt, rtm);
221                     KASSERT(rt->rt_ifp != NULL);
222                     rtm->rtm_index = rt->rt_ifp->if_index;
223                     rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
224                     rtm->rtm_addrs = info.rti_addrs;
225                     if ((error = copyout(rtm, w->w_where, size)) != 0)
226                               w->w_where = NULL;
227                     else
228                               w->w_where = (char *)w->w_where + size;
229           }
230           return error;
231 }
232 
233 static int
sysctl_iflist_if(struct ifnet * ifp,struct rt_walkarg * w,struct rt_addrinfo * info,size_t len)234 sysctl_iflist_if(struct ifnet *ifp, struct rt_walkarg *w,
235     struct rt_addrinfo *info, size_t len)
236 {
237           struct if_xmsghdr *ifm;
238           int error;
239 
240           ifm = (struct if_xmsghdr *)w->w_tmem;
241           ifm->ifm_index = ifp->if_index;
242           ifm->ifm_flags = ifp->if_flags;
243           if_export_if_data(ifp, &ifm->ifm_data, false);
244           ifm->ifm_addrs = info->rti_addrs;
245           if ((error = copyout(ifm, w->w_where, len)) == 0)
246                     w->w_where = (char *)w->w_where + len;
247           return error;
248 }
249 
250 static int
sysctl_iflist_addr(struct rt_walkarg * w,struct ifaddr * ifa,struct rt_addrinfo * info)251 sysctl_iflist_addr(struct rt_walkarg *w, struct ifaddr *ifa,
252      struct rt_addrinfo *info)
253 {
254           int len, error;
255 
256           if ((error = rt_msg2(RTM_XNEWADDR, info, 0, w, &len)))
257                     return error;
258           if (w->w_where && w->w_tmem && w->w_needed <= 0) {
259                     struct ifa_xmsghdr *ifam;
260 
261                     ifam = (struct ifa_xmsghdr *)w->w_tmem;
262                     ifam->ifam_index = ifa->ifa_ifp->if_index;
263                     ifam->ifam_flags = ifa->ifa_flags;
264                     ifam->ifam_metric = ifa->ifa_metric;
265                     ifam->ifam_addrs = info->rti_addrs;
266                     ifam->ifam_pid = 0;
267                     ifam->ifam_addrflags = if_addrflags(ifa);
268                     if ((error = copyout(w->w_tmem, w->w_where, len)) == 0)
269                               w->w_where = (char *)w->w_where + len;
270           }
271           return error;
272 }
273 
274 static int
sysctl_iflist(int af,struct rt_walkarg * w,int type)275 sysctl_iflist(int af, struct rt_walkarg *w, int type)
276 {
277           struct ifnet *ifp;
278           struct ifaddr *ifa;
279           struct    rt_addrinfo info;
280           int       cmd, len, error = 0;
281           int s;
282           struct psref psref;
283           int bound;
284 
285           switch (type) {
286           case NET_RT_IFLIST:
287                     cmd = RTM_IFINFO;
288                     break;
289           case NET_RT_OOOIFLIST:
290                     cmd = RTM_OOIFINFO;
291                     break;
292           case NET_RT_OOIFLIST:
293                     cmd = RTM_OIFINFO;
294                     break;
295           case NET_RT_OIFLIST:
296                     cmd = RTM_IFINFO;
297                     break;
298           default:
299 #ifdef RTSOCK_DEBUG
300                     printf("%s: unsupported IFLIST type %d\n", __func__, type);
301 #endif
302                     return EINVAL;
303           }
304 
305           memset(&info, 0, sizeof(info));
306 
307           bound = curlwp_bind();
308           s = pserialize_read_enter();
309           IFNET_READER_FOREACH(ifp) {
310                     int _s;
311                     if (w->w_arg && w->w_arg != ifp->if_index)
312                               continue;
313                     if (IFADDR_READER_EMPTY(ifp))
314                               continue;
315 
316                     if_acquire(ifp, &psref);
317                     pserialize_read_exit(s);
318 
319                     info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr;
320                     if ((error = rt_msg2(cmd, &info, NULL, w, &len)) != 0)
321                               goto release_exit;
322                     info.rti_info[RTAX_IFP] = NULL;
323                     if (w->w_where && w->w_tmem && w->w_needed <= 0) {
324                               switch (type) {
325                               case NET_RT_OIFLIST: /* old _70 */
326                                         if (!rtsock_iflist_70_hook.hooked) {
327                                                   error = EINVAL;
328                                                   break;
329                                         }
330                                         /* FALLTHROUGH */
331                               case NET_RT_IFLIST: /* current */
332                                         error = sysctl_iflist_if(ifp, w, &info, len);
333                                         break;
334                               case NET_RT_OOIFLIST: /* old _50 */
335                                         MODULE_HOOK_CALL(rtsock_iflist_50_hook,
336                                             (ifp, w, &info, len), enosys(), error);
337                                         break;
338                               case NET_RT_OOOIFLIST: /* old _14 */
339                                         MODULE_HOOK_CALL(rtsock_iflist_14_hook,
340                                            (ifp, w, &info, len), enosys(), error);
341                                         break;
342                               default:
343                                         error = EINVAL;
344                               }
345                               if (error != 0) {
346                                         if (error == ENOSYS)
347                                                   error = EINVAL;
348                                         goto release_exit;
349                               }
350                     }
351                     _s = pserialize_read_enter();
352                     IFADDR_READER_FOREACH(ifa, ifp) {
353                               struct psref _psref;
354                               if (af && af != ifa->ifa_addr->sa_family)
355                                         continue;
356                               ifa_acquire(ifa, &_psref);
357                               pserialize_read_exit(_s);
358 
359                               info.rti_info[RTAX_IFA] = ifa->ifa_addr;
360                               info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
361                               info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
362                               switch (type) {
363                               case NET_RT_IFLIST:
364                                         error = sysctl_iflist_addr(w, ifa, &info);
365                                         break;
366                               case NET_RT_OIFLIST:
367                               case NET_RT_OOIFLIST:
368                               case NET_RT_OOOIFLIST:
369                                         MODULE_HOOK_CALL(rtsock_iflist_70_hook,
370                                             (w, ifa, &info), enosys(), error);
371                                         break;
372                               default:
373                                         error = EINVAL;
374                               }
375 
376                               _s = pserialize_read_enter();
377                               ifa_release(ifa, &_psref);
378                               if (error != 0) {
379                                         pserialize_read_exit(_s);
380                                         goto release_exit;
381                               }
382                     }
383                     pserialize_read_exit(_s);
384                     info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] =
385                         info.rti_info[RTAX_BRD] = NULL;
386 
387                     s = pserialize_read_enter();
388                     if_release(ifp, &psref);
389           }
390           pserialize_read_exit(s);
391           curlwp_bindx(bound);
392 
393           return 0;
394 
395 release_exit:
396           if_release(ifp, &psref);
397           curlwp_bindx(bound);
398           return error;
399 }
400 
401 static int
sysctl_rtable(SYSCTLFN_ARGS)402 sysctl_rtable(SYSCTLFN_ARGS)
403 {
404           void      *where = oldp;
405           size_t    *given = oldlenp;
406           int       i, error = EINVAL;
407           u_char  af;
408           struct    rt_walkarg w;
409 
410           if (namelen == 1 && name[0] == CTL_QUERY)
411                     return sysctl_query(SYSCTLFN_CALL(rnode));
412 
413           if (newp)
414                     return EPERM;
415           if (namelen != 3)
416                     return EINVAL;
417           af = name[0];
418           w.w_tmemneeded = 0;
419           w.w_tmemsize = 0;
420           w.w_tmem = NULL;
421 again:
422           /* we may return here if a later [re]alloc of the t_mem buffer fails */
423           if (w.w_tmemneeded) {
424                     w.w_tmem = kmem_zalloc(w.w_tmemneeded, KM_SLEEP);
425                     w.w_tmemsize = w.w_tmemneeded;
426                     w.w_tmemneeded = 0;
427           }
428           w.w_op = name[1];
429           w.w_arg = name[2];
430           w.w_given = *given;
431           w.w_needed = 0 - w.w_given;
432           w.w_where = where;
433 
434           KERNEL_LOCK_UNLESS_NET_MPSAFE();
435           const int s = splsoftnet();
436           switch (w.w_op) {
437 
438           case NET_RT_DUMP:
439           case NET_RT_FLAGS:
440 #if defined(INET) || defined(INET6)
441                     /*
442                      * take care of llinfo entries, the caller must
443                      * specify an AF
444                      */
445                     if (w.w_op == NET_RT_FLAGS &&
446                         (w.w_arg == 0 || w.w_arg & RTF_LLDATA)) {
447                               if (af != 0)
448                                         error = lltable_sysctl_dump(af, &w);
449                               else
450                                         error = EINVAL;
451                               break;
452                     }
453 #endif
454 
455                     for (i = 1; i <= AF_MAX; i++) {
456                               if (af == 0 || af == i) {
457                                         error = rt_walktree(i, sysctl_dumpentry, &w);
458                                         if (error != 0)
459                                                   break;
460 #if defined(INET) || defined(INET6)
461                                         /*
462                                          * Return ARP/NDP entries too for
463                                          * backward compatibility.
464                                          */
465                                         error = lltable_sysctl_dump(i, &w);
466                                         if (error != 0)
467                                                   break;
468 #endif
469                               }
470                     }
471                     break;
472 
473           case NET_RT_OOOIFLIST:                  /* compat_14 */
474           case NET_RT_OOIFLIST:                   /* compat_50 */
475           case NET_RT_OIFLIST:                    /* compat_70 */
476           case NET_RT_IFLIST:           /* current */
477                     error = sysctl_iflist(af, &w, w.w_op);
478                     break;
479           }
480           splx(s);
481           KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
482 
483           /* check to see if we couldn't allocate memory with NOWAIT */
484           if (error == ENOBUFS && w.w_tmem == 0 && w.w_tmemneeded)
485                     goto again;
486 
487           if (w.w_tmem)
488                     kmem_free(w.w_tmem, w.w_tmemsize);
489           w.w_needed += w.w_given;
490           if (where) {
491                     *given = (char *)w.w_where - (char *)where;
492                     if (*given < w.w_needed)
493                               return ENOMEM;
494           } else {
495                     *given = (11 * w.w_needed) / 10;
496           }
497           return error;
498 }
499 
500 void
sysctl_net_route_setup(struct sysctllog ** clog,int pf,const char * name)501 sysctl_net_route_setup(struct sysctllog **clog, int pf, const char *name)
502 {
503           const struct sysctlnode *rnode = NULL;
504 
505           sysctl_createv(clog, 0, NULL, &rnode,
506                            CTLFLAG_PERMANENT,
507                            CTLTYPE_NODE, name,
508                            SYSCTL_DESCR("PF_ROUTE information"),
509                            NULL, 0, NULL, 0,
510                            CTL_NET, pf, CTL_EOL);
511 
512           sysctl_createv(clog, 0, NULL, NULL,
513                            CTLFLAG_PERMANENT,
514                            CTLTYPE_NODE, "rtable",
515                            SYSCTL_DESCR("Routing table information"),
516                            sysctl_rtable, 0, NULL, 0,
517                            CTL_NET, pf, 0 /* any protocol */, CTL_EOL);
518 
519           sysctl_createv(clog, 0, &rnode, NULL,
520                            CTLFLAG_PERMANENT,
521                            CTLTYPE_STRUCT, "stats",
522                            SYSCTL_DESCR("Routing statistics"),
523                            NULL, 0, &rtstat, sizeof(rtstat),
524                            CTL_CREATE, CTL_EOL);
525 }
526