aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2022-01-08 04:12:50 +0000
committerCy Schubert <cy@FreeBSD.org>2022-01-08 05:46:53 +0000
commit08ab34a06a9b0a84e979ff43f2d6f2d60fb37ed9 (patch)
tree8af0d4ce06fd5448250753878464e60d5134dc8b
parent15964f1cb3935b612c833b863219fef0a3932edf (diff)
downloadsrc-08ab34a06a9b0a84e979ff43f2d6f2d60fb37ed9.tar.gz
src-08ab34a06a9b0a84e979ff43f2d6f2d60fb37ed9.zip
ipfilter: Restore ipfsync
ipfsync is a WIP sync daemon designed to be used in a failover scenario. It was removed by 5ee61c7daa511927aae8652d6a3ea78866a50ef8. This commit restores its three files. ipfsync is in my work queue. MFC after: 10 days X-MFC with: 5ee61c7daa511927aae8652d6a3ea78866a50ef8
-rw-r--r--sbin/ipf/ipfsync/ipfsyncd.c671
-rw-r--r--sbin/ipf/ipfsync/ipsyncm.c256
-rw-r--r--sbin/ipf/ipfsync/ipsyncs.c274
3 files changed, 1201 insertions, 0 deletions
diff --git a/sbin/ipf/ipfsync/ipfsyncd.c b/sbin/ipf/ipfsync/ipfsyncd.c
new file mode 100644
index 000000000000..ead92b70371c
--- /dev/null
+++ b/sbin/ipf/ipfsync/ipfsyncd.c
@@ -0,0 +1,671 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id: ipfsyncd.c,v 1.1.2.2 2012/07/22 08:04:24 darren_r Exp $";
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+
+#include "ipf.h"
+#include "opts.h"
+
+
+#define R_IO_ERROR -1
+#define R_OKAY 0
+#define R_MORE 1
+#define R_SKIP 2
+#if defined(sun) && !defined(SOLARIS2)
+# define STRERROR(x) sys_errlist[x]
+extern char *sys_errlist[];
+#else
+# define STRERROR(x) strerror(x)
+#endif
+
+
+int main(int, char *[]);
+void usage(char *);
+void printsynchdr(synchdr_t *);
+void printtable(int);
+void printsmcproto(char *);
+void printcommand(int);
+int do_kbuff(int, char *, int *);
+int do_packet(int, char *);
+int buildsocket(char *, struct sockaddr_in *);
+void do_io(void);
+void handleterm(int);
+
+int terminate = 0;
+int igmpfd = -1;
+int nfd = -1;
+int lfd = -1;
+int opts = 0;
+
+void
+usage(progname)
+ char *progname;
+{
+ fprintf(stderr,
+ "Usage: %s [-d] [-p port] [-i address] -I <interface>\n",
+ progname);
+}
+
+void
+handleterm(sig)
+ int sig;
+{
+ terminate = sig;
+}
+
+
+/* should be large enough to hold header + any datatype */
+#define BUFFERLEN 1400
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct sockaddr_in sin;
+ char *interface;
+ char *progname;
+ int opt, tries;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) {
+ progname++;
+ } else {
+ progname = argv[0];
+ }
+
+ opts = 0;
+ tries = 0;
+ interface = NULL;
+
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(0xaf6c);
+ sin.sin_addr.s_addr = htonl(INADDR_UNSPEC_GROUP | 0x697066);
+
+ while ((opt = getopt(argc, argv, "di:I:p:")) != -1)
+ switch (opt)
+ {
+ case 'd' :
+ debuglevel++;
+ break;
+ case 'I' :
+ interface = optarg;
+ break;
+ case 'i' :
+ sin.sin_addr.s_addr = inet_addr(optarg);
+ break;
+ case 'p' :
+ sin.sin_port = htons(atoi(optarg));
+ break;
+ }
+
+ if (interface == NULL) {
+ usage(progname);
+ exit(1);
+ }
+
+ if (!debuglevel) {
+
+#ifdef BSD
+ daemon(0, 0);
+#else
+ int fd = open("/dev/null", O_RDWR);
+
+ switch (fork())
+ {
+ case 0 :
+ break;
+
+ case -1 :
+ fprintf(stderr, "%s: fork() failed: %s\n",
+ argv[0], STRERROR(errno));
+ exit(1);
+ /* NOTREACHED */
+
+ default :
+ exit(0);
+ /* NOTREACHED */
+ }
+
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ close(fd);
+
+ setsid();
+#endif
+ }
+
+ signal(SIGHUP, handleterm);
+ signal(SIGINT, handleterm);
+ signal(SIGTERM, handleterm);
+
+ openlog(progname, LOG_PID, LOG_SECURITY);
+
+ while (!terminate) {
+ if (lfd != -1) {
+ close(lfd);
+ lfd = -1;
+ }
+ if (nfd != -1) {
+ close(nfd);
+ nfd = -1;
+ }
+ if (igmpfd != -1) {
+ close(igmpfd);
+ igmpfd = -1;
+ }
+
+ if (buildsocket(interface, &sin) == -1)
+ goto tryagain;
+
+ lfd = open(IPSYNC_NAME, O_RDWR);
+ if (lfd == -1) {
+ syslog(LOG_ERR, "open(%s):%m", IPSYNC_NAME);
+ debug(1, "open(%s): %s\n", IPSYNC_NAME,
+ STRERROR(errno));
+ goto tryagain;
+ }
+
+ tries = -1;
+ do_io();
+tryagain:
+ tries++;
+ syslog(LOG_INFO, "retry in %d seconds", 1 << tries);
+ debug(1, "wait %d seconds\n", 1 << tries);
+ sleep(1 << tries);
+ }
+
+
+ /* terminate */
+ if (lfd != -1)
+ close(lfd);
+ if (nfd != -1)
+ close(nfd);
+
+ syslog(LOG_ERR, "signal %d received, exiting...", terminate);
+ debug(1, "signal %d received, exiting...", terminate);
+
+ exit(1);
+}
+
+
+void
+do_io()
+{
+ char nbuff[BUFFERLEN];
+ char buff[BUFFERLEN];
+ fd_set mrd, rd;
+ int maxfd;
+ int inbuf;
+ int n1;
+ int left;
+
+ FD_ZERO(&mrd);
+ FD_SET(lfd, &mrd);
+ FD_SET(nfd, &mrd);
+ maxfd = nfd;
+ if (lfd > maxfd)
+ maxfd = lfd;
+ debug(2, "nfd %d lfd %d maxfd %d\n", nfd, lfd, maxfd);
+
+ inbuf = 0;
+ /*
+ * A threaded approach to this loop would have one thread
+ * work on reading lfd (only) all the time and another thread
+ * working on reading nfd all the time.
+ */
+ while (!terminate) {
+ int n;
+
+ rd = mrd;
+
+ n = select(maxfd + 1, &rd, NULL, NULL, NULL);
+ if (n < 0) {
+ switch (errno)
+ {
+ case EINTR :
+ continue;
+ default :
+ syslog(LOG_ERR, "select error: %m");
+ debug(1, "select error: %s\n", STRERROR(errno));
+ return;
+ }
+ }
+
+ if (FD_ISSET(lfd, &rd)) {
+ n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf);
+
+ debug(3, "read(K):%d\n", n1);
+
+ if (n1 <= 0) {
+ syslog(LOG_ERR, "read error (k-header): %m");
+ debug(1, "read error (k-header): %s\n",
+ STRERROR(errno));
+ return;
+ }
+
+ left = 0;
+
+ switch (do_kbuff(n1, buff, &left))
+ {
+ case R_IO_ERROR :
+ return;
+ case R_MORE :
+ inbuf += left;
+ break;
+ default :
+ inbuf = 0;
+ break;
+ }
+ }
+
+ if (FD_ISSET(nfd, &rd)) {
+ n1 = recv(nfd, nbuff, sizeof(nbuff), 0);
+
+ debug(3, "read(N):%d\n", n1);
+
+ if (n1 <= 0) {
+ syslog(LOG_ERR, "read error (n-header): %m");
+ debug(1, "read error (n-header): %s\n",
+ STRERROR(errno));
+ return;
+ }
+
+ switch (do_packet(n1, nbuff))
+ {
+ case R_IO_ERROR :
+ return;
+ default :
+ break;
+ }
+ }
+ }
+}
+
+
+int
+buildsocket(nicname, sinp)
+ char *nicname;
+ struct sockaddr_in *sinp;
+{
+ struct sockaddr_in *reqip;
+ struct ifreq req;
+ char opt;
+
+ debug(2, "binding to %s:%s\n", nicname, inet_ntoa(sinp->sin_addr));
+
+ if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
+ struct in_addr addr;
+ struct ip_mreq mreq;
+
+ igmpfd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
+ if (igmpfd == -1) {
+ syslog(LOG_ERR, "socket:%m");
+ debug(1, "socket:%s\n", STRERROR(errno));
+ return -1;
+ }
+
+ bzero((char *)&req, sizeof(req));
+ strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
+ req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
+ if (ioctl(igmpfd, SIOCGIFADDR, &req) == -1) {
+ syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
+ debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+ reqip = (struct sockaddr_in *)&req.ifr_addr;
+
+ addr = reqip->sin_addr;
+ if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_IF,
+ (char *)&addr, sizeof(addr)) == -1) {
+ syslog(LOG_ERR, "setsockopt(IP_MULTICAST_IF(%s)):%m",
+ inet_ntoa(addr));
+ debug(1, "setsockopt(IP_MULTICAST_IF(%s)):%s\n",
+ inet_ntoa(addr), STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+
+ opt = 0;
+ if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_LOOP,
+ (char *)&opt, sizeof(opt)) == -1) {
+ syslog(LOG_ERR, "setsockopt(IP_MULTICAST_LOOP=0):%m");
+ debug(1, "setsockopt(IP_MULTICAST_LOOP=0):%s\n",
+ STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+
+ opt = 63;
+ if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_TTL,
+ (char *)&opt, sizeof(opt)) == -1) {
+ syslog(LOG_ERR, "setsockopt(IP_MULTICAST_TTL=%d):%m",
+ opt);
+ debug(1, "setsockopt(IP_MULTICAST_TTL=%d):%s\n", opt,
+ STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+
+ mreq.imr_multiaddr.s_addr = sinp->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = reqip->sin_addr.s_addr;
+
+ if (setsockopt(igmpfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *)&mreq, sizeof(mreq)) == -1) {
+ char buffer[80];
+
+ snprintf(buffer, sizeof(buffer), "%s,", inet_ntoa(sinp->sin_addr));
+ strcat(buffer, inet_ntoa(reqip->sin_addr));
+
+ syslog(LOG_ERR,
+ "setsockpt(IP_ADD_MEMBERSHIP,%s):%m", buffer);
+ debug(1, "setsockpt(IP_ADD_MEMBERSHIP,%s):%s\n",
+ buffer, STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+ }
+ nfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (nfd == -1) {
+ syslog(LOG_ERR, "socket:%m");
+ if (igmpfd != -1) {
+ close(igmpfd);
+ igmpfd = -1;
+ }
+ return -1;
+ }
+ bzero((char *)&req, sizeof(req));
+ strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
+ req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
+ if (ioctl(nfd, SIOCGIFADDR, &req) == -1) {
+ syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
+ debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+
+ if (bind(nfd, (struct sockaddr *)&req.ifr_addr,
+ sizeof(req.ifr_addr)) == -1) {
+ syslog(LOG_ERR, "bind:%m");
+ debug(1, "bind:%s\n", STRERROR(errno));
+ close(nfd);
+ if (igmpfd != -1) {
+ close(igmpfd);
+ igmpfd = -1;
+ }
+ nfd = -1;
+ return -1;
+ }
+
+ if (connect(nfd, (struct sockaddr *)sinp, sizeof(*sinp)) == -1) {
+ syslog(LOG_ERR, "connect:%m");
+ debug(1, "connect:%s\n", STRERROR(errno));
+ close(nfd);
+ if (igmpfd != -1) {
+ close(igmpfd);
+ igmpfd = -1;
+ }
+ nfd = -1;
+ return -1;
+ }
+ syslog(LOG_INFO, "Sending data to %s", inet_ntoa(sinp->sin_addr));
+ debug(3, "Sending data to %s\n", inet_ntoa(sinp->sin_addr));
+
+ return nfd;
+}
+
+
+int
+do_packet(pklen, buff)
+ int pklen;
+ char *buff;
+{
+ synchdr_t *sh;
+ u_32_t magic;
+ int len;
+ int n2;
+ int n3;
+
+ while (pklen > 0) {
+ if (pklen < sizeof(*sh)) {
+ syslog(LOG_ERR, "packet length too short:%d", pklen);
+ debug(2, "packet length too short:%d\n", pklen);
+ return R_SKIP;
+ }
+
+ sh = (synchdr_t *)buff;
+ len = ntohl(sh->sm_len);
+ magic = ntohl(sh->sm_magic);
+
+ if (magic != SYNHDRMAGIC) {
+ syslog(LOG_ERR, "invalid header magic %x", magic);
+ debug(2, "invalid header magic %x\n", magic);
+ return R_SKIP;
+ }
+
+ if (pklen < len + sizeof(*sh)) {
+ syslog(LOG_ERR, "packet length too short:%d", pklen);
+ debug(2, "packet length too short:%d\n", pklen);
+ return R_SKIP;
+ }
+
+ if (debuglevel > 3) {
+ printsynchdr(sh);
+ printcommand(sh->sm_cmd);
+ printtable(sh->sm_table);
+ printsmcproto(buff);
+ }
+
+ n2 = sizeof(*sh) + len;
+
+ do {
+ n3 = write(lfd, buff, n2);
+ if (n3 <= 0) {
+ syslog(LOG_ERR, "write error: %m");
+ debug(1, "write error: %s\n", STRERROR(errno));
+ return R_IO_ERROR;
+ }
+
+ n2 -= n3;
+ buff += n3;
+ pklen -= n3;
+ } while (n3 != 0);
+ }
+
+ return R_OKAY;
+}
+
+
+
+int
+do_kbuff(inbuf, buf, left)
+ int inbuf, *left;
+ char *buf;
+{
+ synchdr_t *sh;
+ u_32_t magic;
+ int complete;
+ int sendlen;
+ int error;
+ int bytes;
+ int len;
+ int n2;
+ int n3;
+
+ sendlen = 0;
+ bytes = inbuf;
+ error = R_OKAY;
+ sh = (synchdr_t *)buf;
+
+ for (complete = 0; bytes > 0; complete++) {
+ len = ntohl(sh->sm_len);
+ magic = ntohl(sh->sm_magic);
+
+ if (magic != SYNHDRMAGIC) {
+ syslog(LOG_ERR,
+ "read invalid header magic 0x%x, flushing",
+ magic);
+ debug(2, "read invalid header magic 0x%x, flushing\n",
+ magic);
+ n2 = SMC_RLOG;
+ (void) ioctl(lfd, SIOCIPFFL, &n2);
+ break;
+ }
+
+ if (debuglevel > 3) {
+ printsynchdr(sh);
+ printcommand(sh->sm_cmd);
+ printtable(sh->sm_table);
+ putchar('\n');
+ }
+
+ if (bytes < sizeof(*sh) + len) {
+ debug(3, "Not enough bytes %d < %d\n", bytes,
+ sizeof(*sh) + len);
+ error = R_MORE;
+ break;
+ }
+
+ if (debuglevel > 3) {
+ printsmcproto(buf);
+ }
+
+ sendlen += len + sizeof(*sh);
+ sh = (synchdr_t *)(buf + sendlen);
+ bytes -= sendlen;
+ }
+
+ if (complete) {
+ n3 = send(nfd, buf, sendlen, 0);
+ if (n3 <= 0) {
+ syslog(LOG_ERR, "write error: %m");
+ debug(1, "write error: %s\n", STRERROR(errno));
+ return R_IO_ERROR;
+ }
+ debug(3, "send on %d len %d = %d\n", nfd, sendlen, n3);
+ error = R_OKAY;
+ }
+
+ /* move buffer to the front,we might need to make
+ * this more efficient, by using a rolling pointer
+ * over the buffer and only copying it, when
+ * we are reaching the end
+ */
+ if (bytes > 0) {
+ bcopy(buf + bytes, buf, bytes);
+ error = R_MORE;
+ }
+ debug(4, "complete %d bytes %d error %d\n", complete, bytes, error);
+
+ *left = bytes;
+
+ return error;
+}
+
+
+void
+printcommand(cmd)
+ int cmd;
+{
+
+ switch (cmd)
+ {
+ case SMC_CREATE :
+ printf(" cmd:CREATE");
+ break;
+ case SMC_UPDATE :
+ printf(" cmd:UPDATE");
+ break;
+ default :
+ printf(" cmd:Unknown(%d)", cmd);
+ break;
+ }
+}
+
+
+void
+printtable(table)
+ int table;
+{
+ switch (table)
+ {
+ case SMC_NAT :
+ printf(" table:NAT");
+ break;
+ case SMC_STATE :
+ printf(" table:STATE");
+ break;
+ default :
+ printf(" table:Unknown(%d)", table);
+ break;
+ }
+}
+
+
+void
+printsmcproto(buff)
+ char *buff;
+{
+ syncupdent_t *su;
+ synchdr_t *sh;
+
+ sh = (synchdr_t *)buff;
+
+ if (sh->sm_cmd == SMC_CREATE) {
+ ;
+
+ } else if (sh->sm_cmd == SMC_UPDATE) {
+ su = (syncupdent_t *)buff;
+ if (sh->sm_p == IPPROTO_TCP) {
+ printf(" TCP Update: age %lu state %d/%d\n",
+ su->sup_tcp.stu_age,
+ su->sup_tcp.stu_state[0],
+ su->sup_tcp.stu_state[1]);
+ }
+ } else {
+ printf("Unknown command\n");
+ }
+}
+
+
+void
+printsynchdr(sh)
+ synchdr_t *sh;
+{
+
+ printf("v:%d p:%d num:%d len:%d magic:%x", sh->sm_v, sh->sm_p,
+ ntohl(sh->sm_num), ntohl(sh->sm_len), ntohl(sh->sm_magic));
+}
diff --git a/sbin/ipf/ipfsync/ipsyncm.c b/sbin/ipf/ipfsync/ipsyncm.c
new file mode 100644
index 000000000000..d57196379210
--- /dev/null
+++ b/sbin/ipf/ipfsync/ipsyncm.c
@@ -0,0 +1,256 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_sync.h"
+
+
+int main(int, char *[]);
+void usage(const char *);
+
+int terminate = 0;
+
+void usage(const char *progname) {
+ fprintf(stderr, "Usage: %s <destination IP> <destination port>\n", progname);
+}
+
+#if 0
+static void handleterm(int sig)
+{
+ terminate = sig;
+}
+#endif
+
+
+/* should be large enough to hold header + any datatype */
+#define BUFFERLEN 1400
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct sockaddr_in sin;
+ char buff[BUFFERLEN];
+ synclogent_t *sl;
+ syncupdent_t *su;
+ int nfd = -1, lfd = -1, n1, n2, n3, len;
+ int inbuf;
+ u_32_t magic;
+ synchdr_t *sh;
+ char *progname;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) {
+ progname++;
+ } else {
+ progname = argv[0];
+ }
+
+
+ if (argc < 2) {
+ usage(progname);
+ exit(1);
+ }
+
+#if 0
+ signal(SIGHUP, handleterm);
+ signal(SIGINT, handleterm);
+ signal(SIGTERM, handleterm);
+#endif
+
+ openlog(progname, LOG_PID, LOG_SECURITY);
+
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = inet_addr(argv[1]);
+ if (argc > 2)
+ sin.sin_port = htons(atoi(argv[2]));
+ else
+ sin.sin_port = htons(43434);
+
+ while (1) {
+
+ if (lfd != -1)
+ close(lfd);
+ if (nfd != -1)
+ close(nfd);
+
+ lfd = open(IPSYNC_NAME, O_RDONLY);
+ if (lfd == -1) {
+ syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME);
+ goto tryagain;
+ }
+
+ nfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (nfd == -1) {
+ syslog(LOG_ERR, "Socket :%m");
+ goto tryagain;
+ }
+
+ if (connect(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+ syslog(LOG_ERR, "Connect: %m");
+ goto tryagain;
+ }
+
+ syslog(LOG_INFO, "Sending data to %s",
+ inet_ntoa(sin.sin_addr));
+
+ inbuf = 0;
+ while (1) {
+
+ n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf);
+
+ printf("header : %d bytes read (header = %d bytes)\n",
+ n1, (int) sizeof(*sh));
+
+ if (n1 < 0) {
+ syslog(LOG_ERR, "Read error (header): %m");
+ goto tryagain;
+ }
+
+ if (n1 == 0) {
+ /* XXX can this happen??? */
+ syslog(LOG_ERR,
+ "Read error (header) : No data");
+ sleep(1);
+ continue;
+ }
+
+ inbuf += n1;
+
+moreinbuf:
+ if (inbuf < sizeof(*sh)) {
+ continue; /* need more data */
+ }
+
+ sh = (synchdr_t *)buff;
+ len = ntohl(sh->sm_len);
+ magic = ntohl(sh->sm_magic);
+
+ if (magic != SYNHDRMAGIC) {
+ syslog(LOG_ERR,
+ "Invalid header magic %x", magic);
+ goto tryagain;
+ }
+
+#define IPSYNC_DEBUG
+#ifdef IPSYNC_DEBUG
+ printf("v:%d p:%d len:%d magic:%x", sh->sm_v,
+ sh->sm_p, len, magic);
+
+ if (sh->sm_cmd == SMC_CREATE)
+ printf(" cmd:CREATE");
+ else if (sh->sm_cmd == SMC_UPDATE)
+ printf(" cmd:UPDATE");
+ else
+ printf(" cmd:Unknown(%d)", sh->sm_cmd);
+
+ if (sh->sm_table == SMC_NAT)
+ printf(" table:NAT");
+ else if (sh->sm_table == SMC_STATE)
+ printf(" table:STATE");
+ else
+ printf(" table:Unknown(%d)", sh->sm_table);
+
+ printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num));
+#endif
+
+ if (inbuf < sizeof(*sh) + len) {
+ continue; /* need more data */
+ goto tryagain;
+ }
+
+#ifdef IPSYNC_DEBUG
+ if (sh->sm_cmd == SMC_CREATE) {
+ sl = (synclogent_t *)buff;
+
+ } else if (sh->sm_cmd == SMC_UPDATE) {
+ su = (syncupdent_t *)buff;
+ if (sh->sm_p == IPPROTO_TCP) {
+ printf(" TCP Update: age %lu state %d/%d\n",
+ su->sup_tcp.stu_age,
+ su->sup_tcp.stu_state[0],
+ su->sup_tcp.stu_state[1]);
+ }
+ } else {
+ printf("Unknown command\n");
+ }
+#endif
+
+ n2 = sizeof(*sh) + len;
+ n3 = write(nfd, buff, n2);
+ if (n3 <= 0) {
+ syslog(LOG_ERR, "Write error: %m");
+ goto tryagain;
+ }
+
+
+ if (n3 != n2) {
+ syslog(LOG_ERR, "Incomplete write (%d/%d)",
+ n3, n2);
+ goto tryagain;
+ }
+
+ /* signal received? */
+ if (terminate)
+ break;
+
+ /* move buffer to the front,we might need to make
+ * this more efficient, by using a rolling pointer
+ * over the buffer and only copying it, when
+ * we are reaching the end
+ */
+ inbuf -= n2;
+ if (inbuf) {
+ bcopy(buff+n2, buff, inbuf);
+ printf("More data in buffer\n");
+ goto moreinbuf;
+ }
+ }
+
+ if (terminate)
+ break;
+tryagain:
+ sleep(1);
+ }
+
+
+ /* terminate */
+ if (lfd != -1)
+ close(lfd);
+ if (nfd != -1)
+ close(nfd);
+
+ syslog(LOG_ERR, "signal %d received, exiting...", terminate);
+
+ exit(1);
+}
+
diff --git a/sbin/ipf/ipfsync/ipsyncs.c b/sbin/ipf/ipfsync/ipsyncs.c
new file mode 100644
index 000000000000..a53cfb8c9508
--- /dev/null
+++ b/sbin/ipf/ipfsync/ipsyncs.c
@@ -0,0 +1,274 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_sync.h"
+
+int main(int, char *[]);
+void usage(const char *progname);
+
+int terminate = 0;
+
+void usage(const char *progname) {
+ fprintf(stderr,
+ "Usage: %s <destination IP> <destination port> [remote IP]\n",
+ progname);
+}
+
+#if 0
+static void handleterm(int sig)
+{
+ terminate = sig;
+}
+#endif
+
+#define BUFFERLEN 1400
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int nfd = -1 , lfd = -1;
+ int n1, n2, n3, magic, len, inbuf;
+ struct sockaddr_in sin;
+ struct sockaddr_in in;
+ char buff[BUFFERLEN];
+ synclogent_t *sl;
+ syncupdent_t *su;
+ synchdr_t *sh;
+ char *progname;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) {
+ progname++;
+ } else {
+ progname = argv[0];
+ }
+
+ if (argc < 2) {
+ usage(progname);
+ exit(1);
+ }
+
+#if 0
+ signal(SIGHUP, handleterm);
+ signal(SIGINT, handleterm);
+ signal(SIGTERM, handleterm);
+#endif
+
+ openlog(progname, LOG_PID, LOG_SECURITY);
+
+ lfd = open(IPSYNC_NAME, O_WRONLY);
+ if (lfd == -1) {
+ syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME);
+ exit(1);
+ }
+
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ if (argc > 1)
+ sin.sin_addr.s_addr = inet_addr(argv[1]);
+ if (argc > 2)
+ sin.sin_port = htons(atoi(argv[2]));
+ else
+ sin.sin_port = htons(43434);
+ if (argc > 3)
+ in.sin_addr.s_addr = inet_addr(argv[3]);
+ else
+ in.sin_addr.s_addr = 0;
+ in.sin_port = 0;
+
+ while(1) {
+
+ if (lfd != -1)
+ close(lfd);
+ if (nfd != -1)
+ close(nfd);
+
+ lfd = open(IPSYNC_NAME, O_WRONLY);
+ if (lfd == -1) {
+ syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME);
+ goto tryagain;
+ }
+
+ nfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (nfd == -1) {
+ syslog(LOG_ERR, "Socket :%m");
+ goto tryagain;
+ }
+
+ n1 = 1;
+ setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &n1, sizeof(n1));
+
+ if (bind(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+ syslog(LOG_ERR, "Bind: %m");
+ goto tryagain;
+ }
+
+ syslog(LOG_INFO, "Listening to %s", inet_ntoa(sin.sin_addr));
+
+ inbuf = 0;
+ while (1) {
+
+
+ /*
+ * XXX currently we do not check the source address
+ * of a datagram, this can be a security risk
+ */
+ n1 = read(nfd, buff+inbuf, BUFFERLEN-inbuf);
+
+ printf("header : %d bytes read (header = %d bytes)\n",
+ n1, (int) sizeof(*sh));
+
+ if (n1 < 0) {
+ syslog(LOG_ERR, "Read error (header): %m");
+ goto tryagain;
+ }
+
+ if (n1 == 0) {
+ /* XXX can this happen??? */
+ syslog(LOG_ERR,
+ "Read error (header) : No data");
+ sleep(1);
+ continue;
+ }
+
+ inbuf += n1;
+
+moreinbuf:
+ if (inbuf < sizeof(*sh)) {
+ continue; /* need more data */
+ }
+
+ sh = (synchdr_t *)buff;
+ len = ntohl(sh->sm_len);
+ magic = ntohl(sh->sm_magic);
+
+ if (magic != SYNHDRMAGIC) {
+ syslog(LOG_ERR, "Invalid header magic %x",
+ magic);
+ goto tryagain;
+ }
+
+#define IPSYNC_DEBUG
+#ifdef IPSYNC_DEBUG
+ printf("v:%d p:%d len:%d magic:%x", sh->sm_v,
+ sh->sm_p, len, magic);
+
+ if (sh->sm_cmd == SMC_CREATE)
+ printf(" cmd:CREATE");
+ else if (sh->sm_cmd == SMC_UPDATE)
+ printf(" cmd:UPDATE");
+ else
+ printf(" cmd:Unknown(%d)", sh->sm_cmd);
+
+ if (sh->sm_table == SMC_NAT)
+ printf(" table:NAT");
+ else if (sh->sm_table == SMC_STATE)
+ printf(" table:STATE");
+ else
+ printf(" table:Unknown(%d)", sh->sm_table);
+
+ printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num));
+#endif
+
+ if (inbuf < sizeof(*sh) + len) {
+ continue; /* need more data */
+ goto tryagain;
+ }
+
+#ifdef IPSYNC_DEBUG
+ if (sh->sm_cmd == SMC_CREATE) {
+ sl = (synclogent_t *)buff;
+
+ } else if (sh->sm_cmd == SMC_UPDATE) {
+ su = (syncupdent_t *)buff;
+ if (sh->sm_p == IPPROTO_TCP) {
+ printf(" TCP Update: age %lu state %d/%d\n",
+ su->sup_tcp.stu_age,
+ su->sup_tcp.stu_state[0],
+ su->sup_tcp.stu_state[1]);
+ }
+ } else {
+ printf("Unknown command\n");
+ }
+#endif
+
+ n2 = sizeof(*sh) + len;
+ n3 = write(lfd, buff, n2);
+ if (n3 <= 0) {
+ syslog(LOG_ERR, "%s: Write error: %m",
+ IPSYNC_NAME);
+ goto tryagain;
+ }
+
+
+ if (n3 != n2) {
+ syslog(LOG_ERR, "%s: Incomplete write (%d/%d)",
+ IPSYNC_NAME, n3, n2);
+ goto tryagain;
+ }
+
+ /* signal received? */
+ if (terminate)
+ break;
+
+ /* move buffer to the front,we might need to make
+ * this more efficient, by using a rolling pointer
+ * over the buffer and only copying it, when
+ * we are reaching the end
+ */
+ inbuf -= n2;
+ if (inbuf) {
+ bcopy(buff+n2, buff, inbuf);
+ printf("More data in buffer\n");
+ goto moreinbuf;
+ }
+ }
+
+ if (terminate)
+ break;
+tryagain:
+ sleep(1);
+ }
+
+
+ /* terminate */
+ if (lfd != -1)
+ close(lfd);
+ if (nfd != -1)
+ close(nfd);
+
+ syslog(LOG_ERR, "signal %d received, exiting...", terminate);
+
+ exit(1);
+}