]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/libalias/alias_ftp.c
zfs: merge openzfs/zfs@0ee9b0239
[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 /*
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
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
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
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
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
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
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
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
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
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
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
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
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 }