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