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