Home | History | Annotate | Line # | Download | only in tools
      1  1.2   darrenr /*	$NetBSD: ipfsyncd.c,v 1.2 2012/07/22 14:27:51 darrenr Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*
      4  1.2   darrenr  * Copyright (C) 2012 by Darren Reed.
      5  1.1  christos  *
      6  1.1  christos  * See the IPFILTER.LICENCE file for details on licencing.
      7  1.1  christos  */
      8  1.1  christos #if !defined(lint)
      9  1.1  christos static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
     10  1.2   darrenr static const char rcsid[] = "@(#)Id: ipfsyncd.c,v 1.1.1.2 2012/07/22 13:44:55 darrenr Exp $";
     11  1.1  christos #endif
     12  1.1  christos #include <sys/types.h>
     13  1.1  christos #include <sys/time.h>
     14  1.1  christos #include <sys/socket.h>
     15  1.1  christos #include <sys/ioctl.h>
     16  1.1  christos #include <sys/sockio.h>
     17  1.1  christos #include <sys/errno.h>
     18  1.1  christos 
     19  1.1  christos #include <netinet/in.h>
     20  1.1  christos #include <net/if.h>
     21  1.1  christos 
     22  1.1  christos #include <arpa/inet.h>
     23  1.1  christos 
     24  1.1  christos #include <stdio.h>
     25  1.1  christos #include <stdlib.h>
     26  1.1  christos #include <fcntl.h>
     27  1.1  christos #include <unistd.h>
     28  1.1  christos #include <string.h>
     29  1.1  christos #include <syslog.h>
     30  1.1  christos #include <signal.h>
     31  1.1  christos 
     32  1.1  christos #include "ipf.h"
     33  1.1  christos #include "opts.h"
     34  1.1  christos 
     35  1.1  christos 
     36  1.1  christos #define	R_IO_ERROR	-1
     37  1.1  christos #define	R_OKAY		0
     38  1.1  christos #define	R_MORE		1
     39  1.1  christos #define	R_SKIP		2
     40  1.1  christos #if	defined(sun) && !defined(SOLARIS2)
     41  1.1  christos # define	STRERROR(x)     sys_errlist[x]
     42  1.1  christos extern  char    *sys_errlist[];
     43  1.1  christos #else
     44  1.1  christos # define	STRERROR(x)     strerror(x)
     45  1.1  christos #endif
     46  1.1  christos 
     47  1.1  christos 
     48  1.1  christos int	main __P((int, char *[]));
     49  1.1  christos void	usage __P((char *));
     50  1.1  christos void	printsynchdr __P((synchdr_t *));
     51  1.1  christos void	printtable __P((int));
     52  1.1  christos void	printsmcproto __P((char *));
     53  1.1  christos void	printcommand __P((int));
     54  1.1  christos int	do_kbuff __P((int, char *, int *));
     55  1.1  christos int	do_packet __P((int, char *));
     56  1.1  christos int	buildsocket __P((char *, struct sockaddr_in *));
     57  1.1  christos void	do_io __P((void));
     58  1.1  christos void	handleterm __P((int));
     59  1.1  christos 
     60  1.1  christos int	terminate = 0;
     61  1.1  christos int	igmpfd = -1;
     62  1.1  christos int	nfd = -1;
     63  1.1  christos int	lfd = -1;
     64  1.1  christos int	opts = 0;
     65  1.1  christos 
     66  1.1  christos void
     67  1.1  christos usage(progname)
     68  1.1  christos 	char *progname;
     69  1.1  christos {
     70  1.1  christos 	fprintf(stderr,
     71  1.1  christos 		"Usage: %s [-d] [-p port] [-i address] -I <interface>\n",
     72  1.1  christos 		progname);
     73  1.1  christos }
     74  1.1  christos 
     75  1.1  christos void
     76  1.1  christos handleterm(sig)
     77  1.1  christos 	int sig;
     78  1.1  christos {
     79  1.1  christos 	terminate = sig;
     80  1.1  christos }
     81  1.1  christos 
     82  1.1  christos 
     83  1.1  christos /* should be large enough to hold header + any datatype */
     84  1.1  christos #define BUFFERLEN 1400
     85  1.1  christos 
     86  1.1  christos int
     87  1.1  christos main(argc, argv)
     88  1.1  christos 	int argc;
     89  1.1  christos 	char *argv[];
     90  1.1  christos {
     91  1.1  christos 	struct sockaddr_in sin;
     92  1.1  christos 	char *interface;
     93  1.1  christos 	char *progname;
     94  1.1  christos 	int opt, tries;
     95  1.1  christos 
     96  1.1  christos 	progname = strrchr(argv[0], '/');
     97  1.1  christos 	if (progname) {
     98  1.1  christos 		progname++;
     99  1.1  christos 	} else {
    100  1.1  christos 		progname = argv[0];
    101  1.1  christos 	}
    102  1.1  christos 
    103  1.1  christos 	opts = 0;
    104  1.1  christos 	tries = 0;
    105  1.1  christos 	interface = NULL;
    106  1.1  christos 
    107  1.1  christos 	bzero((char *)&sin, sizeof(sin));
    108  1.1  christos 	sin.sin_family = AF_INET;
    109  1.1  christos 	sin.sin_port = htons(0xaf6c);
    110  1.1  christos 	sin.sin_addr.s_addr = htonl(INADDR_UNSPEC_GROUP | 0x697066);
    111  1.1  christos 
    112  1.1  christos 	while ((opt = getopt(argc, argv, "di:I:p:")) != -1)
    113  1.1  christos 		switch (opt)
    114  1.1  christos 		{
    115  1.1  christos 		case 'd' :
    116  1.1  christos 			debuglevel++;
    117  1.1  christos 			break;
    118  1.1  christos 		case 'I' :
    119  1.1  christos 			interface = optarg;
    120  1.1  christos 			break;
    121  1.1  christos 		case 'i' :
    122  1.1  christos 			sin.sin_addr.s_addr = inet_addr(optarg);
    123  1.1  christos 			break;
    124  1.1  christos 		case 'p' :
    125  1.1  christos 			sin.sin_port = htons(atoi(optarg));
    126  1.1  christos 			break;
    127  1.1  christos 		}
    128  1.1  christos 
    129  1.1  christos 	if (interface == NULL) {
    130  1.1  christos 		usage(progname);
    131  1.1  christos 		exit(1);
    132  1.1  christos 	}
    133  1.1  christos 
    134  1.1  christos 	if (!debuglevel) {
    135  1.1  christos 
    136  1.1  christos #if BSD >= 199306
    137  1.1  christos 		daemon(0, 0);
    138  1.1  christos #else
    139  1.1  christos 		int fd = open("/dev/null", O_RDWR);
    140  1.1  christos 
    141  1.1  christos 		switch (fork())
    142  1.1  christos 		{
    143  1.1  christos 		case 0 :
    144  1.1  christos 			break;
    145  1.1  christos 
    146  1.1  christos 		case -1 :
    147  1.1  christos 			fprintf(stderr, "%s: fork() failed: %s\n",
    148  1.1  christos 				argv[0], STRERROR(errno));
    149  1.1  christos 			exit(1);
    150  1.1  christos 			/* NOTREACHED */
    151  1.1  christos 
    152  1.1  christos 		default :
    153  1.1  christos 			exit(0);
    154  1.1  christos 			/* NOTREACHED */
    155  1.1  christos 		}
    156  1.1  christos 
    157  1.1  christos 		dup2(fd, 0);
    158  1.1  christos 		dup2(fd, 1);
    159  1.1  christos 		dup2(fd, 2);
    160  1.1  christos 		close(fd);
    161  1.1  christos 
    162  1.1  christos 		setsid();
    163  1.1  christos #endif
    164  1.1  christos 	}
    165  1.1  christos 
    166  1.1  christos        	signal(SIGHUP, handleterm);
    167  1.1  christos        	signal(SIGINT, handleterm);
    168  1.1  christos        	signal(SIGTERM, handleterm);
    169  1.1  christos 
    170  1.1  christos 	openlog(progname, LOG_PID, LOG_SECURITY);
    171  1.1  christos 
    172  1.1  christos 	while (!terminate) {
    173  1.1  christos 		if (lfd != -1) {
    174  1.1  christos 			close(lfd);
    175  1.1  christos 			lfd = -1;
    176  1.1  christos 		}
    177  1.1  christos 		if (nfd != -1) {
    178  1.1  christos 			close(nfd);
    179  1.1  christos 			nfd = -1;
    180  1.1  christos 		}
    181  1.1  christos 		if (igmpfd != -1) {
    182  1.1  christos 			close(igmpfd);
    183  1.1  christos 			igmpfd = -1;
    184  1.1  christos 		}
    185  1.1  christos 
    186  1.1  christos 		if (buildsocket(interface, &sin) == -1)
    187  1.1  christos 			goto tryagain;
    188  1.1  christos 
    189  1.1  christos 		lfd = open(IPSYNC_NAME, O_RDWR);
    190  1.1  christos 		if (lfd == -1) {
    191  1.1  christos 			syslog(LOG_ERR, "open(%s):%m", IPSYNC_NAME);
    192  1.1  christos 			debug(1, "open(%s): %s\n", IPSYNC_NAME,
    193  1.1  christos 			      STRERROR(errno));
    194  1.1  christos 			goto tryagain;
    195  1.1  christos 		}
    196  1.1  christos 
    197  1.1  christos 		tries = -1;
    198  1.1  christos 		do_io();
    199  1.1  christos tryagain:
    200  1.1  christos 		tries++;
    201  1.1  christos 		syslog(LOG_INFO, "retry in %d seconds", 1 << tries);
    202  1.1  christos 		debug(1, "wait %d seconds\n", 1 << tries);
    203  1.1  christos 		sleep(1 << tries);
    204  1.1  christos 	}
    205  1.1  christos 
    206  1.1  christos 
    207  1.1  christos 	/* terminate */
    208  1.1  christos 	if (lfd != -1)
    209  1.1  christos 		close(lfd);
    210  1.1  christos 	if (nfd != -1)
    211  1.1  christos 		close(nfd);
    212  1.1  christos 
    213  1.1  christos 	syslog(LOG_ERR, "signal %d received, exiting...", terminate);
    214  1.1  christos 	debug(1, "signal %d received, exiting...", terminate);
    215  1.1  christos 
    216  1.1  christos 	exit(1);
    217  1.1  christos }
    218  1.1  christos 
    219  1.1  christos 
    220  1.1  christos void
    221  1.1  christos do_io()
    222  1.1  christos {
    223  1.1  christos 	char nbuff[BUFFERLEN];
    224  1.1  christos 	char buff[BUFFERLEN];
    225  1.1  christos 	fd_set mrd, rd;
    226  1.1  christos 	int maxfd;
    227  1.1  christos 	int inbuf;
    228  1.1  christos 	int n1;
    229  1.1  christos 	int left;
    230  1.1  christos 
    231  1.1  christos 	FD_ZERO(&mrd);
    232  1.1  christos 	FD_SET(lfd, &mrd);
    233  1.1  christos 	FD_SET(nfd, &mrd);
    234  1.1  christos 	maxfd = nfd;
    235  1.1  christos 	if (lfd > maxfd)
    236  1.1  christos 		maxfd = lfd;
    237  1.1  christos 	debug(2, "nfd %d lfd %d maxfd %d\n", nfd, lfd, maxfd);
    238  1.1  christos 
    239  1.1  christos 	inbuf = 0;
    240  1.1  christos 	/*
    241  1.1  christos 	 * A threaded approach to this loop would have one thread
    242  1.1  christos 	 * work on reading lfd (only) all the time and another thread
    243  1.1  christos 	 * working on reading nfd all the time.
    244  1.1  christos 	 */
    245  1.1  christos 	while (!terminate) {
    246  1.1  christos 		int n;
    247  1.1  christos 
    248  1.1  christos 		rd = mrd;
    249  1.1  christos 
    250  1.1  christos 		n = select(maxfd + 1, &rd, NULL, NULL, NULL);
    251  1.1  christos 		if (n < 0) {
    252  1.1  christos 			switch (errno)
    253  1.1  christos 			{
    254  1.1  christos 			case EINTR :
    255  1.1  christos 				continue;
    256  1.1  christos 			default :
    257  1.1  christos 				syslog(LOG_ERR, "select error: %m");
    258  1.1  christos 				debug(1, "select error: %s\n", STRERROR(errno));
    259  1.1  christos 				return;
    260  1.1  christos 			}
    261  1.1  christos 		}
    262  1.1  christos 
    263  1.1  christos 		if (FD_ISSET(lfd, &rd)) {
    264  1.1  christos 			n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf);
    265  1.1  christos 
    266  1.1  christos 			debug(3, "read(K):%d\n", n1);
    267  1.1  christos 
    268  1.1  christos 			if (n1 <= 0) {
    269  1.1  christos 				syslog(LOG_ERR, "read error (k-header): %m");
    270  1.1  christos 				debug(1, "read error (k-header): %s\n",
    271  1.1  christos 				      STRERROR(errno));
    272  1.1  christos 				return;
    273  1.1  christos 			}
    274  1.1  christos 
    275  1.1  christos 			left = 0;
    276  1.1  christos 
    277  1.1  christos 			switch (do_kbuff(n1, buff, &left))
    278  1.1  christos 			{
    279  1.1  christos 			case R_IO_ERROR :
    280  1.1  christos 				return;
    281  1.1  christos 			case R_MORE :
    282  1.1  christos 				inbuf += left;
    283  1.1  christos 				break;
    284  1.1  christos 			default :
    285  1.1  christos 				inbuf = 0;
    286  1.1  christos 				break;
    287  1.1  christos 			}
    288  1.1  christos 		}
    289  1.1  christos 
    290  1.1  christos 		if (FD_ISSET(nfd, &rd)) {
    291  1.1  christos 			n1 = recv(nfd, nbuff, sizeof(nbuff), 0);
    292  1.1  christos 
    293  1.1  christos 			debug(3, "read(N):%d\n", n1);
    294  1.1  christos 
    295  1.1  christos 			if (n1 <= 0) {
    296  1.1  christos 				syslog(LOG_ERR, "read error (n-header): %m");
    297  1.1  christos 				debug(1, "read error (n-header): %s\n",
    298  1.1  christos 				      STRERROR(errno));
    299  1.1  christos 				return;
    300  1.1  christos 			}
    301  1.1  christos 
    302  1.1  christos 			switch (do_packet(n1, nbuff))
    303  1.1  christos 			{
    304  1.1  christos 			case R_IO_ERROR :
    305  1.1  christos 				return;
    306  1.1  christos 			default :
    307  1.1  christos 				break;
    308  1.1  christos 			}
    309  1.1  christos 		}
    310  1.1  christos 	}
    311  1.1  christos }
    312  1.1  christos 
    313  1.1  christos 
    314  1.1  christos int
    315  1.1  christos buildsocket(nicname, sinp)
    316  1.1  christos 	char *nicname;
    317  1.1  christos 	struct sockaddr_in *sinp;
    318  1.1  christos {
    319  1.1  christos 	struct sockaddr_in *reqip;
    320  1.1  christos 	struct ifreq req;
    321  1.1  christos 	char opt;
    322  1.1  christos 
    323  1.1  christos 	debug(2, "binding to %s:%s\n", nicname, inet_ntoa(sinp->sin_addr));
    324  1.1  christos 
    325  1.1  christos 	if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
    326  1.1  christos 		struct in_addr addr;
    327  1.1  christos 		struct ip_mreq mreq;
    328  1.1  christos 
    329  1.1  christos 		igmpfd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
    330  1.1  christos 		if (igmpfd == -1) {
    331  1.1  christos 			syslog(LOG_ERR, "socket:%m");
    332  1.1  christos 			debug(1, "socket:%s\n", STRERROR(errno));
    333  1.1  christos 			return -1;
    334  1.1  christos 		}
    335  1.1  christos 
    336  1.1  christos 		bzero((char *)&req, sizeof(req));
    337  1.1  christos 		strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
    338  1.1  christos 		req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
    339  1.1  christos 		if (ioctl(igmpfd, SIOCGIFADDR, &req) == -1) {
    340  1.1  christos 			syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
    341  1.1  christos 			debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
    342  1.1  christos 			close(igmpfd);
    343  1.1  christos 			igmpfd = -1;
    344  1.1  christos 			return -1;
    345  1.1  christos 		}
    346  1.1  christos 		reqip = (struct sockaddr_in *)&req.ifr_addr;
    347  1.1  christos 
    348  1.1  christos 		addr = reqip->sin_addr;
    349  1.1  christos 		if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_IF,
    350  1.1  christos 			       (char *)&addr, sizeof(addr)) == -1) {
    351  1.1  christos 			syslog(LOG_ERR, "setsockopt(IP_MULTICAST_IF(%s)):%m",
    352  1.1  christos 			       inet_ntoa(addr));
    353  1.1  christos 			debug(1, "setsockopt(IP_MULTICAST_IF(%s)):%s\n",
    354  1.1  christos 			      inet_ntoa(addr), STRERROR(errno));
    355  1.1  christos 			close(igmpfd);
    356  1.1  christos 			igmpfd = -1;
    357  1.1  christos 			return -1;
    358  1.1  christos 		}
    359  1.1  christos 
    360  1.1  christos 		opt = 0;
    361  1.1  christos 		if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_LOOP,
    362  1.1  christos 			       (char *)&opt, sizeof(opt)) == -1) {
    363  1.1  christos 			syslog(LOG_ERR, "setsockopt(IP_MULTICAST_LOOP=0):%m");
    364  1.1  christos 			debug(1, "setsockopt(IP_MULTICAST_LOOP=0):%s\n",
    365  1.1  christos 			      STRERROR(errno));
    366  1.1  christos 			close(igmpfd);
    367  1.1  christos 			igmpfd = -1;
    368  1.1  christos 			return -1;
    369  1.1  christos 		}
    370  1.1  christos 
    371  1.1  christos 		opt = 63;
    372  1.1  christos 		if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_TTL,
    373  1.1  christos 			       (char *)&opt, sizeof(opt)) == -1) {
    374  1.1  christos 			syslog(LOG_ERR, "setsockopt(IP_MULTICAST_TTL=%d):%m",
    375  1.1  christos 			       opt);
    376  1.1  christos 			debug(1, "setsockopt(IP_MULTICAST_TTL=%d):%s\n", opt,
    377  1.1  christos 			      STRERROR(errno));
    378  1.1  christos 			close(igmpfd);
    379  1.1  christos 			igmpfd = -1;
    380  1.1  christos 			return -1;
    381  1.1  christos 		}
    382  1.1  christos 
    383  1.1  christos 		mreq.imr_multiaddr.s_addr = sinp->sin_addr.s_addr;
    384  1.1  christos 		mreq.imr_interface.s_addr = reqip->sin_addr.s_addr;
    385  1.1  christos 
    386  1.1  christos 		if (setsockopt(igmpfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
    387  1.1  christos 			       (char *)&mreq, sizeof(mreq)) == -1) {
    388  1.1  christos 			char buffer[80];
    389  1.1  christos 
    390  1.1  christos 			sprintf(buffer, "%s,", inet_ntoa(sinp->sin_addr));
    391  1.1  christos 			strcat(buffer, inet_ntoa(reqip->sin_addr));
    392  1.1  christos 
    393  1.1  christos 			syslog(LOG_ERR,
    394  1.1  christos 			       "setsockpt(IP_ADD_MEMBERSHIP,%s):%m", buffer);
    395  1.1  christos 			debug(1, "setsockpt(IP_ADD_MEMBERSHIP,%s):%s\n",
    396  1.1  christos 			      buffer, STRERROR(errno));
    397  1.1  christos 			close(igmpfd);
    398  1.1  christos 			igmpfd = -1;
    399  1.1  christos 			return -1;
    400  1.1  christos 		}
    401  1.1  christos 	}
    402  1.1  christos 	nfd = socket(AF_INET, SOCK_DGRAM, 0);
    403  1.1  christos 	if (nfd == -1) {
    404  1.1  christos 		syslog(LOG_ERR, "socket:%m");
    405  1.1  christos 		if (igmpfd != -1) {
    406  1.1  christos 			close(igmpfd);
    407  1.1  christos 			igmpfd = -1;
    408  1.1  christos 		}
    409  1.1  christos 		return -1;
    410  1.1  christos 	}
    411  1.1  christos 	bzero((char *)&req, sizeof(req));
    412  1.1  christos 	strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
    413  1.1  christos 	req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
    414  1.1  christos 	if (ioctl(nfd, SIOCGIFADDR, &req) == -1) {
    415  1.1  christos 		syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
    416  1.1  christos 		debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
    417  1.1  christos 		close(igmpfd);
    418  1.1  christos 		igmpfd = -1;
    419  1.1  christos 		return -1;
    420  1.1  christos 	}
    421  1.1  christos 
    422  1.1  christos 	if (bind(nfd, (struct sockaddr *)&req.ifr_addr,
    423  1.1  christos 		 sizeof(req.ifr_addr)) == -1) {
    424  1.1  christos 		syslog(LOG_ERR, "bind:%m");
    425  1.1  christos 		debug(1, "bind:%s\n", STRERROR(errno));
    426  1.1  christos 		close(nfd);
    427  1.1  christos 		if (igmpfd != -1) {
    428  1.1  christos 			close(igmpfd);
    429  1.1  christos 			igmpfd = -1;
    430  1.1  christos 		}
    431  1.1  christos 		nfd = -1;
    432  1.1  christos 		return -1;
    433  1.1  christos 	}
    434  1.1  christos 
    435  1.1  christos 	if (connect(nfd, (struct sockaddr *)sinp, sizeof(*sinp)) == -1) {
    436  1.1  christos 		syslog(LOG_ERR, "connect:%m");
    437  1.1  christos 		debug(1, "connect:%s\n", STRERROR(errno));
    438  1.1  christos 		close(nfd);
    439  1.1  christos 		if (igmpfd != -1) {
    440  1.1  christos 			close(igmpfd);
    441  1.1  christos 			igmpfd = -1;
    442  1.1  christos 		}
    443  1.1  christos 		nfd = -1;
    444  1.1  christos 		return -1;
    445  1.1  christos 	}
    446  1.1  christos 	syslog(LOG_INFO, "Sending data to %s", inet_ntoa(sinp->sin_addr));
    447  1.1  christos 	debug(3, "Sending data to %s\n", inet_ntoa(sinp->sin_addr));
    448  1.1  christos 
    449  1.1  christos 	return nfd;
    450  1.1  christos }
    451  1.1  christos 
    452  1.1  christos 
    453  1.1  christos int
    454  1.1  christos do_packet(pklen, buff)
    455  1.1  christos 	int pklen;
    456  1.1  christos 	char *buff;
    457  1.1  christos {
    458  1.1  christos 	synchdr_t *sh;
    459  1.1  christos 	u_32_t magic;
    460  1.1  christos 	int len;
    461  1.1  christos 	int n2;
    462  1.1  christos 	int n3;
    463  1.1  christos 
    464  1.1  christos 	while (pklen > 0) {
    465  1.1  christos 		if (pklen < sizeof(*sh)) {
    466  1.1  christos 			syslog(LOG_ERR, "packet length too short:%d", pklen);
    467  1.1  christos 			debug(2, "packet length too short:%d\n", pklen);
    468  1.1  christos 			return R_SKIP;
    469  1.1  christos 		}
    470  1.1  christos 
    471  1.1  christos 		sh = (synchdr_t *)buff;
    472  1.1  christos 		len = ntohl(sh->sm_len);
    473  1.1  christos 		magic = ntohl(sh->sm_magic);
    474  1.1  christos 
    475  1.1  christos 		if (magic != SYNHDRMAGIC) {
    476  1.1  christos 			syslog(LOG_ERR, "invalid header magic %x", magic);
    477  1.1  christos 			debug(2, "invalid header magic %x\n", magic);
    478  1.1  christos 			return R_SKIP;
    479  1.1  christos 		}
    480  1.1  christos 
    481  1.1  christos 		if (pklen < len + sizeof(*sh)) {
    482  1.1  christos 			syslog(LOG_ERR, "packet length too short:%d", pklen);
    483  1.1  christos 			debug(2, "packet length too short:%d\n", pklen);
    484  1.1  christos 			return R_SKIP;
    485  1.1  christos 		}
    486  1.1  christos 
    487  1.1  christos 		if (debuglevel > 3) {
    488  1.1  christos 			printsynchdr(sh);
    489  1.1  christos 			printcommand(sh->sm_cmd);
    490  1.1  christos 			printtable(sh->sm_table);
    491  1.1  christos 			printsmcproto(buff);
    492  1.1  christos 		}
    493  1.1  christos 
    494  1.1  christos 		n2 = sizeof(*sh) + len;
    495  1.1  christos 
    496  1.1  christos 		do {
    497  1.1  christos 			n3 = write(lfd, buff, n2);
    498  1.1  christos 			if (n3 <= 0) {
    499  1.1  christos 				syslog(LOG_ERR, "write error: %m");
    500  1.1  christos 				debug(1, "write error: %s\n", STRERROR(errno));
    501  1.1  christos 				return R_IO_ERROR;
    502  1.1  christos 			}
    503  1.1  christos 
    504  1.1  christos 			n2 -= n3;
    505  1.1  christos 			buff += n3;
    506  1.1  christos 			pklen -= n3;
    507  1.1  christos 		} while (n3 != 0);
    508  1.1  christos 	}
    509  1.1  christos 
    510  1.1  christos 	return R_OKAY;
    511  1.1  christos }
    512  1.1  christos 
    513  1.1  christos 
    514  1.1  christos 
    515  1.1  christos int
    516  1.1  christos do_kbuff(inbuf, buf, left)
    517  1.1  christos 	int inbuf, *left;
    518  1.1  christos 	char *buf;
    519  1.1  christos {
    520  1.1  christos 	synchdr_t *sh;
    521  1.1  christos 	u_32_t magic;
    522  1.1  christos 	int complete;
    523  1.1  christos 	int sendlen;
    524  1.1  christos 	int error;
    525  1.1  christos 	int bytes;
    526  1.1  christos 	int len;
    527  1.1  christos 	int n2;
    528  1.1  christos 	int n3;
    529  1.1  christos 
    530  1.1  christos 	sendlen = 0;
    531  1.1  christos 	bytes = inbuf;
    532  1.1  christos 	error = R_OKAY;
    533  1.1  christos 	sh = (synchdr_t *)buf;
    534  1.1  christos 
    535  1.1  christos 	for (complete = 0; bytes > 0; complete++) {
    536  1.1  christos 		len = ntohl(sh->sm_len);
    537  1.1  christos 		magic = ntohl(sh->sm_magic);
    538  1.1  christos 
    539  1.1  christos 		if (magic != SYNHDRMAGIC) {
    540  1.1  christos 			syslog(LOG_ERR,
    541  1.1  christos 			       "read invalid header magic 0x%x, flushing",
    542  1.1  christos 			       magic);
    543  1.1  christos 			debug(2, "read invalid header magic 0x%x, flushing\n",
    544  1.1  christos 			       magic);
    545  1.1  christos 			n2 = SMC_RLOG;
    546  1.1  christos 			(void) ioctl(lfd, SIOCIPFFL, &n2);
    547  1.1  christos 			break;
    548  1.1  christos 		}
    549  1.1  christos 
    550  1.1  christos 		if (debuglevel > 3) {
    551  1.1  christos 			printsynchdr(sh);
    552  1.1  christos 			printcommand(sh->sm_cmd);
    553  1.1  christos 			printtable(sh->sm_table);
    554  1.1  christos 			putchar('\n');
    555  1.1  christos 		}
    556  1.1  christos 
    557  1.1  christos 		if (bytes < sizeof(*sh) + len) {
    558  1.1  christos 			debug(3, "Not enough bytes %d < %d\n", bytes,
    559  1.1  christos 			      sizeof(*sh) + len);
    560  1.1  christos 			error = R_MORE;
    561  1.1  christos 			break;
    562  1.1  christos 		}
    563  1.1  christos 
    564  1.1  christos 		if (debuglevel > 3) {
    565  1.1  christos 			printsmcproto(buf);
    566  1.1  christos 		}
    567  1.1  christos 
    568  1.1  christos 		sendlen += len + sizeof(*sh);
    569  1.1  christos 		sh = (synchdr_t *)(buf + sendlen);
    570  1.1  christos 		bytes -= sendlen;
    571  1.1  christos 	}
    572  1.1  christos 
    573  1.1  christos 	if (complete) {
    574  1.1  christos 		n3 = send(nfd, buf, sendlen, 0);
    575  1.1  christos 		if (n3 <= 0) {
    576  1.1  christos 			syslog(LOG_ERR, "write error: %m");
    577  1.1  christos 			debug(1, "write error: %s\n", STRERROR(errno));
    578  1.1  christos 			return R_IO_ERROR;
    579  1.1  christos 		}
    580  1.1  christos 		debug(3, "send on %d len %d = %d\n", nfd, sendlen, n3);
    581  1.1  christos 		error = R_OKAY;
    582  1.1  christos 	}
    583  1.1  christos 
    584  1.1  christos 	/* move buffer to the front,we might need to make
    585  1.1  christos 	 * this more efficient, by using a rolling pointer
    586  1.1  christos 	 * over the buffer and only copying it, when
    587  1.1  christos 	 * we are reaching the end
    588  1.1  christos 	 */
    589  1.1  christos 	if (bytes > 0) {
    590  1.1  christos 		bcopy(buf + bytes, buf, bytes);
    591  1.1  christos 		error = R_MORE;
    592  1.1  christos 	}
    593  1.1  christos 	debug(4, "complete %d bytes %d error %d\n", complete, bytes, error);
    594  1.1  christos 
    595  1.1  christos 	*left = bytes;
    596  1.1  christos 
    597  1.1  christos 	return error;
    598  1.1  christos }
    599  1.1  christos 
    600  1.1  christos 
    601  1.1  christos void
    602  1.1  christos printcommand(cmd)
    603  1.1  christos 	int cmd;
    604  1.1  christos {
    605  1.1  christos 
    606  1.1  christos 	switch (cmd)
    607  1.1  christos 	{
    608  1.1  christos 	case SMC_CREATE :
    609  1.1  christos 		printf(" cmd:CREATE");
    610  1.1  christos 		break;
    611  1.1  christos 	case SMC_UPDATE :
    612  1.1  christos 		printf(" cmd:UPDATE");
    613  1.1  christos 		break;
    614  1.1  christos 	default :
    615  1.1  christos 		printf(" cmd:Unknown(%d)", cmd);
    616  1.1  christos 		break;
    617  1.1  christos 	}
    618  1.1  christos }
    619  1.1  christos 
    620  1.1  christos 
    621  1.1  christos void
    622  1.1  christos printtable(table)
    623  1.1  christos 	int table;
    624  1.1  christos {
    625  1.1  christos 	switch (table)
    626  1.1  christos 	{
    627  1.1  christos 	case SMC_NAT :
    628  1.1  christos 		printf(" table:NAT");
    629  1.1  christos 		break;
    630  1.1  christos 	case SMC_STATE :
    631  1.1  christos 		printf(" table:STATE");
    632  1.1  christos 		break;
    633  1.1  christos 	default :
    634  1.1  christos 		printf(" table:Unknown(%d)", table);
    635  1.1  christos 		break;
    636  1.1  christos 	}
    637  1.1  christos }
    638  1.1  christos 
    639  1.1  christos 
    640  1.1  christos void
    641  1.1  christos printsmcproto(buff)
    642  1.1  christos 	char *buff;
    643  1.1  christos {
    644  1.1  christos 	syncupdent_t *su;
    645  1.1  christos 	synchdr_t *sh;
    646  1.1  christos 
    647  1.1  christos 	sh = (synchdr_t *)buff;
    648  1.1  christos 
    649  1.1  christos 	if (sh->sm_cmd == SMC_CREATE) {
    650  1.1  christos 		;
    651  1.1  christos 
    652  1.1  christos 	} else if (sh->sm_cmd == SMC_UPDATE) {
    653  1.1  christos 		su = (syncupdent_t *)buff;
    654  1.1  christos 		if (sh->sm_p == IPPROTO_TCP) {
    655  1.1  christos 			printf(" TCP Update: age %lu state %d/%d\n",
    656  1.1  christos 				su->sup_tcp.stu_age,
    657  1.1  christos 				su->sup_tcp.stu_state[0],
    658  1.1  christos 				su->sup_tcp.stu_state[1]);
    659  1.1  christos 		}
    660  1.1  christos 	} else {
    661  1.1  christos 		printf("Unknown command\n");
    662  1.1  christos 	}
    663  1.1  christos }
    664  1.1  christos 
    665  1.1  christos 
    666  1.1  christos void
    667  1.1  christos printsynchdr(sh)
    668  1.1  christos 	synchdr_t *sh;
    669  1.1  christos {
    670  1.1  christos 
    671  1.1  christos 	printf("v:%d p:%d num:%d len:%d magic:%x", sh->sm_v, sh->sm_p,
    672  1.1  christos 	       ntohl(sh->sm_num), ntohl(sh->sm_len), ntohl(sh->sm_magic));
    673  1.1  christos }
    674