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