]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/libalias/alias_ftp.c
Fix memory disclosure vulnerability in libalias.
[FreeBSD/FreeBSD.git] / sys / netinet / libalias / alias_ftp.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }