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