main.c revision 122760
160786Sps/*
260786Sps * Copyright (c) 1985, 1993
360786Sps *	The Regents of the University of California.  All rights reserved.
460786Sps *
560786Sps * Copyright (c) 1995 John Hay.  All rights reserved.
660786Sps *
789019Sps * This file includes significant work done at Cornell University by
860786Sps * Bill Nesheim.  That work included by permission.
960786Sps *
10170256Sdelphij * Redistribution and use in source and binary forms, with or without
11170256Sdelphij * modification, are permitted provided that the following conditions
1260786Sps * are met:
1360786Sps * 1. Redistributions of source code must retain the above copyright
1460786Sps *    notice, this list of conditions and the following disclaimer.
15195941Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
16195941Sdelphij *    notice, this list of conditions and the following disclaimer in the
17195941Sdelphij *    documentation and/or other materials provided with the distribution.
18195941Sdelphij * 3. All advertising materials mentioning features or use of this software
19195941Sdelphij *    must display the following acknowledgement:
20195941Sdelphij *	This product includes software developed by the University of
21195941Sdelphij *	California, Berkeley and its contributors.
22195941Sdelphij * 4. Neither the name of the University nor the names of its contributors
23195941Sdelphij *    may be used to endorse or promote products derived from this software
24195941Sdelphij *    without specific prior written permission.
25195941Sdelphij *
26195941Sdelphij * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27191930Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2860786Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29191930Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30191930Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31191930Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32191930Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33191930Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34191930Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35191930Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36191930Sdelphij * SUCH DAMAGE.
37191930Sdelphij *
38191930Sdelphij * $FreeBSD: head/usr.sbin/IPXrouted/main.c 122760 2003-11-15 17:10:56Z trhodes $
39191930Sdelphij */
40191930Sdelphij
41191930Sdelphij#ifndef lint
42191930Sdelphijstatic const char copyright[] =
43191930Sdelphij"@(#) Copyright (c) 1985, 1993\n\
44191930Sdelphij	The Regents of the University of California.  All rights reserved.\n";
45191930Sdelphij#endif /* not lint */
46191930Sdelphij
47191930Sdelphij#ifndef lint
48191930Sdelphijstatic const char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/5/93";
49191930Sdelphij#endif /* not lint */
50191930Sdelphij
51191930Sdelphij/*
52191930Sdelphij * IPX Routing Information Protocol Daemon
53191930Sdelphij */
54191930Sdelphij#include "defs.h"
55191930Sdelphij#include <sys/time.h>
56191930Sdelphij
57191930Sdelphij#include <net/if.h>
58191930Sdelphij
59191930Sdelphij#include <errno.h>
60191930Sdelphij#include <nlist.h>
61191930Sdelphij#include <signal.h>
62191930Sdelphij#include <paths.h>
63191930Sdelphij#include <stdlib.h>
64191930Sdelphij#include <unistd.h>
65191930Sdelphij
66191930Sdelphij#define SAP_PKT		0
67191930Sdelphij#define RIP_PKT		1
68191930Sdelphij
69191930Sdelphijstruct	sockaddr_ipx addr;	/* Daemon's Address */
70191930Sdelphijint	ripsock;		/* RIP Socket to listen on */
71191930Sdelphijint	sapsock;		/* SAP Socket to listen on */
72191930Sdelphijint	kmem;
73191930Sdelphijint	install;		/* if 1 call kernel */
74191930Sdelphijint	lookforinterfaces;	/* if 1 probe kernel for new up interfaces */
75191930Sdelphijint	performnlist;		/* if 1 check if /kernel has changed */
76191930Sdelphijint	externalinterfaces;	/* # of remote and local interfaces */
77191930Sdelphijint	timeval;		/* local idea of time */
78191930Sdelphijint	noteremoterequests;	/* squawk on requests from non-local nets */
79191930Sdelphijint	r;			/* Routing socket to install updates with */
80191930Sdelphijstruct	sockaddr_ipx ipx_netmask;	/* Used in installing routes */
81191930Sdelphij
82191930Sdelphijchar	packet[MAXRXPACKETSIZE+1];
83191930Sdelphij
84173932Sdelphijchar	**argv0;
85173682Sdelphij
86173682Sdelphijint	supplier = -1;		/* process should supply updates */
87173682Sdelphijint	dosap = 1;		/* By default do SAP services. */
88173682Sdelphijint	dobcast = 1;		/* A RIP/SAP broadcast is needed. */
89173682Sdelphijtime_t	lastbcast;		/* Time of last RIP/SAP broadcast */
90173682Sdelphij
91173682Sdelphijstruct	rip *msg = (struct rip *) &packet[sizeof (struct ipx)];
92173682Sdelphijstruct	sap_packet *sap_msg =
93173682Sdelphij		(struct sap_packet *) &packet[sizeof (struct ipx)];
94173682Sdelphijvoid	hup(), fkexit(), timer();
95172597Sdelphijvoid	process(int fd, int pkt_type);
96172468Sdelphijint	getsocket(int type, int proto, struct sockaddr_ipx *sipx);
97172468Sdelphijvoid	getinfo();
98172468Sdelphijvoid	catchtimer();
99172468Sdelphij
100172468Sdelphijint
101172468Sdelphijmain(argc, argv)
102172468Sdelphij	int argc;
103172468Sdelphij	char *argv[];
104172468Sdelphij{
105172597Sdelphij	int nfds;
106172597Sdelphij	fd_set fdvar;
107172468Sdelphij	time_t ttime;
108172468Sdelphij	struct itimerval tval;
109170964Sdelphij
110170256Sdelphij	argv0 = argv;
111170256Sdelphij	argv++, argc--;
112170256Sdelphij	while (argc > 0 && **argv == '-') {
113170256Sdelphij		if (strcmp(*argv, "-s") == 0) {
114170256Sdelphij			supplier = 1;
115170256Sdelphij			argv++, argc--;
116170256Sdelphij			continue;
117170256Sdelphij		}
118170256Sdelphij		if (strcmp(*argv, "-q") == 0) {
119170256Sdelphij			supplier = 0;
120170256Sdelphij			argv++, argc--;
121170256Sdelphij			continue;
122170256Sdelphij		}
123170256Sdelphij		if (strcmp(*argv, "-R") == 0) {
124170256Sdelphij			noteremoterequests++;
125170256Sdelphij			argv++, argc--;
126170256Sdelphij			continue;
127170256Sdelphij		}
128170256Sdelphij		if (strcmp(*argv, "-S") == 0) {
129170256Sdelphij			dosap = 0;
130170256Sdelphij			argv++, argc--;
131170256Sdelphij			continue;
132170256Sdelphij		}
133170256Sdelphij		if (strcmp(*argv, "-t") == 0) {
134170256Sdelphij			tracepackets++;
135170256Sdelphij			argv++, argc--;
136170256Sdelphij			ftrace = stderr;
137170256Sdelphij			tracing = 1;
138170256Sdelphij			continue;
139170256Sdelphij		}
140170256Sdelphij		if (strcmp(*argv, "-g") == 0) {
141170256Sdelphij			gateway = 1;
142170256Sdelphij			argv++, argc--;
143170256Sdelphij			continue;
144170256Sdelphij		}
145170256Sdelphij		if (strcmp(*argv, "-l") == 0) {
146170256Sdelphij			gateway = -1;
147170256Sdelphij			argv++, argc--;
148170256Sdelphij			continue;
149170256Sdelphij		}
150170256Sdelphij		if (strcmp(*argv, "-N") == 0) {
151170256Sdelphij			dognreply = 0;
152170256Sdelphij			argv++, argc--;
153170256Sdelphij			continue;
154170256Sdelphij		}
155170256Sdelphij		fprintf(stderr,
156161475Sdelphij			"usage: ipxrouted [ -s ] [ -q ] [ -t ] [ -g ] [ -l ] [ -N ]\n");
157161475Sdelphij		exit(1);
158161475Sdelphij	}
159161475Sdelphij
160161475Sdelphij
161161475Sdelphij#ifndef DEBUG
162161475Sdelphij	if (!tracepackets)
163161475Sdelphij		daemon(0, 0);
164161475Sdelphij#endif
165161475Sdelphij	openlog("IPXrouted", LOG_PID, LOG_DAEMON);
166161475Sdelphij
167161475Sdelphij	addr.sipx_family = AF_IPX;
168161475Sdelphij	addr.sipx_len = sizeof(addr);
169161475Sdelphij	addr.sipx_port = htons(IPXPORT_RIP);
170161475Sdelphij	ipx_anynet.s_net[0] = ipx_anynet.s_net[1] = -1;
171161475Sdelphij	ipx_netmask.sipx_addr.x_net = ipx_anynet;
172161475Sdelphij	ipx_netmask.sipx_len = 6;
173161475Sdelphij	ipx_netmask.sipx_family = AF_IPX;
174161475Sdelphij	r = socket(AF_ROUTE, SOCK_RAW, 0);
175161475Sdelphij	/* later, get smart about lookingforinterfaces */
176161475Sdelphij	if (r)
177161475Sdelphij		shutdown(r, 0); /* for now, don't want reponses */
178161475Sdelphij	else {
179161475Sdelphij		fprintf(stderr, "IPXrouted: no routing socket\n");
180161475Sdelphij		exit(1);
181161475Sdelphij	}
182161475Sdelphij	ripsock = getsocket(SOCK_DGRAM, 0, &addr);
183161475Sdelphij	if (ripsock < 0)
184161475Sdelphij		exit(1);
185161475Sdelphij
186161475Sdelphij	if (dosap) {
187161475Sdelphij		addr.sipx_port = htons(IPXPORT_SAP);
188161475Sdelphij		sapsock = getsocket(SOCK_DGRAM, 0, &addr);
189161475Sdelphij		if (sapsock < 0)
190161475Sdelphij			exit(1);
191161475Sdelphij	} else
192161475Sdelphij		sapsock = -1;
193161475Sdelphij
194161475Sdelphij	/*
195161475Sdelphij	 * Any extra argument is considered
196161475Sdelphij	 * a tracing log file.
197161475Sdelphij	 */
198161475Sdelphij	if (argc > 0)
199161475Sdelphij		traceon(*argv);
200161475Sdelphij	/*
201161475Sdelphij	 * Collect an initial view of the world by
202161475Sdelphij	 * snooping in the kernel.  Then, send a request packet on all
203161475Sdelphij	 * directly connected networks to find out what
204161475Sdelphij	 * everyone else thinks.
205161475Sdelphij	 */
206161475Sdelphij	rtinit();
207161475Sdelphij	sapinit();
208161475Sdelphij	ifinit();
209161475Sdelphij	if (supplier < 0)
210161475Sdelphij		supplier = 0;
211161475Sdelphij	/* request the state of the world */
212128345Stjr	msg->rip_cmd = htons(RIPCMD_REQUEST);
21389019Sps	msg->rip_nets[0].rip_dst = ipx_anynet;
214128345Stjr	msg->rip_nets[0].rip_metric =  htons(HOPCNT_INFINITY);
215128345Stjr	msg->rip_nets[0].rip_ticks =  htons(-1);
216128345Stjr	toall(sndmsg, NULL, 0);
217128345Stjr
218128345Stjr	if (dosap) {
219128345Stjr		sap_msg->sap_cmd = htons(SAP_REQ);
220128345Stjr		sap_msg->sap[0].ServType = htons(SAP_WILDCARD);
221128345Stjr		toall(sapsndmsg, NULL, 0);
222128345Stjr	}
223128345Stjr
224128345Stjr	signal(SIGALRM, catchtimer);
225128345Stjr	signal(SIGHUP, hup);
226128345Stjr	signal(SIGINT, hup);
227128345Stjr	signal(SIGEMT, fkexit);
228128345Stjr	signal(SIGINFO, getinfo);
229128345Stjr
230128345Stjr	tval.it_interval.tv_sec = TIMER_RATE;
231128345Stjr	tval.it_interval.tv_usec = 0;
232128345Stjr	tval.it_value.tv_sec = TIMER_RATE;
233128345Stjr	tval.it_value.tv_usec = 0;
234128345Stjr	setitimer(ITIMER_REAL, &tval, NULL);
235128345Stjr
236128345Stjr	nfds = 1 + max(sapsock, ripsock);
237128345Stjr
238128345Stjr	for (;;) {
239128345Stjr		if (dobcast) {
240128345Stjr			dobcast = 0;
241128345Stjr			lastbcast = time(NULL);
242128345Stjr			timer();
243128345Stjr		}
244128345Stjr
24589019Sps		FD_ZERO(&fdvar);
24689019Sps		if (dosap) {
24789019Sps			FD_SET(sapsock, &fdvar);
24889019Sps		}
24989019Sps		FD_SET(ripsock, &fdvar);
25089019Sps
25189019Sps		if(select(nfds, &fdvar, (fd_set *)NULL, (fd_set *)NULL,
25289019Sps		   (struct timeval *)NULL) < 0) {
25389019Sps			if(errno == EINTR)
25489019Sps				continue;
25589019Sps			perror("during select");
25689019Sps			exit(1);
25789019Sps		}
25889019Sps
25989019Sps		if(FD_ISSET(ripsock, &fdvar))
26089019Sps			process(ripsock, RIP_PKT);
26189019Sps
26289019Sps		if(dosap && FD_ISSET(sapsock, &fdvar))
26389019Sps			process(sapsock, SAP_PKT);
26489019Sps
26589019Sps		ttime = time(NULL);
26689019Sps		if (ttime > (lastbcast + TIMER_RATE + (TIMER_RATE * 2 / 3))) {
26789019Sps			dobcast = 1;
26889019Sps			syslog(LOG_ERR, "Missed alarm");
26989019Sps		}
27089019Sps	}
271128345Stjr}
272128345Stjr
27389019Spsvoid
274128345Stjrprocess(fd, pkt_type)
275128345Stjr	int fd;
27689019Sps	int pkt_type;
27789019Sps{
27889019Sps	struct sockaddr from;
27989019Sps	int fromlen = sizeof (from), cc, omask;
28089019Sps	struct ipx *ipxdp = (struct ipx *)packet;
28189019Sps
28289019Sps	cc = recvfrom(fd, packet, sizeof (packet), 0, &from, &fromlen);
28389019Sps	if (cc <= 0) {
284128345Stjr		if (cc < 0 && errno != EINTR)
285128345Stjr			syslog(LOG_ERR, "recvfrom: %m");
28689019Sps		return;
28789019Sps	}
28889019Sps	if (tracepackets > 1 && ftrace) {
28989019Sps	    fprintf(ftrace,"rcv %d bytes on %s ",
29089019Sps		    cc, ipxdp_ntoa(&ipxdp->ipx_dna));
29189019Sps	    fprintf(ftrace," from %s\n", ipxdp_ntoa(&ipxdp->ipx_sna));
29263128Sps	}
29363128Sps
29463128Sps	if (noteremoterequests &&
29563128Sps	    !ipx_neteqnn(ipxdp->ipx_sna.x_net, ipx_zeronet) &&
29663128Sps	    !ipx_neteq(ipxdp->ipx_sna, ipxdp->ipx_dna))
29763128Sps	{
29863128Sps		syslog(LOG_ERR,
29963128Sps		       "net of interface (%s) != net on ether (%s)!\n",
30063128Sps		       ipxdp_nettoa(ipxdp->ipx_dna.x_net),
30163128Sps		       ipxdp_nettoa(ipxdp->ipx_sna.x_net));
30263128Sps	}
30363128Sps
30463128Sps	/* We get the IPX header in front of the RIF packet*/
30563128Sps	cc -= sizeof (struct ipx);
30660786Sps#define	mask(s)	(1<<((s)-1))
30760786Sps	omask = sigblock(mask(SIGALRM));
30860786Sps	switch(pkt_type) {
30960786Sps		case SAP_PKT: sap_input(&from, cc);
31060786Sps				break;
31160786Sps		case RIP_PKT: rip_input(&from, cc);
31260786Sps				break;
31360786Sps	}
31460786Sps	sigsetmask(omask);
31560786Sps}
31660786Sps
31760786Spsint
31860786Spsgetsocket(type, proto, sipx)
31960786Sps	int type, proto;
32060786Sps	struct sockaddr_ipx *sipx;
32160786Sps{
32260786Sps	int domain = sipx->sipx_family;
32360786Sps	int retry, s, on = 1;
32460786Sps
32560786Sps	retry = 1;
32660786Sps	while ((s = socket(domain, type, proto)) < 0 && retry) {
32760786Sps		syslog(LOG_ERR, "socket: %m");
32860786Sps		sleep(5 * retry);
32960786Sps		retry <<= 1;
33060786Sps	}
33160786Sps	if (retry == 0)
33260786Sps		return (-1);
33360786Sps	while (bind(s, (struct sockaddr *)sipx, sizeof (*sipx)) < 0 && retry) {
33460786Sps		syslog(LOG_ERR, "bind: %m");
33560786Sps		sleep(5 * retry);
33660786Sps		retry <<= 1;
33760786Sps	}
33860786Sps	if (retry == 0)
33960786Sps		return (-1);
34060786Sps	if (domain==AF_IPX) {
34160786Sps		struct ipx ipxdp;
34260786Sps		if (setsockopt(s, 0, SO_HEADERS_ON_INPUT, &on, sizeof(on))) {
34360786Sps			syslog(LOG_ERR, "setsockopt SEE HEADERS: %m");
34460786Sps			exit(1);
34560786Sps		}
34660786Sps		if (ntohs(sipx->sipx_addr.x_port) == IPXPORT_RIP)
34760786Sps			ipxdp.ipx_pt = IPXPROTO_RI;
34860786Sps		else if (ntohs(sipx->sipx_addr.x_port) == IPXPORT_SAP)
34960786Sps#ifdef IPXPROTO_SAP
35060786Sps			ipxdp.ipx_pt = IPXPROTO_SAP;
35160786Sps#else
35260786Sps			ipxdp.ipx_pt = IPXPROTO_PXP;
35360786Sps#endif
35460786Sps		else {
35560786Sps			syslog(LOG_ERR, "port should be either RIP or SAP");
35660786Sps			exit(1);
35760786Sps		}
35860786Sps		if (setsockopt(s, 0, SO_DEFAULT_HEADERS, &ipxdp, sizeof(ipxdp))) {
35960786Sps			syslog(LOG_ERR, "setsockopt SET HEADER: %m");
36060786Sps			exit(1);
36160786Sps		}
36260786Sps	}
36360786Sps	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
36460786Sps		syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
36560786Sps		exit(1);
36660786Sps	}
36760786Sps	return (s);
36860786Sps}
36960786Sps
37060786Sps/*
37160786Sps * Fork and exit on EMT-- for profiling.
37260786Sps */
37360786Spsvoid
37460786Spsfkexit()
37560786Sps{
37660786Sps	if (fork() == 0)
37760786Sps		exit(0);
37860786Sps}
37960786Sps
38060786Spsvoid
38160786Spscatchtimer()
38260786Sps{
38360786Sps	dobcast = 1;
38460786Sps}
38560786Sps
38660786Spsvoid
38760786Spsgetinfo()
38860786Sps{
38960786Sps	FILE *fh;
39060786Sps
39160786Sps	fh = fopen("/var/log/ipxrouted.dmp", "a");
39260786Sps	if(fh == NULL)
39360786Sps		return;
39460786Sps
39560786Sps	dumpriptable(fh);
39660786Sps	dumpsaptable(fh, sap_head);
39760786Sps
39860786Sps	fclose(fh);
39960786Sps}
40060786Sps
40160786Sps