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. |
20 |
21 |
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) |
32 Differential checksum computation for change |
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 |
38 within the packet aliasing module. |
39 40 See HISTORY file for record of revisions. 41 |
42 $FreeBSD: head/sys/netinet/libalias/alias_ftp.c 59075 2000-04-06 15:54:52Z ru $ |
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 |
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); |
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; |
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 |
79/* Return if data length is too long or too short */ |
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++) |
110 { |
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; |
118 |
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 } |
145 |
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} |
156 |
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 } |
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 } |
235} 236 237static void 238NewFtpPortCommand(struct ip *pip, 239 struct alias_link *link, 240 struct in_addr true_addr, 241 u_short true_port, |
242 int maxpacketsize, 243 int is_eprt) |
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) --- 21 unchanged lines hidden (view full) --- 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 { |
288/* Decompose alias port into pair format */ |
289 ptr = (char *) &alias_port; 290 p1 = *ptr++; p2=*ptr; |
291 |
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 } |
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 } --- 34 unchanged lines hidden --- |