108ab34a0SCy Schubert /*
208ab34a0SCy Schubert * Copyright (C) 2012 by Darren Reed.
308ab34a0SCy Schubert *
408ab34a0SCy Schubert * See the IPFILTER.LICENCE file for details on licencing.
508ab34a0SCy Schubert */
608ab34a0SCy Schubert #include <sys/types.h>
708ab34a0SCy Schubert #include <sys/time.h>
808ab34a0SCy Schubert #include <sys/socket.h>
908ab34a0SCy Schubert #include <sys/ioctl.h>
1008ab34a0SCy Schubert #include <sys/sockio.h>
1108ab34a0SCy Schubert #include <sys/errno.h>
1208ab34a0SCy Schubert
1308ab34a0SCy Schubert #include <netinet/in.h>
1408ab34a0SCy Schubert #include <net/if.h>
1508ab34a0SCy Schubert
1608ab34a0SCy Schubert #include <arpa/inet.h>
1708ab34a0SCy Schubert
1808ab34a0SCy Schubert #include <stdio.h>
1908ab34a0SCy Schubert #include <stdlib.h>
2008ab34a0SCy Schubert #include <fcntl.h>
2108ab34a0SCy Schubert #include <unistd.h>
2208ab34a0SCy Schubert #include <string.h>
2308ab34a0SCy Schubert #include <syslog.h>
2408ab34a0SCy Schubert #include <signal.h>
2508ab34a0SCy Schubert
2608ab34a0SCy Schubert #include "ipf.h"
2708ab34a0SCy Schubert #include "opts.h"
2808ab34a0SCy Schubert
2908ab34a0SCy Schubert
3008ab34a0SCy Schubert #define R_IO_ERROR -1
3108ab34a0SCy Schubert #define R_OKAY 0
3208ab34a0SCy Schubert #define R_MORE 1
3308ab34a0SCy Schubert #define R_SKIP 2
3408ab34a0SCy Schubert #if defined(sun) && !defined(SOLARIS2)
3508ab34a0SCy Schubert # define STRERROR(x) sys_errlist[x]
3608ab34a0SCy Schubert extern char *sys_errlist[];
3708ab34a0SCy Schubert #else
3808ab34a0SCy Schubert # define STRERROR(x) strerror(x)
3908ab34a0SCy Schubert #endif
4008ab34a0SCy Schubert
4108ab34a0SCy Schubert
4208ab34a0SCy Schubert int main(int, char *[]);
4308ab34a0SCy Schubert void usage(char *);
4408ab34a0SCy Schubert void printsynchdr(synchdr_t *);
4508ab34a0SCy Schubert void printtable(int);
4608ab34a0SCy Schubert void printsmcproto(char *);
4708ab34a0SCy Schubert void printcommand(int);
4808ab34a0SCy Schubert int do_kbuff(int, char *, int *);
4908ab34a0SCy Schubert int do_packet(int, char *);
5008ab34a0SCy Schubert int buildsocket(char *, struct sockaddr_in *);
5108ab34a0SCy Schubert void do_io(void);
5208ab34a0SCy Schubert void handleterm(int);
5308ab34a0SCy Schubert
5408ab34a0SCy Schubert int terminate = 0;
5508ab34a0SCy Schubert int igmpfd = -1;
5608ab34a0SCy Schubert int nfd = -1;
5708ab34a0SCy Schubert int lfd = -1;
5808ab34a0SCy Schubert int opts = 0;
5908ab34a0SCy Schubert
6008ab34a0SCy Schubert void
usage(progname)6108ab34a0SCy Schubert usage(progname)
6208ab34a0SCy Schubert char *progname;
6308ab34a0SCy Schubert {
6408ab34a0SCy Schubert fprintf(stderr,
6508ab34a0SCy Schubert "Usage: %s [-d] [-p port] [-i address] -I <interface>\n",
6608ab34a0SCy Schubert progname);
6708ab34a0SCy Schubert }
6808ab34a0SCy Schubert
6908ab34a0SCy Schubert void
handleterm(sig)7008ab34a0SCy Schubert handleterm(sig)
7108ab34a0SCy Schubert int sig;
7208ab34a0SCy Schubert {
7308ab34a0SCy Schubert terminate = sig;
7408ab34a0SCy Schubert }
7508ab34a0SCy Schubert
7608ab34a0SCy Schubert
7708ab34a0SCy Schubert /* should be large enough to hold header + any datatype */
7808ab34a0SCy Schubert #define BUFFERLEN 1400
7908ab34a0SCy Schubert
8008ab34a0SCy Schubert int
main(argc,argv)8108ab34a0SCy Schubert main(argc, argv)
8208ab34a0SCy Schubert int argc;
8308ab34a0SCy Schubert char *argv[];
8408ab34a0SCy Schubert {
8508ab34a0SCy Schubert struct sockaddr_in sin;
8608ab34a0SCy Schubert char *interface;
8708ab34a0SCy Schubert char *progname;
8808ab34a0SCy Schubert int opt, tries;
8908ab34a0SCy Schubert
9008ab34a0SCy Schubert progname = strrchr(argv[0], '/');
9108ab34a0SCy Schubert if (progname) {
9208ab34a0SCy Schubert progname++;
9308ab34a0SCy Schubert } else {
9408ab34a0SCy Schubert progname = argv[0];
9508ab34a0SCy Schubert }
9608ab34a0SCy Schubert
9708ab34a0SCy Schubert opts = 0;
9808ab34a0SCy Schubert tries = 0;
9908ab34a0SCy Schubert interface = NULL;
10008ab34a0SCy Schubert
10108ab34a0SCy Schubert bzero((char *)&sin, sizeof(sin));
10208ab34a0SCy Schubert sin.sin_family = AF_INET;
10308ab34a0SCy Schubert sin.sin_port = htons(0xaf6c);
10408ab34a0SCy Schubert sin.sin_addr.s_addr = htonl(INADDR_UNSPEC_GROUP | 0x697066);
10508ab34a0SCy Schubert
10608ab34a0SCy Schubert while ((opt = getopt(argc, argv, "di:I:p:")) != -1)
10708ab34a0SCy Schubert switch (opt)
10808ab34a0SCy Schubert {
10908ab34a0SCy Schubert case 'd' :
11008ab34a0SCy Schubert debuglevel++;
11108ab34a0SCy Schubert break;
11208ab34a0SCy Schubert case 'I' :
11308ab34a0SCy Schubert interface = optarg;
11408ab34a0SCy Schubert break;
11508ab34a0SCy Schubert case 'i' :
11608ab34a0SCy Schubert sin.sin_addr.s_addr = inet_addr(optarg);
11708ab34a0SCy Schubert break;
11808ab34a0SCy Schubert case 'p' :
11908ab34a0SCy Schubert sin.sin_port = htons(atoi(optarg));
12008ab34a0SCy Schubert break;
12108ab34a0SCy Schubert }
12208ab34a0SCy Schubert
12308ab34a0SCy Schubert if (interface == NULL) {
12408ab34a0SCy Schubert usage(progname);
12508ab34a0SCy Schubert exit(1);
12608ab34a0SCy Schubert }
12708ab34a0SCy Schubert
12808ab34a0SCy Schubert if (!debuglevel) {
12908ab34a0SCy Schubert
13008ab34a0SCy Schubert #ifdef BSD
13108ab34a0SCy Schubert daemon(0, 0);
13208ab34a0SCy Schubert #else
13308ab34a0SCy Schubert int fd = open("/dev/null", O_RDWR);
13408ab34a0SCy Schubert
13508ab34a0SCy Schubert switch (fork())
13608ab34a0SCy Schubert {
13708ab34a0SCy Schubert case 0 :
13808ab34a0SCy Schubert break;
13908ab34a0SCy Schubert
14008ab34a0SCy Schubert case -1 :
14108ab34a0SCy Schubert fprintf(stderr, "%s: fork() failed: %s\n",
14208ab34a0SCy Schubert argv[0], STRERROR(errno));
14308ab34a0SCy Schubert exit(1);
14408ab34a0SCy Schubert /* NOTREACHED */
14508ab34a0SCy Schubert
14608ab34a0SCy Schubert default :
14708ab34a0SCy Schubert exit(0);
14808ab34a0SCy Schubert /* NOTREACHED */
14908ab34a0SCy Schubert }
15008ab34a0SCy Schubert
15108ab34a0SCy Schubert dup2(fd, 0);
15208ab34a0SCy Schubert dup2(fd, 1);
15308ab34a0SCy Schubert dup2(fd, 2);
15408ab34a0SCy Schubert close(fd);
15508ab34a0SCy Schubert
15608ab34a0SCy Schubert setsid();
15708ab34a0SCy Schubert #endif
15808ab34a0SCy Schubert }
15908ab34a0SCy Schubert
16008ab34a0SCy Schubert signal(SIGHUP, handleterm);
16108ab34a0SCy Schubert signal(SIGINT, handleterm);
16208ab34a0SCy Schubert signal(SIGTERM, handleterm);
16308ab34a0SCy Schubert
16408ab34a0SCy Schubert openlog(progname, LOG_PID, LOG_SECURITY);
16508ab34a0SCy Schubert
16608ab34a0SCy Schubert while (!terminate) {
16708ab34a0SCy Schubert if (lfd != -1) {
16808ab34a0SCy Schubert close(lfd);
16908ab34a0SCy Schubert lfd = -1;
17008ab34a0SCy Schubert }
17108ab34a0SCy Schubert if (nfd != -1) {
17208ab34a0SCy Schubert close(nfd);
17308ab34a0SCy Schubert nfd = -1;
17408ab34a0SCy Schubert }
17508ab34a0SCy Schubert if (igmpfd != -1) {
17608ab34a0SCy Schubert close(igmpfd);
17708ab34a0SCy Schubert igmpfd = -1;
17808ab34a0SCy Schubert }
17908ab34a0SCy Schubert
18008ab34a0SCy Schubert if (buildsocket(interface, &sin) == -1)
18108ab34a0SCy Schubert goto tryagain;
18208ab34a0SCy Schubert
18308ab34a0SCy Schubert lfd = open(IPSYNC_NAME, O_RDWR);
18408ab34a0SCy Schubert if (lfd == -1) {
18508ab34a0SCy Schubert syslog(LOG_ERR, "open(%s):%m", IPSYNC_NAME);
18608ab34a0SCy Schubert debug(1, "open(%s): %s\n", IPSYNC_NAME,
18708ab34a0SCy Schubert STRERROR(errno));
18808ab34a0SCy Schubert goto tryagain;
18908ab34a0SCy Schubert }
19008ab34a0SCy Schubert
19108ab34a0SCy Schubert tries = -1;
19208ab34a0SCy Schubert do_io();
19308ab34a0SCy Schubert tryagain:
19408ab34a0SCy Schubert tries++;
19508ab34a0SCy Schubert syslog(LOG_INFO, "retry in %d seconds", 1 << tries);
19608ab34a0SCy Schubert debug(1, "wait %d seconds\n", 1 << tries);
19708ab34a0SCy Schubert sleep(1 << tries);
19808ab34a0SCy Schubert }
19908ab34a0SCy Schubert
20008ab34a0SCy Schubert
20108ab34a0SCy Schubert /* terminate */
20208ab34a0SCy Schubert if (lfd != -1)
20308ab34a0SCy Schubert close(lfd);
20408ab34a0SCy Schubert if (nfd != -1)
20508ab34a0SCy Schubert close(nfd);
20608ab34a0SCy Schubert
20708ab34a0SCy Schubert syslog(LOG_ERR, "signal %d received, exiting...", terminate);
20808ab34a0SCy Schubert debug(1, "signal %d received, exiting...", terminate);
20908ab34a0SCy Schubert
21008ab34a0SCy Schubert exit(1);
21108ab34a0SCy Schubert }
21208ab34a0SCy Schubert
21308ab34a0SCy Schubert
21408ab34a0SCy Schubert void
do_io()21508ab34a0SCy Schubert do_io()
21608ab34a0SCy Schubert {
21708ab34a0SCy Schubert char nbuff[BUFFERLEN];
21808ab34a0SCy Schubert char buff[BUFFERLEN];
21908ab34a0SCy Schubert fd_set mrd, rd;
22008ab34a0SCy Schubert int maxfd;
22108ab34a0SCy Schubert int inbuf;
22208ab34a0SCy Schubert int n1;
22308ab34a0SCy Schubert int left;
22408ab34a0SCy Schubert
22508ab34a0SCy Schubert FD_ZERO(&mrd);
22608ab34a0SCy Schubert FD_SET(lfd, &mrd);
22708ab34a0SCy Schubert FD_SET(nfd, &mrd);
22808ab34a0SCy Schubert maxfd = nfd;
22908ab34a0SCy Schubert if (lfd > maxfd)
23008ab34a0SCy Schubert maxfd = lfd;
23108ab34a0SCy Schubert debug(2, "nfd %d lfd %d maxfd %d\n", nfd, lfd, maxfd);
23208ab34a0SCy Schubert
23308ab34a0SCy Schubert inbuf = 0;
23408ab34a0SCy Schubert /*
23508ab34a0SCy Schubert * A threaded approach to this loop would have one thread
23608ab34a0SCy Schubert * work on reading lfd (only) all the time and another thread
23708ab34a0SCy Schubert * working on reading nfd all the time.
23808ab34a0SCy Schubert */
23908ab34a0SCy Schubert while (!terminate) {
24008ab34a0SCy Schubert int n;
24108ab34a0SCy Schubert
24208ab34a0SCy Schubert rd = mrd;
24308ab34a0SCy Schubert
24408ab34a0SCy Schubert n = select(maxfd + 1, &rd, NULL, NULL, NULL);
24508ab34a0SCy Schubert if (n < 0) {
24608ab34a0SCy Schubert switch (errno)
24708ab34a0SCy Schubert {
24808ab34a0SCy Schubert case EINTR :
24908ab34a0SCy Schubert continue;
25008ab34a0SCy Schubert default :
25108ab34a0SCy Schubert syslog(LOG_ERR, "select error: %m");
25208ab34a0SCy Schubert debug(1, "select error: %s\n", STRERROR(errno));
25308ab34a0SCy Schubert return;
25408ab34a0SCy Schubert }
25508ab34a0SCy Schubert }
25608ab34a0SCy Schubert
25708ab34a0SCy Schubert if (FD_ISSET(lfd, &rd)) {
25808ab34a0SCy Schubert n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf);
25908ab34a0SCy Schubert
26008ab34a0SCy Schubert debug(3, "read(K):%d\n", n1);
26108ab34a0SCy Schubert
26208ab34a0SCy Schubert if (n1 <= 0) {
26308ab34a0SCy Schubert syslog(LOG_ERR, "read error (k-header): %m");
26408ab34a0SCy Schubert debug(1, "read error (k-header): %s\n",
26508ab34a0SCy Schubert STRERROR(errno));
26608ab34a0SCy Schubert return;
26708ab34a0SCy Schubert }
26808ab34a0SCy Schubert
26908ab34a0SCy Schubert left = 0;
27008ab34a0SCy Schubert
27108ab34a0SCy Schubert switch (do_kbuff(n1, buff, &left))
27208ab34a0SCy Schubert {
27308ab34a0SCy Schubert case R_IO_ERROR :
27408ab34a0SCy Schubert return;
27508ab34a0SCy Schubert case R_MORE :
27608ab34a0SCy Schubert inbuf += left;
27708ab34a0SCy Schubert break;
27808ab34a0SCy Schubert default :
27908ab34a0SCy Schubert inbuf = 0;
28008ab34a0SCy Schubert break;
28108ab34a0SCy Schubert }
28208ab34a0SCy Schubert }
28308ab34a0SCy Schubert
28408ab34a0SCy Schubert if (FD_ISSET(nfd, &rd)) {
28508ab34a0SCy Schubert n1 = recv(nfd, nbuff, sizeof(nbuff), 0);
28608ab34a0SCy Schubert
28708ab34a0SCy Schubert debug(3, "read(N):%d\n", n1);
28808ab34a0SCy Schubert
28908ab34a0SCy Schubert if (n1 <= 0) {
29008ab34a0SCy Schubert syslog(LOG_ERR, "read error (n-header): %m");
29108ab34a0SCy Schubert debug(1, "read error (n-header): %s\n",
29208ab34a0SCy Schubert STRERROR(errno));
29308ab34a0SCy Schubert return;
29408ab34a0SCy Schubert }
29508ab34a0SCy Schubert
29608ab34a0SCy Schubert switch (do_packet(n1, nbuff))
29708ab34a0SCy Schubert {
29808ab34a0SCy Schubert case R_IO_ERROR :
29908ab34a0SCy Schubert return;
30008ab34a0SCy Schubert default :
30108ab34a0SCy Schubert break;
30208ab34a0SCy Schubert }
30308ab34a0SCy Schubert }
30408ab34a0SCy Schubert }
30508ab34a0SCy Schubert }
30608ab34a0SCy Schubert
30708ab34a0SCy Schubert
30808ab34a0SCy Schubert int
buildsocket(nicname,sinp)30908ab34a0SCy Schubert buildsocket(nicname, sinp)
31008ab34a0SCy Schubert char *nicname;
31108ab34a0SCy Schubert struct sockaddr_in *sinp;
31208ab34a0SCy Schubert {
31308ab34a0SCy Schubert struct sockaddr_in *reqip;
31408ab34a0SCy Schubert struct ifreq req;
31508ab34a0SCy Schubert char opt;
31608ab34a0SCy Schubert
31708ab34a0SCy Schubert debug(2, "binding to %s:%s\n", nicname, inet_ntoa(sinp->sin_addr));
31808ab34a0SCy Schubert
31908ab34a0SCy Schubert if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
32008ab34a0SCy Schubert struct in_addr addr;
32108ab34a0SCy Schubert struct ip_mreq mreq;
32208ab34a0SCy Schubert
32308ab34a0SCy Schubert igmpfd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
32408ab34a0SCy Schubert if (igmpfd == -1) {
32508ab34a0SCy Schubert syslog(LOG_ERR, "socket:%m");
32608ab34a0SCy Schubert debug(1, "socket:%s\n", STRERROR(errno));
32708ab34a0SCy Schubert return -1;
32808ab34a0SCy Schubert }
32908ab34a0SCy Schubert
33008ab34a0SCy Schubert bzero((char *)&req, sizeof(req));
33108ab34a0SCy Schubert strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
33208ab34a0SCy Schubert req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
33308ab34a0SCy Schubert if (ioctl(igmpfd, SIOCGIFADDR, &req) == -1) {
33408ab34a0SCy Schubert syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
33508ab34a0SCy Schubert debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
33608ab34a0SCy Schubert close(igmpfd);
33708ab34a0SCy Schubert igmpfd = -1;
33808ab34a0SCy Schubert return -1;
33908ab34a0SCy Schubert }
34008ab34a0SCy Schubert reqip = (struct sockaddr_in *)&req.ifr_addr;
34108ab34a0SCy Schubert
34208ab34a0SCy Schubert addr = reqip->sin_addr;
34308ab34a0SCy Schubert if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_IF,
34408ab34a0SCy Schubert (char *)&addr, sizeof(addr)) == -1) {
34508ab34a0SCy Schubert syslog(LOG_ERR, "setsockopt(IP_MULTICAST_IF(%s)):%m",
34608ab34a0SCy Schubert inet_ntoa(addr));
34708ab34a0SCy Schubert debug(1, "setsockopt(IP_MULTICAST_IF(%s)):%s\n",
34808ab34a0SCy Schubert inet_ntoa(addr), STRERROR(errno));
34908ab34a0SCy Schubert close(igmpfd);
35008ab34a0SCy Schubert igmpfd = -1;
35108ab34a0SCy Schubert return -1;
35208ab34a0SCy Schubert }
35308ab34a0SCy Schubert
35408ab34a0SCy Schubert opt = 0;
35508ab34a0SCy Schubert if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_LOOP,
35608ab34a0SCy Schubert (char *)&opt, sizeof(opt)) == -1) {
35708ab34a0SCy Schubert syslog(LOG_ERR, "setsockopt(IP_MULTICAST_LOOP=0):%m");
35808ab34a0SCy Schubert debug(1, "setsockopt(IP_MULTICAST_LOOP=0):%s\n",
35908ab34a0SCy Schubert STRERROR(errno));
36008ab34a0SCy Schubert close(igmpfd);
36108ab34a0SCy Schubert igmpfd = -1;
36208ab34a0SCy Schubert return -1;
36308ab34a0SCy Schubert }
36408ab34a0SCy Schubert
36508ab34a0SCy Schubert opt = 63;
36608ab34a0SCy Schubert if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_TTL,
36708ab34a0SCy Schubert (char *)&opt, sizeof(opt)) == -1) {
36808ab34a0SCy Schubert syslog(LOG_ERR, "setsockopt(IP_MULTICAST_TTL=%d):%m",
36908ab34a0SCy Schubert opt);
37008ab34a0SCy Schubert debug(1, "setsockopt(IP_MULTICAST_TTL=%d):%s\n", opt,
37108ab34a0SCy Schubert STRERROR(errno));
37208ab34a0SCy Schubert close(igmpfd);
37308ab34a0SCy Schubert igmpfd = -1;
37408ab34a0SCy Schubert return -1;
37508ab34a0SCy Schubert }
37608ab34a0SCy Schubert
37708ab34a0SCy Schubert mreq.imr_multiaddr.s_addr = sinp->sin_addr.s_addr;
37808ab34a0SCy Schubert mreq.imr_interface.s_addr = reqip->sin_addr.s_addr;
37908ab34a0SCy Schubert
38008ab34a0SCy Schubert if (setsockopt(igmpfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
38108ab34a0SCy Schubert (char *)&mreq, sizeof(mreq)) == -1) {
38208ab34a0SCy Schubert char buffer[80];
38308ab34a0SCy Schubert
38408ab34a0SCy Schubert snprintf(buffer, sizeof(buffer), "%s,", inet_ntoa(sinp->sin_addr));
38508ab34a0SCy Schubert strcat(buffer, inet_ntoa(reqip->sin_addr));
38608ab34a0SCy Schubert
38708ab34a0SCy Schubert syslog(LOG_ERR,
38808ab34a0SCy Schubert "setsockpt(IP_ADD_MEMBERSHIP,%s):%m", buffer);
38908ab34a0SCy Schubert debug(1, "setsockpt(IP_ADD_MEMBERSHIP,%s):%s\n",
39008ab34a0SCy Schubert buffer, STRERROR(errno));
39108ab34a0SCy Schubert close(igmpfd);
39208ab34a0SCy Schubert igmpfd = -1;
39308ab34a0SCy Schubert return -1;
39408ab34a0SCy Schubert }
39508ab34a0SCy Schubert }
39608ab34a0SCy Schubert nfd = socket(AF_INET, SOCK_DGRAM, 0);
39708ab34a0SCy Schubert if (nfd == -1) {
39808ab34a0SCy Schubert syslog(LOG_ERR, "socket:%m");
39908ab34a0SCy Schubert if (igmpfd != -1) {
40008ab34a0SCy Schubert close(igmpfd);
40108ab34a0SCy Schubert igmpfd = -1;
40208ab34a0SCy Schubert }
40308ab34a0SCy Schubert return -1;
40408ab34a0SCy Schubert }
40508ab34a0SCy Schubert bzero((char *)&req, sizeof(req));
40608ab34a0SCy Schubert strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
40708ab34a0SCy Schubert req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
40808ab34a0SCy Schubert if (ioctl(nfd, SIOCGIFADDR, &req) == -1) {
40908ab34a0SCy Schubert syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
41008ab34a0SCy Schubert debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
41108ab34a0SCy Schubert close(igmpfd);
41208ab34a0SCy Schubert igmpfd = -1;
41308ab34a0SCy Schubert return -1;
41408ab34a0SCy Schubert }
41508ab34a0SCy Schubert
41608ab34a0SCy Schubert if (bind(nfd, (struct sockaddr *)&req.ifr_addr,
41708ab34a0SCy Schubert sizeof(req.ifr_addr)) == -1) {
41808ab34a0SCy Schubert syslog(LOG_ERR, "bind:%m");
41908ab34a0SCy Schubert debug(1, "bind:%s\n", STRERROR(errno));
42008ab34a0SCy Schubert close(nfd);
42108ab34a0SCy Schubert if (igmpfd != -1) {
42208ab34a0SCy Schubert close(igmpfd);
42308ab34a0SCy Schubert igmpfd = -1;
42408ab34a0SCy Schubert }
42508ab34a0SCy Schubert nfd = -1;
42608ab34a0SCy Schubert return -1;
42708ab34a0SCy Schubert }
42808ab34a0SCy Schubert
42908ab34a0SCy Schubert if (connect(nfd, (struct sockaddr *)sinp, sizeof(*sinp)) == -1) {
43008ab34a0SCy Schubert syslog(LOG_ERR, "connect:%m");
43108ab34a0SCy Schubert debug(1, "connect:%s\n", STRERROR(errno));
43208ab34a0SCy Schubert close(nfd);
43308ab34a0SCy Schubert if (igmpfd != -1) {
43408ab34a0SCy Schubert close(igmpfd);
43508ab34a0SCy Schubert igmpfd = -1;
43608ab34a0SCy Schubert }
43708ab34a0SCy Schubert nfd = -1;
43808ab34a0SCy Schubert return -1;
43908ab34a0SCy Schubert }
44008ab34a0SCy Schubert syslog(LOG_INFO, "Sending data to %s", inet_ntoa(sinp->sin_addr));
44108ab34a0SCy Schubert debug(3, "Sending data to %s\n", inet_ntoa(sinp->sin_addr));
44208ab34a0SCy Schubert
44308ab34a0SCy Schubert return nfd;
44408ab34a0SCy Schubert }
44508ab34a0SCy Schubert
44608ab34a0SCy Schubert
44708ab34a0SCy Schubert int
do_packet(pklen,buff)44808ab34a0SCy Schubert do_packet(pklen, buff)
44908ab34a0SCy Schubert int pklen;
45008ab34a0SCy Schubert char *buff;
45108ab34a0SCy Schubert {
45208ab34a0SCy Schubert synchdr_t *sh;
45308ab34a0SCy Schubert u_32_t magic;
45408ab34a0SCy Schubert int len;
45508ab34a0SCy Schubert int n2;
45608ab34a0SCy Schubert int n3;
45708ab34a0SCy Schubert
45808ab34a0SCy Schubert while (pklen > 0) {
45908ab34a0SCy Schubert if (pklen < sizeof(*sh)) {
46008ab34a0SCy Schubert syslog(LOG_ERR, "packet length too short:%d", pklen);
46108ab34a0SCy Schubert debug(2, "packet length too short:%d\n", pklen);
46208ab34a0SCy Schubert return R_SKIP;
46308ab34a0SCy Schubert }
46408ab34a0SCy Schubert
46508ab34a0SCy Schubert sh = (synchdr_t *)buff;
46608ab34a0SCy Schubert len = ntohl(sh->sm_len);
46708ab34a0SCy Schubert magic = ntohl(sh->sm_magic);
46808ab34a0SCy Schubert
46908ab34a0SCy Schubert if (magic != SYNHDRMAGIC) {
47008ab34a0SCy Schubert syslog(LOG_ERR, "invalid header magic %x", magic);
47108ab34a0SCy Schubert debug(2, "invalid header magic %x\n", magic);
47208ab34a0SCy Schubert return R_SKIP;
47308ab34a0SCy Schubert }
47408ab34a0SCy Schubert
47508ab34a0SCy Schubert if (pklen < len + sizeof(*sh)) {
47608ab34a0SCy Schubert syslog(LOG_ERR, "packet length too short:%d", pklen);
47708ab34a0SCy Schubert debug(2, "packet length too short:%d\n", pklen);
47808ab34a0SCy Schubert return R_SKIP;
47908ab34a0SCy Schubert }
48008ab34a0SCy Schubert
48108ab34a0SCy Schubert if (debuglevel > 3) {
48208ab34a0SCy Schubert printsynchdr(sh);
48308ab34a0SCy Schubert printcommand(sh->sm_cmd);
48408ab34a0SCy Schubert printtable(sh->sm_table);
48508ab34a0SCy Schubert printsmcproto(buff);
48608ab34a0SCy Schubert }
48708ab34a0SCy Schubert
48808ab34a0SCy Schubert n2 = sizeof(*sh) + len;
48908ab34a0SCy Schubert
49008ab34a0SCy Schubert do {
49108ab34a0SCy Schubert n3 = write(lfd, buff, n2);
49208ab34a0SCy Schubert if (n3 <= 0) {
49308ab34a0SCy Schubert syslog(LOG_ERR, "write error: %m");
49408ab34a0SCy Schubert debug(1, "write error: %s\n", STRERROR(errno));
49508ab34a0SCy Schubert return R_IO_ERROR;
49608ab34a0SCy Schubert }
49708ab34a0SCy Schubert
49808ab34a0SCy Schubert n2 -= n3;
49908ab34a0SCy Schubert buff += n3;
50008ab34a0SCy Schubert pklen -= n3;
50108ab34a0SCy Schubert } while (n3 != 0);
50208ab34a0SCy Schubert }
50308ab34a0SCy Schubert
50408ab34a0SCy Schubert return R_OKAY;
50508ab34a0SCy Schubert }
50608ab34a0SCy Schubert
50708ab34a0SCy Schubert
50808ab34a0SCy Schubert
50908ab34a0SCy Schubert int
do_kbuff(inbuf,buf,left)51008ab34a0SCy Schubert do_kbuff(inbuf, buf, left)
51108ab34a0SCy Schubert int inbuf, *left;
51208ab34a0SCy Schubert char *buf;
51308ab34a0SCy Schubert {
51408ab34a0SCy Schubert synchdr_t *sh;
51508ab34a0SCy Schubert u_32_t magic;
51608ab34a0SCy Schubert int complete;
51708ab34a0SCy Schubert int sendlen;
51808ab34a0SCy Schubert int error;
51908ab34a0SCy Schubert int bytes;
52008ab34a0SCy Schubert int len;
52108ab34a0SCy Schubert int n2;
52208ab34a0SCy Schubert int n3;
52308ab34a0SCy Schubert
52408ab34a0SCy Schubert sendlen = 0;
52508ab34a0SCy Schubert bytes = inbuf;
52608ab34a0SCy Schubert error = R_OKAY;
52708ab34a0SCy Schubert sh = (synchdr_t *)buf;
52808ab34a0SCy Schubert
52908ab34a0SCy Schubert for (complete = 0; bytes > 0; complete++) {
53008ab34a0SCy Schubert len = ntohl(sh->sm_len);
53108ab34a0SCy Schubert magic = ntohl(sh->sm_magic);
53208ab34a0SCy Schubert
53308ab34a0SCy Schubert if (magic != SYNHDRMAGIC) {
53408ab34a0SCy Schubert syslog(LOG_ERR,
53508ab34a0SCy Schubert "read invalid header magic 0x%x, flushing",
53608ab34a0SCy Schubert magic);
53708ab34a0SCy Schubert debug(2, "read invalid header magic 0x%x, flushing\n",
53808ab34a0SCy Schubert magic);
53908ab34a0SCy Schubert n2 = SMC_RLOG;
54008ab34a0SCy Schubert (void) ioctl(lfd, SIOCIPFFL, &n2);
54108ab34a0SCy Schubert break;
54208ab34a0SCy Schubert }
54308ab34a0SCy Schubert
54408ab34a0SCy Schubert if (debuglevel > 3) {
54508ab34a0SCy Schubert printsynchdr(sh);
54608ab34a0SCy Schubert printcommand(sh->sm_cmd);
54708ab34a0SCy Schubert printtable(sh->sm_table);
54808ab34a0SCy Schubert putchar('\n');
54908ab34a0SCy Schubert }
55008ab34a0SCy Schubert
55108ab34a0SCy Schubert if (bytes < sizeof(*sh) + len) {
55208ab34a0SCy Schubert debug(3, "Not enough bytes %d < %d\n", bytes,
55308ab34a0SCy Schubert sizeof(*sh) + len);
55408ab34a0SCy Schubert error = R_MORE;
55508ab34a0SCy Schubert break;
55608ab34a0SCy Schubert }
55708ab34a0SCy Schubert
55808ab34a0SCy Schubert if (debuglevel > 3) {
55908ab34a0SCy Schubert printsmcproto(buf);
56008ab34a0SCy Schubert }
56108ab34a0SCy Schubert
56208ab34a0SCy Schubert sendlen += len + sizeof(*sh);
56308ab34a0SCy Schubert sh = (synchdr_t *)(buf + sendlen);
56408ab34a0SCy Schubert bytes -= sendlen;
56508ab34a0SCy Schubert }
56608ab34a0SCy Schubert
56708ab34a0SCy Schubert if (complete) {
56808ab34a0SCy Schubert n3 = send(nfd, buf, sendlen, 0);
56908ab34a0SCy Schubert if (n3 <= 0) {
57008ab34a0SCy Schubert syslog(LOG_ERR, "write error: %m");
57108ab34a0SCy Schubert debug(1, "write error: %s\n", STRERROR(errno));
57208ab34a0SCy Schubert return R_IO_ERROR;
57308ab34a0SCy Schubert }
57408ab34a0SCy Schubert debug(3, "send on %d len %d = %d\n", nfd, sendlen, n3);
57508ab34a0SCy Schubert error = R_OKAY;
57608ab34a0SCy Schubert }
57708ab34a0SCy Schubert
57808ab34a0SCy Schubert /* move buffer to the front,we might need to make
57908ab34a0SCy Schubert * this more efficient, by using a rolling pointer
58008ab34a0SCy Schubert * over the buffer and only copying it, when
58108ab34a0SCy Schubert * we are reaching the end
58208ab34a0SCy Schubert */
58308ab34a0SCy Schubert if (bytes > 0) {
58408ab34a0SCy Schubert bcopy(buf + bytes, buf, bytes);
58508ab34a0SCy Schubert error = R_MORE;
58608ab34a0SCy Schubert }
58708ab34a0SCy Schubert debug(4, "complete %d bytes %d error %d\n", complete, bytes, error);
58808ab34a0SCy Schubert
58908ab34a0SCy Schubert *left = bytes;
59008ab34a0SCy Schubert
59108ab34a0SCy Schubert return error;
59208ab34a0SCy Schubert }
59308ab34a0SCy Schubert
59408ab34a0SCy Schubert
59508ab34a0SCy Schubert void
printcommand(cmd)59608ab34a0SCy Schubert printcommand(cmd)
59708ab34a0SCy Schubert int cmd;
59808ab34a0SCy Schubert {
59908ab34a0SCy Schubert
60008ab34a0SCy Schubert switch (cmd)
60108ab34a0SCy Schubert {
60208ab34a0SCy Schubert case SMC_CREATE :
60308ab34a0SCy Schubert printf(" cmd:CREATE");
60408ab34a0SCy Schubert break;
60508ab34a0SCy Schubert case SMC_UPDATE :
60608ab34a0SCy Schubert printf(" cmd:UPDATE");
60708ab34a0SCy Schubert break;
60808ab34a0SCy Schubert default :
60908ab34a0SCy Schubert printf(" cmd:Unknown(%d)", cmd);
61008ab34a0SCy Schubert break;
61108ab34a0SCy Schubert }
61208ab34a0SCy Schubert }
61308ab34a0SCy Schubert
61408ab34a0SCy Schubert
61508ab34a0SCy Schubert void
printtable(table)61608ab34a0SCy Schubert printtable(table)
61708ab34a0SCy Schubert int table;
61808ab34a0SCy Schubert {
61908ab34a0SCy Schubert switch (table)
62008ab34a0SCy Schubert {
62108ab34a0SCy Schubert case SMC_NAT :
62208ab34a0SCy Schubert printf(" table:NAT");
62308ab34a0SCy Schubert break;
62408ab34a0SCy Schubert case SMC_STATE :
62508ab34a0SCy Schubert printf(" table:STATE");
62608ab34a0SCy Schubert break;
62708ab34a0SCy Schubert default :
62808ab34a0SCy Schubert printf(" table:Unknown(%d)", table);
62908ab34a0SCy Schubert break;
63008ab34a0SCy Schubert }
63108ab34a0SCy Schubert }
63208ab34a0SCy Schubert
63308ab34a0SCy Schubert
63408ab34a0SCy Schubert void
printsmcproto(buff)63508ab34a0SCy Schubert printsmcproto(buff)
63608ab34a0SCy Schubert char *buff;
63708ab34a0SCy Schubert {
63808ab34a0SCy Schubert syncupdent_t *su;
63908ab34a0SCy Schubert synchdr_t *sh;
64008ab34a0SCy Schubert
64108ab34a0SCy Schubert sh = (synchdr_t *)buff;
64208ab34a0SCy Schubert
64308ab34a0SCy Schubert if (sh->sm_cmd == SMC_CREATE) {
64408ab34a0SCy Schubert ;
64508ab34a0SCy Schubert
64608ab34a0SCy Schubert } else if (sh->sm_cmd == SMC_UPDATE) {
64708ab34a0SCy Schubert su = (syncupdent_t *)buff;
64808ab34a0SCy Schubert if (sh->sm_p == IPPROTO_TCP) {
64908ab34a0SCy Schubert printf(" TCP Update: age %lu state %d/%d\n",
65008ab34a0SCy Schubert su->sup_tcp.stu_age,
65108ab34a0SCy Schubert su->sup_tcp.stu_state[0],
65208ab34a0SCy Schubert su->sup_tcp.stu_state[1]);
65308ab34a0SCy Schubert }
65408ab34a0SCy Schubert } else {
65508ab34a0SCy Schubert printf("Unknown command\n");
65608ab34a0SCy Schubert }
65708ab34a0SCy Schubert }
65808ab34a0SCy Schubert
65908ab34a0SCy Schubert
66008ab34a0SCy Schubert void
printsynchdr(sh)66108ab34a0SCy Schubert printsynchdr(sh)
66208ab34a0SCy Schubert synchdr_t *sh;
66308ab34a0SCy Schubert {
66408ab34a0SCy Schubert
66508ab34a0SCy Schubert printf("v:%d p:%d num:%d len:%d magic:%x", sh->sm_v, sh->sm_p,
66608ab34a0SCy Schubert ntohl(sh->sm_num), ntohl(sh->sm_len), ntohl(sh->sm_magic));
66708ab34a0SCy Schubert }
668