Blame rdisc.c

Packit Service 6f2e62
/*
Packit Service 6f2e62
 * Rdisc (this program) was developed by Sun Microsystems, Inc. and is
Packit Service 6f2e62
 * provided for unrestricted use provided that this legend is included on
Packit Service 6f2e62
 * all tape media and as a part of the software program in whole or part.
Packit Service 6f2e62
 * Users may copy or modify Rdisc without charge, and they may freely
Packit Service 6f2e62
 * distribute it.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * RDISC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
Packit Service 6f2e62
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
Packit Service 6f2e62
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Rdisc is provided with no support and without any obligation on the
Packit Service 6f2e62
 * part of Sun Microsystems, Inc. to assist in its use, correction,
Packit Service 6f2e62
 * modification or enhancement.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
Packit Service 6f2e62
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY RDISC
Packit Service 6f2e62
 * OR ANY PART THEREOF.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
Packit Service 6f2e62
 * or profits or other special, indirect and consequential damages, even if
Packit Service 6f2e62
 * Sun has been advised of the possibility of such damages.
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Sun Microsystems, Inc.
Packit Service 6f2e62
 * 2550 Garcia Avenue
Packit Service 6f2e62
 * Mountain View, California  94043
Packit Service 6f2e62
 */
Packit Service 6f2e62
#include <stdio.h>
Packit Service 6f2e62
#include <errno.h>
Packit Service 6f2e62
#include <signal.h>
Packit Service 6f2e62
#include <unistd.h>
Packit Service 6f2e62
#include <stdlib.h>
Packit Service 6f2e62
#include <sys/types.h>
Packit Service 6f2e62
#include <sys/time.h>
Packit Service 6f2e62
/* Do not use "improved" glibc version! */
Packit Service 6f2e62
#include <linux/limits.h>
Packit Service 6f2e62
Packit Service 6f2e62
#include <sys/param.h>
Packit Service 6f2e62
#include <sys/socket.h>
Packit Service 6f2e62
#include <sys/types.h>
Packit Service 6f2e62
#include <sys/file.h>
Packit Service 6f2e62
#include <malloc.h>
Packit Service 6f2e62
Packit Service 6f2e62
#include <sys/ioctl.h>
Packit Service 6f2e62
#include <linux/if.h>
Packit Service 6f2e62
#include <linux/route.h>
Packit Service 6f2e62
Packit Service 6f2e62
#include <netinet/in.h>
Packit Service 6f2e62
#include <netinet/ip.h>
Packit Service 6f2e62
#include <netinet/ip_icmp.h>
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * The next include contains all defs and structures for multicast
Packit Service 6f2e62
 * that are not in SunOS 4.1.x. On a SunOS 4.1.x system none of this code
Packit Service 6f2e62
 * is ever used because it does not support multicast
Packit Service 6f2e62
 * Fraser Gardiner - Sun Microsystems Australia
Packit Service 6f2e62
 */
Packit Service 6f2e62
Packit Service 6f2e62
#include <netdb.h>
Packit Service 6f2e62
#include <arpa/inet.h>
Packit Service 6f2e62
Packit Service 6f2e62
#include <string.h>
Packit Service 6f2e62
#include <syslog.h>
Packit Service 6f2e62
Packit Service 6f2e62
#include "SNAPSHOT.h"
Packit Service 6f2e62
Packit Service 6f2e62
struct interface
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct in_addr 	address;	/* Used to identify the interface */
Packit Service 6f2e62
	struct in_addr	localaddr;	/* Actual address if the interface */
Packit Service 6f2e62
	int 		preference;
Packit Service 6f2e62
	int		flags;
Packit Service 6f2e62
	struct in_addr	bcastaddr;
Packit Service 6f2e62
	struct in_addr	remoteaddr;
Packit Service 6f2e62
	struct in_addr	netmask;
Packit Service 6f2e62
	int		ifindex;
Packit Service 6f2e62
	char		name[IFNAMSIZ];
Packit Service 6f2e62
};
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * TBD
Packit Service 6f2e62
 *	Use 255.255.255.255 for broadcasts - not the interface broadcast
Packit Service 6f2e62
 *	address.
Packit Service 6f2e62
 */
Packit Service 6f2e62
Packit Service 6f2e62
#define ALLIGN(ptr)	(ptr)
Packit Service 6f2e62
Packit Service 6f2e62
static int join(int sock, struct sockaddr_in *sin);
Packit Service 6f2e62
static void solicitor(struct sockaddr_in *);
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
static void advertise(struct sockaddr_in *, int lft);
Packit Service 6f2e62
#endif
Packit Service 6f2e62
static char *pr_name(struct in_addr addr);
Packit Service 6f2e62
static void pr_pack(char *buf, int cc, struct sockaddr_in *from);
Packit Service 6f2e62
static void age_table(int time);
Packit Service 6f2e62
static void record_router(struct in_addr router, int preference, int ttl);
Packit Service 6f2e62
static void add_route(struct in_addr addr);
Packit Service 6f2e62
static void del_route(struct in_addr addr);
Packit Service 6f2e62
static void rtioctl(struct in_addr addr, int op);
Packit Service 6f2e62
static int support_multicast(void);
Packit Service 6f2e62
static int sendbcast(int s, char *packet, int packetlen);
Packit Service 6f2e62
static int sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *);
Packit Service 6f2e62
static int sendbcastif(int s, char *packet, int packetlen, struct interface *ifp);
Packit Service 6f2e62
static int sendmcastif(int s, char *packet, int packetlen, struct sockaddr_in *sin, struct interface *ifp);
Packit Service 6f2e62
static int is_directly_connected(struct in_addr in);
Packit Service 6f2e62
static void initlog(void);
Packit Service 6f2e62
static void discard_table(void);
Packit Service 6f2e62
static void init(void);
Packit Service 6f2e62
Packit Service 6f2e62
#define ICMP_ROUTER_ADVERTISEMENT	9
Packit Service 6f2e62
#define ICMP_ROUTER_SOLICITATION	10
Packit Service 6f2e62
Packit Service 6f2e62
#define ALL_HOSTS_ADDRESS		"224.0.0.1"
Packit Service 6f2e62
#define ALL_ROUTERS_ADDRESS		"224.0.0.2"
Packit Service 6f2e62
Packit Service 6f2e62
#define MAXIFS 32
Packit Service 6f2e62
Packit Service 6f2e62
#if defined(__GLIBC__) && __GLIBC__ < 2
Packit Service 6f2e62
/* For router advertisement */
Packit Service 6f2e62
struct icmp_ra
Packit Service 6f2e62
{
Packit Service 6f2e62
	unsigned char	icmp_type;		/* type of message, see below */
Packit Service 6f2e62
	unsigned char	icmp_code;		/* type sub code */
Packit Service 6f2e62
	unsigned short	icmp_cksum;		/* ones complement cksum of struct */
Packit Service 6f2e62
	unsigned char	icmp_num_addrs;
Packit Service 6f2e62
	unsigned char	icmp_wpa;		/* Words per address */
Packit Service 6f2e62
	short 	icmp_lifetime;
Packit Service 6f2e62
};
Packit Service 6f2e62
Packit Service 6f2e62
struct icmp_ra_addr
Packit Service 6f2e62
{
Packit Service 6f2e62
	__u32	ira_addr;
Packit Service 6f2e62
	__u32	ira_preference;
Packit Service 6f2e62
};
Packit Service 6f2e62
#else
Packit Service 6f2e62
#define icmp_ra icmp
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
/* Router constants */
Packit Service 6f2e62
#define	MAX_INITIAL_ADVERT_INTERVAL	16
Packit Service 6f2e62
#define	MAX_INITIAL_ADVERTISEMENTS  	3
Packit Service 6f2e62
#define	MAX_RESPONSE_DELAY		2	/* Not used */
Packit Service 6f2e62
Packit Service 6f2e62
/* Host constants */
Packit Service 6f2e62
#define MAX_SOLICITATIONS 		3
Packit Service 6f2e62
#define SOLICITATION_INTERVAL 		3
Packit Service 6f2e62
#define MAX_SOLICITATION_DELAY		1	/* Not used */
Packit Service 6f2e62
Packit Service 6f2e62
#define INELIGIBLE_PREF			0x80000000	/* Maximum negative */
Packit Service 6f2e62
Packit Service 6f2e62
#define MAX_ADV_INT 600
Packit Service 6f2e62
Packit Service 6f2e62
/* Statics */
Packit Service 6f2e62
static int num_interfaces;
Packit Service 6f2e62
Packit Service 6f2e62
static struct interface *interfaces;
Packit Service 6f2e62
static int interfaces_size;			/* Number of elements in interfaces */
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
#define	MAXPACKET	4096	/* max packet size */
Packit Service 6f2e62
Packit Service 6f2e62
/* fraser */
Packit Service 6f2e62
int debugfile;
Packit Service 6f2e62
Packit Service 6f2e62
const char usage[] =
Packit Service 6f2e62
"Usage:	rdisc [-b] [-d] [-s] [-v] [-f] [-a] [-V] [send_address] [receive_address]\n"
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
"       rdisc -r [-b] [-d] [-s] [-v] [-f] [-a] [-V] [-p <preference>] [-T <secs>]\n"
Packit Service 6f2e62
"		 [send_address] [receive_address]\n"
Packit Service 6f2e62
#endif
Packit Service 6f2e62
;
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
int s;			/* Socket file descriptor */
Packit Service 6f2e62
struct sockaddr_in whereto;/* Address to send to */
Packit Service 6f2e62
Packit Service 6f2e62
/* Common variables */
Packit Service 6f2e62
int verbose = 0;
Packit Service 6f2e62
int debug = 0;
Packit Service 6f2e62
int trace = 0;
Packit Service 6f2e62
int solicit = 0;
Packit Service 6f2e62
int ntransmitted = 0;
Packit Service 6f2e62
int nreceived = 0;
Packit Service 6f2e62
int forever = 0;	/* Never give up on host. If 0 defer fork until
Packit Service 6f2e62
			 * first response.
Packit Service 6f2e62
			 */
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
/* Router variables */
Packit Service 6f2e62
int responder;
Packit Service 6f2e62
int max_adv_int = MAX_ADV_INT;
Packit Service 6f2e62
int min_adv_int;
Packit Service 6f2e62
int lifetime;
Packit Service 6f2e62
int initial_advert_interval = MAX_INITIAL_ADVERT_INTERVAL;
Packit Service 6f2e62
int initial_advertisements = MAX_INITIAL_ADVERTISEMENTS;
Packit Service 6f2e62
int preference = 0;		/* Setable with -p option */
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
/* Host variables */
Packit Service 6f2e62
int max_solicitations = MAX_SOLICITATIONS;
Packit Service 6f2e62
unsigned int solicitation_interval = SOLICITATION_INTERVAL;
Packit Service 6f2e62
int best_preference = 1;  	/* Set to record only the router(s) with the
Packit Service 6f2e62
				   best preference in the kernel. Not set
Packit Service 6f2e62
				   puts all routes in the kernel. */
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
static void graceful_finish(void);
Packit Service 6f2e62
static void finish(void);
Packit Service 6f2e62
static void timer(void);
Packit Service 6f2e62
static void initifs(void);
Packit Service 6f2e62
static unsigned short in_cksum(unsigned short *addr, int len);
Packit Service 6f2e62
Packit Service 6f2e62
static int logging = 0;
Packit Service 6f2e62
Packit Service 6f2e62
#define logerr(fmt...) ({ if (logging) syslog(LOG_ERR, fmt); \
Packit Service 6f2e62
			  else fprintf(stderr, fmt); })
Packit Service 6f2e62
#define logtrace(fmt...) ({ if (logging) syslog(LOG_INFO, fmt); \
Packit Service 6f2e62
			  else fprintf(stderr, fmt); })
Packit Service 6f2e62
#define logdebug(fmt...) ({ if (logging) syslog(LOG_DEBUG, fmt); \
Packit Service 6f2e62
			  else fprintf(stderr, fmt); })
Packit Service 6f2e62
static void logperror(char *str);
Packit Service 6f2e62
Packit Service 6f2e62
static __inline__ int isbroadcast(struct sockaddr_in *sin)
Packit Service 6f2e62
{
Packit Service 6f2e62
	return (sin->sin_addr.s_addr == INADDR_BROADCAST);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
static __inline__ int ismulticast(struct sockaddr_in *sin)
Packit Service 6f2e62
{
Packit Service 6f2e62
	return IN_CLASSD(ntohl(sin->sin_addr.s_addr));
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
static void prusage(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	fputs(usage, stderr);
Packit Service 6f2e62
	exit(1);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void do_fork(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int t;
Packit Service 6f2e62
	pid_t pid;
Packit Service 6f2e62
	long open_max;
Packit Service 6f2e62
Packit Service 6f2e62
	if (trace)
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	if ((open_max = sysconf(_SC_OPEN_MAX)) == -1) {
Packit Service 6f2e62
		if (errno == 0) {
Packit Service 6f2e62
			(void) fprintf(stderr, "OPEN_MAX is not supported\n");
Packit Service 6f2e62
		} 
Packit Service 6f2e62
		else {
Packit Service 6f2e62
			(void) fprintf(stderr, "sysconf() error\n");
Packit Service 6f2e62
		}
Packit Service 6f2e62
		exit(1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
	if ((pid=fork()) != 0)
Packit Service 6f2e62
		exit(0);
Packit Service 6f2e62
Packit Service 6f2e62
	for (t = 0; t < open_max; t++)
Packit Service 6f2e62
		if (t != s)
Packit Service 6f2e62
			close(t);
Packit Service 6f2e62
Packit Service 6f2e62
	setsid();
Packit Service 6f2e62
	initlog();
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void signal_setup(int signo, void (*handler)(void))
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct sigaction sa;
Packit Service 6f2e62
Packit Service 6f2e62
	memset(&sa, 0, sizeof(sa));
Packit Service 6f2e62
Packit Service 6f2e62
	sa.sa_handler = (void (*)(int))handler;
Packit Service 6f2e62
#ifdef SA_INTERRUPT
Packit Service 6f2e62
	sa.sa_flags = SA_INTERRUPT;
Packit Service 6f2e62
#endif
Packit Service 6f2e62
	sigaction(signo, &sa, NULL);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * 			M A I N
Packit Service 6f2e62
 */
Packit Service 6f2e62
char    *sendaddress, *recvaddress;
Packit Service 6f2e62
Packit Service 6f2e62
int main(int argc, char **argv)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct sockaddr_in from;
Packit Service 6f2e62
	char **av = argv;
Packit Service 6f2e62
	struct sockaddr_in *to = &whereto;
Packit Service 6f2e62
	struct sockaddr_in joinaddr;
Packit Service 6f2e62
	sigset_t sset, sset_empty;
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
	int val;
Packit Service 6f2e62
Packit Service 6f2e62
	min_adv_int =( max_adv_int * 3 / 4);
Packit Service 6f2e62
	lifetime = (3*max_adv_int);
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
	argc--, av++;
Packit Service 6f2e62
	while (argc > 0 && *av[0] == '-') {
Packit Service 6f2e62
		while (*++av[0]) {
Packit Service 6f2e62
			switch (*av[0]) {
Packit Service 6f2e62
			case 'd':
Packit Service 6f2e62
				debug = 1;
Packit Service 6f2e62
				break;
Packit Service 6f2e62
			case 't':
Packit Service 6f2e62
				trace = 1;
Packit Service 6f2e62
				break;
Packit Service 6f2e62
			case 'v':
Packit Service 6f2e62
				verbose++;
Packit Service 6f2e62
				break;
Packit Service 6f2e62
			case 's':
Packit Service 6f2e62
				solicit = 1;
Packit Service 6f2e62
				break;
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
			case 'r':
Packit Service 6f2e62
				responder = 1;
Packit Service 6f2e62
				break;
Packit Service 6f2e62
#endif
Packit Service 6f2e62
			case 'a':
Packit Service 6f2e62
				best_preference = 0;
Packit Service 6f2e62
				break;
Packit Service 6f2e62
			case 'b':
Packit Service 6f2e62
				best_preference = 1;
Packit Service 6f2e62
				break;
Packit Service 6f2e62
			case 'f':
Packit Service 6f2e62
				forever = 1;
Packit Service 6f2e62
				break;
Packit Service 6f2e62
			case 'V':
Packit Service 6f2e62
				printf("rdisc utility, iputils-%s\n", SNAPSHOT);
Packit Service 6f2e62
				exit(0);
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
			case 'T':
Packit Service 6f2e62
				argc--, av++;
Packit Service 6f2e62
				if (argc != 0) {
Packit Service 6f2e62
					val = strtol(av[0], (char **)NULL, 0);
Packit Service 6f2e62
					if (val < 4 || val > 1800) {
Packit Service 6f2e62
						(void) fprintf(stderr,
Packit Service 6f2e62
							       "Bad Max Advertizement Interval\n");
Packit Service 6f2e62
						exit(1);
Packit Service 6f2e62
					}
Packit Service 6f2e62
					max_adv_int = val;
Packit Service 6f2e62
					min_adv_int =( max_adv_int * 3 / 4);
Packit Service 6f2e62
					lifetime = (3*max_adv_int);
Packit Service 6f2e62
				} else {
Packit Service 6f2e62
					prusage();
Packit Service 6f2e62
					/* NOTREACHED*/
Packit Service 6f2e62
				}
Packit Service 6f2e62
				goto next;
Packit Service 6f2e62
			case 'p':
Packit Service 6f2e62
				argc--, av++;
Packit Service 6f2e62
				if (argc != 0) {
Packit Service 6f2e62
					val = strtol(av[0], (char **)NULL, 0);
Packit Service 6f2e62
					preference = val;
Packit Service 6f2e62
				} else {
Packit Service 6f2e62
					prusage();
Packit Service 6f2e62
					/* NOTREACHED*/
Packit Service 6f2e62
				}
Packit Service 6f2e62
				goto next;
Packit Service 6f2e62
#endif
Packit Service 6f2e62
			default:
Packit Service 6f2e62
				prusage();
Packit Service 6f2e62
				/* NOTREACHED*/
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
next:
Packit Service 6f2e62
#endif
Packit Service 6f2e62
		argc--, av++;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if( argc < 1)  {
Packit Service 6f2e62
		if (support_multicast()) {
Packit Service 6f2e62
			sendaddress = ALL_ROUTERS_ADDRESS;
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
			if (responder)
Packit Service 6f2e62
				sendaddress = ALL_HOSTS_ADDRESS;
Packit Service 6f2e62
#endif
Packit Service 6f2e62
		} else
Packit Service 6f2e62
			sendaddress = "255.255.255.255";
Packit Service 6f2e62
	} else {
Packit Service 6f2e62
		sendaddress = av[0];
Packit Service 6f2e62
		argc--;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (argc < 1) {
Packit Service 6f2e62
		if (support_multicast()) {
Packit Service 6f2e62
			recvaddress = ALL_HOSTS_ADDRESS;
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
			if (responder)
Packit Service 6f2e62
				recvaddress = ALL_ROUTERS_ADDRESS;
Packit Service 6f2e62
#endif
Packit Service 6f2e62
		} else
Packit Service 6f2e62
			recvaddress = "255.255.255.255";
Packit Service 6f2e62
	} else {
Packit Service 6f2e62
		recvaddress = av[0];
Packit Service 6f2e62
		argc--;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (argc != 0) {
Packit Service 6f2e62
		(void) fprintf(stderr, "Extra parameters\n");
Packit Service 6f2e62
		prusage();
Packit Service 6f2e62
		/* NOTREACHED */
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
	if (solicit && responder) {
Packit Service 6f2e62
		prusage();
Packit Service 6f2e62
		/* NOTREACHED */
Packit Service 6f2e62
	}
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
	if (!(solicit && !forever)) {
Packit Service 6f2e62
		do_fork();
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * Added the next line to stop forking a second time
Packit Service 6f2e62
 * Fraser Gardiner - Sun Microsystems Australia
Packit Service 6f2e62
 */
Packit Service 6f2e62
		forever = 1;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	memset( (char *)&whereto, 0, sizeof(struct sockaddr_in) );
Packit Service 6f2e62
	to->sin_family = AF_INET;
Packit Service 6f2e62
	to->sin_addr.s_addr = inet_addr(sendaddress);
Packit Service 6f2e62
Packit Service 6f2e62
	memset( (char *)&joinaddr, 0, sizeof(struct sockaddr_in) );
Packit Service 6f2e62
	joinaddr.sin_family = AF_INET;
Packit Service 6f2e62
	joinaddr.sin_addr.s_addr = inet_addr(recvaddress);
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
	if (responder)
Packit Service 6f2e62
		srandom((int)gethostid());
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
Packit Service 6f2e62
		logperror("socket");
Packit Service 6f2e62
		exit(5);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	setlinebuf( stdout );
Packit Service 6f2e62
Packit Service 6f2e62
	signal_setup(SIGINT, finish );
Packit Service 6f2e62
	signal_setup(SIGTERM, graceful_finish );
Packit Service 6f2e62
	signal_setup(SIGHUP, initifs );
Packit Service 6f2e62
	signal_setup(SIGALRM, timer );
Packit Service 6f2e62
Packit Service 6f2e62
	sigemptyset(&sset);
Packit Service 6f2e62
	sigemptyset(&sset_empty);
Packit Service 6f2e62
	sigaddset(&sset, SIGALRM);
Packit Service 6f2e62
	sigaddset(&sset, SIGHUP);
Packit Service 6f2e62
	sigaddset(&sset, SIGTERM);
Packit Service 6f2e62
	sigaddset(&sset, SIGINT);
Packit Service 6f2e62
Packit Service 6f2e62
	init();
Packit Service 6f2e62
	if (join(s, &joinaddr) < 0) {
Packit Service 6f2e62
		logerr("Failed joining addresses\n");
Packit Service 6f2e62
		exit (2);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	timer();	/* start things going */
Packit Service 6f2e62
Packit Service 6f2e62
	for (;;) {
Packit Service 6f2e62
		unsigned char	packet[MAXPACKET];
Packit Service 6f2e62
		int len = sizeof (packet);
Packit Service 6f2e62
		socklen_t fromlen = sizeof (from);
Packit Service 6f2e62
		int cc;
Packit Service 6f2e62
Packit Service 6f2e62
		cc=recvfrom(s, (char *)packet, len, 0,
Packit Service 6f2e62
			    (struct sockaddr *)&from, &fromlen);
Packit Service 6f2e62
		if (cc<0) {
Packit Service 6f2e62
			if (errno == EINTR)
Packit Service 6f2e62
				continue;
Packit Service 6f2e62
			logperror("recvfrom");
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		sigprocmask(SIG_SETMASK, &sset, NULL);
Packit Service 6f2e62
		pr_pack( (char *)packet, cc, &from );
Packit Service 6f2e62
		sigprocmask(SIG_SETMASK, &sset_empty, NULL);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	/*NOTREACHED*/
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
#define TIMER_INTERVAL 	3
Packit Service 6f2e62
#define GETIFCONF_TIMER	30
Packit Service 6f2e62
Packit Service 6f2e62
static int left_until_advertise;
Packit Service 6f2e62
Packit Service 6f2e62
/* Called every TIMER_INTERVAL */
Packit Service 6f2e62
void timer()
Packit Service 6f2e62
{
Packit Service 6f2e62
	static int time;
Packit Service 6f2e62
	static int left_until_getifconf;
Packit Service 6f2e62
	static int left_until_solicit;
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
	time += TIMER_INTERVAL;
Packit Service 6f2e62
Packit Service 6f2e62
	left_until_getifconf -= TIMER_INTERVAL;
Packit Service 6f2e62
	left_until_advertise -= TIMER_INTERVAL;
Packit Service 6f2e62
	left_until_solicit -= TIMER_INTERVAL;
Packit Service 6f2e62
Packit Service 6f2e62
	if (left_until_getifconf < 0) {
Packit Service 6f2e62
		initifs();
Packit Service 6f2e62
		left_until_getifconf = GETIFCONF_TIMER;
Packit Service 6f2e62
	}
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
	if (responder && left_until_advertise <= 0) {
Packit Service 6f2e62
		ntransmitted++;
Packit Service 6f2e62
		advertise(&whereto, lifetime);
Packit Service 6f2e62
		if (ntransmitted < initial_advertisements)
Packit Service 6f2e62
			left_until_advertise = initial_advert_interval;
Packit Service 6f2e62
		else
Packit Service 6f2e62
			left_until_advertise = min_adv_int +
Packit Service 6f2e62
				((max_adv_int - min_adv_int) *
Packit Service 6f2e62
				 (random() % 1000)/1000);
Packit Service 6f2e62
	} else
Packit Service 6f2e62
#endif
Packit Service 6f2e62
	if (solicit && left_until_solicit <= 0) {
Packit Service 6f2e62
		ntransmitted++;
Packit Service 6f2e62
		solicitor(&whereto);
Packit Service 6f2e62
		if (ntransmitted < max_solicitations)
Packit Service 6f2e62
			left_until_solicit = solicitation_interval;
Packit Service 6f2e62
		else {
Packit Service 6f2e62
			solicit = 0;
Packit Service 6f2e62
			if (!forever && nreceived == 0)
Packit Service 6f2e62
				exit(5);
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	age_table(TIMER_INTERVAL);
Packit Service 6f2e62
	alarm(TIMER_INTERVAL);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * 			S O L I C I T O R
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Compose and transmit an ICMP ROUTER SOLICITATION REQUEST packet.
Packit Service 6f2e62
 * The IP packet will be added on by the kernel.
Packit Service 6f2e62
 */
Packit Service 6f2e62
void
Packit Service 6f2e62
solicitor(struct sockaddr_in *sin)
Packit Service 6f2e62
{
Packit Service 6f2e62
	static unsigned char outpack[MAXPACKET];
Packit Service 6f2e62
	struct icmphdr *icp = (struct icmphdr *) ALLIGN(outpack);
Packit Service 6f2e62
	int packetlen, i;
Packit Service 6f2e62
Packit Service 6f2e62
	if (verbose) {
Packit Service 6f2e62
		logtrace("Sending solicitation to %s\n",
Packit Service 6f2e62
			 pr_name(sin->sin_addr));
Packit Service 6f2e62
	}
Packit Service 6f2e62
	icp->type = ICMP_ROUTER_SOLICITATION;
Packit Service 6f2e62
	icp->code = 0;
Packit Service 6f2e62
	icp->checksum = 0;
Packit Service 6f2e62
	icp->un.gateway = 0; /* Reserved */
Packit Service 6f2e62
	packetlen = 8;
Packit Service 6f2e62
Packit Service 6f2e62
	/* Compute ICMP checksum here */
Packit Service 6f2e62
	icp->checksum = in_cksum( (unsigned short *)icp, packetlen );
Packit Service 6f2e62
Packit Service 6f2e62
	if (isbroadcast(sin))
Packit Service 6f2e62
		i = sendbcast(s, (char *)outpack, packetlen);
Packit Service 6f2e62
	else if (ismulticast(sin))
Packit Service 6f2e62
		i = sendmcast(s, (char *)outpack, packetlen, sin);
Packit Service 6f2e62
	else
Packit Service 6f2e62
		i = sendto( s, (char *)outpack, packetlen, 0,
Packit Service 6f2e62
			   (struct sockaddr *)sin, sizeof(struct sockaddr));
Packit Service 6f2e62
Packit Service 6f2e62
	if( i < 0 || i != packetlen )  {
Packit Service 6f2e62
		if( i<0 ) {
Packit Service 6f2e62
		    logperror("solicitor:sendto");
Packit Service 6f2e62
		}
Packit Service 6f2e62
		logerr("wrote %s %d chars, ret=%d\n",
Packit Service 6f2e62
			sendaddress, packetlen, i );
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * 			A V E R T I S E
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Compose and transmit an ICMP ROUTER ADVERTISEMENT packet.
Packit Service 6f2e62
 * The IP packet will be added on by the kernel.
Packit Service 6f2e62
 */
Packit Service 6f2e62
void
Packit Service 6f2e62
advertise(struct sockaddr_in *sin, int lft)
Packit Service 6f2e62
{
Packit Service 6f2e62
	static unsigned char outpack[MAXPACKET];
Packit Service 6f2e62
	struct icmp_ra *rap = (struct icmp_ra *) ALLIGN(outpack);
Packit Service 6f2e62
	struct icmp_ra_addr *ap;
Packit Service 6f2e62
	int packetlen, i, cc;
Packit Service 6f2e62
Packit Service 6f2e62
	if (verbose) {
Packit Service 6f2e62
		logtrace("Sending advertisement to %s\n",
Packit Service 6f2e62
			 pr_name(sin->sin_addr));
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	for (i = 0; i < num_interfaces; i++) {
Packit Service 6f2e62
		rap->icmp_type = ICMP_ROUTER_ADVERTISEMENT;
Packit Service 6f2e62
		rap->icmp_code = 0;
Packit Service 6f2e62
		rap->icmp_cksum = 0;
Packit Service 6f2e62
		rap->icmp_num_addrs = 0;
Packit Service 6f2e62
		rap->icmp_wpa = 2;
Packit Service 6f2e62
		rap->icmp_lifetime = htons(lft);
Packit Service 6f2e62
		packetlen = 8;
Packit Service 6f2e62
Packit Service 6f2e62
		/*
Packit Service 6f2e62
		 * TODO handle multiple logical interfaces per
Packit Service 6f2e62
		 * physical interface. (increment with rap->icmp_wpa * 4 for
Packit Service 6f2e62
		 * each address.)
Packit Service 6f2e62
		 */
Packit Service 6f2e62
		ap = (struct icmp_ra_addr *)ALLIGN(outpack + ICMP_MINLEN);
Packit Service 6f2e62
		ap->ira_addr = interfaces[i].localaddr.s_addr;
Packit Service 6f2e62
		ap->ira_preference = htonl(interfaces[i].preference);
Packit Service 6f2e62
		packetlen += rap->icmp_wpa * 4;
Packit Service 6f2e62
		rap->icmp_num_addrs++;
Packit Service 6f2e62
Packit Service 6f2e62
		/* Compute ICMP checksum here */
Packit Service 6f2e62
		rap->icmp_cksum = in_cksum( (unsigned short *)rap, packetlen );
Packit Service 6f2e62
Packit Service 6f2e62
		if (isbroadcast(sin))
Packit Service 6f2e62
			cc = sendbcastif(s, (char *)outpack, packetlen,
Packit Service 6f2e62
					&interfaces[i]);
Packit Service 6f2e62
		else if (ismulticast(sin))
Packit Service 6f2e62
			cc = sendmcastif( s, (char *)outpack, packetlen, sin,
Packit Service 6f2e62
					&interfaces[i]);
Packit Service 6f2e62
		else {
Packit Service 6f2e62
			struct interface *ifp = &interfaces[i];
Packit Service 6f2e62
			/*
Packit Service 6f2e62
			 * Verify that the interface matches the destination
Packit Service 6f2e62
			 * address.
Packit Service 6f2e62
			 */
Packit Service 6f2e62
			if ((sin->sin_addr.s_addr & ifp->netmask.s_addr) ==
Packit Service 6f2e62
			    (ifp->address.s_addr & ifp->netmask.s_addr)) {
Packit Service 6f2e62
				if (debug) {
Packit Service 6f2e62
					logdebug("Unicast to %s ",
Packit Service 6f2e62
						 pr_name(sin->sin_addr));
Packit Service 6f2e62
					logdebug("on interface %s, %s\n",
Packit Service 6f2e62
						 ifp->name,
Packit Service 6f2e62
						 pr_name(ifp->address));
Packit Service 6f2e62
				}
Packit Service 6f2e62
				cc = sendto( s, (char *)outpack, packetlen, 0,
Packit Service 6f2e62
					    (struct sockaddr *)sin,
Packit Service 6f2e62
					    sizeof(struct sockaddr));
Packit Service 6f2e62
			} else
Packit Service 6f2e62
				cc = packetlen;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if( cc < 0 || cc != packetlen )  {
Packit Service 6f2e62
			if (cc < 0) {
Packit Service 6f2e62
				logperror("sendto");
Packit Service 6f2e62
			} else {
Packit Service 6f2e62
				logerr("wrote %s %d chars, ret=%d\n",
Packit Service 6f2e62
				       sendaddress, packetlen, cc );
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * 			P R _ T Y P E
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Convert an ICMP "type" field to a printable string.
Packit Service 6f2e62
 */
Packit Service 6f2e62
char *
Packit Service 6f2e62
pr_type(int t)
Packit Service 6f2e62
{
Packit Service 6f2e62
	static char *ttab[] = {
Packit Service 6f2e62
		"Echo Reply",
Packit Service 6f2e62
		"ICMP 1",
Packit Service 6f2e62
		"ICMP 2",
Packit Service 6f2e62
		"Dest Unreachable",
Packit Service 6f2e62
		"Source Quench",
Packit Service 6f2e62
		"Redirect",
Packit Service 6f2e62
		"ICMP 6",
Packit Service 6f2e62
		"ICMP 7",
Packit Service 6f2e62
		"Echo",
Packit Service 6f2e62
		"Router Advertise",
Packit Service 6f2e62
		"Router Solicitation",
Packit Service 6f2e62
		"Time Exceeded",
Packit Service 6f2e62
		"Parameter Problem",
Packit Service 6f2e62
		"Timestamp",
Packit Service 6f2e62
		"Timestamp Reply",
Packit Service 6f2e62
		"Info Request",
Packit Service 6f2e62
		"Info Reply",
Packit Service 6f2e62
		"Netmask Request",
Packit Service 6f2e62
		"Netmask Reply"
Packit Service 6f2e62
	};
Packit Service 6f2e62
Packit Service 6f2e62
	if ( t < 0 || t > 16 )
Packit Service 6f2e62
		return("OUT-OF-RANGE");
Packit Service 6f2e62
Packit Service 6f2e62
	return(ttab[t]);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 *			P R _ N A M E
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Return a string name for the given IP address.
Packit Service 6f2e62
 */
Packit Service 6f2e62
char *pr_name(struct in_addr addr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = addr };
Packit Service 6f2e62
	char hnamebuf[NI_MAXHOST] = "";
Packit Service 6f2e62
	static char buf[80];
Packit Service 6f2e62
Packit Service 6f2e62
	getnameinfo((struct sockaddr *) &sin, sizeof sin, hnamebuf, sizeof hnamebuf, NULL, 0, 0);
Packit Service 6f2e62
	snprintf(buf, sizeof buf, "%s (%s)", hnamebuf, inet_ntoa(addr));
Packit Service 6f2e62
	return(buf);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 *			P R _ P A C K
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Print out the packet, if it came from us.  This logic is necessary
Packit Service 6f2e62
 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
Packit Service 6f2e62
 * which arrive ('tis only fair).  This permits multiple copies of this
Packit Service 6f2e62
 * program to be run without having intermingled output (or statistics!).
Packit Service 6f2e62
 */
Packit Service 6f2e62
void
Packit Service 6f2e62
pr_pack(char *buf, int cc, struct sockaddr_in *from)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct iphdr *ip;
Packit Service 6f2e62
	struct icmphdr *icp;
Packit Service 6f2e62
	int i;
Packit Service 6f2e62
	int hlen;
Packit Service 6f2e62
Packit Service 6f2e62
	ip = (struct iphdr *) ALLIGN(buf);
Packit Service 6f2e62
	hlen = ip->ihl << 2;
Packit Service 6f2e62
	if (cc < hlen + 8) {
Packit Service 6f2e62
		if (verbose)
Packit Service 6f2e62
			logtrace("packet too short (%d bytes) from %s\n", cc,
Packit Service 6f2e62
				 pr_name(from->sin_addr));
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	cc -= hlen;
Packit Service 6f2e62
	icp = (struct icmphdr *)ALLIGN(buf + hlen);
Packit Service 6f2e62
Packit Service 6f2e62
	switch (icp->type) {
Packit Service 6f2e62
	case ICMP_ROUTER_ADVERTISEMENT:
Packit Service 6f2e62
	{
Packit Service 6f2e62
		struct icmp_ra *rap = (struct icmp_ra *)ALLIGN(icp);
Packit Service 6f2e62
		struct icmp_ra_addr *ap;
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
		if (responder)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
		/* TBD verify that the link is multicast or broadcast */
Packit Service 6f2e62
		/* XXX Find out the link it came in over? */
Packit Service 6f2e62
		if (in_cksum((unsigned short *)ALLIGN(buf+hlen), cc)) {
Packit Service 6f2e62
			if (verbose)
Packit Service 6f2e62
				logtrace("ICMP %s from %s: Bad checksum\n",
Packit Service 6f2e62
					 pr_type((int)rap->icmp_type),
Packit Service 6f2e62
					 pr_name(from->sin_addr));
Packit Service 6f2e62
			return;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (rap->icmp_code != 0) {
Packit Service 6f2e62
			if (verbose)
Packit Service 6f2e62
				logtrace("ICMP %s from %s: Code = %d\n",
Packit Service 6f2e62
					 pr_type((int)rap->icmp_type),
Packit Service 6f2e62
					 pr_name(from->sin_addr),
Packit Service 6f2e62
					 rap->icmp_code);
Packit Service 6f2e62
			return;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (rap->icmp_num_addrs < 1) {
Packit Service 6f2e62
			if (verbose)
Packit Service 6f2e62
				logtrace("ICMP %s from %s: No addresses\n",
Packit Service 6f2e62
					 pr_type((int)rap->icmp_type),
Packit Service 6f2e62
					 pr_name(from->sin_addr));
Packit Service 6f2e62
			return;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (rap->icmp_wpa < 2) {
Packit Service 6f2e62
			if (verbose)
Packit Service 6f2e62
				logtrace("ICMP %s from %s: Words/addr = %d\n",
Packit Service 6f2e62
					 pr_type((int)rap->icmp_type),
Packit Service 6f2e62
					 pr_name(from->sin_addr),
Packit Service 6f2e62
					 rap->icmp_wpa);
Packit Service 6f2e62
			return;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if ((unsigned)cc <
Packit Service 6f2e62
		    8 + rap->icmp_num_addrs * rap->icmp_wpa * 4) {
Packit Service 6f2e62
			if (verbose)
Packit Service 6f2e62
				logtrace("ICMP %s from %s: Too short %d, %d\n",
Packit Service 6f2e62
					      pr_type((int)rap->icmp_type),
Packit Service 6f2e62
					      pr_name(from->sin_addr),
Packit Service 6f2e62
					      cc,
Packit Service 6f2e62
					      8 + rap->icmp_num_addrs * rap->icmp_wpa * 4);
Packit Service 6f2e62
			return;
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		if (verbose)
Packit Service 6f2e62
			logtrace("ICMP %s from %s, lifetime %d\n",
Packit Service 6f2e62
				      pr_type((int)rap->icmp_type),
Packit Service 6f2e62
				      pr_name(from->sin_addr),
Packit Service 6f2e62
				      ntohs(rap->icmp_lifetime));
Packit Service 6f2e62
Packit Service 6f2e62
		/* Check that at least one router address is a neighboor
Packit Service 6f2e62
		 * on the arriving link.
Packit Service 6f2e62
		 */
Packit Service 6f2e62
		for (i = 0; (unsigned)i < rap->icmp_num_addrs; i++) {
Packit Service 6f2e62
			struct in_addr ina;
Packit Service 6f2e62
			ap = (struct icmp_ra_addr *)
Packit Service 6f2e62
				ALLIGN(buf + hlen + 8 +
Packit Service 6f2e62
				       i * rap->icmp_wpa * 4);
Packit Service 6f2e62
			ina.s_addr = ap->ira_addr;
Packit Service 6f2e62
			if (verbose)
Packit Service 6f2e62
				logtrace("\taddress %s, preference 0x%x\n",
Packit Service 6f2e62
					      pr_name(ina),
Packit Service 6f2e62
					      (unsigned int)ntohl(ap->ira_preference));
Packit Service 6f2e62
			if (is_directly_connected(ina))
Packit Service 6f2e62
				record_router(ina,
Packit Service 6f2e62
					      ntohl(ap->ira_preference),
Packit Service 6f2e62
					      ntohs(rap->icmp_lifetime));
Packit Service 6f2e62
		}
Packit Service 6f2e62
		nreceived++;
Packit Service 6f2e62
		if (!forever) {
Packit Service 6f2e62
			do_fork();
Packit Service 6f2e62
			forever = 1;
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * The next line was added so that the alarm is set for the new procces
Packit Service 6f2e62
 * Fraser Gardiner Sun Microsystems Australia
Packit Service 6f2e62
 */
Packit Service 6f2e62
			(void) alarm(TIMER_INTERVAL);
Packit Service 6f2e62
		}
Packit Service 6f2e62
		break;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
	case ICMP_ROUTER_SOLICITATION:
Packit Service 6f2e62
	{
Packit Service 6f2e62
		struct sockaddr_in sin;
Packit Service 6f2e62
Packit Service 6f2e62
		if (!responder)
Packit Service 6f2e62
			break;
Packit Service 6f2e62
Packit Service 6f2e62
		/* TBD verify that the link is multicast or broadcast */
Packit Service 6f2e62
		/* XXX Find out the link it came in over? */
Packit Service 6f2e62
Packit Service 6f2e62
		if (in_cksum((unsigned short *)ALLIGN(buf+hlen), cc)) {
Packit Service 6f2e62
			if (verbose)
Packit Service 6f2e62
				logtrace("ICMP %s from %s: Bad checksum\n",
Packit Service 6f2e62
					      pr_type((int)icp->type),
Packit Service 6f2e62
					      pr_name(from->sin_addr));
Packit Service 6f2e62
			return;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (icp->code != 0) {
Packit Service 6f2e62
			if (verbose)
Packit Service 6f2e62
				logtrace("ICMP %s from %s: Code = %d\n",
Packit Service 6f2e62
					      pr_type((int)icp->type),
Packit Service 6f2e62
					      pr_name(from->sin_addr),
Packit Service 6f2e62
					      icp->code);
Packit Service 6f2e62
			return;
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		if (cc < ICMP_MINLEN) {
Packit Service 6f2e62
			if (verbose)
Packit Service 6f2e62
				logtrace("ICMP %s from %s: Too short %d, %d\n",
Packit Service 6f2e62
					      pr_type((int)icp->type),
Packit Service 6f2e62
					      pr_name(from->sin_addr),
Packit Service 6f2e62
					      cc,
Packit Service 6f2e62
					      ICMP_MINLEN);
Packit Service 6f2e62
			return;
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		if (verbose)
Packit Service 6f2e62
			logtrace("ICMP %s from %s\n",
Packit Service 6f2e62
				      pr_type((int)icp->type),
Packit Service 6f2e62
				      pr_name(from->sin_addr));
Packit Service 6f2e62
Packit Service 6f2e62
		/* Check that ip_src is either a neighboor
Packit Service 6f2e62
		 * on the arriving link or 0.
Packit Service 6f2e62
		 */
Packit Service 6f2e62
		sin.sin_family = AF_INET;
Packit Service 6f2e62
		if (ip->saddr == 0) {
Packit Service 6f2e62
			/* If it was sent to the broadcast address we respond
Packit Service 6f2e62
			 * to the broadcast address.
Packit Service 6f2e62
			 */
Packit Service 6f2e62
			if (IN_CLASSD(ntohl(ip->daddr)))
Packit Service 6f2e62
				sin.sin_addr.s_addr = htonl(0xe0000001);
Packit Service 6f2e62
			else
Packit Service 6f2e62
				sin.sin_addr.s_addr = INADDR_BROADCAST;
Packit Service 6f2e62
			/* Restart the timer when we broadcast */
Packit Service 6f2e62
			left_until_advertise = min_adv_int +
Packit Service 6f2e62
				((max_adv_int - min_adv_int)
Packit Service 6f2e62
				 * (random() % 1000)/1000);
Packit Service 6f2e62
		} else {
Packit Service 6f2e62
			sin.sin_addr.s_addr = ip->saddr;
Packit Service 6f2e62
			if (!is_directly_connected(sin.sin_addr)) {
Packit Service 6f2e62
				if (verbose)
Packit Service 6f2e62
					logtrace("ICMP %s from %s: source not directly connected\n",
Packit Service 6f2e62
						      pr_type((int)icp->type),
Packit Service 6f2e62
						      pr_name(from->sin_addr));
Packit Service 6f2e62
				break;
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
		nreceived++;
Packit Service 6f2e62
		ntransmitted++;
Packit Service 6f2e62
		advertise(&sin, lifetime);
Packit Service 6f2e62
		break;
Packit Service 6f2e62
	}
Packit Service 6f2e62
#endif
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 *			I N _ C K S U M
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Checksum routine for Internet Protocol family headers (C Version)
Packit Service 6f2e62
 *
Packit Service 6f2e62
 */
Packit Service 6f2e62
#if BYTE_ORDER == LITTLE_ENDIAN
Packit Service 6f2e62
# define ODDBYTE(v)	(v)
Packit Service 6f2e62
#elif BYTE_ORDER == BIG_ENDIAN
Packit Service 6f2e62
# define ODDBYTE(v)	((unsigned short)(v) << 8)
Packit Service 6f2e62
#else
Packit Service 6f2e62
# define ODDBYTE(v)	htons((unsigned short)(v) << 8)
Packit Service 6f2e62
#endif
Packit Service 6f2e62
Packit Service 6f2e62
unsigned short in_cksum(unsigned short *addr, int len)
Packit Service 6f2e62
{
Packit Service 6f2e62
	register int nleft = len;
Packit Service 6f2e62
	register unsigned short *w = addr;
Packit Service 6f2e62
	register unsigned short answer;
Packit Service 6f2e62
	register int sum = 0;
Packit Service 6f2e62
Packit Service 6f2e62
	/*
Packit Service 6f2e62
	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
Packit Service 6f2e62
	 *  we add sequential 16 bit words to it, and at the end, fold
Packit Service 6f2e62
	 *  back all the carry bits from the top 16 bits into the lower
Packit Service 6f2e62
	 *  16 bits.
Packit Service 6f2e62
	 */
Packit Service 6f2e62
	while( nleft > 1 )  {
Packit Service 6f2e62
		sum += *w++;
Packit Service 6f2e62
		nleft -= 2;
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	/* mop up an odd byte, if necessary */
Packit Service 6f2e62
	if( nleft == 1 )
Packit Service 6f2e62
		sum += ODDBYTE(*(unsigned char *)w);	/* le16toh() may be unavailable on old systems */
Packit Service 6f2e62
Packit Service 6f2e62
	/*
Packit Service 6f2e62
	 * add back carry outs from top 16 bits to low 16 bits
Packit Service 6f2e62
	 */
Packit Service 6f2e62
	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
Packit Service 6f2e62
	sum += (sum >> 16);			/* add carry */
Packit Service 6f2e62
	answer = ~sum;				/* truncate to 16 bits */
Packit Service 6f2e62
	return (answer);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 *			F I N I S H
Packit Service 6f2e62
 *
Packit Service 6f2e62
 * Print out statistics, and give up.
Packit Service 6f2e62
 * Heavily buffered STDIO is used here, so that all the statistics
Packit Service 6f2e62
 * will be written with 1 sys-write call.  This is nice when more
Packit Service 6f2e62
 * than one copy of the program is running on a terminal;  it prevents
Packit Service 6f2e62
 * the statistics output from becomming intermingled.
Packit Service 6f2e62
 */
Packit Service 6f2e62
void
Packit Service 6f2e62
finish()
Packit Service 6f2e62
{
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
	if (responder) {
Packit Service 6f2e62
		/* Send out a packet with a preference so that all
Packit Service 6f2e62
		 * hosts will know that we are dead.
Packit Service 6f2e62
		 *
Packit Service 6f2e62
		 * Wrong comment, wrong code.
Packit Service 6f2e62
		 *	ttl must be set to 0 instead. --ANK
Packit Service 6f2e62
		 */
Packit Service 6f2e62
		logerr("terminated\n");
Packit Service 6f2e62
		ntransmitted++;
Packit Service 6f2e62
		advertise(&whereto, 0);
Packit Service 6f2e62
	}
Packit Service 6f2e62
#endif
Packit Service 6f2e62
	logtrace("\n----%s rdisc Statistics----\n", sendaddress );
Packit Service 6f2e62
	logtrace("%d packets transmitted, ", ntransmitted );
Packit Service 6f2e62
	logtrace("%d packets received, ", nreceived );
Packit Service 6f2e62
	logtrace("\n");
Packit Service 6f2e62
	(void) fflush(stdout);
Packit Service 6f2e62
	exit(0);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void
Packit Service 6f2e62
graceful_finish()
Packit Service 6f2e62
{
Packit Service 6f2e62
	discard_table();
Packit Service 6f2e62
	finish();
Packit Service 6f2e62
	exit(0);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
/* From libc/rpc/pmap_rmt.c */
Packit Service 6f2e62
Packit Service 6f2e62
int
Packit Service 6f2e62
sendbcast(int s, char *packet, int packetlen)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int i, cc;
Packit Service 6f2e62
Packit Service 6f2e62
	for (i = 0; i < num_interfaces; i++) {
Packit Service 6f2e62
		if ((interfaces[i].flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		cc = sendbcastif(s, packet, packetlen, &interfaces[i]);
Packit Service 6f2e62
		if (cc!= packetlen) {
Packit Service 6f2e62
			return (cc);
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return (packetlen);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int
Packit Service 6f2e62
sendbcastif(int s, char *packet, int packetlen, struct interface *ifp)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int on;
Packit Service 6f2e62
	int cc;
Packit Service 6f2e62
	struct sockaddr_in baddr;
Packit Service 6f2e62
Packit Service 6f2e62
	baddr.sin_family = AF_INET;
Packit Service 6f2e62
	baddr.sin_addr = ifp->bcastaddr;
Packit Service 6f2e62
	if (debug)
Packit Service 6f2e62
		logdebug("Broadcast to %s\n",
Packit Service 6f2e62
			 pr_name(baddr.sin_addr));
Packit Service 6f2e62
	on = 1;
Packit Service 6f2e62
	setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
Packit Service 6f2e62
	cc = sendto(s, packet, packetlen, 0,
Packit Service 6f2e62
		    (struct sockaddr *)&baddr, sizeof (struct sockaddr));
Packit Service 6f2e62
	if (cc!= packetlen) {
Packit Service 6f2e62
		logperror("sendbcast: sendto");
Packit Service 6f2e62
		logerr("Cannot send broadcast packet to %s\n",
Packit Service 6f2e62
		       pr_name(baddr.sin_addr));
Packit Service 6f2e62
	}
Packit Service 6f2e62
	on = 0;
Packit Service 6f2e62
	setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
Packit Service 6f2e62
	return (cc);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int
Packit Service 6f2e62
sendmcast(int s, char *packet, int packetlen, struct sockaddr_in *sin)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int i, cc;
Packit Service 6f2e62
Packit Service 6f2e62
	for (i = 0; i < num_interfaces; i++) {
Packit Service 6f2e62
		if ((interfaces[i].flags & (IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST)) == 0)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		cc = sendmcastif(s, packet, packetlen, sin, &interfaces[i]);
Packit Service 6f2e62
		if (cc!= packetlen) {
Packit Service 6f2e62
			return (cc);
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return (packetlen);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int
Packit Service 6f2e62
sendmcastif(int s, char *packet, int packetlen,	struct sockaddr_in *sin,
Packit Service 6f2e62
	    struct interface *ifp)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int cc;
Packit Service 6f2e62
	struct ip_mreqn mreq;
Packit Service 6f2e62
Packit Service 6f2e62
	memset(&mreq, 0, sizeof(mreq));
Packit Service 6f2e62
	mreq.imr_ifindex = ifp->ifindex;
Packit Service 6f2e62
	mreq.imr_address = ifp->localaddr;
Packit Service 6f2e62
	if (debug)
Packit Service 6f2e62
		logdebug("Multicast to interface %s, %s\n",
Packit Service 6f2e62
			 ifp->name,
Packit Service 6f2e62
			 pr_name(mreq.imr_address));
Packit Service 6f2e62
	if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
Packit Service 6f2e62
		       (char *)&mreq,
Packit Service 6f2e62
		       sizeof(mreq)) < 0) {
Packit Service 6f2e62
		logperror("setsockopt (IP_MULTICAST_IF)");
Packit Service 6f2e62
		logerr("Cannot send multicast packet over interface %s, %s\n",
Packit Service 6f2e62
		       ifp->name,
Packit Service 6f2e62
		       pr_name(mreq.imr_address));
Packit Service 6f2e62
		return (-1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	cc = sendto(s, packet, packetlen, 0,
Packit Service 6f2e62
		    (struct sockaddr *)sin, sizeof (struct sockaddr));
Packit Service 6f2e62
	if (cc!= packetlen) {
Packit Service 6f2e62
		logperror("sendmcast: sendto");
Packit Service 6f2e62
		logerr("Cannot send multicast packet over interface %s, %s\n",
Packit Service 6f2e62
		       ifp->name, pr_name(mreq.imr_address));
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return (cc);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void
Packit Service 6f2e62
init()
Packit Service 6f2e62
{
Packit Service 6f2e62
	initifs();
Packit Service 6f2e62
#ifdef RDISC_SERVER
Packit Service 6f2e62
	{
Packit Service 6f2e62
		int i;
Packit Service 6f2e62
		for (i = 0; i < interfaces_size; i++)
Packit Service 6f2e62
			interfaces[i].preference = preference;
Packit Service 6f2e62
	}
Packit Service 6f2e62
#endif
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void
Packit Service 6f2e62
initifs()
Packit Service 6f2e62
{
Packit Service 6f2e62
	int	sock;
Packit Service 6f2e62
	struct ifconf ifc;
Packit Service 6f2e62
	struct ifreq ifreq, *ifr;
Packit Service 6f2e62
	struct sockaddr_in *sin;
Packit Service 6f2e62
	int n, i;
Packit Service 6f2e62
	char *buf;
Packit Service 6f2e62
	int numifs;
Packit Service 6f2e62
	unsigned bufsize;
Packit Service 6f2e62
Packit Service 6f2e62
	sock = socket(AF_INET, SOCK_DGRAM, 0);
Packit Service 6f2e62
	if (sock < 0) {
Packit Service 6f2e62
		logperror("initifs: socket");
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
#ifdef SIOCGIFNUM
Packit Service 6f2e62
	if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) {
Packit Service 6f2e62
		numifs = MAXIFS;
Packit Service 6f2e62
	}
Packit Service 6f2e62
#else
Packit Service 6f2e62
	numifs = MAXIFS;
Packit Service 6f2e62
#endif
Packit Service 6f2e62
	bufsize = numifs * sizeof(struct ifreq);
Packit Service 6f2e62
	buf = (char *)malloc(bufsize);
Packit Service 6f2e62
	if (buf == NULL) {
Packit Service 6f2e62
		logerr("out of memory\n");
Packit Service 6f2e62
		(void) close(sock);
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (interfaces != NULL)
Packit Service 6f2e62
		(void) free(interfaces);
Packit Service 6f2e62
	interfaces = (struct interface *)ALLIGN(malloc(numifs *
Packit Service 6f2e62
					sizeof(struct interface)));
Packit Service 6f2e62
	if (interfaces == NULL) {
Packit Service 6f2e62
		logerr("out of memory\n");
Packit Service 6f2e62
		(void) close(sock);
Packit Service 6f2e62
		(void) free(buf);
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	interfaces_size = numifs;
Packit Service 6f2e62
Packit Service 6f2e62
	ifc.ifc_len = bufsize;
Packit Service 6f2e62
	ifc.ifc_buf = buf;
Packit Service 6f2e62
	if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
Packit Service 6f2e62
		logperror("initifs: ioctl (get interface configuration)");
Packit Service 6f2e62
		(void) close(sock);
Packit Service 6f2e62
		(void) free(buf);
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	ifr = ifc.ifc_req;
Packit Service 6f2e62
	for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
Packit Service 6f2e62
		ifreq = *ifr;
Packit Service 6f2e62
		if (strlen(ifreq.ifr_name) >= IFNAMSIZ)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
Packit Service 6f2e62
			logperror("initifs: ioctl (get interface flags)");
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (ifr->ifr_addr.sa_family != AF_INET)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		if ((ifreq.ifr_flags & IFF_UP) == 0)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		if (ifreq.ifr_flags & IFF_LOOPBACK)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		if ((ifreq.ifr_flags & (IFF_MULTICAST|IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		strncpy(interfaces[i].name, ifr->ifr_name, IFNAMSIZ-1);
Packit Service 6f2e62
Packit Service 6f2e62
		sin = (struct sockaddr_in *)ALLIGN(&ifr->ifr_addr);
Packit Service 6f2e62
		interfaces[i].localaddr = sin->sin_addr;
Packit Service 6f2e62
		interfaces[i].flags = ifreq.ifr_flags;
Packit Service 6f2e62
		interfaces[i].netmask.s_addr = (__u32)0xffffffff;
Packit Service 6f2e62
		if (ioctl(sock, SIOCGIFINDEX, (char *)&ifreq) < 0) {
Packit Service 6f2e62
			logperror("initifs: ioctl (get ifindex)");
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		interfaces[i].ifindex = ifreq.ifr_ifindex;
Packit Service 6f2e62
		if (ifreq.ifr_flags & IFF_POINTOPOINT) {
Packit Service 6f2e62
			if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
Packit Service 6f2e62
				logperror("initifs: ioctl (get destination addr)");
Packit Service 6f2e62
				continue;
Packit Service 6f2e62
			}
Packit Service 6f2e62
			sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
Packit Service 6f2e62
			/* A pt-pt link is identified by the remote address */
Packit Service 6f2e62
			interfaces[i].address = sin->sin_addr;
Packit Service 6f2e62
			interfaces[i].remoteaddr = sin->sin_addr;
Packit Service 6f2e62
			/* Simulate broadcast for pt-pt */
Packit Service 6f2e62
			interfaces[i].bcastaddr = sin->sin_addr;
Packit Service 6f2e62
			interfaces[i].flags |= IFF_BROADCAST;
Packit Service 6f2e62
		} else {
Packit Service 6f2e62
			/* Non pt-pt links are identified by the local address */
Packit Service 6f2e62
			interfaces[i].address = interfaces[i].localaddr;
Packit Service 6f2e62
			interfaces[i].remoteaddr = interfaces[i].address;
Packit Service 6f2e62
			if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
Packit Service 6f2e62
				logperror("initifs: ioctl (get netmask)");
Packit Service 6f2e62
				continue;
Packit Service 6f2e62
			}
Packit Service 6f2e62
			sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
Packit Service 6f2e62
			interfaces[i].netmask = sin->sin_addr;
Packit Service 6f2e62
			if (ifreq.ifr_flags & IFF_BROADCAST) {
Packit Service 6f2e62
				if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
Packit Service 6f2e62
					logperror("initifs: ioctl (get broadcast address)");
Packit Service 6f2e62
					continue;
Packit Service 6f2e62
				}
Packit Service 6f2e62
				sin = (struct sockaddr_in *)ALLIGN(&ifreq.ifr_addr);
Packit Service 6f2e62
				interfaces[i].bcastaddr = sin->sin_addr;
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
#ifdef notdef
Packit Service 6f2e62
		if (debug)
Packit Service 6f2e62
			logdebug("Found interface %s, flags 0x%x\n",
Packit Service 6f2e62
				 pr_name(interfaces[i].localaddr),
Packit Service 6f2e62
				 interfaces[i].flags);
Packit Service 6f2e62
#endif
Packit Service 6f2e62
		i++;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	num_interfaces = i;
Packit Service 6f2e62
#ifdef notdef
Packit Service 6f2e62
	if (debug)
Packit Service 6f2e62
		logdebug("Found %d interfaces\n", num_interfaces);
Packit Service 6f2e62
#endif
Packit Service 6f2e62
	(void) close(sock);
Packit Service 6f2e62
	(void) free(buf);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int
Packit Service 6f2e62
join(int sock, struct sockaddr_in *sin)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int i, j;
Packit Service 6f2e62
	struct ip_mreqn mreq;
Packit Service 6f2e62
	int joined[num_interfaces];
Packit Service 6f2e62
Packit Service 6f2e62
	memset(joined, 0, sizeof(joined));
Packit Service 6f2e62
Packit Service 6f2e62
	if (isbroadcast(sin))
Packit Service 6f2e62
		return (0);
Packit Service 6f2e62
Packit Service 6f2e62
	mreq.imr_multiaddr = sin->sin_addr;
Packit Service 6f2e62
	for (i = 0; i < num_interfaces; i++) {
Packit Service 6f2e62
		for (j = 0; j < i; j++) {
Packit Service 6f2e62
			if (joined[j] == interfaces[i].ifindex)
Packit Service 6f2e62
				break;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		if (j != i)
Packit Service 6f2e62
			continue;
Packit Service 6f2e62
Packit Service 6f2e62
		mreq.imr_ifindex = interfaces[i].ifindex;
Packit Service 6f2e62
		mreq.imr_address.s_addr = 0;
Packit Service 6f2e62
Packit Service 6f2e62
		if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
Packit Service 6f2e62
			       (char *)&mreq, sizeof(mreq)) < 0) {
Packit Service 6f2e62
			logperror("setsockopt (IP_ADD_MEMBERSHIP)");
Packit Service 6f2e62
			return (-1);
Packit Service 6f2e62
		}
Packit Service 6f2e62
Packit Service 6f2e62
		joined[i] = interfaces[i].ifindex;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return (0);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int support_multicast()
Packit Service 6f2e62
{
Packit Service 6f2e62
	int sock;
Packit Service 6f2e62
	unsigned char ttl = 1;
Packit Service 6f2e62
Packit Service 6f2e62
	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Packit Service 6f2e62
	if (sock < 0) {
Packit Service 6f2e62
		logperror("support_multicast: socket");
Packit Service 6f2e62
		return (0);
Packit Service 6f2e62
	}
Packit Service 6f2e62
Packit Service 6f2e62
	if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
Packit Service 6f2e62
		       (char *)&ttl, sizeof(ttl)) < 0) {
Packit Service 6f2e62
		(void) close(sock);
Packit Service 6f2e62
		return (0);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	(void) close(sock);
Packit Service 6f2e62
	return (1);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int
Packit Service 6f2e62
is_directly_connected(struct in_addr in)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int i;
Packit Service 6f2e62
Packit Service 6f2e62
	for (i = 0; i < num_interfaces; i++) {
Packit Service 6f2e62
		/* Check that the subnetwork numbers match */
Packit Service 6f2e62
Packit Service 6f2e62
		if ((in.s_addr & interfaces[i].netmask.s_addr ) ==
Packit Service 6f2e62
		    (interfaces[i].remoteaddr.s_addr & interfaces[i].netmask.s_addr))
Packit Service 6f2e62
			return (1);
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return (0);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * TABLES
Packit Service 6f2e62
 */
Packit Service 6f2e62
struct table {
Packit Service 6f2e62
	struct in_addr	router;
Packit Service 6f2e62
	int		preference;
Packit Service 6f2e62
	int		remaining_time;
Packit Service 6f2e62
	int		in_kernel;
Packit Service 6f2e62
	struct table	*next;
Packit Service 6f2e62
};
Packit Service 6f2e62
Packit Service 6f2e62
struct table *table;
Packit Service 6f2e62
Packit Service 6f2e62
struct table *
Packit Service 6f2e62
find_router(struct in_addr addr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct table *tp;
Packit Service 6f2e62
Packit Service 6f2e62
	tp = table;
Packit Service 6f2e62
	while (tp) {
Packit Service 6f2e62
		if (tp->router.s_addr == addr.s_addr)
Packit Service 6f2e62
			return (tp);
Packit Service 6f2e62
		tp = tp->next;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return (NULL);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
int max_preference(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct table *tp;
Packit Service 6f2e62
	int max = (int)INELIGIBLE_PREF;
Packit Service 6f2e62
Packit Service 6f2e62
	tp = table;
Packit Service 6f2e62
	while (tp) {
Packit Service 6f2e62
		if (tp->preference > max)
Packit Service 6f2e62
			max = tp->preference;
Packit Service 6f2e62
		tp = tp->next;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	return (max);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
/* Note: this might leave the kernel with no default route for a short time. */
Packit Service 6f2e62
void
Packit Service 6f2e62
age_table(int time)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct table **tpp, *tp;
Packit Service 6f2e62
	int recalculate_max = 0;
Packit Service 6f2e62
	int max = max_preference();
Packit Service 6f2e62
Packit Service 6f2e62
	tpp = &table;
Packit Service 6f2e62
	while (*tpp != NULL) {
Packit Service 6f2e62
		tp = *tpp;
Packit Service 6f2e62
		tp->remaining_time -= time;
Packit Service 6f2e62
		if (tp->remaining_time <= 0) {
Packit Service 6f2e62
			*tpp = tp->next;
Packit Service 6f2e62
			if (tp->in_kernel)
Packit Service 6f2e62
				del_route(tp->router);
Packit Service 6f2e62
			if (best_preference &&
Packit Service 6f2e62
			    tp->preference == max)
Packit Service 6f2e62
				recalculate_max++;
Packit Service 6f2e62
			free((char *)tp);
Packit Service 6f2e62
		} else {
Packit Service 6f2e62
			tpp = &tp->next;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (recalculate_max) {
Packit Service 6f2e62
		int max = max_preference();
Packit Service 6f2e62
Packit Service 6f2e62
		if (max != INELIGIBLE_PREF) {
Packit Service 6f2e62
			tp = table;
Packit Service 6f2e62
			while (tp) {
Packit Service 6f2e62
				if (tp->preference == max && !tp->in_kernel) {
Packit Service 6f2e62
					add_route(tp->router);
Packit Service 6f2e62
					tp->in_kernel++;
Packit Service 6f2e62
				}
Packit Service 6f2e62
				tp = tp->next;
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void discard_table(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct table **tpp, *tp;
Packit Service 6f2e62
Packit Service 6f2e62
	tpp = &table;
Packit Service 6f2e62
	while (*tpp != NULL) {
Packit Service 6f2e62
		tp = *tpp;
Packit Service 6f2e62
		*tpp = tp->next;
Packit Service 6f2e62
		if (tp->in_kernel)
Packit Service 6f2e62
			del_route(tp->router);
Packit Service 6f2e62
		free((char *)tp);
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
void
Packit Service 6f2e62
record_router(struct in_addr router, int preference, int ttl)
Packit Service 6f2e62
{
Packit Service 6f2e62
	struct table *tp;
Packit Service 6f2e62
	int old_max = max_preference();
Packit Service 6f2e62
	int changed_up = 0;	/* max preference could have increased */
Packit Service 6f2e62
	int changed_down = 0;	/* max preference could have decreased */
Packit Service 6f2e62
Packit Service 6f2e62
	if (ttl < 4)
Packit Service 6f2e62
		preference = INELIGIBLE_PREF;
Packit Service 6f2e62
Packit Service 6f2e62
	if (debug)
Packit Service 6f2e62
		logdebug("Recording %s, ttl %d, preference 0x%x\n",
Packit Service 6f2e62
			 pr_name(router),
Packit Service 6f2e62
			 ttl,
Packit Service 6f2e62
			 preference);
Packit Service 6f2e62
	tp = find_router(router);
Packit Service 6f2e62
	if (tp) {
Packit Service 6f2e62
		if (tp->preference > preference &&
Packit Service 6f2e62
		    tp->preference == old_max)
Packit Service 6f2e62
			changed_down++;
Packit Service 6f2e62
		else if (preference > tp->preference)
Packit Service 6f2e62
			changed_up++;
Packit Service 6f2e62
		tp->preference = preference;
Packit Service 6f2e62
		tp->remaining_time = ttl;
Packit Service 6f2e62
	} else {
Packit Service 6f2e62
		if (preference > old_max)
Packit Service 6f2e62
			changed_up++;
Packit Service 6f2e62
		tp = (struct table *)ALLIGN(malloc(sizeof(struct table)));
Packit Service 6f2e62
		if (tp == NULL) {
Packit Service 6f2e62
			logerr("Out of memory\n");
Packit Service 6f2e62
			return;
Packit Service 6f2e62
		}
Packit Service 6f2e62
		tp->router = router;
Packit Service 6f2e62
		tp->preference = preference;
Packit Service 6f2e62
		tp->remaining_time = ttl;
Packit Service 6f2e62
		tp->in_kernel = 0;
Packit Service 6f2e62
		tp->next = table;
Packit Service 6f2e62
		table = tp;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (!tp->in_kernel &&
Packit Service 6f2e62
	    (!best_preference || tp->preference == max_preference()) &&
Packit Service 6f2e62
	    tp->preference != INELIGIBLE_PREF) {
Packit Service 6f2e62
		add_route(tp->router);
Packit Service 6f2e62
		tp->in_kernel++;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (tp->preference == INELIGIBLE_PREF && tp->in_kernel) {
Packit Service 6f2e62
		del_route(tp->router);
Packit Service 6f2e62
		tp->in_kernel = 0;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (best_preference && changed_down) {
Packit Service 6f2e62
		/* Check if we should add routes */
Packit Service 6f2e62
		int new_max = max_preference();
Packit Service 6f2e62
		if (new_max != INELIGIBLE_PREF) {
Packit Service 6f2e62
			tp = table;
Packit Service 6f2e62
			while (tp) {
Packit Service 6f2e62
				if (tp->preference == new_max &&
Packit Service 6f2e62
				    !tp->in_kernel) {
Packit Service 6f2e62
					add_route(tp->router);
Packit Service 6f2e62
					tp->in_kernel++;
Packit Service 6f2e62
				}
Packit Service 6f2e62
				tp = tp->next;
Packit Service 6f2e62
			}
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (best_preference && (changed_up || changed_down)) {
Packit Service 6f2e62
		/* Check if we should remove routes already in the kernel */
Packit Service 6f2e62
		int new_max = max_preference();
Packit Service 6f2e62
		tp = table;
Packit Service 6f2e62
		while (tp) {
Packit Service 6f2e62
			if (tp->preference < new_max && tp->in_kernel) {
Packit Service 6f2e62
				del_route(tp->router);
Packit Service 6f2e62
				tp->in_kernel = 0;
Packit Service 6f2e62
			}
Packit Service 6f2e62
			tp = tp->next;
Packit Service 6f2e62
		}
Packit Service 6f2e62
	}
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void
Packit Service 6f2e62
add_route(struct in_addr addr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	if (debug)
Packit Service 6f2e62
		logdebug("Add default route to %s\n", pr_name(addr));
Packit Service 6f2e62
	rtioctl(addr, SIOCADDRT);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void
Packit Service 6f2e62
del_route(struct in_addr addr)
Packit Service 6f2e62
{
Packit Service 6f2e62
	if (debug)
Packit Service 6f2e62
		logdebug("Delete default route to %s\n", pr_name(addr));
Packit Service 6f2e62
	rtioctl(addr, SIOCDELRT);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
void
Packit Service 6f2e62
rtioctl(struct in_addr addr, int op)
Packit Service 6f2e62
{
Packit Service 6f2e62
	int sock;
Packit Service 6f2e62
	struct rtentry rt;
Packit Service 6f2e62
	struct sockaddr_in *sin;
Packit Service 6f2e62
Packit Service 6f2e62
	memset((char *)&rt, 0, sizeof(struct rtentry));
Packit Service 6f2e62
	rt.rt_dst.sa_family = AF_INET;
Packit Service 6f2e62
	rt.rt_gateway.sa_family = AF_INET;
Packit Service 6f2e62
	rt.rt_genmask.sa_family = AF_INET;
Packit Service 6f2e62
	sin = (struct sockaddr_in *)ALLIGN(&rt.rt_gateway);
Packit Service 6f2e62
	sin->sin_addr = addr;
Packit Service 6f2e62
	rt.rt_flags = RTF_UP | RTF_GATEWAY;
Packit Service 6f2e62
Packit Service 6f2e62
	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Packit Service 6f2e62
	if (sock < 0) {
Packit Service 6f2e62
		logperror("rtioctl: socket");
Packit Service 6f2e62
		return;
Packit Service 6f2e62
	}
Packit Service 6f2e62
	if (ioctl(sock, op, (char *)&rt) < 0) {
Packit Service 6f2e62
		if (!(op == SIOCADDRT && errno == EEXIST))
Packit Service 6f2e62
			logperror("ioctl (add/delete route)");
Packit Service 6f2e62
	}
Packit Service 6f2e62
	(void) close(sock);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
/*
Packit Service 6f2e62
 * LOGGER
Packit Service 6f2e62
 */
Packit Service 6f2e62
Packit Service 6f2e62
void initlog(void)
Packit Service 6f2e62
{
Packit Service 6f2e62
	logging++;
Packit Service 6f2e62
	openlog("in.rdiscd", LOG_PID | LOG_CONS, LOG_DAEMON);
Packit Service 6f2e62
}
Packit Service 6f2e62
Packit Service 6f2e62
Packit Service 6f2e62
void
Packit Service 6f2e62
logperror(char *str)
Packit Service 6f2e62
{
Packit Service 6f2e62
	if (logging)
Packit Service 6f2e62
		syslog(LOG_ERR, "%s: %m", str);
Packit Service 6f2e62
	else
Packit Service 6f2e62
		(void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
Packit Service 6f2e62
}