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}
|