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