111820Sjulian/*
211820Sjulian * Copyright (c) 1985, 1993
311820Sjulian *	The Regents of the University of California.  All rights reserved.
411820Sjulian *
511820Sjulian * Copyright (c) 1995 John Hay.  All rights reserved.
611820Sjulian *
711820Sjulian * This file includes significant work done at Cornell University by
811820Sjulian * Bill Nesheim.  That work included by permission.
911820Sjulian *
1011820Sjulian * Redistribution and use in source and binary forms, with or without
1111820Sjulian * modification, are permitted provided that the following conditions
1211820Sjulian * are met:
1311820Sjulian * 1. Redistributions of source code must retain the above copyright
1411820Sjulian *    notice, this list of conditions and the following disclaimer.
1511820Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1611820Sjulian *    notice, this list of conditions and the following disclaimer in the
1711820Sjulian *    documentation and/or other materials provided with the distribution.
1811820Sjulian * 3. All advertising materials mentioning features or use of this software
1911820Sjulian *    must display the following acknowledgement:
2011820Sjulian *	This product includes software developed by the University of
2111820Sjulian *	California, Berkeley and its contributors.
2211820Sjulian * 4. Neither the name of the University nor the names of its contributors
2311820Sjulian *    may be used to endorse or promote products derived from this software
2411820Sjulian *    without specific prior written permission.
2511820Sjulian *
2611820Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2711820Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2811820Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2911820Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3011820Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3111820Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3211820Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3311820Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3411820Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3511820Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3611820Sjulian * SUCH DAMAGE.
3711820Sjulian *
3850479Speter * $FreeBSD$
3911820Sjulian */
4011820Sjulian
4111820Sjulian#ifndef lint
42122760Strhodesstatic const char copyright[] =
4311820Sjulian"@(#) Copyright (c) 1985, 1993\n\
4411820Sjulian	The Regents of the University of California.  All rights reserved.\n";
4511820Sjulian#endif /* not lint */
4611820Sjulian
4711820Sjulian#ifndef lint
48122760Strhodesstatic const char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/5/93";
4911820Sjulian#endif /* not lint */
5011820Sjulian
5111820Sjulian/*
5211820Sjulian * IPX Routing Information Protocol Daemon
5311820Sjulian */
5411820Sjulian#include "defs.h"
5511820Sjulian#include <sys/time.h>
5611820Sjulian
5711820Sjulian#include <net/if.h>
5811820Sjulian
5911820Sjulian#include <errno.h>
6011820Sjulian#include <nlist.h>
6111820Sjulian#include <signal.h>
6211820Sjulian#include <paths.h>
6311820Sjulian#include <stdlib.h>
6411820Sjulian#include <unistd.h>
6511820Sjulian
6611820Sjulian#define SAP_PKT		0
6711820Sjulian#define RIP_PKT		1
6811820Sjulian
6911820Sjulianstruct	sockaddr_ipx addr;	/* Daemon's Address */
7011820Sjulianint	ripsock;		/* RIP Socket to listen on */
7111820Sjulianint	sapsock;		/* SAP Socket to listen on */
7211820Sjulianint	kmem;
7311820Sjulianint	install;		/* if 1 call kernel */
7411820Sjulianint	lookforinterfaces;	/* if 1 probe kernel for new up interfaces */
7511820Sjulianint	performnlist;		/* if 1 check if /kernel has changed */
7611820Sjulianint	externalinterfaces;	/* # of remote and local interfaces */
7711820Sjulianint	timeval;		/* local idea of time */
7811820Sjulianint	noteremoterequests;	/* squawk on requests from non-local nets */
7911820Sjulianint	r;			/* Routing socket to install updates with */
8011820Sjulianstruct	sockaddr_ipx ipx_netmask;	/* Used in installing routes */
8111820Sjulian
8215248Sjhaychar	packet[MAXRXPACKETSIZE+1];
8311820Sjulian
8411820Sjulianchar	**argv0;
8511820Sjulian
8611820Sjulianint	supplier = -1;		/* process should supply updates */
8711820Sjulianint	dosap = 1;		/* By default do SAP services. */
8827244Sjhayint	dobcast = 1;		/* A RIP/SAP broadcast is needed. */
8927244Sjhaytime_t	lastbcast;		/* Time of last RIP/SAP broadcast */
9011820Sjulian
9111840Sjulianstruct	rip *msg = (struct rip *) &packet[sizeof (struct ipx)];
9211820Sjulianstruct	sap_packet *sap_msg =
9311840Sjulian		(struct sap_packet *) &packet[sizeof (struct ipx)];
9411820Sjulianvoid	hup(), fkexit(), timer();
9511820Sjulianvoid	process(int fd, int pkt_type);
9611820Sjulianint	getsocket(int type, int proto, struct sockaddr_ipx *sipx);
9715248Sjhayvoid	getinfo();
9827244Sjhayvoid	catchtimer();
9911820Sjulian
10011820Sjulianint
10111820Sjulianmain(argc, argv)
10211820Sjulian	int argc;
10311820Sjulian	char *argv[];
10411820Sjulian{
10511820Sjulian	int nfds;
10611820Sjulian	fd_set fdvar;
10727244Sjhay	time_t ttime;
10827244Sjhay	struct itimerval tval;
10911820Sjulian
11011820Sjulian	argv0 = argv;
11111820Sjulian	argv++, argc--;
11211820Sjulian	while (argc > 0 && **argv == '-') {
11311820Sjulian		if (strcmp(*argv, "-s") == 0) {
11411820Sjulian			supplier = 1;
11511820Sjulian			argv++, argc--;
11611820Sjulian			continue;
11711820Sjulian		}
11811820Sjulian		if (strcmp(*argv, "-q") == 0) {
11911820Sjulian			supplier = 0;
12011820Sjulian			argv++, argc--;
12111820Sjulian			continue;
12211820Sjulian		}
12311820Sjulian		if (strcmp(*argv, "-R") == 0) {
12411820Sjulian			noteremoterequests++;
12511820Sjulian			argv++, argc--;
12611820Sjulian			continue;
12711820Sjulian		}
12811820Sjulian		if (strcmp(*argv, "-S") == 0) {
12911820Sjulian			dosap = 0;
13011820Sjulian			argv++, argc--;
13111820Sjulian			continue;
13211820Sjulian		}
13311820Sjulian		if (strcmp(*argv, "-t") == 0) {
13411820Sjulian			tracepackets++;
13511820Sjulian			argv++, argc--;
13611820Sjulian			ftrace = stderr;
13711820Sjulian			tracing = 1;
13811820Sjulian			continue;
13911820Sjulian		}
14011820Sjulian		if (strcmp(*argv, "-g") == 0) {
14111820Sjulian			gateway = 1;
14211820Sjulian			argv++, argc--;
14311820Sjulian			continue;
14411820Sjulian		}
14511820Sjulian		if (strcmp(*argv, "-l") == 0) {
14611820Sjulian			gateway = -1;
14711820Sjulian			argv++, argc--;
14811820Sjulian			continue;
14911820Sjulian		}
15045988Sjhay		if (strcmp(*argv, "-N") == 0) {
15145988Sjhay			dognreply = 0;
15245988Sjhay			argv++, argc--;
15345988Sjhay			continue;
15445988Sjhay		}
15511820Sjulian		fprintf(stderr,
15645988Sjhay			"usage: ipxrouted [ -s ] [ -q ] [ -t ] [ -g ] [ -l ] [ -N ]\n");
15711820Sjulian		exit(1);
15811820Sjulian	}
15911820Sjulian
16011820Sjulian
16111820Sjulian#ifndef DEBUG
16211820Sjulian	if (!tracepackets)
16311820Sjulian		daemon(0, 0);
16411820Sjulian#endif
16511820Sjulian	openlog("IPXrouted", LOG_PID, LOG_DAEMON);
16611820Sjulian
16711820Sjulian	addr.sipx_family = AF_IPX;
16811820Sjulian	addr.sipx_len = sizeof(addr);
16911820Sjulian	addr.sipx_port = htons(IPXPORT_RIP);
17011820Sjulian	ipx_anynet.s_net[0] = ipx_anynet.s_net[1] = -1;
17111820Sjulian	ipx_netmask.sipx_addr.x_net = ipx_anynet;
17211820Sjulian	ipx_netmask.sipx_len = 6;
17311820Sjulian	ipx_netmask.sipx_family = AF_IPX;
17411820Sjulian	r = socket(AF_ROUTE, SOCK_RAW, 0);
17511820Sjulian	/* later, get smart about lookingforinterfaces */
17611820Sjulian	if (r)
177146076Sjmallett		shutdown(r, SHUT_RD); /* for now, don't want reponses */
17811820Sjulian	else {
17911820Sjulian		fprintf(stderr, "IPXrouted: no routing socket\n");
18011820Sjulian		exit(1);
18111820Sjulian	}
18211820Sjulian	ripsock = getsocket(SOCK_DGRAM, 0, &addr);
18311820Sjulian	if (ripsock < 0)
18411820Sjulian		exit(1);
18511820Sjulian
18611820Sjulian	if (dosap) {
18711820Sjulian		addr.sipx_port = htons(IPXPORT_SAP);
18811820Sjulian		sapsock = getsocket(SOCK_DGRAM, 0, &addr);
18911820Sjulian		if (sapsock < 0)
19011820Sjulian			exit(1);
19111820Sjulian	} else
19211820Sjulian		sapsock = -1;
19311820Sjulian
19411820Sjulian	/*
19511820Sjulian	 * Any extra argument is considered
19611820Sjulian	 * a tracing log file.
19711820Sjulian	 */
19811820Sjulian	if (argc > 0)
19911820Sjulian		traceon(*argv);
20011820Sjulian	/*
20111820Sjulian	 * Collect an initial view of the world by
20211820Sjulian	 * snooping in the kernel.  Then, send a request packet on all
20311820Sjulian	 * directly connected networks to find out what
20411820Sjulian	 * everyone else thinks.
20511820Sjulian	 */
20611820Sjulian	rtinit();
20711820Sjulian	sapinit();
20811820Sjulian	ifinit();
20911820Sjulian	if (supplier < 0)
21011820Sjulian		supplier = 0;
21111820Sjulian	/* request the state of the world */
21211820Sjulian	msg->rip_cmd = htons(RIPCMD_REQUEST);
21311820Sjulian	msg->rip_nets[0].rip_dst = ipx_anynet;
21411820Sjulian	msg->rip_nets[0].rip_metric =  htons(HOPCNT_INFINITY);
21511820Sjulian	msg->rip_nets[0].rip_ticks =  htons(-1);
21627244Sjhay	toall(sndmsg, NULL, 0);
21711820Sjulian
21811820Sjulian	if (dosap) {
21911820Sjulian		sap_msg->sap_cmd = htons(SAP_REQ);
22011820Sjulian		sap_msg->sap[0].ServType = htons(SAP_WILDCARD);
22127244Sjhay		toall(sapsndmsg, NULL, 0);
22211820Sjulian	}
22311820Sjulian
22427244Sjhay	signal(SIGALRM, catchtimer);
22511820Sjulian	signal(SIGHUP, hup);
22611820Sjulian	signal(SIGINT, hup);
22711820Sjulian	signal(SIGEMT, fkexit);
22815248Sjhay	signal(SIGINFO, getinfo);
22927244Sjhay
23027244Sjhay	tval.it_interval.tv_sec = TIMER_RATE;
23127244Sjhay	tval.it_interval.tv_usec = 0;
23227244Sjhay	tval.it_value.tv_sec = TIMER_RATE;
23327244Sjhay	tval.it_value.tv_usec = 0;
23427244Sjhay	setitimer(ITIMER_REAL, &tval, NULL);
23527244Sjhay
23611820Sjulian	nfds = 1 + max(sapsock, ripsock);
23711820Sjulian
23811820Sjulian	for (;;) {
23927244Sjhay		if (dobcast) {
24027244Sjhay			dobcast = 0;
24127244Sjhay			lastbcast = time(NULL);
24227244Sjhay			timer();
24327244Sjhay		}
24427244Sjhay
24511820Sjulian		FD_ZERO(&fdvar);
24611820Sjulian		if (dosap) {
24711820Sjulian			FD_SET(sapsock, &fdvar);
24811820Sjulian		}
24911820Sjulian		FD_SET(ripsock, &fdvar);
25011820Sjulian
25111820Sjulian		if(select(nfds, &fdvar, (fd_set *)NULL, (fd_set *)NULL,
25211820Sjulian		   (struct timeval *)NULL) < 0) {
25312692Sjulian			if(errno == EINTR)
25412692Sjulian				continue;
25512692Sjulian			perror("during select");
25612692Sjulian			exit(1);
25711820Sjulian		}
25811820Sjulian
25911820Sjulian		if(FD_ISSET(ripsock, &fdvar))
26011820Sjulian			process(ripsock, RIP_PKT);
26111820Sjulian
26211820Sjulian		if(dosap && FD_ISSET(sapsock, &fdvar))
26311820Sjulian			process(sapsock, SAP_PKT);
26427244Sjhay
26527244Sjhay		ttime = time(NULL);
26627244Sjhay		if (ttime > (lastbcast + TIMER_RATE + (TIMER_RATE * 2 / 3))) {
26727244Sjhay			dobcast = 1;
26827244Sjhay			syslog(LOG_ERR, "Missed alarm");
26927244Sjhay		}
27011820Sjulian	}
27111820Sjulian}
27211820Sjulian
27311820Sjulianvoid
27411820Sjulianprocess(fd, pkt_type)
27511820Sjulian	int fd;
27611820Sjulian	int pkt_type;
27711820Sjulian{
27811820Sjulian	struct sockaddr from;
279162492Skan	int  cc, omask;
280162492Skan	socklen_t fromlen = sizeof (from);
28111840Sjulian	struct ipx *ipxdp = (struct ipx *)packet;
28211820Sjulian
28311820Sjulian	cc = recvfrom(fd, packet, sizeof (packet), 0, &from, &fromlen);
28411820Sjulian	if (cc <= 0) {
28511820Sjulian		if (cc < 0 && errno != EINTR)
28611820Sjulian			syslog(LOG_ERR, "recvfrom: %m");
28711820Sjulian		return;
28811820Sjulian	}
28911820Sjulian	if (tracepackets > 1 && ftrace) {
29011820Sjulian	    fprintf(ftrace,"rcv %d bytes on %s ",
29111840Sjulian		    cc, ipxdp_ntoa(&ipxdp->ipx_dna));
29211840Sjulian	    fprintf(ftrace," from %s\n", ipxdp_ntoa(&ipxdp->ipx_sna));
29311820Sjulian	}
29411820Sjulian
29511820Sjulian	if (noteremoterequests &&
29611840Sjulian	    !ipx_neteqnn(ipxdp->ipx_sna.x_net, ipx_zeronet) &&
29711840Sjulian	    !ipx_neteq(ipxdp->ipx_sna, ipxdp->ipx_dna))
29811820Sjulian	{
29911820Sjulian		syslog(LOG_ERR,
30011820Sjulian		       "net of interface (%s) != net on ether (%s)!\n",
30111840Sjulian		       ipxdp_nettoa(ipxdp->ipx_dna.x_net),
30211840Sjulian		       ipxdp_nettoa(ipxdp->ipx_sna.x_net));
30311820Sjulian	}
30411820Sjulian
30511820Sjulian	/* We get the IPX header in front of the RIF packet*/
30611840Sjulian	cc -= sizeof (struct ipx);
30711820Sjulian#define	mask(s)	(1<<((s)-1))
30811820Sjulian	omask = sigblock(mask(SIGALRM));
30911820Sjulian	switch(pkt_type) {
31011820Sjulian		case SAP_PKT: sap_input(&from, cc);
31111820Sjulian				break;
31211820Sjulian		case RIP_PKT: rip_input(&from, cc);
31311820Sjulian				break;
31411820Sjulian	}
31511820Sjulian	sigsetmask(omask);
31611820Sjulian}
31711820Sjulian
31811820Sjulianint
31911820Sjuliangetsocket(type, proto, sipx)
32011820Sjulian	int type, proto;
32111820Sjulian	struct sockaddr_ipx *sipx;
32211820Sjulian{
32311820Sjulian	int domain = sipx->sipx_family;
32411820Sjulian	int retry, s, on = 1;
32511820Sjulian
32611820Sjulian	retry = 1;
32711820Sjulian	while ((s = socket(domain, type, proto)) < 0 && retry) {
32811820Sjulian		syslog(LOG_ERR, "socket: %m");
32911820Sjulian		sleep(5 * retry);
33011820Sjulian		retry <<= 1;
33111820Sjulian	}
33211820Sjulian	if (retry == 0)
33311820Sjulian		return (-1);
33411820Sjulian	while (bind(s, (struct sockaddr *)sipx, sizeof (*sipx)) < 0 && retry) {
33511820Sjulian		syslog(LOG_ERR, "bind: %m");
33611820Sjulian		sleep(5 * retry);
33711820Sjulian		retry <<= 1;
33811820Sjulian	}
33911820Sjulian	if (retry == 0)
34011820Sjulian		return (-1);
34111820Sjulian	if (domain==AF_IPX) {
34211840Sjulian		struct ipx ipxdp;
34311820Sjulian		if (setsockopt(s, 0, SO_HEADERS_ON_INPUT, &on, sizeof(on))) {
34411820Sjulian			syslog(LOG_ERR, "setsockopt SEE HEADERS: %m");
34511820Sjulian			exit(1);
34611820Sjulian		}
34711820Sjulian		if (ntohs(sipx->sipx_addr.x_port) == IPXPORT_RIP)
34811840Sjulian			ipxdp.ipx_pt = IPXPROTO_RI;
34911820Sjulian		else if (ntohs(sipx->sipx_addr.x_port) == IPXPORT_SAP)
35027244Sjhay#ifdef IPXPROTO_SAP
35111840Sjulian			ipxdp.ipx_pt = IPXPROTO_SAP;
35227244Sjhay#else
35327244Sjhay			ipxdp.ipx_pt = IPXPROTO_PXP;
35427244Sjhay#endif
35511820Sjulian		else {
35611820Sjulian			syslog(LOG_ERR, "port should be either RIP or SAP");
35711820Sjulian			exit(1);
35811820Sjulian		}
35911820Sjulian		if (setsockopt(s, 0, SO_DEFAULT_HEADERS, &ipxdp, sizeof(ipxdp))) {
36011820Sjulian			syslog(LOG_ERR, "setsockopt SET HEADER: %m");
36111820Sjulian			exit(1);
36211820Sjulian		}
36311820Sjulian	}
36411820Sjulian	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
36511820Sjulian		syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
36611820Sjulian		exit(1);
36711820Sjulian	}
36811820Sjulian	return (s);
36911820Sjulian}
37011820Sjulian
37111820Sjulian/*
37211820Sjulian * Fork and exit on EMT-- for profiling.
37311820Sjulian */
37411820Sjulianvoid
37511820Sjulianfkexit()
37611820Sjulian{
37711820Sjulian	if (fork() == 0)
37811820Sjulian		exit(0);
37911820Sjulian}
38015248Sjhay
38115248Sjhayvoid
38227244Sjhaycatchtimer()
38327244Sjhay{
38427244Sjhay	dobcast = 1;
38527244Sjhay}
38627244Sjhay
38727244Sjhayvoid
38815248Sjhaygetinfo()
38915248Sjhay{
39015248Sjhay	FILE *fh;
39115248Sjhay
39250306Sjhay	fh = fopen("/var/log/ipxrouted.dmp", "a");
39315248Sjhay	if(fh == NULL)
39415248Sjhay		return;
39515248Sjhay
39615248Sjhay	dumpriptable(fh);
39715248Sjhay	dumpsaptable(fh, sap_head);
39815248Sjhay
39915248Sjhay	fclose(fh);
40015248Sjhay}
40115248Sjhay
402