Merge branch 'vendor/AWK'
[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.4 2007/05/18 17:05:12 dillon 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, SHUT_RD); /* 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, NULL, NULL, NULL) < 0) {
244                         if(errno == EINTR)
245                                 continue;
246                         perror("during select");
247                         exit(1);
248                 }
249
250                 if(FD_ISSET(ripsock, &fdvar))
251                         process(ripsock, RIP_PKT);
252
253                 if(dosap && FD_ISSET(sapsock, &fdvar))
254                         process(sapsock, SAP_PKT);
255
256                 ttime = time(NULL);
257                 if (ttime > (lastbcast + TIMER_RATE + (TIMER_RATE * 2 / 3))) {
258                         dobcast = 1;
259                         syslog(LOG_ERR, "Missed alarm");
260                 }
261         }
262 }
263
264 void
265 process(int fd, int pkt_type)
266 {
267         struct sockaddr from;
268         int fromlen = sizeof (from), cc, omask;
269         struct ipx *ipxdp = (struct ipx *)packet;
270
271         cc = recvfrom(fd, packet, sizeof (packet), 0, &from, &fromlen);
272         if (cc <= 0) {
273                 if (cc < 0 && errno != EINTR)
274                         syslog(LOG_ERR, "recvfrom: %m");
275                 return;
276         }
277         if (tracepackets > 1 && ftrace) {
278             fprintf(ftrace,"rcv %d bytes on %s ", 
279                     cc, ipxdp_ntoa(&ipxdp->ipx_dna));
280             fprintf(ftrace," from %s\n", ipxdp_ntoa(&ipxdp->ipx_sna));
281         }
282         
283         if (noteremoterequests && 
284             !ipx_neteqnn(ipxdp->ipx_sna.x_net, ipx_zeronet) &&
285             !ipx_neteq(ipxdp->ipx_sna, ipxdp->ipx_dna))
286         {
287                 syslog(LOG_ERR,
288                        "net of interface (%s) != net on ether (%s)!\n",
289                        ipxdp_nettoa(ipxdp->ipx_dna.x_net),
290                        ipxdp_nettoa(ipxdp->ipx_sna.x_net));
291         }
292                         
293         /* We get the IPX header in front of the RIF packet*/
294         cc -= sizeof (struct ipx);
295 #define mask(s) (1<<((s)-1))
296         omask = sigblock(mask(SIGALRM));
297         switch(pkt_type) {
298                 case SAP_PKT: sap_input(&from, cc);
299                                 break;
300                 case RIP_PKT: rip_input(&from, cc);
301                                 break;
302         }
303         sigsetmask(omask);
304 }
305
306 int
307 getsocket(int type, int proto, struct sockaddr_ipx *sipx)
308 {
309         int domain = sipx->sipx_family;
310         int retry, s, on = 1;
311
312         retry = 1;
313         while ((s = socket(domain, type, proto)) < 0 && retry) {
314                 syslog(LOG_ERR, "socket: %m");
315                 sleep(5 * retry);
316                 retry <<= 1;
317         }
318         if (retry == 0)
319                 return (-1);
320         while (bind(s, (struct sockaddr *)sipx, sizeof (*sipx)) < 0 && retry) {
321                 syslog(LOG_ERR, "bind: %m");
322                 sleep(5 * retry);
323                 retry <<= 1;
324         }
325         if (retry == 0)
326                 return (-1);
327         if (domain==AF_IPX) {
328                 struct ipx ipxdp;
329                 if (setsockopt(s, 0, SO_HEADERS_ON_INPUT, &on, sizeof(on))) {
330                         syslog(LOG_ERR, "setsockopt SEE HEADERS: %m");
331                         exit(1);
332                 }
333                 if (ntohs(sipx->sipx_addr.x_port) == IPXPORT_RIP)
334                         ipxdp.ipx_pt = IPXPROTO_RI;
335                 else if (ntohs(sipx->sipx_addr.x_port) == IPXPORT_SAP)
336 #ifdef IPXPROTO_SAP
337                         ipxdp.ipx_pt = IPXPROTO_SAP;
338 #else
339                         ipxdp.ipx_pt = IPXPROTO_PXP;
340 #endif
341                 else {
342                         syslog(LOG_ERR, "port should be either RIP or SAP");
343                         exit(1);
344                 }
345                 if (setsockopt(s, 0, SO_DEFAULT_HEADERS, &ipxdp, sizeof(ipxdp))) {
346                         syslog(LOG_ERR, "setsockopt SET HEADER: %m");
347                         exit(1);
348                 }
349         }
350         if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
351                 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
352                 exit(1);
353         }
354         return (s);
355 }
356
357 /*
358  * Fork and exit on EMT-- for profiling.
359  */
360 void
361 fkexit(void)
362 {
363         if (fork() == 0)
364                 exit(0);
365 }
366
367 void
368 catchtimer(void)
369 {
370         dobcast = 1;
371 }
372
373 void
374 getinfo(void)
375 {
376         FILE *fh;
377
378         fh = fopen("/var/log/ipxrouted.dmp", "a");
379         if(fh == NULL)
380                 return;
381
382         dumpriptable(fh);
383         dumpsaptable(fh, sap_head);
384
385         fclose(fh);
386 }
387