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