rc.d: Add ipfw3 rc script
[dragonfly.git] / sbin / routed / main.c
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
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_ODELAY, 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
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
529 sigterm(int sig)
530 {
531         stopint = sig;
532         signal(sig, SIG_DFL);   /* catch it only once */
533 }
534
535
536 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
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 */
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 #ifdef _HAVE_SIN_LEN
628         in.sin_len = sizeof(in);
629 #endif
630         in.sin_family = AF_INET;
631         in.sin_port = htons(RIP_PORT);
632         in.sin_addr.s_addr = addr;
633         if (bind(s, (struct sockaddr *)&in, sizeof(in)) < 0) {
634                 if (serious)
635                         BADERR(errno != EADDRINUSE, "bind(rip_sock)");
636                 return -1;
637         }
638         fix_sock(s,"rip_sock");
639
640         ttl = 1;
641         if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
642                        &ttl, sizeof(ttl)) < 0)
643                 DBGERR(1,"rip_sock setsockopt(IP_MULTICAST_TTL)");
644
645         return s;
646 }
647
648
649 /* turn off main RIP socket */
650 void
651 rip_off(void)
652 {
653         struct interface *ifp;
654         naddr addr;
655
656
657         if (rip_sock >= 0 && !mhome) {
658                 trace_act("turn off RIP");
659
660                 close(rip_sock);
661                 rip_sock = -1;
662
663                 /* get non-broadcast sockets to listen to queries.
664                  */
665                 for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
666                         if (ifp->int_state & IS_REMOTE)
667                                 continue;
668                         if (ifp->int_rip_sock < 0) {
669                                 addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
670                                         ? ifp->int_dstaddr
671                                         : ifp->int_addr);
672                                 ifp->int_rip_sock = get_rip_sock(addr, 0);
673                         }
674                 }
675
676                 fix_select();
677
678                 age(0);
679         }
680 }
681
682
683 /* turn on RIP multicast input via an interface
684  */
685 static void
686 rip_mcast_on(struct interface *ifp)
687 {
688         struct ip_mreq m;
689
690         if (!IS_RIP_IN_OFF(ifp->int_state)
691             && (ifp->int_if_flags & IFF_MULTICAST)
692 #ifdef MCAST_PPP_BUG
693             && !(ifp->int_if_flags & IFF_POINTOPOINT)
694 #endif
695             && !(ifp->int_state & IS_ALIAS)) {
696                 m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
697                 m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
698                                           ? ifp->int_dstaddr
699                                           : ifp->int_addr);
700                 if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP,
701                                &m, sizeof(m)) < 0)
702                         LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)");
703         }
704 }
705
706
707 /* Prepare socket used for RIP.
708  */
709 void
710 rip_on(struct interface *ifp)
711 {
712         /* If the main RIP socket is already alive, only start receiving
713          * multicasts for this interface.
714          */
715         if (rip_sock >= 0) {
716                 if (ifp != NULL)
717                         rip_mcast_on(ifp);
718                 return;
719         }
720
721         /* If the main RIP socket is off and it makes sense to turn it on,
722          * then turn it on for all of the interfaces.
723          * It makes sense if either router discovery is off, or if
724          * router discover is on and at most one interface is doing RIP.
725          */
726         if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) {
727                 trace_act("turn on RIP");
728
729                 /* Close all of the query sockets so that we can open
730                  * the main socket.  SO_REUSEPORT is not a solution,
731                  * since that would let two daemons bind to the broadcast
732                  * socket.
733                  */
734                 for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
735                         if (ifp->int_rip_sock >= 0) {
736                                 close(ifp->int_rip_sock);
737                                 ifp->int_rip_sock = -1;
738                         }
739                 }
740
741                 rip_sock = get_rip_sock(INADDR_ANY, 1);
742                 rip_sock_mcast = NULL;
743
744                 /* Do not advertise anything until we have heard something
745                  */
746                 if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME)
747                         next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME;
748
749                 for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
750                         ifp->int_query_time = NEVER;
751                         rip_mcast_on(ifp);
752                 }
753                 ifinit_timer.tv_sec = now.tv_sec;
754
755         } else if (ifp != NULL
756                    && !(ifp->int_state & IS_REMOTE)
757                    && ifp->int_rip_sock < 0) {
758                 /* RIP is off, so ensure there are sockets on which
759                  * to listen for queries.
760                  */
761                 ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0);
762         }
763
764         fix_select();
765 }
766
767
768 /* die if malloc(3) fails
769  */
770 void *
771 rtmalloc(size_t size,
772          const char *msg)
773 {
774         void *p = malloc(size);
775         if (p == NULL)
776                 logbad(1,"malloc(%lu) failed in %s", (u_long)size, msg);
777         return p;
778 }
779
780
781 /* get a random instant in an interval
782  */
783 void
784 intvl_random(struct timeval *tp,        /* put value here */
785              u_long lo,                 /* value is after this second */
786              u_long hi)                 /* and before this */
787 {
788         tp->tv_sec = (time_t)(hi == lo
789                               ? lo
790                               : (lo + random() % ((hi - lo))));
791         tp->tv_usec = random() % 1000000;
792 }
793
794
795 void
796 timevaladd(struct timeval *t1,
797            struct timeval *t2)
798 {
799
800         t1->tv_sec += t2->tv_sec;
801         if ((t1->tv_usec += t2->tv_usec) >= 1000000) {
802                 t1->tv_sec++;
803                 t1->tv_usec -= 1000000;
804         }
805 }
806
807
808 /* t1 = t2 - t3
809  */
810 static void
811 timevalsub(struct timeval *t1,
812            struct timeval *t2,
813            struct timeval *t3)
814 {
815         t1->tv_sec = t2->tv_sec - t3->tv_sec;
816         if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) {
817                 t1->tv_sec--;
818                 t1->tv_usec += 1000000;
819         }
820 }
821
822
823 /* put a message into the system log
824  */
825 void
826 msglog(const char *p, ...)
827 {
828         va_list args;
829
830         trace_flush();
831
832         va_start(args, p);
833         vsyslog(LOG_ERR, p, args);
834
835         if (ftrace != 0) {
836                 if (ftrace == stdout)
837                         fputs("routed: ", ftrace);
838                 vfprintf(ftrace, p, args);
839                 fputc('\n', ftrace);
840         }
841 }
842
843
844 /* Put a message about a bad system into the system log if
845  * we have not complained about it recently.
846  *
847  * It is desirable to complain about all bad systems, but not too often.
848  * In the worst case, it is not practical to keep track of all bad systems.
849  * For example, there can be many systems with the wrong password.
850  */
851 void
852 msglim(struct msg_limit *lim, naddr addr, const char *p, ...)
853 {
854         va_list args;
855         int i;
856         struct msg_sub *ms1, *ms;
857         const char *p1;
858
859         va_start(args, p);
860
861         /* look for the oldest slot in the table
862          * or the slot for the bad router.
863          */
864         ms = ms1 = lim->subs;
865         for (i = MSG_SUBJECT_N; ; i--, ms1++) {
866                 if (i == 0) {
867                         /* Reuse a slot at most once every 10 minutes.
868                          */
869                         if (lim->reuse > now.tv_sec) {
870                                 ms = NULL;
871                         } else {
872                                 ms = ms1;
873                                 lim->reuse = now.tv_sec + 10*60;
874                         }
875                         break;
876                 }
877                 if (ms->addr == addr) {
878                         /* Repeat a complaint about a given system at
879                          * most once an hour.
880                          */
881                         if (ms->until > now.tv_sec)
882                                 ms = NULL;
883                         break;
884                 }
885                 if (ms->until < ms1->until)
886                         ms = ms1;
887         }
888         if (ms != NULL) {
889                 ms->addr = addr;
890                 ms->until = now.tv_sec + 60*60; /* 60 minutes */
891
892                 trace_flush();
893                 for (p1 = p; *p1 == ' '; p1++)
894                         continue;
895                 vsyslog(LOG_ERR, p1, args);
896         }
897
898         /* always display the message if tracing */
899         if (ftrace != 0) {
900                 vfprintf(ftrace, p, args);
901                 fputc('\n', ftrace);
902         }
903 }
904
905
906 void
907 logbad(int dump, const char *p, ...)
908 {
909         va_list args;
910
911         trace_flush();
912
913         va_start(args, p);
914         vsyslog(LOG_ERR, p, args);
915
916         fputs("routed: ", stderr);
917         vfprintf(stderr, p, args);
918         fputs("; giving up\n",stderr);
919         fflush(stderr);
920
921         if (dump)
922                 abort();
923         exit(1);
924 }