108ab34a0SCy Schubert
208ab34a0SCy Schubert /*
308ab34a0SCy Schubert * Copyright (C) 2012 by Darren Reed.
408ab34a0SCy Schubert *
508ab34a0SCy Schubert * See the IPFILTER.LICENCE file for details on licencing.
608ab34a0SCy Schubert */
708ab34a0SCy Schubert #include <sys/types.h>
808ab34a0SCy Schubert #include <sys/time.h>
908ab34a0SCy Schubert #include <sys/socket.h>
1008ab34a0SCy Schubert
1108ab34a0SCy Schubert #include <netinet/in.h>
1208ab34a0SCy Schubert #include <net/if.h>
1308ab34a0SCy Schubert
1408ab34a0SCy Schubert #include <arpa/inet.h>
1508ab34a0SCy Schubert
1608ab34a0SCy Schubert #include <stdio.h>
1708ab34a0SCy Schubert #include <stdlib.h>
1808ab34a0SCy Schubert #include <fcntl.h>
1908ab34a0SCy Schubert #include <string.h>
2008ab34a0SCy Schubert #include <unistd.h>
2108ab34a0SCy Schubert #include <syslog.h>
2208ab34a0SCy Schubert #include <errno.h>
2308ab34a0SCy Schubert #include <signal.h>
2408ab34a0SCy Schubert
2508ab34a0SCy Schubert #include "netinet/ip_compat.h"
2608ab34a0SCy Schubert #include "netinet/ip_fil.h"
2708ab34a0SCy Schubert #include "netinet/ip_state.h"
2808ab34a0SCy Schubert #include "netinet/ip_nat.h"
2908ab34a0SCy Schubert #include "netinet/ip_sync.h"
3008ab34a0SCy Schubert
3108ab34a0SCy Schubert int main(int, char *[]);
3208ab34a0SCy Schubert void usage(const char *progname);
3308ab34a0SCy Schubert
3408ab34a0SCy Schubert int terminate = 0;
3508ab34a0SCy Schubert
usage(const char * progname)3608ab34a0SCy Schubert void usage(const char *progname) {
3708ab34a0SCy Schubert fprintf(stderr,
3808ab34a0SCy Schubert "Usage: %s <destination IP> <destination port> [remote IP]\n",
3908ab34a0SCy Schubert progname);
4008ab34a0SCy Schubert }
4108ab34a0SCy Schubert
4208ab34a0SCy Schubert #if 0
4308ab34a0SCy Schubert static void handleterm(int sig)
4408ab34a0SCy Schubert {
4508ab34a0SCy Schubert terminate = sig;
4608ab34a0SCy Schubert }
4708ab34a0SCy Schubert #endif
4808ab34a0SCy Schubert
4908ab34a0SCy Schubert #define BUFFERLEN 1400
5008ab34a0SCy Schubert
main(argc,argv)5108ab34a0SCy Schubert int main(argc, argv)
5208ab34a0SCy Schubert int argc;
5308ab34a0SCy Schubert char *argv[];
5408ab34a0SCy Schubert {
5508ab34a0SCy Schubert int nfd = -1 , lfd = -1;
5608ab34a0SCy Schubert int n1, n2, n3, magic, len, inbuf;
5708ab34a0SCy Schubert struct sockaddr_in sin;
5808ab34a0SCy Schubert struct sockaddr_in in;
5908ab34a0SCy Schubert char buff[BUFFERLEN];
6008ab34a0SCy Schubert synclogent_t *sl;
6108ab34a0SCy Schubert syncupdent_t *su;
6208ab34a0SCy Schubert synchdr_t *sh;
6308ab34a0SCy Schubert char *progname;
6408ab34a0SCy Schubert
6508ab34a0SCy Schubert progname = strrchr(argv[0], '/');
6608ab34a0SCy Schubert if (progname) {
6708ab34a0SCy Schubert progname++;
6808ab34a0SCy Schubert } else {
6908ab34a0SCy Schubert progname = argv[0];
7008ab34a0SCy Schubert }
7108ab34a0SCy Schubert
7208ab34a0SCy Schubert if (argc < 2) {
7308ab34a0SCy Schubert usage(progname);
7408ab34a0SCy Schubert exit(1);
7508ab34a0SCy Schubert }
7608ab34a0SCy Schubert
7708ab34a0SCy Schubert #if 0
7808ab34a0SCy Schubert signal(SIGHUP, handleterm);
7908ab34a0SCy Schubert signal(SIGINT, handleterm);
8008ab34a0SCy Schubert signal(SIGTERM, handleterm);
8108ab34a0SCy Schubert #endif
8208ab34a0SCy Schubert
8308ab34a0SCy Schubert openlog(progname, LOG_PID, LOG_SECURITY);
8408ab34a0SCy Schubert
8508ab34a0SCy Schubert lfd = open(IPSYNC_NAME, O_WRONLY);
8608ab34a0SCy Schubert if (lfd == -1) {
8708ab34a0SCy Schubert syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME);
8808ab34a0SCy Schubert exit(1);
8908ab34a0SCy Schubert }
9008ab34a0SCy Schubert
9108ab34a0SCy Schubert bzero((char *)&sin, sizeof(sin));
9208ab34a0SCy Schubert sin.sin_family = AF_INET;
9308ab34a0SCy Schubert if (argc > 1)
9408ab34a0SCy Schubert sin.sin_addr.s_addr = inet_addr(argv[1]);
9508ab34a0SCy Schubert if (argc > 2)
9608ab34a0SCy Schubert sin.sin_port = htons(atoi(argv[2]));
9708ab34a0SCy Schubert else
9808ab34a0SCy Schubert sin.sin_port = htons(43434);
9908ab34a0SCy Schubert if (argc > 3)
10008ab34a0SCy Schubert in.sin_addr.s_addr = inet_addr(argv[3]);
10108ab34a0SCy Schubert else
10208ab34a0SCy Schubert in.sin_addr.s_addr = 0;
10308ab34a0SCy Schubert in.sin_port = 0;
10408ab34a0SCy Schubert
10508ab34a0SCy Schubert while(1) {
10608ab34a0SCy Schubert
10708ab34a0SCy Schubert if (lfd != -1)
10808ab34a0SCy Schubert close(lfd);
10908ab34a0SCy Schubert if (nfd != -1)
11008ab34a0SCy Schubert close(nfd);
11108ab34a0SCy Schubert
11208ab34a0SCy Schubert lfd = open(IPSYNC_NAME, O_WRONLY);
11308ab34a0SCy Schubert if (lfd == -1) {
11408ab34a0SCy Schubert syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME);
11508ab34a0SCy Schubert goto tryagain;
11608ab34a0SCy Schubert }
11708ab34a0SCy Schubert
11808ab34a0SCy Schubert nfd = socket(AF_INET, SOCK_DGRAM, 0);
11908ab34a0SCy Schubert if (nfd == -1) {
12008ab34a0SCy Schubert syslog(LOG_ERR, "Socket :%m");
12108ab34a0SCy Schubert goto tryagain;
12208ab34a0SCy Schubert }
12308ab34a0SCy Schubert
12408ab34a0SCy Schubert n1 = 1;
12508ab34a0SCy Schubert setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &n1, sizeof(n1));
12608ab34a0SCy Schubert
12708ab34a0SCy Schubert if (bind(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
12808ab34a0SCy Schubert syslog(LOG_ERR, "Bind: %m");
12908ab34a0SCy Schubert goto tryagain;
13008ab34a0SCy Schubert }
13108ab34a0SCy Schubert
13208ab34a0SCy Schubert syslog(LOG_INFO, "Listening to %s", inet_ntoa(sin.sin_addr));
13308ab34a0SCy Schubert
13408ab34a0SCy Schubert inbuf = 0;
13508ab34a0SCy Schubert while (1) {
13608ab34a0SCy Schubert
13708ab34a0SCy Schubert
13808ab34a0SCy Schubert /*
13908ab34a0SCy Schubert * XXX currently we do not check the source address
14008ab34a0SCy Schubert * of a datagram, this can be a security risk
14108ab34a0SCy Schubert */
14208ab34a0SCy Schubert n1 = read(nfd, buff+inbuf, BUFFERLEN-inbuf);
14308ab34a0SCy Schubert
14408ab34a0SCy Schubert printf("header : %d bytes read (header = %d bytes)\n",
14508ab34a0SCy Schubert n1, (int) sizeof(*sh));
14608ab34a0SCy Schubert
14708ab34a0SCy Schubert if (n1 < 0) {
14808ab34a0SCy Schubert syslog(LOG_ERR, "Read error (header): %m");
14908ab34a0SCy Schubert goto tryagain;
15008ab34a0SCy Schubert }
15108ab34a0SCy Schubert
15208ab34a0SCy Schubert if (n1 == 0) {
15308ab34a0SCy Schubert /* XXX can this happen??? */
15408ab34a0SCy Schubert syslog(LOG_ERR,
15508ab34a0SCy Schubert "Read error (header) : No data");
15608ab34a0SCy Schubert sleep(1);
15708ab34a0SCy Schubert continue;
15808ab34a0SCy Schubert }
15908ab34a0SCy Schubert
16008ab34a0SCy Schubert inbuf += n1;
16108ab34a0SCy Schubert
16208ab34a0SCy Schubert moreinbuf:
16308ab34a0SCy Schubert if (inbuf < sizeof(*sh)) {
16408ab34a0SCy Schubert continue; /* need more data */
16508ab34a0SCy Schubert }
16608ab34a0SCy Schubert
16708ab34a0SCy Schubert sh = (synchdr_t *)buff;
16808ab34a0SCy Schubert len = ntohl(sh->sm_len);
16908ab34a0SCy Schubert magic = ntohl(sh->sm_magic);
17008ab34a0SCy Schubert
17108ab34a0SCy Schubert if (magic != SYNHDRMAGIC) {
17208ab34a0SCy Schubert syslog(LOG_ERR, "Invalid header magic %x",
17308ab34a0SCy Schubert magic);
17408ab34a0SCy Schubert goto tryagain;
17508ab34a0SCy Schubert }
17608ab34a0SCy Schubert
17708ab34a0SCy Schubert #define IPSYNC_DEBUG
17808ab34a0SCy Schubert #ifdef IPSYNC_DEBUG
17908ab34a0SCy Schubert printf("v:%d p:%d len:%d magic:%x", sh->sm_v,
18008ab34a0SCy Schubert sh->sm_p, len, magic);
18108ab34a0SCy Schubert
18208ab34a0SCy Schubert if (sh->sm_cmd == SMC_CREATE)
18308ab34a0SCy Schubert printf(" cmd:CREATE");
18408ab34a0SCy Schubert else if (sh->sm_cmd == SMC_UPDATE)
18508ab34a0SCy Schubert printf(" cmd:UPDATE");
18608ab34a0SCy Schubert else
18708ab34a0SCy Schubert printf(" cmd:Unknown(%d)", sh->sm_cmd);
18808ab34a0SCy Schubert
18908ab34a0SCy Schubert if (sh->sm_table == SMC_NAT)
19008ab34a0SCy Schubert printf(" table:NAT");
19108ab34a0SCy Schubert else if (sh->sm_table == SMC_STATE)
19208ab34a0SCy Schubert printf(" table:STATE");
19308ab34a0SCy Schubert else
19408ab34a0SCy Schubert printf(" table:Unknown(%d)", sh->sm_table);
19508ab34a0SCy Schubert
19608ab34a0SCy Schubert printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num));
19708ab34a0SCy Schubert #endif
19808ab34a0SCy Schubert
19908ab34a0SCy Schubert if (inbuf < sizeof(*sh) + len) {
20008ab34a0SCy Schubert continue; /* need more data */
20108ab34a0SCy Schubert goto tryagain;
20208ab34a0SCy Schubert }
20308ab34a0SCy Schubert
20408ab34a0SCy Schubert #ifdef IPSYNC_DEBUG
20508ab34a0SCy Schubert if (sh->sm_cmd == SMC_CREATE) {
20608ab34a0SCy Schubert sl = (synclogent_t *)buff;
20708ab34a0SCy Schubert
20808ab34a0SCy Schubert } else if (sh->sm_cmd == SMC_UPDATE) {
20908ab34a0SCy Schubert su = (syncupdent_t *)buff;
21008ab34a0SCy Schubert if (sh->sm_p == IPPROTO_TCP) {
21108ab34a0SCy Schubert printf(" TCP Update: age %lu state %d/%d\n",
21208ab34a0SCy Schubert su->sup_tcp.stu_age,
21308ab34a0SCy Schubert su->sup_tcp.stu_state[0],
21408ab34a0SCy Schubert su->sup_tcp.stu_state[1]);
21508ab34a0SCy Schubert }
21608ab34a0SCy Schubert } else {
21708ab34a0SCy Schubert printf("Unknown command\n");
21808ab34a0SCy Schubert }
21908ab34a0SCy Schubert #endif
22008ab34a0SCy Schubert
22108ab34a0SCy Schubert n2 = sizeof(*sh) + len;
22208ab34a0SCy Schubert n3 = write(lfd, buff, n2);
22308ab34a0SCy Schubert if (n3 <= 0) {
22408ab34a0SCy Schubert syslog(LOG_ERR, "%s: Write error: %m",
22508ab34a0SCy Schubert IPSYNC_NAME);
22608ab34a0SCy Schubert goto tryagain;
22708ab34a0SCy Schubert }
22808ab34a0SCy Schubert
22908ab34a0SCy Schubert
23008ab34a0SCy Schubert if (n3 != n2) {
23108ab34a0SCy Schubert syslog(LOG_ERR, "%s: Incomplete write (%d/%d)",
23208ab34a0SCy Schubert IPSYNC_NAME, n3, n2);
23308ab34a0SCy Schubert goto tryagain;
23408ab34a0SCy Schubert }
23508ab34a0SCy Schubert
23608ab34a0SCy Schubert /* signal received? */
23708ab34a0SCy Schubert if (terminate)
23808ab34a0SCy Schubert break;
23908ab34a0SCy Schubert
24008ab34a0SCy Schubert /* move buffer to the front,we might need to make
24108ab34a0SCy Schubert * this more efficient, by using a rolling pointer
24208ab34a0SCy Schubert * over the buffer and only copying it, when
24308ab34a0SCy Schubert * we are reaching the end
24408ab34a0SCy Schubert */
24508ab34a0SCy Schubert inbuf -= n2;
24608ab34a0SCy Schubert if (inbuf) {
24708ab34a0SCy Schubert bcopy(buff+n2, buff, inbuf);
24808ab34a0SCy Schubert printf("More data in buffer\n");
24908ab34a0SCy Schubert goto moreinbuf;
25008ab34a0SCy Schubert }
25108ab34a0SCy Schubert }
25208ab34a0SCy Schubert
25308ab34a0SCy Schubert if (terminate)
25408ab34a0SCy Schubert break;
25508ab34a0SCy Schubert tryagain:
25608ab34a0SCy Schubert sleep(1);
25708ab34a0SCy Schubert }
25808ab34a0SCy Schubert
25908ab34a0SCy Schubert
26008ab34a0SCy Schubert /* terminate */
26108ab34a0SCy Schubert if (lfd != -1)
26208ab34a0SCy Schubert close(lfd);
26308ab34a0SCy Schubert if (nfd != -1)
26408ab34a0SCy Schubert close(nfd);
26508ab34a0SCy Schubert
26608ab34a0SCy Schubert syslog(LOG_ERR, "signal %d received, exiting...", terminate);
26708ab34a0SCy Schubert
26808ab34a0SCy Schubert exit(1);
26908ab34a0SCy Schubert }
270