Deleted Added
full compact
alias_ftp.c (124621) alias_ftp.c (127094)
1/*-
2 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_ftp.c 124621 2004-01-17 10:52:21Z phk $");
28__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_ftp.c 127094 2004-03-16 21:30:41Z des $");
29
30/*
31 Alias_ftp.c performs special processing for FTP sessions under
32 TCP. Specifically, when a PORT/EPRT command from the client
33 side or 227/229 reply from the server is sent, it is intercepted
34 and modified. The address is changed to the gateway machine
35 and an aliasing port is used.
36
37 For this routine to work, the message must fit entirely into a
38 single TCP packet. This is typically the case, but exceptions
39 can easily be envisioned under the actual specifications.
40
41 Probably the most troubling aspect of the approach taken here is
42 that the new message will typically be a different length, and
43 this causes a certain amount of bookkeeping to keep track of the
44 changes of sequence and acknowledgment numbers, since the client
45 machine is totally unaware of the modification to the TCP stream.
46
47
48 References: RFC 959, RFC 2428.
49
50 Initial version: August, 1996 (cjm)
51
52 Version 1.6
53 Brian Somers and Martin Renters identified an IP checksum
54 error for modified IP packets.
55
56 Version 1.7: January 9, 1996 (cjm)
57 Differential checksum computation for change
58 in IP packet length.
59
60 Version 2.1: May, 1997 (cjm)
61 Very minor changes to conform with
62 local/global/function naming conventions
63 within the packet aliasing module.
64
65 Version 3.1: May, 2000 (eds)
66 Add support for passive mode, alias the 227 replies.
67
68 See HISTORY file for record of revisions.
69*/
70
71/* Includes */
72#include <ctype.h>
73#include <stdio.h>
74#include <string.h>
75#include <sys/types.h>
76#include <netinet/in_systm.h>
77#include <netinet/in.h>
78#include <netinet/ip.h>
79#include <netinet/tcp.h>
80
81#include "alias_local.h"
82
83#define FTP_CONTROL_PORT_NUMBER 21
84#define MAX_MESSAGE_SIZE 128
85
86/* FTP protocol flags. */
87#define WAIT_CRLF 0x01
88
89enum ftp_message_type {
29
30/*
31 Alias_ftp.c performs special processing for FTP sessions under
32 TCP. Specifically, when a PORT/EPRT command from the client
33 side or 227/229 reply from the server is sent, it is intercepted
34 and modified. The address is changed to the gateway machine
35 and an aliasing port is used.
36
37 For this routine to work, the message must fit entirely into a
38 single TCP packet. This is typically the case, but exceptions
39 can easily be envisioned under the actual specifications.
40
41 Probably the most troubling aspect of the approach taken here is
42 that the new message will typically be a different length, and
43 this causes a certain amount of bookkeeping to keep track of the
44 changes of sequence and acknowledgment numbers, since the client
45 machine is totally unaware of the modification to the TCP stream.
46
47
48 References: RFC 959, RFC 2428.
49
50 Initial version: August, 1996 (cjm)
51
52 Version 1.6
53 Brian Somers and Martin Renters identified an IP checksum
54 error for modified IP packets.
55
56 Version 1.7: January 9, 1996 (cjm)
57 Differential checksum computation for change
58 in IP packet length.
59
60 Version 2.1: May, 1997 (cjm)
61 Very minor changes to conform with
62 local/global/function naming conventions
63 within the packet aliasing module.
64
65 Version 3.1: May, 2000 (eds)
66 Add support for passive mode, alias the 227 replies.
67
68 See HISTORY file for record of revisions.
69*/
70
71/* Includes */
72#include <ctype.h>
73#include <stdio.h>
74#include <string.h>
75#include <sys/types.h>
76#include <netinet/in_systm.h>
77#include <netinet/in.h>
78#include <netinet/ip.h>
79#include <netinet/tcp.h>
80
81#include "alias_local.h"
82
83#define FTP_CONTROL_PORT_NUMBER 21
84#define MAX_MESSAGE_SIZE 128
85
86/* FTP protocol flags. */
87#define WAIT_CRLF 0x01
88
89enum ftp_message_type {
90 FTP_PORT_COMMAND,
91 FTP_EPRT_COMMAND,
92 FTP_227_REPLY,
93 FTP_229_REPLY,
94 FTP_UNKNOWN_MESSAGE
90 FTP_PORT_COMMAND,
91 FTP_EPRT_COMMAND,
92 FTP_227_REPLY,
93 FTP_229_REPLY,
94 FTP_UNKNOWN_MESSAGE
95};
96
95};
96
97static int ParseFtpPortCommand(struct libalias *la, char *, int);
98static int ParseFtpEprtCommand(struct libalias *la, char *, int);
99static int ParseFtp227Reply(struct libalias *la, char *, int);
100static int ParseFtp229Reply(struct libalias *la, char *, int);
101static void NewFtpMessage(struct libalias *la, struct ip *, struct alias_link *, int, int);
97static int ParseFtpPortCommand(struct libalias *la, char *, int);
98static int ParseFtpEprtCommand(struct libalias *la, char *, int);
99static int ParseFtp227Reply(struct libalias *la, char *, int);
100static int ParseFtp229Reply(struct libalias *la, char *, int);
101static void NewFtpMessage(struct libalias *la, struct ip *, struct alias_link *, int, int);
102
103void
104AliasHandleFtpOut(
102
103void
104AliasHandleFtpOut(
105struct libalias *la,
106struct ip *pip, /* IP packet to examine/patch */
107struct alias_link *link, /* The link to go through (aliased port) */
108int maxpacketsize /* The maximum size this packet can grow to (including headers) */)
105 struct libalias *la,
106 struct ip *pip, /* IP packet to examine/patch */
107 struct alias_link *link, /* The link to go through (aliased port) */
108 int maxpacketsize /* The maximum size this packet can grow to
109 (including headers) */ )
109{
110{
110 int hlen, tlen, dlen, pflags;
111 char *sptr;
112 struct tcphdr *tc;
113 int ftp_message_type;
111 int hlen, tlen, dlen, pflags;
112 char *sptr;
113 struct tcphdr *tc;
114 int ftp_message_type;
114
115/* Calculate data length of TCP packet */
115
116/* Calculate data length of TCP packet */
116 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
117 hlen = (pip->ip_hl + tc->th_off) << 2;
118 tlen = ntohs(pip->ip_len);
119 dlen = tlen - hlen;
117 tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
118 hlen = (pip->ip_hl + tc->th_off) << 2;
119 tlen = ntohs(pip->ip_len);
120 dlen = tlen - hlen;
120
121/* Place string pointer and beginning of data */
121
122/* Place string pointer and beginning of data */
122 sptr = (char *) pip;
123 sptr += hlen;
123 sptr = (char *)pip;
124 sptr += hlen;
124
125/*
126 * Check that data length is not too long and previous message was
127 * properly terminated with CRLF.
128 */
125
126/*
127 * Check that data length is not too long and previous message was
128 * properly terminated with CRLF.
129 */
129 pflags = GetProtocolFlags(link);
130 if (dlen <= MAX_MESSAGE_SIZE && !(pflags & WAIT_CRLF)) {
131 ftp_message_type = FTP_UNKNOWN_MESSAGE;
130 pflags = GetProtocolFlags(link);
131 if (dlen <= MAX_MESSAGE_SIZE && !(pflags & WAIT_CRLF)) {
132 ftp_message_type = FTP_UNKNOWN_MESSAGE;
132
133
133 if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER) {
134 if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER) {
134/*
135 * When aliasing a client, check for the PORT/EPRT command.
136 */
135/*
136 * When aliasing a client, check for the PORT/EPRT command.
137 */
137 if (ParseFtpPortCommand(la, sptr, dlen))
138 ftp_message_type = FTP_PORT_COMMAND;
139 else if (ParseFtpEprtCommand(la, sptr, dlen))
140 ftp_message_type = FTP_EPRT_COMMAND;
141 } else {
138 if (ParseFtpPortCommand(la, sptr, dlen))
139 ftp_message_type = FTP_PORT_COMMAND;
140 else if (ParseFtpEprtCommand(la, sptr, dlen))
141 ftp_message_type = FTP_EPRT_COMMAND;
142 } else {
142/*
143 * When aliasing a server, check for the 227/229 reply.
144 */
143/*
144 * When aliasing a server, check for the 227/229 reply.
145 */
145 if (ParseFtp227Reply(la, sptr, dlen))
146 ftp_message_type = FTP_227_REPLY;
147 else if (ParseFtp229Reply(la, sptr, dlen)) {
148 ftp_message_type = FTP_229_REPLY;
149 la->true_addr.s_addr = pip->ip_src.s_addr;
150 }
151 }
146 if (ParseFtp227Reply(la, sptr, dlen))
147 ftp_message_type = FTP_227_REPLY;
148 else if (ParseFtp229Reply(la, sptr, dlen)) {
149 ftp_message_type = FTP_229_REPLY;
150 la->true_addr.s_addr = pip->ip_src.s_addr;
151 }
152 }
152
153
153 if (ftp_message_type != FTP_UNKNOWN_MESSAGE)
154 NewFtpMessage(la, pip, link, maxpacketsize, ftp_message_type);
155 }
156
154 if (ftp_message_type != FTP_UNKNOWN_MESSAGE)
155 NewFtpMessage(la, pip, link, maxpacketsize, ftp_message_type);
156 }
157/* Track the msgs which are CRLF term'd for PORT/PASV FW breach */
158
157/* Track the msgs which are CRLF term'd for PORT/PASV FW breach */
158
159 if (dlen) { /* only if there's data */
160 sptr = (char *) pip; /* start over at beginning */
161 tlen = ntohs(pip->ip_len); /* recalc tlen, pkt may have grown */
162 if (sptr[tlen-2] == '\r' && sptr[tlen-1] == '\n')
163 pflags &= ~WAIT_CRLF;
164 else
165 pflags |= WAIT_CRLF;
166 SetProtocolFlags(link, pflags);
167 }
159 if (dlen) { /* only if there's data */
160 sptr = (char *)pip; /* start over at beginning */
161 tlen = ntohs(pip->ip_len); /* recalc tlen, pkt may
162 * have grown */
163 if (sptr[tlen - 2] == '\r' && sptr[tlen - 1] == '\n')
164 pflags &= ~WAIT_CRLF;
165 else
166 pflags |= WAIT_CRLF;
167 SetProtocolFlags(link, pflags);
168 }
168}
169
170static int
171ParseFtpPortCommand(struct libalias *la, char *sptr, int dlen)
172{
169}
170
171static int
172ParseFtpPortCommand(struct libalias *la, char *sptr, int dlen)
173{
173 char ch;
174 int i, state;
175 u_int32_t addr;
176 u_short port;
177 u_int8_t octet;
174 char ch;
175 int i, state;
176 u_int32_t addr;
177 u_short port;
178 u_int8_t octet;
178
179
179 /* Format: "PORT A,D,D,R,PO,RT". */
180 /* Format: "PORT A,D,D,R,PO,RT". */
180
181
181 /* Return if data length is too short. */
182 if (dlen < 18)
183 return 0;
182 /* Return if data length is too short. */
183 if (dlen < 18)
184 return 0;
184
185
185 addr = port = octet = 0;
186 state = -4;
187 for (i = 0; i < dlen; i++) {
188 ch = sptr[i];
189 switch (state) {
190 case -4: if (ch == 'P') state++; else return 0; break;
191 case -3: if (ch == 'O') state++; else return 0; break;
192 case -2: if (ch == 'R') state++; else return 0; break;
193 case -1: if (ch == 'T') state++; else return 0; break;
186 addr = port = octet = 0;
187 state = -4;
188 for (i = 0; i < dlen; i++) {
189 ch = sptr[i];
190 switch (state) {
191 case -4:
192 if (ch == 'P')
193 state++;
194 else
195 return 0;
196 break;
197 case -3:
198 if (ch == 'O')
199 state++;
200 else
201 return 0;
202 break;
203 case -2:
204 if (ch == 'R')
205 state++;
206 else
207 return 0;
208 break;
209 case -1:
210 if (ch == 'T')
211 state++;
212 else
213 return 0;
214 break;
194
215
195 case 0:
196 if (isspace(ch))
197 break;
198 else
199 state++;
200 case 1: case 3: case 5: case 7: case 9: case 11:
201 if (isdigit(ch)) {
202 octet = ch - '0';
203 state++;
204 } else
205 return 0;
206 break;
207 case 2: case 4: case 6: case 8:
208 if (isdigit(ch))
209 octet = 10 * octet + ch - '0';
210 else if (ch == ',') {
211 addr = (addr << 8) + octet;
212 state++;
213 } else
214 return 0;
215 break;
216 case 10: case 12:
217 if (isdigit(ch))
218 octet = 10 * octet + ch - '0';
219 else if (ch == ',' || state == 12) {
220 port = (port << 8) + octet;
221 state++;
222 } else
223 return 0;
224 break;
216 case 0:
217 if (isspace(ch))
218 break;
219 else
220 state++;
221 case 1:
222 case 3:
223 case 5:
224 case 7:
225 case 9:
226 case 11:
227 if (isdigit(ch)) {
228 octet = ch - '0';
229 state++;
230 } else
231 return 0;
232 break;
233 case 2:
234 case 4:
235 case 6:
236 case 8:
237 if (isdigit(ch))
238 octet = 10 * octet + ch - '0';
239 else if (ch == ',') {
240 addr = (addr << 8) + octet;
241 state++;
242 } else
243 return 0;
244 break;
245 case 10:
246 case 12:
247 if (isdigit(ch))
248 octet = 10 * octet + ch - '0';
249 else if (ch == ',' || state == 12) {
250 port = (port << 8) + octet;
251 state++;
252 } else
253 return 0;
254 break;
255 }
225 }
256 }
226 }
227
257
228 if (state == 13) {
229 la->true_addr.s_addr = htonl(addr);
230 la->true_port = port;
231 return 1;
232 } else
233 return 0;
258 if (state == 13) {
259 la->true_addr.s_addr = htonl(addr);
260 la->true_port = port;
261 return 1;
262 } else
263 return 0;
234}
235
236static int
237ParseFtpEprtCommand(struct libalias *la, char *sptr, int dlen)
238{
264}
265
266static int
267ParseFtpEprtCommand(struct libalias *la, char *sptr, int dlen)
268{
239 char ch, delim;
240 int i, state;
241 u_int32_t addr;
242 u_short port;
243 u_int8_t octet;
269 char ch, delim;
270 int i, state;
271 u_int32_t addr;
272 u_short port;
273 u_int8_t octet;
244
274
245 /* Format: "EPRT |1|A.D.D.R|PORT|". */
275 /* Format: "EPRT |1|A.D.D.R|PORT|". */
246
276
247 /* Return if data length is too short. */
248 if (dlen < 18)
249 return 0;
277 /* Return if data length is too short. */
278 if (dlen < 18)
279 return 0;
250
280
251 addr = port = octet = 0;
252 delim = '|'; /* XXX gcc -Wuninitialized */
253 state = -4;
254 for (i = 0; i < dlen; i++) {
255 ch = sptr[i];
256 switch (state)
257 {
258 case -4: if (ch == 'E') state++; else return 0; break;
259 case -3: if (ch == 'P') state++; else return 0; break;
260 case -2: if (ch == 'R') state++; else return 0; break;
261 case -1: if (ch == 'T') state++; else return 0; break;
281 addr = port = octet = 0;
282 delim = '|'; /* XXX gcc -Wuninitialized */
283 state = -4;
284 for (i = 0; i < dlen; i++) {
285 ch = sptr[i];
286 switch (state) {
287 case -4:
288 if (ch == 'E')
289 state++;
290 else
291 return 0;
292 break;
293 case -3:
294 if (ch == 'P')
295 state++;
296 else
297 return 0;
298 break;
299 case -2:
300 if (ch == 'R')
301 state++;
302 else
303 return 0;
304 break;
305 case -1:
306 if (ch == 'T')
307 state++;
308 else
309 return 0;
310 break;
262
311
263 case 0:
264 if (!isspace(ch)) {
265 delim = ch;
266 state++;
267 }
268 break;
269 case 1:
270 if (ch == '1') /* IPv4 address */
271 state++;
272 else
273 return 0;
274 break;
275 case 2:
276 if (ch == delim)
277 state++;
278 else
279 return 0;
280 break;
281 case 3: case 5: case 7: case 9:
282 if (isdigit(ch)) {
283 octet = ch - '0';
284 state++;
285 } else
286 return 0;
287 break;
288 case 4: case 6: case 8: case 10:
289 if (isdigit(ch))
290 octet = 10 * octet + ch - '0';
291 else if (ch == '.' || state == 10) {
292 addr = (addr << 8) + octet;
293 state++;
294 } else
295 return 0;
296 break;
297 case 11:
298 if (isdigit(ch)) {
299 port = ch - '0';
300 state++;
301 } else
302 return 0;
303 break;
304 case 12:
305 if (isdigit(ch))
306 port = 10 * port + ch - '0';
307 else if (ch == delim)
308 state++;
309 else
310 return 0;
311 break;
312 case 0:
313 if (!isspace(ch)) {
314 delim = ch;
315 state++;
316 }
317 break;
318 case 1:
319 if (ch == '1') /* IPv4 address */
320 state++;
321 else
322 return 0;
323 break;
324 case 2:
325 if (ch == delim)
326 state++;
327 else
328 return 0;
329 break;
330 case 3:
331 case 5:
332 case 7:
333 case 9:
334 if (isdigit(ch)) {
335 octet = ch - '0';
336 state++;
337 } else
338 return 0;
339 break;
340 case 4:
341 case 6:
342 case 8:
343 case 10:
344 if (isdigit(ch))
345 octet = 10 * octet + ch - '0';
346 else if (ch == '.' || state == 10) {
347 addr = (addr << 8) + octet;
348 state++;
349 } else
350 return 0;
351 break;
352 case 11:
353 if (isdigit(ch)) {
354 port = ch - '0';
355 state++;
356 } else
357 return 0;
358 break;
359 case 12:
360 if (isdigit(ch))
361 port = 10 * port + ch - '0';
362 else if (ch == delim)
363 state++;
364 else
365 return 0;
366 break;
367 }
312 }
368 }
313 }
314
369
315 if (state == 13) {
316 la->true_addr.s_addr = htonl(addr);
317 la->true_port = port;
318 return 1;
319 } else
320 return 0;
370 if (state == 13) {
371 la->true_addr.s_addr = htonl(addr);
372 la->true_port = port;
373 return 1;
374 } else
375 return 0;
321}
322
323static int
324ParseFtp227Reply(struct libalias *la, char *sptr, int dlen)
325{
376}
377
378static int
379ParseFtp227Reply(struct libalias *la, char *sptr, int dlen)
380{
326 char ch;
327 int i, state;
328 u_int32_t addr;
329 u_short port;
330 u_int8_t octet;
381 char ch;
382 int i, state;
383 u_int32_t addr;
384 u_short port;
385 u_int8_t octet;
331
386
332 /* Format: "227 Entering Passive Mode (A,D,D,R,PO,RT)" */
387 /* Format: "227 Entering Passive Mode (A,D,D,R,PO,RT)" */
333
388
334 /* Return if data length is too short. */
335 if (dlen < 17)
336 return 0;
389 /* Return if data length is too short. */
390 if (dlen < 17)
391 return 0;
337
392
338 addr = port = octet = 0;
393 addr = port = octet = 0;
339
394
340 state = -3;
341 for (i = 0; i < dlen; i++) {
342 ch = sptr[i];
343 switch (state)
344 {
345 case -3: if (ch == '2') state++; else return 0; break;
346 case -2: if (ch == '2') state++; else return 0; break;
347 case -1: if (ch == '7') state++; else return 0; break;
395 state = -3;
396 for (i = 0; i < dlen; i++) {
397 ch = sptr[i];
398 switch (state) {
399 case -3:
400 if (ch == '2')
401 state++;
402 else
403 return 0;
404 break;
405 case -2:
406 if (ch == '2')
407 state++;
408 else
409 return 0;
410 break;
411 case -1:
412 if (ch == '7')
413 state++;
414 else
415 return 0;
416 break;
348
417
349 case 0:
350 if (ch == '(')
351 state++;
352 break;
353 case 1: case 3: case 5: case 7: case 9: case 11:
354 if (isdigit(ch)) {
355 octet = ch - '0';
356 state++;
357 } else
358 return 0;
359 break;
360 case 2: case 4: case 6: case 8:
361 if (isdigit(ch))
362 octet = 10 * octet + ch - '0';
363 else if (ch == ',') {
364 addr = (addr << 8) + octet;
365 state++;
366 } else
367 return 0;
368 break;
369 case 10: case 12:
370 if (isdigit(ch))
371 octet = 10 * octet + ch - '0';
372 else if (ch == ',' || (state == 12 && ch == ')')) {
373 port = (port << 8) + octet;
374 state++;
375 } else
376 return 0;
377 break;
418 case 0:
419 if (ch == '(')
420 state++;
421 break;
422 case 1:
423 case 3:
424 case 5:
425 case 7:
426 case 9:
427 case 11:
428 if (isdigit(ch)) {
429 octet = ch - '0';
430 state++;
431 } else
432 return 0;
433 break;
434 case 2:
435 case 4:
436 case 6:
437 case 8:
438 if (isdigit(ch))
439 octet = 10 * octet + ch - '0';
440 else if (ch == ',') {
441 addr = (addr << 8) + octet;
442 state++;
443 } else
444 return 0;
445 break;
446 case 10:
447 case 12:
448 if (isdigit(ch))
449 octet = 10 * octet + ch - '0';
450 else if (ch == ',' || (state == 12 && ch == ')')) {
451 port = (port << 8) + octet;
452 state++;
453 } else
454 return 0;
455 break;
456 }
378 }
457 }
379 }
380
458
381 if (state == 13) {
382 la->true_port = port;
383 la->true_addr.s_addr = htonl(addr);
384 return 1;
385 } else
386 return 0;
459 if (state == 13) {
460 la->true_port = port;
461 la->true_addr.s_addr = htonl(addr);
462 return 1;
463 } else
464 return 0;
387}
388
389static int
390ParseFtp229Reply(struct libalias *la, char *sptr, int dlen)
391{
465}
466
467static int
468ParseFtp229Reply(struct libalias *la, char *sptr, int dlen)
469{
392 char ch, delim;
393 int i, state;
394 u_short port;
470 char ch, delim;
471 int i, state;
472 u_short port;
395
473
396 /* Format: "229 Entering Extended Passive Mode (|||PORT|)" */
474 /* Format: "229 Entering Extended Passive Mode (|||PORT|)" */
397
475
398 /* Return if data length is too short. */
399 if (dlen < 11)
400 return 0;
476 /* Return if data length is too short. */
477 if (dlen < 11)
478 return 0;
401
479
402 port = 0;
403 delim = '|'; /* XXX gcc -Wuninitialized */
480 port = 0;
481 delim = '|'; /* XXX gcc -Wuninitialized */
404
482
405 state = -3;
406 for (i = 0; i < dlen; i++) {
407 ch = sptr[i];
408 switch (state)
409 {
410 case -3: if (ch == '2') state++; else return 0; break;
411 case -2: if (ch == '2') state++; else return 0; break;
412 case -1: if (ch == '9') state++; else return 0; break;
483 state = -3;
484 for (i = 0; i < dlen; i++) {
485 ch = sptr[i];
486 switch (state) {
487 case -3:
488 if (ch == '2')
489 state++;
490 else
491 return 0;
492 break;
493 case -2:
494 if (ch == '2')
495 state++;
496 else
497 return 0;
498 break;
499 case -1:
500 if (ch == '9')
501 state++;
502 else
503 return 0;
504 break;
413
505
414 case 0:
415 if (ch == '(')
416 state++;
417 break;
418 case 1:
419 delim = ch;
420 state++;
421 break;
422 case 2: case 3:
423 if (ch == delim)
424 state++;
425 else
426 return 0;
427 break;
428 case 4:
429 if (isdigit(ch)) {
430 port = ch - '0';
431 state++;
432 } else
433 return 0;
434 break;
435 case 5:
436 if (isdigit(ch))
437 port = 10 * port + ch - '0';
438 else if (ch == delim)
439 state++;
440 else
441 return 0;
442 break;
443 case 6:
444 if (ch == ')')
445 state++;
446 else
447 return 0;
448 break;
506 case 0:
507 if (ch == '(')
508 state++;
509 break;
510 case 1:
511 delim = ch;
512 state++;
513 break;
514 case 2:
515 case 3:
516 if (ch == delim)
517 state++;
518 else
519 return 0;
520 break;
521 case 4:
522 if (isdigit(ch)) {
523 port = ch - '0';
524 state++;
525 } else
526 return 0;
527 break;
528 case 5:
529 if (isdigit(ch))
530 port = 10 * port + ch - '0';
531 else if (ch == delim)
532 state++;
533 else
534 return 0;
535 break;
536 case 6:
537 if (ch == ')')
538 state++;
539 else
540 return 0;
541 break;
542 }
449 }
543 }
450 }
451
544
452 if (state == 7) {
453 la->true_port = port;
454 return 1;
455 } else
456 return 0;
545 if (state == 7) {
546 la->true_port = port;
547 return 1;
548 } else
549 return 0;
457}
458
459static void
460NewFtpMessage(struct libalias *la, struct ip *pip,
550}
551
552static void
553NewFtpMessage(struct libalias *la, struct ip *pip,
461 struct alias_link *link,
462 int maxpacketsize,
463 int ftp_message_type)
554 struct alias_link *link,
555 int maxpacketsize,
556 int ftp_message_type)
464{
557{
465 struct alias_link *ftp_link;
558 struct alias_link *ftp_link;
466
467/* Security checks. */
559
560/* Security checks. */
468 if (pip->ip_src.s_addr != la->true_addr.s_addr)
469 return;
561 if (pip->ip_src.s_addr != la->true_addr.s_addr)
562 return;
470
563
471 if (la->true_port < IPPORT_RESERVED)
472 return;
564 if (la->true_port < IPPORT_RESERVED)
565 return;
473
474/* Establish link to address and port found in FTP control message. */
566
567/* Establish link to address and port found in FTP control message. */
475 ftp_link = FindUdpTcpOut(la, la->true_addr, GetDestAddress(link),
476 htons(la->true_port), 0, IPPROTO_TCP, 1);
568 ftp_link = FindUdpTcpOut(la, la->true_addr, GetDestAddress(link),
569 htons(la->true_port), 0, IPPROTO_TCP, 1);
477
570
478 if (ftp_link != NULL)
479 {
480 int slen, hlen, tlen, dlen;
481 struct tcphdr *tc;
571 if (ftp_link != NULL) {
572 int slen, hlen, tlen, dlen;
573 struct tcphdr *tc;
482
483#ifndef NO_FW_PUNCH
574
575#ifndef NO_FW_PUNCH
484 /* Punch hole in firewall */
485 PunchFWHole(ftp_link);
576 /* Punch hole in firewall */
577 PunchFWHole(ftp_link);
486#endif
487
488/* Calculate data length of TCP packet */
578#endif
579
580/* Calculate data length of TCP packet */
489 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
490 hlen = (pip->ip_hl + tc->th_off) << 2;
491 tlen = ntohs(pip->ip_len);
492 dlen = tlen - hlen;
581 tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
582 hlen = (pip->ip_hl + tc->th_off) << 2;
583 tlen = ntohs(pip->ip_len);
584 dlen = tlen - hlen;
493
494/* Create new FTP message. */
585
586/* Create new FTP message. */
495 {
496 char stemp[MAX_MESSAGE_SIZE + 1];
497 char *sptr;
498 u_short alias_port;
499 u_char *ptr;
500 int a1, a2, a3, a4, p1, p2;
501 struct in_addr alias_address;
587 {
588 char stemp[MAX_MESSAGE_SIZE + 1];
589 char *sptr;
590 u_short alias_port;
591 u_char *ptr;
592 int a1, a2, a3, a4, p1, p2;
593 struct in_addr alias_address;
502
503/* Decompose alias address into quad format */
594
595/* Decompose alias address into quad format */
504 alias_address = GetAliasAddress(link);
505 ptr = (u_char *) &alias_address.s_addr;
506 a1 = *ptr++; a2=*ptr++; a3=*ptr++; a4=*ptr;
596 alias_address = GetAliasAddress(link);
597 ptr = (u_char *) & alias_address.s_addr;
598 a1 = *ptr++;
599 a2 = *ptr++;
600 a3 = *ptr++;
601 a4 = *ptr;
507
602
508 alias_port = GetAliasPort(ftp_link);
603 alias_port = GetAliasPort(ftp_link);
509
604
510 switch (ftp_message_type)
511 {
512 case FTP_PORT_COMMAND:
513 case FTP_227_REPLY:
514 /* Decompose alias port into pair format. */
515 ptr = (char *) &alias_port;
516 p1 = *ptr++; p2=*ptr;
605 switch (ftp_message_type) {
606 case FTP_PORT_COMMAND:
607 case FTP_227_REPLY:
608 /* Decompose alias port into pair format. */
609 ptr = (char *)&alias_port;
610 p1 = *ptr++;
611 p2 = *ptr;
517
612
518 if (ftp_message_type == FTP_PORT_COMMAND) {
519 /* Generate PORT command string. */
520 sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n",
521 a1,a2,a3,a4,p1,p2);
522 } else {
523 /* Generate 227 reply string. */
524 sprintf(stemp,
525 "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
526 a1,a2,a3,a4,p1,p2);
527 }
528 break;
529 case FTP_EPRT_COMMAND:
530 /* Generate EPRT command string. */
531 sprintf(stemp, "EPRT |1|%d.%d.%d.%d|%d|\r\n",
532 a1,a2,a3,a4,ntohs(alias_port));
533 break;
534 case FTP_229_REPLY:
535 /* Generate 229 reply string. */
536 sprintf(stemp, "229 Entering Extended Passive Mode (|||%d|)\r\n",
537 ntohs(alias_port));
538 break;
539 }
613 if (ftp_message_type == FTP_PORT_COMMAND) {
614 /* Generate PORT command string. */
615 sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n",
616 a1, a2, a3, a4, p1, p2);
617 } else {
618 /* Generate 227 reply string. */
619 sprintf(stemp,
620 "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
621 a1, a2, a3, a4, p1, p2);
622 }
623 break;
624 case FTP_EPRT_COMMAND:
625 /* Generate EPRT command string. */
626 sprintf(stemp, "EPRT |1|%d.%d.%d.%d|%d|\r\n",
627 a1, a2, a3, a4, ntohs(alias_port));
628 break;
629 case FTP_229_REPLY:
630 /* Generate 229 reply string. */
631 sprintf(stemp, "229 Entering Extended Passive Mode (|||%d|)\r\n",
632 ntohs(alias_port));
633 break;
634 }
540
541/* Save string length for IP header modification */
635
636/* Save string length for IP header modification */
542 slen = strlen(stemp);
637 slen = strlen(stemp);
543
544/* Copy modified buffer into IP packet. */
638
639/* Copy modified buffer into IP packet. */
545 sptr = (char *) pip; sptr += hlen;
546 strncpy(sptr, stemp, maxpacketsize-hlen);
547 }
640 sptr = (char *)pip;
641 sptr += hlen;
642 strncpy(sptr, stemp, maxpacketsize - hlen);
643 }
548
549/* Save information regarding modified seq and ack numbers */
644
645/* Save information regarding modified seq and ack numbers */
550 {
551 int delta;
646 {
647 int delta;
552
648
553 SetAckModified(link);
554 delta = GetDeltaSeqOut(pip, link);
555 AddSeq(pip, link, delta+slen-dlen);
556 }
649 SetAckModified(link);
650 delta = GetDeltaSeqOut(pip, link);
651 AddSeq(pip, link, delta + slen - dlen);
652 }
557
558/* Revise IP header */
653
654/* Revise IP header */
559 {
560 u_short new_len;
655 {
656 u_short new_len;
561
657
562 new_len = htons(hlen + slen);
563 DifferentialChecksum(&pip->ip_sum,
564 &new_len,
565 &pip->ip_len,
566 1);
567 pip->ip_len = new_len;
568 }
658 new_len = htons(hlen + slen);
659 DifferentialChecksum(&pip->ip_sum,
660 &new_len,
661 &pip->ip_len,
662 1);
663 pip->ip_len = new_len;
664 }
569
570/* Compute TCP checksum for revised packet */
665
666/* Compute TCP checksum for revised packet */
571 tc->th_sum = 0;
572 tc->th_sum = TcpChecksum(pip);
573 }
574 else
575 {
667 tc->th_sum = 0;
668 tc->th_sum = TcpChecksum(pip);
669 } else {
576#ifdef DEBUG
670#ifdef DEBUG
577 fprintf(stderr,
578 "PacketAlias/HandleFtpOut: Cannot allocate FTP data port\n");
671 fprintf(stderr,
672 "PacketAlias/HandleFtpOut: Cannot allocate FTP data port\n");
579#endif
673#endif
580 }
674 }
581}
675}