xref: /dragonfly/sbin/routed/main.c (revision 024d37cd64273c09afb2b0fdbee3de9530314785)
1 /*
2  * Copyright (c) 1983, 1988, 1993
3  *        The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)main.c       8.1 (Berkeley) 6/5/93
30  * $FreeBSD: src/sbin/routed/main.c,v 1.11.2.1 2000/08/14 17:00:03 sheldonh Exp $
31  */
32 
33 #include "defs.h"
34 #include "pathnames.h"
35 #include <signal.h>
36 #include <fcntl.h>
37 #include <sys/file.h>
38 
39 pid_t     mypid;
40 
41 naddr     myaddr;                                 /* system address */
42 char      myname[MAXHOSTNAMELEN+1];
43 
44 int       verbose;
45 
46 int       supplier;                     /* supply or broadcast updates */
47 int       supplier_set;
48 int       ipforwarding = 1;             /* kernel forwarding on */
49 
50 int       default_gateway;              /* 1=advertise default */
51 int       background = 1;
52 int       ridhosts;                     /* 1=reduce host routes */
53 int       mhome;                                  /* 1=want multi-homed host route */
54 int       advertise_mhome;              /* 1=must continue advertising it */
55 int       auth_ok = 1;                            /* 1=ignore auth if we do not care */
56 
57 struct timeval epoch;                             /* when started */
58 struct timeval clk, prev_clk;
59 static int usec_fudge;
60 struct timeval now;                     /* current idea of time */
61 time_t    now_stale;
62 time_t    now_expire;
63 time_t    now_garbage;
64 
65 struct timeval next_bcast;              /* next general broadcast */
66 struct timeval no_flash = {             /* inhibit flash update */
67           EPOCH+SUPPLY_INTERVAL, 0
68 };
69 
70 struct timeval flush_kern_timer;
71 
72 fd_set    fdbits;
73 int       sock_max;
74 int       rip_sock = -1;                          /* RIP socket */
75 struct interface *rip_sock_mcast;       /* current multicast interface */
76 int       rt_sock;                      /* routing socket */
77 int       rt_sock_seqno;
78 
79 
80 static  int get_rip_sock(naddr, int);
81 static void timevalsub(struct timeval *, struct timeval *, struct timeval *);
82 
83 int
main(int argc,char * argv[])84 main(int argc,
85      char *argv[])
86 {
87           int n, mib[4], off;
88           size_t len;
89           char *p, *q;
90           const char *cp;
91           struct timeval wtime, t2;
92           time_t dt;
93           fd_set ibits;
94           naddr p_net, p_mask;
95           struct interface *ifp;
96           struct parm parm;
97           char *tracename = 0;
98 
99 
100           /* Some shells are badly broken and send SIGHUP to backgrounded
101            * processes.
102            */
103           signal(SIGHUP, SIG_IGN);
104 
105           openlog("routed", LOG_PID, LOG_DAEMON);
106           ftrace = stdout;
107 
108           gettimeofday(&clk, 0);
109           prev_clk = clk;
110           epoch = clk;
111           epoch.tv_sec -= EPOCH;
112           now.tv_sec = EPOCH;
113           now_stale = EPOCH - STALE_TIME;
114           now_expire = EPOCH - EXPIRE_TIME;
115           now_garbage = EPOCH - GARBAGE_TIME;
116           wtime.tv_sec = 0;
117 
118           gethostname(myname, sizeof(myname)-1);
119           gethost(myname, &myaddr);
120 
121           while ((n = getopt(argc, argv, "sqdghmpAtvT:F:P:")) != -1) {
122                     switch (n) {
123                     case 's':
124                               supplier = 1;
125                               supplier_set = 1;
126                               break;
127 
128                     case 'q':
129                               supplier = 0;
130                               supplier_set = 1;
131                               break;
132 
133                     case 'd':
134                               background = 0;
135                               break;
136 
137                     case 'g':
138                               memset(&parm, 0, sizeof(parm));
139                               parm.parm_d_metric = 1;
140                               cp = check_parms(&parm);
141                               if (cp != 0)
142                                         msglog("bad -g: %s", cp);
143                               else
144                                         default_gateway = 1;
145                               break;
146 
147                     case 'h':           /* suppress extra host routes */
148                               ridhosts = 1;
149                               break;
150 
151                     case 'm':           /* advertise host route */
152                               mhome = 1;          /* on multi-homed hosts */
153                               break;
154 
155                     case 'A':
156                               /* Ignore authentication if we do not care.
157                                * Crazy as it is, that is what RFC 1723 requires.
158                                */
159                               auth_ok = 0;
160                               break;
161 
162                     case 't':
163                               new_tracelevel++;
164                               break;
165 
166                     case 'T':
167                               tracename = optarg;
168                               break;
169 
170                     case 'F':           /* minimal routes for SLIP */
171                               n = FAKE_METRIC;
172                               p = strchr(optarg,',');
173                               if (p && *p != '\0') {
174                                         n = (int)strtoul(p+1, &q, 0);
175                                         if (*q == '\0'
176                                             && n <= HOPCNT_INFINITY-1
177                                             && n >= 1)
178                                                   *p = '\0';
179                               }
180                               if (!getnet(optarg, &p_net, &p_mask)) {
181                                         msglog("bad network; \"-F %s\"",
182                                                optarg);
183                                         break;
184                               }
185                               memset(&parm, 0, sizeof(parm));
186                               parm.parm_net = p_net;
187                               parm.parm_mask = p_mask;
188                               parm.parm_d_metric = n;
189                               cp = check_parms(&parm);
190                               if (cp != 0)
191                                         msglog("bad -F: %s", cp);
192                               break;
193 
194                     case 'P':
195                               /* handle arbitrary parameters.
196                                */
197                               q = strdup(optarg);
198                               cp = parse_parms(q, 0);
199                               if (cp != 0)
200                                         msglog("%s in \"-P %s\"", cp, optarg);
201                               free(q);
202                               break;
203 
204                     case 'v':
205                               /* display version */
206                               verbose++;
207                               msglog("version 2.22");
208                               break;
209 
210                     default:
211                               goto usage;
212                     }
213           }
214           argc -= optind;
215           argv += optind;
216 
217           if (tracename == 0 && argc >= 1) {
218                     tracename = *argv++;
219                     argc--;
220           }
221           if (tracename != 0 && tracename[0] == '\0')
222                     goto usage;
223           if (argc != 0) {
224 usage:
225                     logbad(0, "usage: routed [-sqdghmpAtv] [-T tracefile]"
226                            " [-F net[,metric]] [-P parms]");
227           }
228           if (geteuid() != 0) {
229                     if (verbose)
230                               exit(0);
231                     logbad(0, "requires UID 0");
232           }
233 
234           mib[0] = CTL_NET;
235           mib[1] = PF_INET;
236           mib[2] = IPPROTO_IP;
237           mib[3] = IPCTL_FORWARDING;
238           len = sizeof(ipforwarding);
239           if (sysctl(mib, 4, &ipforwarding, &len, 0, 0) < 0)
240                     LOGERR("sysctl(IPCTL_FORWARDING)");
241 
242           if (!ipforwarding) {
243                     if (supplier)
244                               msglog("-s incompatible with ipforwarding=0");
245                     if (default_gateway) {
246                               msglog("-g incompatible with ipforwarding=0");
247                               default_gateway = 0;
248                     }
249                     supplier = 0;
250                     supplier_set = 1;
251           }
252           if (default_gateway) {
253                     if (supplier_set && !supplier) {
254                               msglog("-g and -q incompatible");
255                     } else {
256                               supplier = 1;
257                               supplier_set = 1;
258                     }
259           }
260 
261 
262           signal(SIGALRM, sigalrm);
263           if (!background)
264                     signal(SIGHUP, sigterm);    /* SIGHUP fatal during debugging */
265           signal(SIGTERM, sigterm);
266           signal(SIGINT, sigterm);
267           signal(SIGUSR1, sigtrace_on);
268           signal(SIGUSR2, sigtrace_off);
269 
270           /* get into the background */
271           if (background && daemon(0, 1) < 0)
272                     BADERR(0,"daemon()");
273 
274           mypid = getpid();
275           srandom((int)(clk.tv_sec ^ clk.tv_usec ^ mypid));
276 
277           /* prepare socket connected to the kernel.
278            */
279           rt_sock = socket(AF_ROUTE, SOCK_RAW, 0);
280           if (rt_sock < 0)
281                     BADERR(1,"rt_sock = socket()");
282           if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1)
283                     logbad(1, "fcntl(rt_sock) O_NONBLOCK: %s", strerror(errno));
284           off = 0;
285           if (setsockopt(rt_sock, SOL_SOCKET,SO_USELOOPBACK,
286                            &off,sizeof(off)) < 0)
287                     LOGERR("setsockopt(SO_USELOOPBACK,0)");
288 
289           fix_select();
290 
291 
292           if (tracename != 0) {
293                     strncpy(inittracename, tracename, sizeof(inittracename)-1);
294                     set_tracefile(inittracename, "%s", -1);
295           } else {
296                     tracelevel_msg("%s", -1);   /* turn on tracing to stdio */
297           }
298 
299           bufinit();
300 
301           /* initialize radix tree */
302           rtinit();
303 
304           /* Pick a random part of the second for our output to minimize
305            * collisions.
306            *
307            * Start broadcasting after hearing from other routers, and
308            * at a random time so a bunch of systems do not get synchronized
309            * after a power failure.
310            */
311           intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL);
312           age_timer.tv_usec = next_bcast.tv_usec;
313           age_timer.tv_sec = EPOCH+MIN_WAITTIME;
314           rdisc_timer = next_bcast;
315           ifinit_timer.tv_usec = next_bcast.tv_usec;
316 
317           /* Collect an initial view of the world by checking the interface
318            * configuration and the kludge file.
319            */
320           gwkludge();
321           ifinit();
322 
323           /* Ask for routes */
324           rip_query();
325           rdisc_sol();
326 
327           /* Now turn off stdio if not tracing */
328           if (new_tracelevel == 0)
329                     trace_close(background);
330 
331           /* Loop forever, listening and broadcasting.
332            */
333           for (;;) {
334                     prev_clk = clk;
335                     gettimeofday(&clk, 0);
336                     if (prev_clk.tv_sec == clk.tv_sec
337                         && prev_clk.tv_usec == clk.tv_usec+usec_fudge) {
338                               /* Much of `routed` depends on time always advancing.
339                                * On systems that do not guarantee that gettimeofday()
340                                * produces unique timestamps even if called within
341                                * a single tick, use trickery like that in classic
342                                * BSD kernels.
343                                */
344                               clk.tv_usec += ++usec_fudge;
345 
346                     } else {
347                               usec_fudge = 0;
348 
349                               timevalsub(&t2, &clk, &prev_clk);
350                               if (t2.tv_sec < 0
351                                   || t2.tv_sec > wtime.tv_sec + 5) {
352                                         /* Deal with time changes before other
353                                          * housekeeping to keep everything straight.
354                                          */
355                                         dt = t2.tv_sec;
356                                         if (dt > 0)
357                                                   dt -= wtime.tv_sec;
358                                         trace_act("time changed by %d sec", (int)dt);
359                                         epoch.tv_sec += dt;
360                               }
361                     }
362                     timevalsub(&now, &clk, &epoch);
363                     now_stale = now.tv_sec - STALE_TIME;
364                     now_expire = now.tv_sec - EXPIRE_TIME;
365                     now_garbage = now.tv_sec - GARBAGE_TIME;
366 
367                     /* deal with signals that should affect tracing */
368                     set_tracelevel();
369 
370                     if (stopint != 0) {
371                               rip_bcast(0);
372                               rdisc_adv();
373                               trace_off("exiting with signal %d", stopint);
374                               exit(stopint | 128);
375                     }
376 
377                     /* look for new or dead interfaces */
378                     timevalsub(&wtime, &ifinit_timer, &now);
379                     if (wtime.tv_sec <= 0) {
380                               wtime.tv_sec = 0;
381                               ifinit();
382                               rip_query();
383                               continue;
384                     }
385 
386                     /* Check the kernel table occassionally for mysteriously
387                      * evaporated routes
388                      */
389                     timevalsub(&t2, &flush_kern_timer, &now);
390                     if (t2.tv_sec <= 0) {
391                               flush_kern();
392                               flush_kern_timer.tv_sec = (now.tv_sec
393                                                                + CHECK_QUIET_INTERVAL);
394                               continue;
395                     }
396                     if (timercmp(&t2, &wtime, <))
397                               wtime = t2;
398 
399                     /* If it is time, then broadcast our routes.
400                      */
401                     if (supplier || advertise_mhome) {
402                               timevalsub(&t2, &next_bcast, &now);
403                               if (t2.tv_sec <= 0) {
404                                         /* Synchronize the aging and broadcast
405                                          * timers to minimize awakenings
406                                          */
407                                         age(0);
408 
409                                         rip_bcast(0);
410 
411                                         /* It is desirable to send routing updates
412                                          * regularly.  So schedule the next update
413                                          * 30 seconds after the previous one was
414                                          * scheduled, instead of 30 seconds after
415                                          * the previous update was finished.
416                                          * Even if we just started after discovering
417                                          * a 2nd interface or were otherwise delayed,
418                                          * pick a 30-second aniversary of the
419                                          * original broadcast time.
420                                          */
421                                         n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL;
422                                         next_bcast.tv_sec += n*SUPPLY_INTERVAL;
423 
424                                         continue;
425                               }
426 
427                               if (timercmp(&t2, &wtime, <))
428                                         wtime = t2;
429                     }
430 
431                     /* If we need a flash update, either do it now or
432                      * set the delay to end when it is time.
433                      *
434                      * If we are within MIN_WAITTIME seconds of a full update,
435                      * do not bother.
436                      */
437                     if (need_flash
438                         && supplier
439                         && no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) {
440                               /* accurate to the millisecond */
441                               if (!timercmp(&no_flash, &now, >))
442                                         rip_bcast(1);
443                               timevalsub(&t2, &no_flash, &now);
444                               if (timercmp(&t2, &wtime, <))
445                                         wtime = t2;
446                     }
447 
448                     /* trigger the main aging timer.
449                      */
450                     timevalsub(&t2, &age_timer, &now);
451                     if (t2.tv_sec <= 0) {
452                               age(0);
453                               continue;
454                     }
455                     if (timercmp(&t2, &wtime, <))
456                               wtime = t2;
457 
458                     /* update the kernel routing table
459                      */
460                     timevalsub(&t2, &need_kern, &now);
461                     if (t2.tv_sec <= 0) {
462                               age(0);
463                               continue;
464                     }
465                     if (timercmp(&t2, &wtime, <))
466                               wtime = t2;
467 
468                     /* take care of router discovery,
469                      * but do it in the correct the millisecond
470                      */
471                     if (!timercmp(&rdisc_timer, &now, >)) {
472                               rdisc_age(0);
473                               continue;
474                     }
475                     timevalsub(&t2, &rdisc_timer, &now);
476                     if (timercmp(&t2, &wtime, <))
477                               wtime = t2;
478 
479 
480                     /* wait for input or a timer to expire.
481                      */
482                     trace_flush();
483                     ibits = fdbits;
484                     n = select(sock_max, &ibits, 0, 0, &wtime);
485                     if (n <= 0) {
486                               if (n < 0 && errno != EINTR && errno != EAGAIN)
487                                         BADERR(1,"select");
488                               continue;
489                     }
490 
491                     if (FD_ISSET(rt_sock, &ibits)) {
492                               read_rt();
493                               n--;
494                     }
495                     if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) {
496                               read_d();
497                               n--;
498                     }
499                     if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) {
500                               read_rip(rip_sock, 0);
501                               n--;
502                     }
503 
504                     for (ifp = ifnet; n > 0 && 0 != ifp; ifp = ifp->int_next) {
505                               if (ifp->int_rip_sock >= 0
506                                   && FD_ISSET(ifp->int_rip_sock, &ibits)) {
507                                         read_rip(ifp->int_rip_sock, ifp);
508                                         n--;
509                               }
510                     }
511           }
512 }
513 
514 
515 /* ARGSUSED */
516 void
sigalrm(__unused int s)517 sigalrm(__unused int s)
518 {
519           /* Historically, SIGALRM would cause the daemon to check for
520            * new and broken interfaces.
521            */
522           ifinit_timer.tv_sec = now.tv_sec;
523           trace_act("SIGALRM");
524 }
525 
526 
527 /* watch for fatal signals */
528 void
sigterm(int sig)529 sigterm(int sig)
530 {
531           stopint = sig;
532           signal(sig, SIG_DFL);         /* catch it only once */
533 }
534 
535 
536 void
fix_select(void)537 fix_select(void)
538 {
539           struct interface *ifp;
540 
541 
542           FD_ZERO(&fdbits);
543           sock_max = 0;
544 
545           FD_SET(rt_sock, &fdbits);
546           if (sock_max <= rt_sock)
547                     sock_max = rt_sock+1;
548           if (rip_sock >= 0) {
549                     FD_SET(rip_sock, &fdbits);
550                     if (sock_max <= rip_sock)
551                               sock_max = rip_sock+1;
552           }
553           for (ifp = ifnet; NULL != ifp; ifp = ifp->int_next) {
554                     if (ifp->int_rip_sock >= 0) {
555                               FD_SET(ifp->int_rip_sock, &fdbits);
556                               if (sock_max <= ifp->int_rip_sock)
557                                         sock_max = ifp->int_rip_sock+1;
558                     }
559           }
560           if (rdisc_sock >= 0) {
561                     FD_SET(rdisc_sock, &fdbits);
562                     if (sock_max <= rdisc_sock)
563                               sock_max = rdisc_sock+1;
564           }
565 }
566 
567 
568 void
fix_sock(int sock,const char * name)569 fix_sock(int sock,
570            const char *name)
571 {
572           int on;
573 #define MIN_SOCKBUF (4*1024)
574           static int rbuf;
575 
576           if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
577                     logbad(1, "fcntl(%s) O_NONBLOCK: %s",
578                            name, strerror(errno));
579           on = 1;
580           if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST, &on,sizeof(on)) < 0)
581                     msglog("setsockopt(%s,SO_BROADCAST): %s",
582                            name, strerror(errno));
583 #ifdef USE_PASSIFNAME
584           on = 1;
585           if (setsockopt(sock, SOL_SOCKET, SO_PASSIFNAME, &on,sizeof(on)) < 0)
586                     msglog("setsockopt(%s,SO_PASSIFNAME): %s",
587                            name, strerror(errno));
588 #endif
589 
590           if (rbuf >= MIN_SOCKBUF) {
591                     if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
592                                      &rbuf, sizeof(rbuf)) < 0)
593                               msglog("setsockopt(%s,SO_RCVBUF=%d): %s",
594                                      name, rbuf, strerror(errno));
595           } else {
596                     for (rbuf = 60*1024; ; rbuf -= 4096) {
597                               if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
598                                                &rbuf, sizeof(rbuf)) == 0) {
599                                         trace_act("RCVBUF=%d", rbuf);
600                                         break;
601                               }
602                               if (rbuf < MIN_SOCKBUF) {
603                                         msglog("setsockopt(%s,SO_RCVBUF = %d): %s",
604                                                name, rbuf, strerror(errno));
605                                         break;
606                               }
607                     }
608           }
609 }
610 
611 
612 /* get a rip socket
613  */
614 static int                                        /* <0 or file descriptor */
get_rip_sock(naddr addr,int serious)615 get_rip_sock(naddr addr,
616                int serious)             /* 1=failure to bind is serious */
617 {
618           struct sockaddr_in in;
619           unsigned char ttl;
620           int s;
621 
622 
623           if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
624                     BADERR(1,"rip_sock = socket()");
625 
626           memset(&in, 0, sizeof(in));
627           in.sin_len = sizeof(in);
628           in.sin_family = AF_INET;
629           in.sin_port = htons(RIP_PORT);
630           in.sin_addr.s_addr = addr;
631           if (bind(s, (struct sockaddr *)&in, sizeof(in)) < 0) {
632                     if (serious)
633                               BADERR(errno != EADDRINUSE, "bind(rip_sock)");
634                     return -1;
635           }
636           fix_sock(s,"rip_sock");
637 
638           ttl = 1;
639           if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
640                            &ttl, sizeof(ttl)) < 0)
641                     DBGERR(1,"rip_sock setsockopt(IP_MULTICAST_TTL)");
642 
643           return s;
644 }
645 
646 
647 /* turn off main RIP socket */
648 void
rip_off(void)649 rip_off(void)
650 {
651           struct interface *ifp;
652           naddr addr;
653 
654 
655           if (rip_sock >= 0 && !mhome) {
656                     trace_act("turn off RIP");
657 
658                     close(rip_sock);
659                     rip_sock = -1;
660 
661                     /* get non-broadcast sockets to listen to queries.
662                      */
663                     for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
664                               if (ifp->int_state & IS_REMOTE)
665                                         continue;
666                               if (ifp->int_rip_sock < 0) {
667                                         addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
668                                                   ? ifp->int_dstaddr
669                                                   : ifp->int_addr);
670                                         ifp->int_rip_sock = get_rip_sock(addr, 0);
671                               }
672                     }
673 
674                     fix_select();
675 
676                     age(0);
677           }
678 }
679 
680 
681 /* turn on RIP multicast input via an interface
682  */
683 static void
rip_mcast_on(struct interface * ifp)684 rip_mcast_on(struct interface *ifp)
685 {
686           struct ip_mreq m;
687 
688           if (!IS_RIP_IN_OFF(ifp->int_state)
689               && (ifp->int_if_flags & IFF_MULTICAST)
690 #ifdef MCAST_PPP_BUG
691               && !(ifp->int_if_flags & IFF_POINTOPOINT)
692 #endif
693               && !(ifp->int_state & IS_ALIAS)) {
694                     m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
695                     m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
696                                                     ? ifp->int_dstaddr
697                                                     : ifp->int_addr);
698                     if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP,
699                                      &m, sizeof(m)) < 0)
700                               LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)");
701           }
702 }
703 
704 
705 /* Prepare socket used for RIP.
706  */
707 void
rip_on(struct interface * ifp)708 rip_on(struct interface *ifp)
709 {
710           /* If the main RIP socket is already alive, only start receiving
711            * multicasts for this interface.
712            */
713           if (rip_sock >= 0) {
714                     if (ifp != NULL)
715                               rip_mcast_on(ifp);
716                     return;
717           }
718 
719           /* If the main RIP socket is off and it makes sense to turn it on,
720            * then turn it on for all of the interfaces.
721            * It makes sense if either router discovery is off, or if
722            * router discover is on and at most one interface is doing RIP.
723            */
724           if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) {
725                     trace_act("turn on RIP");
726 
727                     /* Close all of the query sockets so that we can open
728                      * the main socket.  SO_REUSEPORT is not a solution,
729                      * since that would let two daemons bind to the broadcast
730                      * socket.
731                      */
732                     for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
733                               if (ifp->int_rip_sock >= 0) {
734                                         close(ifp->int_rip_sock);
735                                         ifp->int_rip_sock = -1;
736                               }
737                     }
738 
739                     rip_sock = get_rip_sock(INADDR_ANY, 1);
740                     rip_sock_mcast = NULL;
741 
742                     /* Do not advertise anything until we have heard something
743                      */
744                     if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME)
745                               next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME;
746 
747                     for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
748                               ifp->int_query_time = NEVER;
749                               rip_mcast_on(ifp);
750                     }
751                     ifinit_timer.tv_sec = now.tv_sec;
752 
753           } else if (ifp != NULL
754                        && !(ifp->int_state & IS_REMOTE)
755                        && ifp->int_rip_sock < 0) {
756                     /* RIP is off, so ensure there are sockets on which
757                      * to listen for queries.
758                      */
759                     ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0);
760           }
761 
762           fix_select();
763 }
764 
765 
766 /* die if malloc(3) fails
767  */
768 void *
rtmalloc(size_t size,const char * msg)769 rtmalloc(size_t size,
770            const char *msg)
771 {
772           void *p = malloc(size);
773           if (p == NULL)
774                     logbad(1,"malloc(%lu) failed in %s", (u_long)size, msg);
775           return p;
776 }
777 
778 
779 /* get a random instant in an interval
780  */
781 void
intvl_random(struct timeval * tp,u_long lo,u_long hi)782 intvl_random(struct timeval *tp,        /* put value here */
783                u_long lo,                         /* value is after this second */
784                u_long hi)                         /* and before this */
785 {
786           tp->tv_sec = (time_t)(hi == lo
787                                     ? lo
788                                     : (lo + random() % ((hi - lo))));
789           tp->tv_usec = random() % 1000000;
790 }
791 
792 
793 void
timevaladd(struct timeval * t1,struct timeval * t2)794 timevaladd(struct timeval *t1,
795              struct timeval *t2)
796 {
797 
798           t1->tv_sec += t2->tv_sec;
799           if ((t1->tv_usec += t2->tv_usec) >= 1000000) {
800                     t1->tv_sec++;
801                     t1->tv_usec -= 1000000;
802           }
803 }
804 
805 
806 /* t1 = t2 - t3
807  */
808 static void
timevalsub(struct timeval * t1,struct timeval * t2,struct timeval * t3)809 timevalsub(struct timeval *t1,
810              struct timeval *t2,
811              struct timeval *t3)
812 {
813           t1->tv_sec = t2->tv_sec - t3->tv_sec;
814           if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) {
815                     t1->tv_sec--;
816                     t1->tv_usec += 1000000;
817           }
818 }
819 
820 
821 /* put a message into the system log
822  */
823 void
msglog(const char * p,...)824 msglog(const char *p, ...)
825 {
826           va_list args;
827 
828           trace_flush();
829 
830           va_start(args, p);
831           vsyslog(LOG_ERR, p, args);
832 
833           if (ftrace != 0) {
834                     if (ftrace == stdout)
835                               fputs("routed: ", ftrace);
836                     vfprintf(ftrace, p, args);
837                     fputc('\n', ftrace);
838           }
839 }
840 
841 
842 /* Put a message about a bad system into the system log if
843  * we have not complained about it recently.
844  *
845  * It is desirable to complain about all bad systems, but not too often.
846  * In the worst case, it is not practical to keep track of all bad systems.
847  * For example, there can be many systems with the wrong password.
848  */
849 void
msglim(struct msg_limit * lim,naddr addr,const char * p,...)850 msglim(struct msg_limit *lim, naddr addr, const char *p, ...)
851 {
852           va_list args;
853           int i;
854           struct msg_sub *ms1, *ms;
855           const char *p1;
856 
857           va_start(args, p);
858 
859           /* look for the oldest slot in the table
860            * or the slot for the bad router.
861            */
862           ms = ms1 = lim->subs;
863           for (i = MSG_SUBJECT_N; ; i--, ms1++) {
864                     if (i == 0) {
865                               /* Reuse a slot at most once every 10 minutes.
866                                */
867                               if (lim->reuse > now.tv_sec) {
868                                         ms = NULL;
869                               } else {
870                                         ms = ms1;
871                                         lim->reuse = now.tv_sec + 10*60;
872                               }
873                               break;
874                     }
875                     if (ms->addr == addr) {
876                               /* Repeat a complaint about a given system at
877                                * most once an hour.
878                                */
879                               if (ms->until > now.tv_sec)
880                                         ms = NULL;
881                               break;
882                     }
883                     if (ms->until < ms1->until)
884                               ms = ms1;
885           }
886           if (ms != NULL) {
887                     ms->addr = addr;
888                     ms->until = now.tv_sec + 60*60;         /* 60 minutes */
889 
890                     trace_flush();
891                     for (p1 = p; *p1 == ' '; p1++)
892                               continue;
893                     vsyslog(LOG_ERR, p1, args);
894           }
895 
896           /* always display the message if tracing */
897           if (ftrace != 0) {
898                     vfprintf(ftrace, p, args);
899                     fputc('\n', ftrace);
900           }
901 }
902 
903 
904 void
logbad(int dump,const char * p,...)905 logbad(int dump, const char *p, ...)
906 {
907           va_list args;
908 
909           trace_flush();
910 
911           va_start(args, p);
912           vsyslog(LOG_ERR, p, args);
913 
914           fputs("routed: ", stderr);
915           vfprintf(stderr, p, args);
916           fputs("; giving up\n",stderr);
917           fflush(stderr);
918 
919           if (dump)
920                     abort();
921           exit(1);
922 }
923