1139825Simp/*
290643Sbenno * Copyright (C) 2012 by Darren Reed.
390643Sbenno *
490643Sbenno * See the IPFILTER.LICENCE file for details on licencing.
590643Sbenno */
690643Sbenno#if !defined(lint)
790643Sbennostatic const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
890643Sbennostatic const char rcsid[] = "@(#)$Id: ipfsyncd.c,v 1.1.2.2 2012/07/22 08:04:24 darren_r Exp $";
990643Sbenno#endif
1090643Sbenno#include <sys/types.h>
1190643Sbenno#include <sys/time.h>
1290643Sbenno#include <sys/socket.h>
1390643Sbenno#include <sys/ioctl.h>
1490643Sbenno#include <sys/sockio.h>
1590643Sbenno#include <sys/errno.h>
1690643Sbenno
1790643Sbenno#include <netinet/in.h>
1890643Sbenno#include <net/if.h>
1990643Sbenno
2090643Sbenno#include <arpa/inet.h>
2190643Sbenno
2290643Sbenno#include <stdio.h>
2390643Sbenno#include <stdlib.h>
2490643Sbenno#include <fcntl.h>
2590643Sbenno#include <unistd.h>
2690643Sbenno#include <string.h>
2790643Sbenno#include <syslog.h>
2890643Sbenno#include <signal.h>
2990643Sbenno
3090643Sbenno#include "ipf.h"
3190643Sbenno#include "opts.h"
3290643Sbenno
3390643Sbenno
3490643Sbenno#define	R_IO_ERROR	-1
3590643Sbenno#define	R_OKAY		0
36139825Simp#define	R_MORE		1
3777957Sbenno#define	R_SKIP		2
3877957Sbenno#if	defined(sun) && !defined(SOLARIS2)
3977957Sbenno# define	STRERROR(x)     sys_errlist[x]
4077957Sbennoextern  char    *sys_errlist[];
4177957Sbenno#else
4277957Sbenno# define	STRERROR(x)     strerror(x)
4377957Sbenno#endif
4477957Sbenno
4577957Sbenno
4677957Sbennoint	main __P((int, char *[]));
4777957Sbennovoid	usage __P((char *));
4877957Sbennovoid	printsynchdr __P((synchdr_t *));
4977957Sbennovoid	printtable __P((int));
5077957Sbennovoid	printsmcproto __P((char *));
5177957Sbennovoid	printcommand __P((int));
5277957Sbennoint	do_kbuff __P((int, char *, int *));
5377957Sbennoint	do_packet __P((int, char *));
5477957Sbennoint	buildsocket __P((char *, struct sockaddr_in *));
5577957Sbennovoid	do_io __P((void));
5677957Sbennovoid	handleterm __P((int));
5777957Sbenno
5877957Sbennoint	terminate = 0;
5977957Sbennoint	igmpfd = -1;
6077957Sbennoint	nfd = -1;
6177957Sbennoint	lfd = -1;
6277957Sbennoint	opts = 0;
6377957Sbenno
6477957Sbennovoid
6577957Sbennousage(progname)
6678880Sbenno	char *progname;
6777957Sbenno{
68139825Simp	fprintf(stderr,
6977957Sbenno		"Usage: %s [-d] [-p port] [-i address] -I <interface>\n",
7077957Sbenno		progname);
7177957Sbenno}
7277957Sbenno
7377957Sbennovoid
7477957Sbennohandleterm(sig)
7577957Sbenno	int sig;
7677957Sbenno{
7777957Sbenno	terminate = sig;
7877957Sbenno}
7977957Sbenno
8077957Sbenno
8177957Sbenno/* should be large enough to hold header + any datatype */
8277957Sbenno#define BUFFERLEN 1400
8377957Sbenno
8477957Sbennoint
8577957Sbennomain(argc, argv)
8677957Sbenno	int argc;
8777957Sbenno	char *argv[];
8877957Sbenno{
8977957Sbenno	struct sockaddr_in sin;
9077957Sbenno	char *interface;
9177957Sbenno	char *progname;
9277957Sbenno	int opt, tries;
93113038Sobrien
94113038Sobrien	progname = strrchr(argv[0], '/');
9577957Sbenno	if (progname) {
9690643Sbenno		progname++;
9790643Sbenno	} else {
9890643Sbenno		progname = argv[0];
9990643Sbenno	}
10090643Sbenno
10190643Sbenno	opts = 0;
10290643Sbenno	tries = 0;
10390643Sbenno	interface = NULL;
10490643Sbenno
10590643Sbenno	bzero((char *)&sin, sizeof(sin));
10690643Sbenno	sin.sin_family = AF_INET;
10790643Sbenno	sin.sin_port = htons(0xaf6c);
10890643Sbenno	sin.sin_addr.s_addr = htonl(INADDR_UNSPEC_GROUP | 0x697066);
10990643Sbenno
11090643Sbenno	while ((opt = getopt(argc, argv, "di:I:p:")) != -1)
11190643Sbenno		switch (opt)
11290643Sbenno		{
11390643Sbenno		case 'd' :
11490643Sbenno			debuglevel++;
11590643Sbenno			break;
11690643Sbenno		case 'I' :
117118239Speter			interface = optarg;
118118239Speter			break;
11977957Sbenno		case 'i' :
12080431Speter			sin.sin_addr.s_addr = inet_addr(optarg);
121222813Sattilio			break;
122222813Sattilio		case 'p' :
12390643Sbenno			sin.sin_port = htons(atoi(optarg));
12490643Sbenno			break;
12590643Sbenno		}
12690643Sbenno
12777957Sbenno	if (interface == NULL) {
128222813Sattilio		usage(progname);
12990643Sbenno		exit(1);
13090643Sbenno	}
13177957Sbenno
13277957Sbenno	if (!debuglevel) {
13390643Sbenno
13490643Sbenno#if BSD >= 199306
135152180Sgrehan		daemon(0, 0);
13677957Sbenno#else
13777957Sbenno		int fd = open("/dev/null", O_RDWR);
13877957Sbenno
13977957Sbenno		switch (fork())
14077957Sbenno		{
14177957Sbenno		case 0 :
14277957Sbenno			break;
14377957Sbenno
14492847Sjeff		case -1 :
14577957Sbenno			fprintf(stderr, "%s: fork() failed: %s\n",
146125687Sgrehan				argv[0], STRERROR(errno));
147192067Snwhitehorn			exit(1);
14883730Smp			/* NOTREACHED */
14990643Sbenno
15090643Sbenno		default :
15190643Sbenno			exit(0);
15277957Sbenno			/* NOTREACHED */
153178628Smarcel		}
15490643Sbenno
155152180Sgrehan		dup2(fd, 0);
15677957Sbenno		dup2(fd, 1);
157152180Sgrehan		dup2(fd, 2);
15877957Sbenno		close(fd);
159152180Sgrehan
160152180Sgrehan		setsid();
16190643Sbenno#endif
16277957Sbenno	}
16390643Sbenno
16490643Sbenno       	signal(SIGHUP, handleterm);
16590643Sbenno       	signal(SIGINT, handleterm);
16690643Sbenno       	signal(SIGTERM, handleterm);
16790643Sbenno
16890643Sbenno	openlog(progname, LOG_PID, LOG_SECURITY);
16990643Sbenno
17090643Sbenno	while (!terminate) {
17190643Sbenno		if (lfd != -1) {
17290643Sbenno			close(lfd);
17377957Sbenno			lfd = -1;
17490643Sbenno		}
17590643Sbenno		if (nfd != -1) {
17690643Sbenno			close(nfd);
17797346Sbenno			nfd = -1;
17897346Sbenno		}
179209975Snwhitehorn		if (igmpfd != -1) {
180209975Snwhitehorn			close(igmpfd);
181100319Sbenno			igmpfd = -1;
18277957Sbenno		}
18390643Sbenno
184134535Salc		if (buildsocket(interface, &sin) == -1)
185134535Salc			goto tryagain;
186152180Sgrehan
187212278Snwhitehorn		lfd = open(IPSYNC_NAME, O_RDWR);
188134535Salc		if (lfd == -1) {
189183094Smarcel			syslog(LOG_ERR, "open(%s):%m", IPSYNC_NAME);
190183094Smarcel			debug(1, "open(%s): %s\n", IPSYNC_NAME,
191183094Smarcel			      STRERROR(errno));
192134535Salc			goto tryagain;
19390643Sbenno		}
19490643Sbenno
195152180Sgrehan		tries = -1;
196152180Sgrehan		do_io();
197152180Sgrehantryagain:
19877957Sbenno		tries++;
19990643Sbenno		syslog(LOG_INFO, "retry in %d seconds", 1 << tries);
20090643Sbenno		debug(1, "wait %d seconds\n", 1 << tries);
20190643Sbenno		sleep(1 << tries);
202152180Sgrehan	}
203152180Sgrehan
204152180Sgrehan
20577957Sbenno	/* terminate */
206152180Sgrehan	if (lfd != -1)
207152180Sgrehan		close(lfd);
20877957Sbenno	if (nfd != -1)
20999037Sbenno		close(nfd);
210152180Sgrehan
211152180Sgrehan	syslog(LOG_ERR, "signal %d received, exiting...", terminate);
21277957Sbenno	debug(1, "signal %d received, exiting...", terminate);
21390643Sbenno
214152180Sgrehan	exit(1);
21577957Sbenno}
216152180Sgrehan
21777957Sbenno
21890643Sbennovoid
21990643Sbennodo_io()
22090643Sbenno{
221152180Sgrehan	char nbuff[BUFFERLEN];
222152180Sgrehan	char buff[BUFFERLEN];
223152180Sgrehan	fd_set mrd, rd;
224152180Sgrehan	int maxfd;
225152180Sgrehan	int inbuf;
226152180Sgrehan	int n1;
227152180Sgrehan	int left;
228152180Sgrehan
22990643Sbenno	FD_ZERO(&mrd);
230152180Sgrehan	FD_SET(lfd, &mrd);
231152180Sgrehan	FD_SET(nfd, &mrd);
232152180Sgrehan	maxfd = nfd;
233152180Sgrehan	if (lfd > maxfd)
234152180Sgrehan		maxfd = lfd;
23590643Sbenno	debug(2, "nfd %d lfd %d maxfd %d\n", nfd, lfd, maxfd);
236152180Sgrehan
237152180Sgrehan	inbuf = 0;
238152180Sgrehan	/*
239152180Sgrehan	 * A threaded approach to this loop would have one thread
240152180Sgrehan	 * work on reading lfd (only) all the time and another thread
241152180Sgrehan	 * working on reading nfd all the time.
24277957Sbenno	 */
24390643Sbenno	while (!terminate) {
244152180Sgrehan		int n;
24590643Sbenno
246152180Sgrehan		rd = mrd;
24777957Sbenno
24890643Sbenno		n = select(maxfd + 1, &rd, NULL, NULL, NULL);
24990643Sbenno		if (n < 0) {
25090643Sbenno			switch (errno)
251152180Sgrehan			{
25277957Sbenno			case EINTR :
25377957Sbenno				continue;
25490643Sbenno			default :
25577957Sbenno				syslog(LOG_ERR, "select error: %m");
256152180Sgrehan				debug(1, "select error: %s\n", STRERROR(errno));
25790643Sbenno				return;
258152180Sgrehan			}
259152180Sgrehan		}
260152180Sgrehan
26190643Sbenno		if (FD_ISSET(lfd, &rd)) {
26290643Sbenno			n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf);
26390643Sbenno
26490643Sbenno			debug(3, "read(K):%d\n", n1);
265159303Salc
266159303Salc			if (n1 <= 0) {
267152180Sgrehan				syslog(LOG_ERR, "read error (k-header): %m");
268152180Sgrehan				debug(1, "read error (k-header): %s\n",
269208990Salc				      STRERROR(errno));
270152180Sgrehan				return;
271152180Sgrehan			}
27290643Sbenno
273152180Sgrehan			left = 0;
274152180Sgrehan
275152180Sgrehan			switch (do_kbuff(n1, buff, &left))
276152180Sgrehan			{
277152180Sgrehan			case R_IO_ERROR :
278152180Sgrehan				return;
279152180Sgrehan			case R_MORE :
280152180Sgrehan				inbuf += left;
281159303Salc				break;
282159303Salc			default :
283159627Sups				inbuf = 0;
284152180Sgrehan				break;
285152180Sgrehan			}
286152180Sgrehan		}
287152180Sgrehan
288214617Salc		if (FD_ISSET(nfd, &rd)) {
289207155Salc			n1 = recv(nfd, nbuff, sizeof(nbuff), 0);
290152180Sgrehan
291152180Sgrehan			debug(3, "read(N):%d\n", n1);
292152180Sgrehan
293173708Salc			if (n1 <= 0) {
294152180Sgrehan				syslog(LOG_ERR, "read error (n-header): %m");
295152180Sgrehan				debug(1, "read error (n-header): %s\n",
296152180Sgrehan				      STRERROR(errno));
297152180Sgrehan				return;
298152180Sgrehan			}
299152180Sgrehan
300152180Sgrehan			switch (do_packet(n1, nbuff))
301152180Sgrehan			{
302160889Salc			case R_IO_ERROR :
303152180Sgrehan				return;
304152180Sgrehan			default :
305152180Sgrehan				break;
306152180Sgrehan			}
307152180Sgrehan		}
308190681Snwhitehorn	}
309152180Sgrehan}
310152180Sgrehan
311213307Snwhitehorn
312152180Sgrehanint
313152180Sgrehanbuildsocket(nicname, sinp)
314213307Snwhitehorn	char *nicname;
315152180Sgrehan	struct sockaddr_in *sinp;
316213307Snwhitehorn{
317152180Sgrehan	struct sockaddr_in *reqip;
318198341Smarcel	struct ifreq req;
319152180Sgrehan	char opt;
320152180Sgrehan
321152180Sgrehan	debug(2, "binding to %s:%s\n", nicname, inet_ntoa(sinp->sin_addr));
322152180Sgrehan
323152180Sgrehan	if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
324152180Sgrehan		struct in_addr addr;
325152180Sgrehan		struct ip_mreq mreq;
326159303Salc
327152180Sgrehan		igmpfd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
328152180Sgrehan		if (igmpfd == -1) {
329152180Sgrehan			syslog(LOG_ERR, "socket:%m");
330152180Sgrehan			debug(1, "socket:%s\n", STRERROR(errno));
331152180Sgrehan			return -1;
332214617Salc		}
333207155Salc
334152180Sgrehan		bzero((char *)&req, sizeof(req));
335152180Sgrehan		strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
336152180Sgrehan		req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
337173708Salc		if (ioctl(igmpfd, SIOCGIFADDR, &req) == -1) {
338152180Sgrehan			syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
339152180Sgrehan			debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
340152180Sgrehan			close(igmpfd);
341152180Sgrehan			igmpfd = -1;
342152180Sgrehan			return -1;
343152180Sgrehan		}
344152180Sgrehan		reqip = (struct sockaddr_in *)&req.ifr_addr;
345152180Sgrehan
346160889Salc		addr = reqip->sin_addr;
347198341Smarcel		if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_IF,
348152180Sgrehan			       (char *)&addr, sizeof(addr)) == -1) {
349152180Sgrehan			syslog(LOG_ERR, "setsockopt(IP_MULTICAST_IF(%s)):%m",
350152180Sgrehan			       inet_ntoa(addr));
351152180Sgrehan			debug(1, "setsockopt(IP_MULTICAST_IF(%s)):%s\n",
352152180Sgrehan			      inet_ntoa(addr), STRERROR(errno));
353213307Snwhitehorn			close(igmpfd);
354152180Sgrehan			igmpfd = -1;
355152180Sgrehan			return -1;
356152180Sgrehan		}
357190681Snwhitehorn
358213307Snwhitehorn		opt = 0;
359152180Sgrehan		if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_LOOP,
360152180Sgrehan			       (char *)&opt, sizeof(opt)) == -1) {
361152180Sgrehan			syslog(LOG_ERR, "setsockopt(IP_MULTICAST_LOOP=0):%m");
362152180Sgrehan			debug(1, "setsockopt(IP_MULTICAST_LOOP=0):%s\n",
363213307Snwhitehorn			      STRERROR(errno));
364152180Sgrehan			close(igmpfd);
365152180Sgrehan			igmpfd = -1;
366152180Sgrehan			return -1;
367152180Sgrehan		}
368152180Sgrehan
369212627Sgrehan		opt = 63;
370152180Sgrehan		if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_TTL,
371213307Snwhitehorn			       (char *)&opt, sizeof(opt)) == -1) {
372213307Snwhitehorn			syslog(LOG_ERR, "setsockopt(IP_MULTICAST_TTL=%d):%m",
373213307Snwhitehorn			       opt);
374213307Snwhitehorn			debug(1, "setsockopt(IP_MULTICAST_TTL=%d):%s\n", opt,
375213307Snwhitehorn			      STRERROR(errno));
376212627Sgrehan			close(igmpfd);
377213307Snwhitehorn			igmpfd = -1;
378213307Snwhitehorn			return -1;
379213307Snwhitehorn		}
380213307Snwhitehorn
381213307Snwhitehorn		mreq.imr_multiaddr.s_addr = sinp->sin_addr.s_addr;
382213307Snwhitehorn		mreq.imr_interface.s_addr = reqip->sin_addr.s_addr;
383213307Snwhitehorn
384213307Snwhitehorn		if (setsockopt(igmpfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
385213307Snwhitehorn			       (char *)&mreq, sizeof(mreq)) == -1) {
386213307Snwhitehorn			char buffer[80];
387213307Snwhitehorn
388213307Snwhitehorn			sprintf(buffer, "%s,", inet_ntoa(sinp->sin_addr));
389213307Snwhitehorn			strcat(buffer, inet_ntoa(reqip->sin_addr));
390213307Snwhitehorn
391213307Snwhitehorn			syslog(LOG_ERR,
392213307Snwhitehorn			       "setsockpt(IP_ADD_MEMBERSHIP,%s):%m", buffer);
393213307Snwhitehorn			debug(1, "setsockpt(IP_ADD_MEMBERSHIP,%s):%s\n",
394213307Snwhitehorn			      buffer, STRERROR(errno));
395213307Snwhitehorn			close(igmpfd);
396213307Snwhitehorn			igmpfd = -1;
397213307Snwhitehorn			return -1;
398213307Snwhitehorn		}
399213307Snwhitehorn	}
400213307Snwhitehorn	nfd = socket(AF_INET, SOCK_DGRAM, 0);
401213307Snwhitehorn	if (nfd == -1) {
402213307Snwhitehorn		syslog(LOG_ERR, "socket:%m");
403213307Snwhitehorn		if (igmpfd != -1) {
404213307Snwhitehorn			close(igmpfd);
405213307Snwhitehorn			igmpfd = -1;
406183094Smarcel		}
407183094Smarcel		return -1;
408183094Smarcel	}
409152180Sgrehan	bzero((char *)&req, sizeof(req));
410183094Smarcel	strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
411213407Snwhitehorn	req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
412183094Smarcel	if (ioctl(nfd, SIOCGIFADDR, &req) == -1) {
413213407Snwhitehorn		syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
414183094Smarcel		debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
415183094Smarcel		close(igmpfd);
416183094Smarcel		igmpfd = -1;
417183094Smarcel		return -1;
418183094Smarcel	}
419183094Smarcel
420183094Smarcel	if (bind(nfd, (struct sockaddr *)&req.ifr_addr,
421183094Smarcel		 sizeof(req.ifr_addr)) == -1) {
422183094Smarcel		syslog(LOG_ERR, "bind:%m");
423183094Smarcel		debug(1, "bind:%s\n", STRERROR(errno));
424183094Smarcel		close(nfd);
425183094Smarcel		if (igmpfd != -1) {
426183094Smarcel			close(igmpfd);
427183094Smarcel			igmpfd = -1;
428183094Smarcel		}
429183094Smarcel		nfd = -1;
43090643Sbenno		return -1;
43190643Sbenno	}
43277957Sbenno
43390643Sbenno	if (connect(nfd, (struct sockaddr *)sinp, sizeof(*sinp)) == -1) {
43490643Sbenno		syslog(LOG_ERR, "connect:%m");
43577957Sbenno		debug(1, "connect:%s\n", STRERROR(errno));
43690643Sbenno		close(nfd);
43790643Sbenno		if (igmpfd != -1) {
43890643Sbenno			close(igmpfd);
43990643Sbenno			igmpfd = -1;
44090643Sbenno		}
44190643Sbenno		nfd = -1;
44290643Sbenno		return -1;
443152180Sgrehan	}
44477957Sbenno	syslog(LOG_INFO, "Sending data to %s", inet_ntoa(sinp->sin_addr));
44577957Sbenno	debug(3, "Sending data to %s\n", inet_ntoa(sinp->sin_addr));
44690643Sbenno
44790643Sbenno	return nfd;
44890643Sbenno}
44990643Sbenno
45090643Sbenno
45190643Sbennoint
45290643Sbennodo_packet(pklen, buff)
45377957Sbenno	int pklen;
454152180Sgrehan	char *buff;
45577957Sbenno{
45690643Sbenno	synchdr_t *sh;
457159928Salc	u_32_t magic;
45890643Sbenno	int len;
45977957Sbenno	int n2;
46077957Sbenno	int n3;
46177957Sbenno
462152180Sgrehan	while (pklen > 0) {
46377957Sbenno		if (pklen < sizeof(*sh)) {
46477957Sbenno			syslog(LOG_ERR, "packet length too short:%d", pklen);
46590643Sbenno			debug(2, "packet length too short:%d\n", pklen);
46677957Sbenno			return R_SKIP;
46777957Sbenno		}
46890643Sbenno
469152180Sgrehan		sh = (synchdr_t *)buff;
47090643Sbenno		len = ntohl(sh->sm_len);
47190643Sbenno		magic = ntohl(sh->sm_magic);
472159928Salc
47390643Sbenno		if (magic != SYNHDRMAGIC) {
47490643Sbenno			syslog(LOG_ERR, "invalid header magic %x", magic);
47590643Sbenno			debug(2, "invalid header magic %x\n", magic);
47677957Sbenno			return R_SKIP;
477152180Sgrehan		}
47877957Sbenno
47990643Sbenno		if (pklen < len + sizeof(*sh)) {
48090643Sbenno			syslog(LOG_ERR, "packet length too short:%d", pklen);
48190643Sbenno			debug(2, "packet length too short:%d\n", pklen);
48290643Sbenno			return R_SKIP;
48377957Sbenno		}
48477957Sbenno
48577957Sbenno		if (debuglevel > 3) {
486152180Sgrehan			printsynchdr(sh);
48777957Sbenno			printcommand(sh->sm_cmd);
48890643Sbenno			printtable(sh->sm_table);
48990643Sbenno			printsmcproto(buff);
49090643Sbenno		}
49190643Sbenno
49277957Sbenno		n2 = sizeof(*sh) + len;
49390643Sbenno
494152180Sgrehan		do {
49590643Sbenno			n3 = write(lfd, buff, n2);
496159928Salc			if (n3 <= 0) {
497159928Salc				syslog(LOG_ERR, "write error: %m");
498159928Salc				debug(1, "write error: %s\n", STRERROR(errno));
49990643Sbenno				return R_IO_ERROR;
50090643Sbenno			}
50190643Sbenno
50290643Sbenno			n2 -= n3;
50390643Sbenno			buff += n3;
50490643Sbenno			pklen -= n3;
50590643Sbenno		} while (n3 != 0);
50690643Sbenno	}
50790643Sbenno
50877957Sbenno	return R_OKAY;
50977957Sbenno}
51090643Sbenno
511152180Sgrehan
51277957Sbenno
51377957Sbennoint
514159928Salcdo_kbuff(inbuf, buf, left)
51590643Sbenno	int inbuf, *left;
51677957Sbenno	char *buf;
51777957Sbenno{
51890643Sbenno	synchdr_t *sh;
519152180Sgrehan	u_32_t magic;
52077957Sbenno	int complete;
52177957Sbenno	int sendlen;
522159928Salc	int error;
523159928Salc	int bytes;
52490643Sbenno	int len;
52590643Sbenno	int n2;
52690643Sbenno	int n3;
52790643Sbenno
528183094Smarcel	sendlen = 0;
52977957Sbenno	bytes = inbuf;
53077957Sbenno	error = R_OKAY;
53190643Sbenno	sh = (synchdr_t *)buf;
532152180Sgrehan
53377957Sbenno	for (complete = 0; bytes > 0; complete++) {
53477957Sbenno		len = ntohl(sh->sm_len);
535159928Salc		magic = ntohl(sh->sm_magic);
53690643Sbenno
53790643Sbenno		if (magic != SYNHDRMAGIC) {
53877957Sbenno			syslog(LOG_ERR,
53990643Sbenno			       "read invalid header magic 0x%x, flushing",
54090643Sbenno			       magic);
54190643Sbenno			debug(2, "read invalid header magic 0x%x, flushing\n",
54277957Sbenno			       magic);
54390643Sbenno			n2 = SMC_RLOG;
544183094Smarcel			(void) ioctl(lfd, SIOCIPFFL, &n2);
54590643Sbenno			break;
546183094Smarcel		}
547152180Sgrehan
54890643Sbenno		if (debuglevel > 3) {
54977957Sbenno			printsynchdr(sh);
55090643Sbenno			printcommand(sh->sm_cmd);
551152180Sgrehan			printtable(sh->sm_table);
55290643Sbenno			putchar('\n');
55390643Sbenno		}
554159928Salc
55590643Sbenno		if (bytes < sizeof(*sh) + len) {
55690643Sbenno			debug(3, "Not enough bytes %d < %d\n", bytes,
55777957Sbenno			      sizeof(*sh) + len);
55890643Sbenno			error = R_MORE;
55977957Sbenno			break;
560183094Smarcel		}
56177957Sbenno
56290643Sbenno		if (debuglevel > 3) {
56390643Sbenno			printsmcproto(buf);
56490643Sbenno		}
56590643Sbenno
56677957Sbenno		sendlen += len + sizeof(*sh);
567183094Smarcel		sh = (synchdr_t *)(buf + sendlen);
56877957Sbenno		bytes -= sendlen;
56990643Sbenno	}
57090643Sbenno
57190643Sbenno	if (complete) {
572152180Sgrehan		n3 = send(nfd, buf, sendlen, 0);
573152180Sgrehan		if (n3 <= 0) {
57477957Sbenno			syslog(LOG_ERR, "write error: %m");
57577957Sbenno			debug(1, "write error: %s\n", STRERROR(errno));
57690643Sbenno			return R_IO_ERROR;
577152180Sgrehan		}
57890643Sbenno		debug(3, "send on %d len %d = %d\n", nfd, sendlen, n3);
57990643Sbenno		error = R_OKAY;
58090643Sbenno	}
58190643Sbenno
58290643Sbenno	/* move buffer to the front,we might need to make
583152180Sgrehan	 * this more efficient, by using a rolling pointer
584152180Sgrehan	 * over the buffer and only copying it, when
58590643Sbenno	 * we are reaching the end
58690643Sbenno	 */
58777957Sbenno	if (bytes > 0) {
58890643Sbenno		bcopy(buf + bytes, buf, bytes);
58977957Sbenno		error = R_MORE;
59090643Sbenno	}
59190643Sbenno	debug(4, "complete %d bytes %d error %d\n", complete, bytes, error);
59290643Sbenno
59390643Sbenno	*left = bytes;
59490643Sbenno
59590643Sbenno	return error;
59690643Sbenno}
59790643Sbenno
59890643Sbenno
59990643Sbennovoid
60090643Sbennoprintcommand(cmd)
60190643Sbenno	int cmd;
60290643Sbenno{
60390643Sbenno
60490643Sbenno	switch (cmd)
60590643Sbenno	{
60677957Sbenno	case SMC_CREATE :
60777957Sbenno		printf(" cmd:CREATE");
60877957Sbenno		break;
609190681Snwhitehorn	case SMC_UPDATE :
610178628Smarcel		printf(" cmd:UPDATE");
611178628Smarcel		break;
612178628Smarcel	default :
613178628Smarcel		printf(" cmd:Unknown(%d)", cmd);
614178628Smarcel		break;
615183094Smarcel	}
616178628Smarcel}
617178628Smarcel
618178628Smarcel
619178628Smarcelvoid
620178628Smarcelprinttable(table)
621178628Smarcel	int table;
622178628Smarcel{
623178628Smarcel	switch (table)
624178629Smarcel	{
625178629Smarcel	case SMC_NAT :
626178629Smarcel		printf(" table:NAT");
627178628Smarcel		break;
628178629Smarcel	case SMC_STATE :
629178629Smarcel		printf(" table:STATE");
630178629Smarcel		break;
631178629Smarcel	default :
632178629Smarcel		printf(" table:Unknown(%d)", table);
633178628Smarcel		break;
634178628Smarcel	}
635178628Smarcel}
636215163Snwhitehorn
637183094Smarcel
638178628Smarcelvoid
639178628Smarcelprintsmcproto(buff)
640178628Smarcel	char *buff;
641178628Smarcel{
642178628Smarcel	syncupdent_t *su;
643179254Smarcel	synchdr_t *sh;
644178628Smarcel
645178628Smarcel	sh = (synchdr_t *)buff;
646178628Smarcel
647152180Sgrehan	if (sh->sm_cmd == SMC_CREATE) {
64877957Sbenno		;
64997346Sbenno
65090643Sbenno	} else if (sh->sm_cmd == SMC_UPDATE) {
65190643Sbenno		su = (syncupdent_t *)buff;
65290643Sbenno		if (sh->sm_p == IPPROTO_TCP) {
653143200Sgrehan			printf(" TCP Update: age %lu state %d/%d\n",
65490643Sbenno				su->sup_tcp.stu_age,
655194784Sjeff				su->sup_tcp.stu_state[0],
656209369Snwhitehorn				su->sup_tcp.stu_state[1]);
65777957Sbenno		}
65899037Sbenno	} else {
659103604Sgrehan		printf("Unknown command\n");
66099037Sbenno	}
66199037Sbenno}
66299037Sbenno
66399037Sbenno
66499037Sbennovoid
66599037Sbennoprintsynchdr(sh)
66699037Sbenno	synchdr_t *sh;
66799037Sbenno{
66899037Sbenno
66999037Sbenno	printf("v:%d p:%d num:%d len:%d magic:%x", sh->sm_v, sh->sm_p,
67099037Sbenno	       ntohl(sh->sm_num), ntohl(sh->sm_len), ntohl(sh->sm_magic));
67199037Sbenno}
67299037Sbenno