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
usage(const char * progname)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
main(argc,argv)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