]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libalias/alias_ftp.c
Add includes to to silence warnings. Bit hackish.
[FreeBSD/FreeBSD.git] / lib / libalias / alias_ftp.c
1 /*
2     Alias_ftp.c performs special processing for FTP sessions under
3     TCP.  Specifically, when a PORT command from the client side
4     is sent, it is intercepted and modified.  The address is changed
5     to the gateway machine and an aliasing port is used.
6
7     For this routine to work, the PORT command must fit entirely
8     into a single TCP packet.  This is typically the case, but exceptions
9     can easily be envisioned under the actual specifications.
10
11     Probably the most troubling aspect of the approach taken here is
12     that the new PORT command will typically be a different length, and
13     this causes a certain amount of bookkeeping to keep track of the
14     changes of sequence and acknowledgment numbers, since the client
15     machine is totally unaware of the modification to the TCP stream.
16
17
18     This software is placed into the public domain with no restrictions
19     on its distribution.
20
21     Initial version:  August, 1996  (cjm)
22
23     Version 1.6
24          Brian Somers and Martin Renters identified an IP checksum
25          error for modified IP packets.
26
27     Version 1.7:  January 9, 1996 (cjm)
28          Differental checksum computation for change
29          in IP packet length.
30    
31     Version 2.1:  May, 1997 (cjm)
32          Very minor changes to conform with
33          local/global/function naming conventions
34          withing the packet alising module.
35
36     See HISTORY file for record of revisions.
37
38     $FreeBSD$
39 */
40
41 /* Includes */
42 #include <ctype.h>
43 #include <stdio.h> 
44 #include <string.h>
45 #include <sys/types.h>
46 #include <netinet/in_systm.h>
47 #include <netinet/in.h>
48 #include <netinet/ip.h>
49 #include <netinet/tcp.h>
50
51 #include "alias_local.h"
52
53 static void NewFtpPortCommand(struct ip *, struct alias_link *, struct in_addr, u_short, int);
54
55
56
57 void
58 AliasHandleFtpOut(
59 struct ip *pip,   /* IP packet to examine/patch */
60 struct alias_link *link, /* The link to go through (aliased port) */
61 int maxpacketsize  /* The maximum size this packet can grow to (including headers) */)
62 {
63     int hlen, tlen, dlen;
64     struct in_addr true_addr;
65     u_short true_port;
66     char *sptr;
67     struct tcphdr *tc;
68         
69 /* Calculate data length of TCP packet */
70     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
71     hlen = (pip->ip_hl + tc->th_off) << 2;
72     tlen = ntohs(pip->ip_len);
73     dlen = tlen - hlen;
74
75 /* Return is data length is too long or too short */
76     if (dlen<10 || dlen>80)
77         return;
78
79 /* Place string pointer and beginning of data */
80     sptr = (char *) pip;  
81     sptr += hlen;
82
83 /* Parse through string using state diagram method */
84     {
85         char ch, zero;
86         int i, state;
87         u_long a1, a2, a3, a4;
88         u_short p1, p2; 
89
90         a1=0; a2=0; a3=0; a4=0; p1=0; p2=0;
91         zero = '0';
92         state=-4;
93         for (i=0; i<dlen; i++)
94         {
95             ch = sptr[i];
96             switch (state)
97             {
98                 case -4: if (ch == 'P') state=-3; else return; break;
99                 case -3: if (ch == 'O') state=-2; else return; break;
100                 case -2: if (ch == 'R') state=-1; else return; break;
101                 case -1: if (ch == 'T') state= 0; else return; break;
102
103                 case 0 :
104                     if (isdigit(ch)) {a1=ch-zero; state=1 ;} break;
105                 case 1 :
106                     if (isdigit(ch)) a1=10*a1+ch-zero; else state=2 ; break;
107                 case 2 :
108                     if (isdigit(ch)) {a2=ch-zero; state=3 ;} break;
109                 case 3 :
110                     if (isdigit(ch)) a2=10*a2+ch-zero; else state=4 ; break;
111                 case 4 :
112                     if (isdigit(ch)) {a3=ch-zero; state=5 ;} break;
113                 case 5 :
114                     if (isdigit(ch)) a3=10*a3+ch-zero; else state=6 ; break;
115                 case 6 :
116                     if (isdigit(ch)) {a4=ch-zero; state=7 ;} break;
117                 case 7 :
118                     if (isdigit(ch)) a4=10*a4+ch-zero; else state=8 ; break;
119                 case 8 :
120                     if (isdigit(ch)) {p1=ch-zero; state=9 ;} break;
121                 case 9 :
122                     if (isdigit(ch)) p1=10*p1+ch-zero; else state=10; break;
123                 case 10:
124                     if (isdigit(ch)) {p2=ch-zero; state=11;} break;
125                 case 11:
126                     if (isdigit(ch)) p2=10*p2+ch-zero; break;
127             }
128         }
129
130         if (state == 11)
131         {
132             true_port = htons((p1<<8) + p2);
133             true_addr.s_addr = htonl((a1<<24) + (a2<<16) +(a3<<8) + a4);
134             NewFtpPortCommand(pip, link, true_addr, true_port, maxpacketsize);
135         }
136     }
137 }
138
139 static void
140 NewFtpPortCommand(struct ip *pip,
141                   struct alias_link *link,
142                   struct in_addr true_addr,
143                   u_short true_port,
144                   int maxpacketsize)
145
146     struct alias_link *ftp_link;
147
148 /* Establish link to address and port found in PORT command */
149     ftp_link = FindUdpTcpOut(true_addr, GetDestAddress(link),
150                              true_port, 0, IPPROTO_TCP);
151
152     if (ftp_link != NULL)
153     {
154         int slen, hlen, tlen, dlen;
155         struct tcphdr *tc;
156
157 #ifndef NO_FW_PUNCH
158 /* Punch hole in firewall */
159         PunchFWHole(ftp_link);
160 #endif
161
162 /* Calculate data length of TCP packet */
163         tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
164         hlen = (pip->ip_hl + tc->th_off) << 2;
165         tlen = ntohs(pip->ip_len);
166         dlen = tlen - hlen;
167
168 /* Create new PORT command */
169         {
170             char stemp[80];
171             char *sptr;
172             u_short alias_port;
173             u_char *ptr;
174             int a1, a2, a3, a4, p1, p2; 
175             struct in_addr alias_address;
176         
177 /* Decompose alias address into quad format */
178             alias_address = GetAliasAddress(link);
179             ptr = (u_char *) &alias_address.s_addr;
180             a1 = *ptr++; a2=*ptr++; a3=*ptr++; a4=*ptr;
181
182 /* Decompose alias port into pair format */
183             alias_port = GetAliasPort(ftp_link);
184             ptr = (char *) &alias_port;
185             p1 = *ptr++; p2=*ptr;
186
187 /* Generate command string */
188             sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n",
189                      a1,a2,a3,a4,p1,p2);
190
191 /* Save string length for IP header modification */
192             slen = strlen(stemp);
193
194 /* Copy into IP packet */
195             sptr = (char *) pip; sptr += hlen;
196             strncpy(sptr, stemp, maxpacketsize-hlen);
197         }
198
199 /* Save information regarding modified seq and ack numbers */
200         {
201             int delta;
202
203             SetAckModified(link);
204             delta = GetDeltaSeqOut(pip, link);
205             AddSeq(pip, link, delta+slen-dlen);
206         }
207
208 /* Revise IP header */
209         {
210             u_short new_len;
211
212             new_len = htons(hlen + slen);
213             DifferentialChecksum(&pip->ip_sum,
214                                  &new_len,
215                                  &pip->ip_len,
216                                  1);
217             pip->ip_len = new_len;
218         }
219
220 /* Compute TCP checksum for revised packet */
221         tc->th_sum = 0;
222         tc->th_sum = TcpChecksum(pip);
223     }
224     else
225     {
226 #ifdef DEBUG
227         fprintf(stderr,
228         "PacketAlias/HandleFtpOut: Cannot allocate FTP data port\n");
229 #endif
230     }
231 }