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