1193326Sed
2193326Sed/*
3193326Sed * Copyright (C) 2012 by Darren Reed.
4193326Sed *
5193326Sed * See the IPFILTER.LICENCE file for details on licencing.
6193326Sed */
7193326Sed#include <sys/types.h>
8193326Sed#include <sys/time.h>
9193326Sed#include <sys/socket.h>
10193326Sed
11193326Sed#include <netinet/in.h>
12193326Sed#include <net/if.h>
13193326Sed
14193326Sed#include <arpa/inet.h>
15193326Sed
16193326Sed#include <stdio.h>
17226890Sdim#include <stdlib.h>
18252723Sdim#include <fcntl.h>
19218893Sdim#include <unistd.h>
20193326Sed#include <string.h>
21193326Sed#include <syslog.h>
22193326Sed#include <signal.h>
23226890Sdim
24226890Sdim#include "netinet/ip_compat.h"
25226890Sdim#include "netinet/ip_fil.h"
26226890Sdim#include "netinet/ip_nat.h"
27218893Sdim#include "netinet/ip_state.h"
28226890Sdim#include "netinet/ip_sync.h"
29193326Sed
30226890Sdim
31226890Sdimint	main(int, char *[]);
32226890Sdimvoid	usage(const char *);
33226890Sdim
34226890Sdimint	terminate = 0;
35226890Sdim
36226890Sdimvoid usage(const char *progname) {
37226890Sdim	fprintf(stderr, "Usage: %s <destination IP> <destination port>\n", progname);
38226890Sdim}
39226890Sdim
40226890Sdim#if 0
41226890Sdimstatic void handleterm(int sig)
42193326Sed{
43193326Sed	terminate = sig;
44193326Sed}
45193326Sed#endif
46193326Sed
47193326Sed
48193326Sed/* should be large enough to hold header + any datatype */
49193326Sed#define BUFFERLEN 1400
50193326Sed
51210299Sedint main(argc, argv)
52210299Sed	int argc;
53193326Sed	char *argv[];
54193326Sed{
55193326Sed	struct sockaddr_in sin;
56193326Sed	char buff[BUFFERLEN];
57193326Sed	synclogent_t *sl;
58200583Srdivacky	syncupdent_t *su;
59200583Srdivacky	int nfd = -1, lfd = -1, n1, n2, n3, len;
60200583Srdivacky	int inbuf;
61193326Sed	u_32_t magic;
62193326Sed	synchdr_t *sh;
63235633Sdim	char *progname;
64198092Srdivacky
65224145Sdim	progname = strrchr(argv[0], '/');
66224145Sdim	if (progname) {
67224145Sdim		progname++;
68226890Sdim	} else {
69252723Sdim		progname = argv[0];
70252723Sdim	}
71252723Sdim
72252723Sdim
73252723Sdim	if (argc < 2) {
74252723Sdim		usage(progname);
75219077Sdim		exit(1);
76219077Sdim	}
77219077Sdim
78219077Sdim#if 0
79219077Sdim       	signal(SIGHUP, handleterm);
80219077Sdim       	signal(SIGINT, handleterm);
81219077Sdim       	signal(SIGTERM, handleterm);
82219077Sdim#endif
83219077Sdim
84219077Sdim	openlog(progname, LOG_PID, LOG_SECURITY);
85226890Sdim
86226890Sdim	bzero((char *)&sin, sizeof(sin));
87226890Sdim	sin.sin_family = AF_INET;
88226890Sdim	sin.sin_addr.s_addr = inet_addr(argv[1]);
89226890Sdim	if (argc > 2)
90226890Sdim		sin.sin_port = htons(atoi(argv[2]));
91226890Sdim	else
92226890Sdim		sin.sin_port = htons(43434);
93226890Sdim
94226890Sdim	while (1) {
95226890Sdim
96226890Sdim		if (lfd != -1)
97226890Sdim			close(lfd);
98226890Sdim		if (nfd != -1)
99226890Sdim			close(nfd);
100226890Sdim
101226890Sdim		lfd = open(IPSYNC_NAME, O_RDONLY);
102226890Sdim		if (lfd == -1) {
103226890Sdim			syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME);
104226890Sdim			goto tryagain;
105226890Sdim		}
106226890Sdim
107226890Sdim		nfd = socket(AF_INET, SOCK_DGRAM, 0);
108226890Sdim		if (nfd == -1) {
109226890Sdim			syslog(LOG_ERR, "Socket :%m");
110226890Sdim			goto tryagain;
111226890Sdim		}
112226890Sdim
113226890Sdim		if (connect(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
114226890Sdim			syslog(LOG_ERR, "Connect: %m");
115226890Sdim			goto tryagain;
116226890Sdim		}
117226890Sdim
118226890Sdim		syslog(LOG_INFO, "Sending data to %s",
119226890Sdim		       inet_ntoa(sin.sin_addr));
120226890Sdim
121226890Sdim		inbuf = 0;
122226890Sdim		while (1) {
123226890Sdim
124226890Sdim			n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf);
125226890Sdim
126226890Sdim			printf("header : %d bytes read (header = %d bytes)\n",
127226890Sdim			       n1, (int) sizeof(*sh));
128226890Sdim
129226890Sdim			if (n1 < 0) {
130226890Sdim				syslog(LOG_ERR, "Read error (header): %m");
131226890Sdim				goto tryagain;
132226890Sdim			}
133226890Sdim
134226890Sdim			if (n1 == 0) {
135226890Sdim				/* XXX can this happen??? */
136226890Sdim				syslog(LOG_ERR,
137226890Sdim				       "Read error (header) : No data");
138226890Sdim				sleep(1);
139252723Sdim				continue;
140226890Sdim			}
141226890Sdim
142226890Sdim			inbuf += n1;
143226890Sdim
144226890Sdimmoreinbuf:
145226890Sdim			if (inbuf < sizeof(*sh)) {
146226890Sdim				continue; /* need more data */
147226890Sdim			}
148226890Sdim
149226890Sdim			sh = (synchdr_t *)buff;
150226890Sdim			len = ntohl(sh->sm_len);
151226890Sdim			magic = ntohl(sh->sm_magic);
152226890Sdim
153226890Sdim			if (magic != SYNHDRMAGIC) {
154226890Sdim				syslog(LOG_ERR,
155226890Sdim				       "Invalid header magic %x", magic);
156226890Sdim				goto tryagain;
157226890Sdim			}
158226890Sdim
159226890Sdim#define IPSYNC_DEBUG
160226890Sdim#ifdef IPSYNC_DEBUG
161226890Sdim			printf("v:%d p:%d len:%d magic:%x", sh->sm_v,
162226890Sdim			       sh->sm_p, len, magic);
163226890Sdim
164226890Sdim			if (sh->sm_cmd == SMC_CREATE)
165226890Sdim				printf(" cmd:CREATE");
166226890Sdim			else if (sh->sm_cmd == SMC_UPDATE)
167226890Sdim				printf(" cmd:UPDATE");
168226890Sdim			else
169226890Sdim				printf(" cmd:Unknown(%d)", sh->sm_cmd);
170226890Sdim
171226890Sdim			if (sh->sm_table == SMC_NAT)
172226890Sdim				printf(" table:NAT");
173226890Sdim			else if (sh->sm_table == SMC_STATE)
174226890Sdim				printf(" table:STATE");
175226890Sdim			else
176226890Sdim				printf(" table:Unknown(%d)", sh->sm_table);
177226890Sdim
178226890Sdim			printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num));
179226890Sdim#endif
180193326Sed
181198092Srdivacky			if (inbuf < sizeof(*sh) + len) {
182193326Sed				continue; /* need more data */
183193326Sed				goto tryagain;
184226890Sdim			}
185193326Sed
186193326Sed#ifdef IPSYNC_DEBUG
187193326Sed			if (sh->sm_cmd == SMC_CREATE) {
188193326Sed				sl = (synclogent_t *)buff;
189
190			} else if (sh->sm_cmd == SMC_UPDATE) {
191				su = (syncupdent_t *)buff;
192				if (sh->sm_p == IPPROTO_TCP) {
193					printf(" TCP Update: age %lu state %d/%d\n",
194						su->sup_tcp.stu_age,
195						su->sup_tcp.stu_state[0],
196						su->sup_tcp.stu_state[1]);
197				}
198			} else {
199				printf("Unknown command\n");
200			}
201#endif
202
203			n2 = sizeof(*sh) + len;
204			n3 = write(nfd, buff, n2);
205			if (n3 <= 0) {
206				syslog(LOG_ERR, "Write error: %m");
207				goto tryagain;
208			}
209
210
211			if (n3 != n2) {
212				syslog(LOG_ERR, "Incomplete write (%d/%d)",
213				       n3, n2);
214				goto tryagain;
215			}
216
217			/* signal received? */
218			if (terminate)
219				break;
220
221			/* move buffer to the front,we might need to make
222			 * this more efficient, by using a rolling pointer
223			 * over the buffer and only copying it, when
224			 * we are reaching the end
225			 */
226			inbuf -= n2;
227			if (inbuf) {
228				bcopy(buff+n2, buff, inbuf);
229				printf("More data in buffer\n");
230				goto moreinbuf;
231			}
232		}
233
234		if (terminate)
235			break;
236tryagain:
237		sleep(1);
238	}
239
240
241	/* terminate */
242	if (lfd != -1)
243		close(lfd);
244	if (nfd != -1)
245		close(nfd);
246
247	syslog(LOG_ERR, "signal %d received, exiting...", terminate);
248
249	exit(1);
250}
251
252