xref: /freebsd/sbin/ipf/ipfsync/ipsyncs.c (revision d9a42747950146bf03cda7f6e25d219253f8a57a)
1 /*	$FreeBSD$	*/
2 
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if !defined(lint)
9 static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10 static const char rcsid[] = "@(#)$Id$";
11 #endif
12 #include <sys/types.h>
13 #include <sys/time.h>
14 #include <sys/socket.h>
15 
16 #include <netinet/in.h>
17 #include <net/if.h>
18 
19 #include <arpa/inet.h>
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <syslog.h>
27 #include <errno.h>
28 #include <signal.h>
29 
30 #include "netinet/ip_compat.h"
31 #include "netinet/ip_fil.h"
32 #include "netinet/ip_state.h"
33 #include "netinet/ip_nat.h"
34 #include "netinet/ip_sync.h"
35 
36 int	main(int, char *[]);
37 void	usage(const char *progname);
38 
39 int	terminate = 0;
40 
41 void usage(const char *progname) {
42 	fprintf(stderr,
43 		"Usage: %s <destination IP> <destination port> [remote IP]\n",
44 		progname);
45 }
46 
47 #if 0
48 static void handleterm(int sig)
49 {
50 	terminate = sig;
51 }
52 #endif
53 
54 #define BUFFERLEN 1400
55 
56 int main(argc, argv)
57 	int argc;
58 	char *argv[];
59 {
60 	int nfd = -1 , lfd = -1;
61 	int n1, n2, n3, magic, len, inbuf;
62 	struct sockaddr_in sin;
63 	struct sockaddr_in in;
64 	char buff[BUFFERLEN];
65 	synclogent_t *sl;
66 	syncupdent_t *su;
67 	synchdr_t *sh;
68 	char *progname;
69 
70 	progname = strrchr(argv[0], '/');
71 	if (progname) {
72 		progname++;
73 	} else {
74 		progname = argv[0];
75 	}
76 
77 	if (argc < 2) {
78 		usage(progname);
79 		exit(1);
80 	}
81 
82 #if 0
83        	signal(SIGHUP, handleterm);
84        	signal(SIGINT, handleterm);
85        	signal(SIGTERM, handleterm);
86 #endif
87 
88 	openlog(progname, LOG_PID, LOG_SECURITY);
89 
90 	lfd = open(IPSYNC_NAME, O_WRONLY);
91 	if (lfd == -1) {
92 		syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME);
93 		exit(1);
94 	}
95 
96 	bzero((char *)&sin, sizeof(sin));
97 	sin.sin_family = AF_INET;
98 	if (argc > 1)
99 		sin.sin_addr.s_addr = inet_addr(argv[1]);
100 	if (argc > 2)
101 		sin.sin_port = htons(atoi(argv[2]));
102 	else
103 		sin.sin_port = htons(43434);
104 	if (argc > 3)
105 		in.sin_addr.s_addr = inet_addr(argv[3]);
106 	else
107 		in.sin_addr.s_addr = 0;
108 	in.sin_port = 0;
109 
110 	while(1) {
111 
112 		if (lfd != -1)
113 			close(lfd);
114 		if (nfd != -1)
115 			close(nfd);
116 
117 		lfd = open(IPSYNC_NAME, O_WRONLY);
118 		if (lfd == -1) {
119 			syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME);
120 			goto tryagain;
121 		}
122 
123 		nfd = socket(AF_INET, SOCK_DGRAM, 0);
124 		if (nfd == -1) {
125 			syslog(LOG_ERR, "Socket :%m");
126 			goto tryagain;
127 		}
128 
129 	        n1 = 1;
130                 setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &n1, sizeof(n1));
131 
132 		if (bind(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
133 			syslog(LOG_ERR, "Bind: %m");
134 			goto tryagain;
135 		}
136 
137 		syslog(LOG_INFO, "Listening to %s", inet_ntoa(sin.sin_addr));
138 
139 		inbuf = 0;
140 		while (1) {
141 
142 
143 			/*
144 			 * XXX currently we do not check the source address
145 			 * of a datagram, this can be a security risk
146 			 */
147 			n1 = read(nfd, buff+inbuf, BUFFERLEN-inbuf);
148 
149 			printf("header : %d bytes read (header = %d bytes)\n",
150 			       n1, (int) sizeof(*sh));
151 
152 			if (n1 < 0) {
153 				syslog(LOG_ERR, "Read error (header): %m");
154 				goto tryagain;
155 			}
156 
157 			if (n1 == 0) {
158 				/* XXX can this happen??? */
159 				syslog(LOG_ERR,
160 				       "Read error (header) : No data");
161 				sleep(1);
162 				continue;
163 			}
164 
165 			inbuf += n1;
166 
167 moreinbuf:
168 			if (inbuf < sizeof(*sh)) {
169 				continue; /* need more data */
170 			}
171 
172 			sh = (synchdr_t *)buff;
173 			len = ntohl(sh->sm_len);
174 			magic = ntohl(sh->sm_magic);
175 
176 			if (magic != SYNHDRMAGIC) {
177 				syslog(LOG_ERR, "Invalid header magic %x",
178 				       magic);
179 				goto tryagain;
180 			}
181 
182 #define IPSYNC_DEBUG
183 #ifdef IPSYNC_DEBUG
184 			printf("v:%d p:%d len:%d magic:%x", sh->sm_v,
185 			       sh->sm_p, len, magic);
186 
187 			if (sh->sm_cmd == SMC_CREATE)
188 				printf(" cmd:CREATE");
189 			else if (sh->sm_cmd == SMC_UPDATE)
190 				printf(" cmd:UPDATE");
191 			else
192 				printf(" cmd:Unknown(%d)", sh->sm_cmd);
193 
194 			if (sh->sm_table == SMC_NAT)
195 				printf(" table:NAT");
196 			else if (sh->sm_table == SMC_STATE)
197 				printf(" table:STATE");
198 			else
199 				printf(" table:Unknown(%d)", sh->sm_table);
200 
201 			printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num));
202 #endif
203 
204 			if (inbuf < sizeof(*sh) + len) {
205 				continue; /* need more data */
206 				goto tryagain;
207 			}
208 
209 #ifdef IPSYNC_DEBUG
210 			if (sh->sm_cmd == SMC_CREATE) {
211 				sl = (synclogent_t *)buff;
212 
213 			} else if (sh->sm_cmd == SMC_UPDATE) {
214 				su = (syncupdent_t *)buff;
215 				if (sh->sm_p == IPPROTO_TCP) {
216 					printf(" TCP Update: age %lu state %d/%d\n",
217 					       su->sup_tcp.stu_age,
218 					       su->sup_tcp.stu_state[0],
219 					       su->sup_tcp.stu_state[1]);
220 				}
221 			} else {
222 				printf("Unknown command\n");
223 			}
224 #endif
225 
226 			n2 = sizeof(*sh) + len;
227 			n3 = write(lfd, buff, n2);
228 			if (n3 <= 0) {
229 				syslog(LOG_ERR, "%s: Write error: %m",
230 				       IPSYNC_NAME);
231 				goto tryagain;
232 			}
233 
234 
235 			if (n3 != n2) {
236 				syslog(LOG_ERR, "%s: Incomplete write (%d/%d)",
237 				       IPSYNC_NAME, n3, n2);
238 				goto tryagain;
239 			}
240 
241 			/* signal received? */
242 			if (terminate)
243 				break;
244 
245 			/* move buffer to the front,we might need to make
246 			 * this more efficient, by using a rolling pointer
247 			 * over the buffer and only copying it, when
248 			 * we are reaching the end
249 			 */
250 			inbuf -= n2;
251 			if (inbuf) {
252 				bcopy(buff+n2, buff, inbuf);
253 				printf("More data in buffer\n");
254 				goto moreinbuf;
255 			}
256 		}
257 
258 		if (terminate)
259 			break;
260 tryagain:
261 		sleep(1);
262 	}
263 
264 
265 	/* terminate */
266 	if (lfd != -1)
267 		close(lfd);
268 	if (nfd != -1)
269 		close(nfd);
270 
271 	syslog(LOG_ERR, "signal %d received, exiting...", terminate);
272 
273 	exit(1);
274 }
275