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
| 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 This version also supports the EPRT command, which is functionally 18 equivalent to the PORT command, but was designed to support both 19 IPv4 and IPv6 addresses. See RFC 2428 for specifications.
|
17
| 20
|
| 21
|
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)
| 22 This software is placed into the public domain with no restrictions 23 on its distribution. 24 25 Initial version: August, 1996 (cjm) 26 27 Version 1.6 28 Brian Somers and Martin Renters identified an IP checksum 29 error for modified IP packets. 30 31 Version 1.7: January 9, 1996 (cjm)
|
28 Differental checksum computation for change
| 32 Differential 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
| 33 in IP packet length. 34 35 Version 2.1: May, 1997 (cjm) 36 Very minor changes to conform with 37 local/global/function naming conventions
|
34 withing the packet alising module.
| 38 within the packet aliasing module.
|
35 36 See HISTORY file for record of revisions. 37
| 39 40 See HISTORY file for record of revisions. 41
|
38 $FreeBSD: head/sys/netinet/libalias/alias_ftp.c 50597 1999-08-29 23:17:04Z billf $
| 42 $FreeBSD: head/sys/netinet/libalias/alias_ftp.c 59075 2000-04-06 15:54:52Z ru $
|
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
| 43*/ 44 45/* Includes */ 46#include <ctype.h> 47#include <stdio.h> 48#include <string.h> 49#include <sys/types.h> 50#include <netinet/in_systm.h> 51#include <netinet/in.h> 52#include <netinet/ip.h> 53#include <netinet/tcp.h> 54 55#include "alias_local.h" 56
|
53static void NewFtpPortCommand(struct ip *, struct alias_link *, struct in_addr, u_short, int);
| 57static int ParseFtpPortCommand(char *, int, struct ip *, struct alias_link *, int); 58static void ParseFtpEprtCommand(char *, int, struct ip *, struct alias_link *, int); 59static void NewFtpPortCommand(struct ip *, struct alias_link *, struct in_addr, u_short, int, int);
|
54 55 56 57void 58AliasHandleFtpOut( 59struct ip *pip, /* IP packet to examine/patch */ 60struct alias_link *link, /* The link to go through (aliased port) */ 61int maxpacketsize /* The maximum size this packet can grow to (including headers) */) 62{ 63 int hlen, tlen, dlen;
| 60 61 62 63void 64AliasHandleFtpOut( 65struct ip *pip, /* IP packet to examine/patch */ 66struct alias_link *link, /* The link to go through (aliased port) */ 67int maxpacketsize /* The maximum size this packet can grow to (including headers) */) 68{ 69 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
| 70 char *sptr; 71 struct tcphdr *tc; 72 73/* Calculate data length of TCP packet */ 74 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 75 hlen = (pip->ip_hl + tc->th_off) << 2; 76 tlen = ntohs(pip->ip_len); 77 dlen = tlen - hlen; 78
|
75/* Return is data length is too long or too short */
| 79/* Return if 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 */
| 80 if (dlen<10 || dlen>80) 81 return; 82 83/* Place string pointer and beginning of data */ 84 sptr = (char *) pip; 85 sptr += hlen; 86 87/* Parse through string using state diagram method */
|
| 88 if (!ParseFtpPortCommand(sptr, dlen, pip, link, maxpacketsize)) 89 ParseFtpEprtCommand(sptr, dlen, pip, link, maxpacketsize); 90} 91 92static int 93ParseFtpPortCommand( 94char *sptr, 95int dlen, 96struct ip *pip, /* IP packet to examine/patch */ 97struct alias_link *link, /* The link to go through (aliased port) */ 98int maxpacketsize /* The maximum size this packet can grow to (including headers) */) 99{ 100 struct in_addr true_addr; 101 u_short true_port; 102 char ch; 103 int i, state; 104 u_long a1, a2, a3, a4; 105 u_short p1, p2; 106 107 a1=0; a2=0; a3=0; a4=0; p1=0; p2=0; 108 state=-4; 109 for (i=0; i<dlen; i++)
|
84 {
| 110 {
|
85 char ch, zero; 86 int i, state; 87 u_long a1, a2, a3, a4; 88 u_short p1, p2;
| 111 ch = sptr[i]; 112 switch (state) 113 { 114 case -4: if (ch == 'P') state++; else return 0; break; 115 case -3: if (ch == 'O') state++; else return 0; break; 116 case -2: if (ch == 'R') state++; else return 0; break; 117 case -1: if (ch == 'T') state++; else return 0; break;
|
89
| 118
|
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;
| 119 case 0 : 120 if (isdigit(ch)) {a1=ch-'0'; state++;} break; 121 case 1 : 122 if (isdigit(ch)) a1=10*a1+ch-'0'; else state++; break; 123 case 2 : 124 if (isdigit(ch)) {a2=ch-'0'; state++;} break; 125 case 3 : 126 if (isdigit(ch)) a2=10*a2+ch-'0'; else state++; break; 127 case 4 : 128 if (isdigit(ch)) {a3=ch-'0'; state++;} break; 129 case 5 : 130 if (isdigit(ch)) a3=10*a3+ch-'0'; else state++; break; 131 case 6 : 132 if (isdigit(ch)) {a4=ch-'0'; state++;} break; 133 case 7 : 134 if (isdigit(ch)) a4=10*a4+ch-'0'; else state++; break; 135 case 8 : 136 if (isdigit(ch)) {p1=ch-'0'; state++;} break; 137 case 9 : 138 if (isdigit(ch)) p1=10*p1+ch-'0'; else state++; break; 139 case 10: 140 if (isdigit(ch)) {p2=ch-'0'; state++;} break; 141 case 11: 142 if (isdigit(ch)) p2=10*p2+ch-'0'; break; 143 } 144 }
|
102
| 145
|
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 }
| 146 if (state == 11) 147 { 148 true_port = htons((p1<<8) + p2); 149 true_addr.s_addr = htonl((a1<<24) + (a2<<16) +(a3<<8) + a4); 150 NewFtpPortCommand(pip, link, true_addr, true_port, maxpacketsize, 0); 151 return 1; 152 } 153 else 154 return 0; 155}
|
129
| 156
|
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 }
| 157static void 158ParseFtpEprtCommand( 159char *sptr, 160int dlen, 161struct ip *pip, /* IP packet to examine/patch */ 162struct alias_link *link, /* The link to go through (aliased port) */ 163int maxpacketsize /* The maximum size this packet can grow to (including headers) */) 164{ 165 struct in_addr true_addr; 166 u_short true_port; 167 char ch, delim; 168 int i, state; 169 u_long a1, a2, a3, a4; 170 u_short pt; 171 172 a1=0; a2=0; a3=0; a4=0; pt=0; 173 delim='|'; /* XXX gcc -Wuninitialized */ 174 state=-4; 175 for (i=0; i<dlen; i++) 176 { 177 ch = sptr[i]; 178 switch (state) 179 { 180 case -4: if (ch == 'E') state++; else return; break; 181 case -3: if (ch == 'P') state++; else return; break; 182 case -2: if (ch == 'R') state++; else return; break; 183 case -1: if (ch == 'T') state++; else return; break; 184 185 case 0 : 186 if (!isspace(ch)) {delim=ch; state++;} break; 187 case 1 : 188 if (ch=='1') /* IPv4 address */ state++; else return; break; 189 case 2 : 190 if (ch==delim) state++; else return; break; 191 case 3 : 192 if (isdigit(ch)) {a1=ch-'0'; state++;} else return; break; 193 case 4 : 194 if (isdigit(ch)) a1=10*a1+ch-'0'; 195 else if (ch=='.') state++; 196 else return; 197 break; 198 case 5 : 199 if (isdigit(ch)) {a2=ch-'0'; state++;} else return; break; 200 case 6 : 201 if (isdigit(ch)) a2=10*a2+ch-'0'; 202 else if (ch=='.') state++; 203 else return; 204 break; 205 case 7: 206 if (isdigit(ch)) {a3=ch-'0'; state++;} else return; break; 207 case 8 : 208 if (isdigit(ch)) a3=10*a3+ch-'0'; 209 else if (ch=='.') state++; 210 else return; 211 break; 212 case 9 : 213 if (isdigit(ch)) {a4=ch-'0'; state++;} else return; break; 214 case 10: 215 if (isdigit(ch)) a4=10*a4+ch-'0'; 216 else if (ch==delim) state++; 217 else return; 218 break; 219 case 11: 220 if (isdigit(ch)) {pt=ch-'0'; state++;} else return; break; 221 case 12: 222 if (isdigit(ch)) pt=10*pt+ch-'0'; 223 else if (ch==delim) state++; 224 else return; 225 break; 226 }
|
136 }
| 227 }
|
| 228 229 if (state == 13) 230 { 231 true_port = htons(pt); 232 true_addr.s_addr = htonl((a1<<24) + (a2<<16) +(a3<<8) + a4); 233 NewFtpPortCommand(pip, link, true_addr, true_port, maxpacketsize, 1); 234 }
|
137} 138 139static void 140NewFtpPortCommand(struct ip *pip, 141 struct alias_link *link, 142 struct in_addr true_addr, 143 u_short true_port,
| 235} 236 237static void 238NewFtpPortCommand(struct ip *pip, 239 struct alias_link *link, 240 struct in_addr true_addr, 241 u_short true_port,
|
144 int maxpacketsize)
| 242 int maxpacketsize, 243 int is_eprt)
|
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
| 244{ 245 struct alias_link *ftp_link; 246 247/* Establish link to address and port found in PORT command */ 248 ftp_link = FindUdpTcpOut(true_addr, GetDestAddress(link), 249 true_port, 0, IPPROTO_TCP); 250 251 if (ftp_link != NULL) 252 { 253 int slen, hlen, tlen, dlen; 254 struct tcphdr *tc; 255 256#ifndef NO_FW_PUNCH 257/* Punch hole in firewall */ 258 PunchFWHole(ftp_link); 259#endif 260 261/* Calculate data length of TCP packet */ 262 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 263 hlen = (pip->ip_hl + tc->th_off) << 2; 264 tlen = ntohs(pip->ip_len); 265 dlen = tlen - hlen; 266 267/* Create new PORT command */ 268 { 269 char stemp[80]; 270 char *sptr; 271 u_short alias_port; 272 u_char *ptr; 273 int a1, a2, a3, a4, p1, p2; 274 struct in_addr alias_address; 275 276/* Decompose alias address into quad format */ 277 alias_address = GetAliasAddress(link); 278 ptr = (u_char *) &alias_address.s_addr; 279 a1 = *ptr++; a2=*ptr++; a3=*ptr++; a4=*ptr; 280
|
| 281 alias_port = GetAliasPort(ftp_link); 282 283 if (is_eprt) { 284/* Generate EPRT command string */ 285 sprintf(stemp, "EPRT |1|%d.%d.%d.%d|%d|\r\n", 286 a1,a2,a3,a4,ntohs(alias_port)); 287 } else {
|
182/* Decompose alias port into pair format */
| 288/* Decompose alias port into pair format */
|
183 alias_port = GetAliasPort(ftp_link); 184 ptr = (char *) &alias_port; 185 p1 = *ptr++; p2=*ptr;
| 289 ptr = (char *) &alias_port; 290 p1 = *ptr++; p2=*ptr;
|
186
| 291
|
187/* Generate command string */ 188 sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n", 189 a1,a2,a3,a4,p1,p2);
| 292/* Generate PORT command string */ 293 sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n", 294 a1,a2,a3,a4,p1,p2); 295 }
|
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}
| 296 297/* Save string length for IP header modification */ 298 slen = strlen(stemp); 299 300/* Copy into IP packet */ 301 sptr = (char *) pip; sptr += hlen; 302 strncpy(sptr, stemp, maxpacketsize-hlen); 303 } 304 305/* Save information regarding modified seq and ack numbers */ 306 { 307 int delta; 308 309 SetAckModified(link); 310 delta = GetDeltaSeqOut(pip, link); 311 AddSeq(pip, link, delta+slen-dlen); 312 } 313 314/* Revise IP header */ 315 { 316 u_short new_len; 317 318 new_len = htons(hlen + slen); 319 DifferentialChecksum(&pip->ip_sum, 320 &new_len, 321 &pip->ip_len, 322 1); 323 pip->ip_len = new_len; 324 } 325 326/* Compute TCP checksum for revised packet */ 327 tc->th_sum = 0; 328 tc->th_sum = TcpChecksum(pip); 329 } 330 else 331 { 332#ifdef DEBUG 333 fprintf(stderr, 334 "PacketAlias/HandleFtpOut: Cannot allocate FTP data port\n"); 335#endif 336 } 337}
|