Correct BSD License clause numbering from 1-2-4 to 1-2-3.
[dragonfly.git] / usr.sbin / IPXrouted / main.c
1 /*
2  * Copyright (c) 1985, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Copyright (c) 1995 John Hay.  All rights reserved.
6  *
7  * This file includes significant work done at Cornell University by
8  * Bill Nesheim.  That work included by permission.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $FreeBSD: src/usr.sbin/IPXrouted/main.c,v 1.10 1999/08/28 01:15:03 peter Exp $
35  * $DragonFly: src/usr.sbin/IPXrouted/main.c,v 1.4 2007/05/18 17:05:12 dillon Exp $
36  *
37  * @(#) Copyright (c) 1985, 1993 The Regents of the University of California.  All rights reserved.
38  * @(#)main.c   8.1 (Berkeley) 6/5/93
39  */
40
41 /*
42  * IPX Routing Information Protocol Daemon
43  */
44 #include "defs.h"
45 #include <sys/time.h>
46
47 #include <net/if.h>
48
49 #include <errno.h>
50 #include <nlist.h>
51 #include <signal.h>
52 #include <paths.h>
53 #include <stdlib.h>
54 #include <unistd.h>
55
56 #define SAP_PKT         0
57 #define RIP_PKT         1
58
59 struct  sockaddr_ipx addr;      /* Daemon's Address */
60 int     ripsock;                /* RIP Socket to listen on */
61 int     sapsock;                /* SAP Socket to listen on */
62 int     kmem;
63 int     install;                /* if 1 call kernel */
64 int     lookforinterfaces;      /* if 1 probe kernel for new up interfaces */
65 int     performnlist;           /* if 1 check if /kernel has changed */
66 int     externalinterfaces;     /* # of remote and local interfaces */
67 int     timeval;                /* local idea of time */
68 int     noteremoterequests;     /* squawk on requests from non-local nets */
69 int     r;                      /* Routing socket to install updates with */
70 struct  sockaddr_ipx ipx_netmask;       /* Used in installing routes */
71
72 char    packet[MAXRXPACKETSIZE+1];
73
74 char    **argv0;
75
76 int     supplier = -1;          /* process should supply updates */
77 int     dosap = 1;              /* By default do SAP services. */
78 int     dobcast = 1;            /* A RIP/SAP broadcast is needed. */
79 time_t  lastbcast;              /* Time of last RIP/SAP broadcast */
80
81 struct  rip *msg = (struct rip *) &packet[sizeof (struct ipx)]; 
82 struct  sap_packet *sap_msg = 
83                 (struct sap_packet *) &packet[sizeof (struct ipx)]; 
84 void    hup(), fkexit(), timer();
85 void    process(int fd, int pkt_type);
86 int     getsocket(int type, int proto, struct sockaddr_ipx *sipx);
87 void    getinfo();
88 void    catchtimer();
89
90 int
91 main(int argc, char *argv[])
92 {
93         int nfds;
94         fd_set fdvar;
95         time_t ttime;
96         struct itimerval tval;
97
98         argv0 = argv;
99         argv++, argc--;
100         while (argc > 0 && **argv == '-') {
101                 if (strcmp(*argv, "-s") == 0) {
102                         supplier = 1;
103                         argv++, argc--;
104                         continue;
105                 }
106                 if (strcmp(*argv, "-q") == 0) {
107                         supplier = 0;
108                         argv++, argc--;
109                         continue;
110                 }
111                 if (strcmp(*argv, "-R") == 0) {
112                         noteremoterequests++;
113                         argv++, argc--;
114                         continue;
115                 }
116                 if (strcmp(*argv, "-S") == 0) {
117                         dosap = 0;
118                         argv++, argc--;
119                         continue;
120                 }
121                 if (strcmp(*argv, "-t") == 0) {
122                         tracepackets++;
123                         argv++, argc--;
124                         ftrace = stderr;
125                         tracing = 1; 
126                         continue;
127                 }
128                 if (strcmp(*argv, "-g") == 0) {
129                         gateway = 1;
130                         argv++, argc--;
131                         continue;
132                 }
133                 if (strcmp(*argv, "-l") == 0) {
134                         gateway = -1;
135                         argv++, argc--;
136                         continue;
137                 }
138                 if (strcmp(*argv, "-N") == 0) {
139                         dognreply = 0;
140                         argv++, argc--;
141                         continue;
142                 }
143                 fprintf(stderr,
144                         "usage: ipxrouted [ -s ] [ -q ] [ -t ] [ -g ] [ -l ] [ -N ]\n");
145                 exit(1);
146         }
147         
148         
149 #ifndef DEBUG
150         if (!tracepackets)
151                 daemon(0, 0);
152 #endif
153         openlog("IPXrouted", LOG_PID, LOG_DAEMON);
154
155         addr.sipx_family = AF_IPX;
156         addr.sipx_len = sizeof(addr);
157         addr.sipx_port = htons(IPXPORT_RIP);
158         ipx_anynet.s_net[0] = ipx_anynet.s_net[1] = -1;
159         ipx_netmask.sipx_addr.x_net = ipx_anynet;
160         ipx_netmask.sipx_len = 6;
161         ipx_netmask.sipx_family = AF_IPX;
162         r = socket(AF_ROUTE, SOCK_RAW, 0);
163         /* later, get smart about lookingforinterfaces */
164         if (r)
165                 shutdown(r, SHUT_RD); /* for now, don't want reponses */
166         else {
167                 fprintf(stderr, "IPXrouted: no routing socket\n");
168                 exit(1);
169         }
170         ripsock = getsocket(SOCK_DGRAM, 0, &addr);
171         if (ripsock < 0)
172                 exit(1);
173
174         if (dosap) {
175                 addr.sipx_port = htons(IPXPORT_SAP);
176                 sapsock = getsocket(SOCK_DGRAM, 0, &addr);
177                 if (sapsock < 0)
178                         exit(1);
179         } else
180                 sapsock = -1;
181
182         /*
183          * Any extra argument is considered
184          * a tracing log file.
185          */
186         if (argc > 0)
187                 traceon(*argv);
188         /*
189          * Collect an initial view of the world by
190          * snooping in the kernel.  Then, send a request packet on all
191          * directly connected networks to find out what
192          * everyone else thinks.
193          */
194         rtinit();
195         sapinit();
196         ifinit();
197         if (supplier < 0)
198                 supplier = 0;
199         /* request the state of the world */
200         msg->rip_cmd = htons(RIPCMD_REQUEST);
201         msg->rip_nets[0].rip_dst = ipx_anynet;
202         msg->rip_nets[0].rip_metric =  htons(HOPCNT_INFINITY);
203         msg->rip_nets[0].rip_ticks =  htons(-1);
204         toall(sndmsg, NULL, 0);
205
206         if (dosap) {
207                 sap_msg->sap_cmd = htons(SAP_REQ);
208                 sap_msg->sap[0].ServType = htons(SAP_WILDCARD);
209                 toall(sapsndmsg, NULL, 0);
210         }
211
212         signal(SIGALRM, catchtimer);
213         signal(SIGHUP, hup);
214         signal(SIGINT, hup);
215         signal(SIGEMT, fkexit);
216         signal(SIGINFO, getinfo);
217  
218         tval.it_interval.tv_sec = TIMER_RATE;
219         tval.it_interval.tv_usec = 0;
220         tval.it_value.tv_sec = TIMER_RATE;
221         tval.it_value.tv_usec = 0;
222         setitimer(ITIMER_REAL, &tval, NULL);
223
224         nfds = 1 + max(sapsock, ripsock);
225
226         for (;;) {
227                 if (dobcast) {
228                         dobcast = 0;
229                         lastbcast = time(NULL);
230                         timer();
231                 }
232
233                 FD_ZERO(&fdvar);
234                 if (dosap) {
235                         FD_SET(sapsock, &fdvar);
236                 }
237                 FD_SET(ripsock, &fdvar);
238
239                 if(select(nfds, &fdvar, NULL, NULL, NULL) < 0) {
240                         if(errno == EINTR)
241                                 continue;
242                         perror("during select");
243                         exit(1);
244                 }
245
246                 if(FD_ISSET(ripsock, &fdvar))
247                         process(ripsock, RIP_PKT);
248
249                 if(dosap && FD_ISSET(sapsock, &fdvar))
250                         process(sapsock, SAP_PKT);
251
252                 ttime = time(NULL);
253                 if (ttime > (lastbcast + TIMER_RATE + (TIMER_RATE * 2 / 3))) {
254                         dobcast = 1;
255                         syslog(LOG_ERR, "Missed alarm");
256                 }
257         }
258 }
259
260 void
261 process(int fd, int pkt_type)
262 {
263         struct sockaddr from;
264         int fromlen = sizeof (from), cc, omask;
265         struct ipx *ipxdp = (struct ipx *)packet;
266
267         cc = recvfrom(fd, packet, sizeof (packet), 0, &from, &fromlen);
268         if (cc <= 0) {
269                 if (cc < 0 && errno != EINTR)
270                         syslog(LOG_ERR, "recvfrom: %m");
271                 return;
272         }
273         if (tracepackets > 1 && ftrace) {
274             fprintf(ftrace,"rcv %d bytes on %s ", 
275                     cc, ipxdp_ntoa(&ipxdp->ipx_dna));
276             fprintf(ftrace," from %s\n", ipxdp_ntoa(&ipxdp->ipx_sna));
277         }
278         
279         if (noteremoterequests && 
280             !ipx_neteqnn(ipxdp->ipx_sna.x_net, ipx_zeronet) &&
281             !ipx_neteq(ipxdp->ipx_sna, ipxdp->ipx_dna))
282         {
283                 syslog(LOG_ERR,
284                        "net of interface (%s) != net on ether (%s)!\n",
285                        ipxdp_nettoa(ipxdp->ipx_dna.x_net),
286                        ipxdp_nettoa(ipxdp->ipx_sna.x_net));
287         }
288                         
289         /* We get the IPX header in front of the RIF packet*/
290         cc -= sizeof (struct ipx);
291 #define mask(s) (1<<((s)-1))
292         omask = sigblock(mask(SIGALRM));
293         switch(pkt_type) {
294                 case SAP_PKT: sap_input(&from, cc);
295                                 break;
296                 case RIP_PKT: rip_input(&from, cc);
297                                 break;
298         }
299         sigsetmask(omask);
300 }
301
302 int
303 getsocket(int type, int proto, struct sockaddr_ipx *sipx)
304 {
305         int domain = sipx->sipx_family;
306         int retry, s, on = 1;
307
308         retry = 1;
309         while ((s = socket(domain, type, proto)) < 0 && retry) {
310                 syslog(LOG_ERR, "socket: %m");
311                 sleep(5 * retry);
312                 retry <<= 1;
313         }
314         if (retry == 0)
315                 return (-1);
316         while (bind(s, (struct sockaddr *)sipx, sizeof (*sipx)) < 0 && retry) {
317                 syslog(LOG_ERR, "bind: %m");
318                 sleep(5 * retry);
319                 retry <<= 1;
320         }
321         if (retry == 0)
322                 return (-1);
323         if (domain==AF_IPX) {
324                 struct ipx ipxdp;
325                 if (setsockopt(s, 0, SO_HEADERS_ON_INPUT, &on, sizeof(on))) {
326                         syslog(LOG_ERR, "setsockopt SEE HEADERS: %m");
327                         exit(1);
328                 }
329                 if (ntohs(sipx->sipx_addr.x_port) == IPXPORT_RIP)
330                         ipxdp.ipx_pt = IPXPROTO_RI;
331                 else if (ntohs(sipx->sipx_addr.x_port) == IPXPORT_SAP)
332 #ifdef IPXPROTO_SAP
333                         ipxdp.ipx_pt = IPXPROTO_SAP;
334 #else
335                         ipxdp.ipx_pt = IPXPROTO_PXP;
336 #endif
337                 else {
338                         syslog(LOG_ERR, "port should be either RIP or SAP");
339                         exit(1);
340                 }
341                 if (setsockopt(s, 0, SO_DEFAULT_HEADERS, &ipxdp, sizeof(ipxdp))) {
342                         syslog(LOG_ERR, "setsockopt SET HEADER: %m");
343                         exit(1);
344                 }
345         }
346         if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
347                 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
348                 exit(1);
349         }
350         return (s);
351 }
352
353 /*
354  * Fork and exit on EMT-- for profiling.
355  */
356 void
357 fkexit(void)
358 {
359         if (fork() == 0)
360                 exit(0);
361 }
362
363 void
364 catchtimer(void)
365 {
366         dobcast = 1;
367 }
368
369 void
370 getinfo(void)
371 {
372         FILE *fh;
373
374         fh = fopen("/var/log/ipxrouted.dmp", "a");
375         if(fh == NULL)
376                 return;
377
378         dumpriptable(fh);
379         dumpsaptable(fh, sap_head);
380
381         fclose(fh);
382 }
383