1/* 2 * Simple FTP transparent proxy for in-kernel use. For use with the NAT 3 * code. 4 *
| 1/* 2 * Simple FTP transparent proxy for in-kernel use. For use with the NAT 3 * code. 4 *
|
5 * $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c 80482 2001-07-28 11:58:26Z darrenr $
| 5 * $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c 92685 2002-03-19 11:44:16Z darrenr $
|
6 */ 7#if SOLARIS && defined(_KERNEL) 8extern kmutex_t ipf_rw; 9#endif 10 11#define isdigit(x) ((x) >= '0' && (x) <= '9') 12#define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z')) 13#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z')) 14#define isalpha(x) (isupper(x) || islower(x)) 15#define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A') 16 17#define IPF_FTP_PROXY 18 19#define IPF_MINPORTLEN 18 20#define IPF_MAXPORTLEN 30 21#define IPF_MIN227LEN 39 22#define IPF_MAX227LEN 51 23#define IPF_FTPBUFSZ 96 /* This *MUST* be >= 53! */ 24 25#define FTPXY_GO 0 26#define FTPXY_INIT 1 27#define FTPXY_USER_1 2 28#define FTPXY_USOK_1 3 29#define FTPXY_PASS_1 4 30#define FTPXY_PAOK_1 5 31#define FTPXY_AUTH_1 6 32#define FTPXY_AUOK_1 7 33#define FTPXY_ADAT_1 8 34#define FTPXY_ADOK_1 9 35#define FTPXY_ACCT_1 10 36#define FTPXY_ACOK_1 11 37#define FTPXY_USER_2 12 38#define FTPXY_USOK_2 13 39#define FTPXY_PASS_2 14 40#define FTPXY_PAOK_2 15 41 42int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 43int ippr_ftp_complete __P((char *, size_t)); 44int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 45int ippr_ftp_init __P((void)); 46int ippr_ftp_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 47int ippr_ftp_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 48int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); 49int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); 50int ippr_ftp_process __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 51int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
| 6 */ 7#if SOLARIS && defined(_KERNEL) 8extern kmutex_t ipf_rw; 9#endif 10 11#define isdigit(x) ((x) >= '0' && (x) <= '9') 12#define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z')) 13#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z')) 14#define isalpha(x) (isupper(x) || islower(x)) 15#define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A') 16 17#define IPF_FTP_PROXY 18 19#define IPF_MINPORTLEN 18 20#define IPF_MAXPORTLEN 30 21#define IPF_MIN227LEN 39 22#define IPF_MAX227LEN 51 23#define IPF_FTPBUFSZ 96 /* This *MUST* be >= 53! */ 24 25#define FTPXY_GO 0 26#define FTPXY_INIT 1 27#define FTPXY_USER_1 2 28#define FTPXY_USOK_1 3 29#define FTPXY_PASS_1 4 30#define FTPXY_PAOK_1 5 31#define FTPXY_AUTH_1 6 32#define FTPXY_AUOK_1 7 33#define FTPXY_ADAT_1 8 34#define FTPXY_ADOK_1 9 35#define FTPXY_ACCT_1 10 36#define FTPXY_ACOK_1 11 37#define FTPXY_USER_2 12 38#define FTPXY_USOK_2 13 39#define FTPXY_PASS_2 14 40#define FTPXY_PAOK_2 15 41 42int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 43int ippr_ftp_complete __P((char *, size_t)); 44int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 45int ippr_ftp_init __P((void)); 46int ippr_ftp_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 47int ippr_ftp_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 48int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); 49int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); 50int ippr_ftp_process __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 51int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
|
52int ippr_ftp_valid __P((char *, size_t));
| 52int ippr_ftp_valid __P((int, char *, size_t)); 53int ippr_ftp_server_valid __P((char *, size_t)); 54int ippr_ftp_client_valid __P((char *, size_t));
|
53u_short ippr_ftp_atoi __P((char **)); 54
| 55u_short ippr_ftp_atoi __P((char **)); 56
|
55static frentry_t natfr;
| 57static frentry_t ftppxyfr;
|
56int ippr_ftp_pasvonly = 0; 57int ippr_ftp_insecure = 0; 58 59 60/* 61 * Initialize local structures. 62 */ 63int ippr_ftp_init() 64{
| 58int ippr_ftp_pasvonly = 0; 59int ippr_ftp_insecure = 0; 60 61 62/* 63 * Initialize local structures. 64 */ 65int ippr_ftp_init() 66{
|
65 bzero((char *)&natfr, sizeof(natfr)); 66 natfr.fr_ref = 1; 67 natfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
| 67 bzero((char *)&ftppxyfr, sizeof(ftppxyfr)); 68 ftppxyfr.fr_ref = 1; 69 ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
|
68 return 0; 69} 70 71 72int ippr_ftp_new(fin, ip, aps, nat) 73fr_info_t *fin; 74ip_t *ip; 75ap_session_t *aps; 76nat_t *nat; 77{ 78 ftpinfo_t *ftp; 79 ftpside_t *f; 80 81 KMALLOC(ftp, ftpinfo_t *); 82 if (ftp == NULL) 83 return -1; 84 aps->aps_data = ftp; 85 aps->aps_psiz = sizeof(ftpinfo_t); 86 87 bzero((char *)ftp, sizeof(*ftp)); 88 f = &ftp->ftp_side[0]; 89 f->ftps_rptr = f->ftps_buf; 90 f->ftps_wptr = f->ftps_buf; 91 f = &ftp->ftp_side[1]; 92 f->ftps_rptr = f->ftps_buf; 93 f->ftps_wptr = f->ftps_buf; 94 ftp->ftp_passok = FTPXY_INIT; 95 return 0; 96} 97 98 99int ippr_ftp_port(fin, ip, nat, f, dlen) 100fr_info_t *fin; 101ip_t *ip; 102nat_t *nat; 103ftpside_t *f; 104int dlen; 105{ 106 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 107 char newbuf[IPF_FTPBUFSZ], *s;
| 70 return 0; 71} 72 73 74int ippr_ftp_new(fin, ip, aps, nat) 75fr_info_t *fin; 76ip_t *ip; 77ap_session_t *aps; 78nat_t *nat; 79{ 80 ftpinfo_t *ftp; 81 ftpside_t *f; 82 83 KMALLOC(ftp, ftpinfo_t *); 84 if (ftp == NULL) 85 return -1; 86 aps->aps_data = ftp; 87 aps->aps_psiz = sizeof(ftpinfo_t); 88 89 bzero((char *)ftp, sizeof(*ftp)); 90 f = &ftp->ftp_side[0]; 91 f->ftps_rptr = f->ftps_buf; 92 f->ftps_wptr = f->ftps_buf; 93 f = &ftp->ftp_side[1]; 94 f->ftps_rptr = f->ftps_buf; 95 f->ftps_wptr = f->ftps_buf; 96 ftp->ftp_passok = FTPXY_INIT; 97 return 0; 98} 99 100 101int ippr_ftp_port(fin, ip, nat, f, dlen) 102fr_info_t *fin; 103ip_t *ip; 104nat_t *nat; 105ftpside_t *f; 106int dlen; 107{ 108 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 109 char newbuf[IPF_FTPBUFSZ], *s;
|
108 u_short a5, a6, sp, dp;
| |
109 u_int a1, a2, a3, a4; 110 struct in_addr swip;
| 110 u_int a1, a2, a3, a4; 111 struct in_addr swip;
|
| 112 u_short a5, a6, sp;
|
111 size_t nlen, olen; 112 fr_info_t fi; 113 int inc, off; 114 nat_t *ipn; 115 mb_t *m; 116#if SOLARIS 117 mb_t *m1; 118#endif 119 120 tcp = (tcphdr_t *)fin->fin_dp; 121 /* 122 * Check for client sending out PORT message. 123 */ 124 if (dlen < IPF_MINPORTLEN) 125 return 0; 126 off = fin->fin_hlen + (tcp->th_off << 2); 127 /* 128 * Skip the PORT command + space 129 */ 130 s = f->ftps_rptr + 5; 131 /* 132 * Pick out the address components, two at a time. 133 */ 134 a1 = ippr_ftp_atoi(&s); 135 if (!s) 136 return 0; 137 a2 = ippr_ftp_atoi(&s); 138 if (!s) 139 return 0; 140 /* 141 * check that IP address in the PORT/PASV reply is the same as the 142 * sender of the command - prevents using PORT for port scanning. 143 */ 144 a1 <<= 16; 145 a1 |= a2; 146 if (a1 != ntohl(nat->nat_inip.s_addr)) 147 return 0; 148 149 a5 = ippr_ftp_atoi(&s); 150 if (!s) 151 return 0; 152 if (*s == ')') 153 s++; 154 155 /* 156 * check for CR-LF at the end. 157 */ 158 if (*s == '\n') 159 s--; 160 if ((*s == '\r') && (*(s + 1) == '\n')) { 161 s += 2; 162 a6 = a5 & 0xff; 163 } else 164 return 0; 165 a5 >>= 8; 166 a5 &= 0xff; 167 /* 168 * Calculate new address parts for PORT command 169 */ 170 a1 = ntohl(ip->ip_src.s_addr); 171 a2 = (a1 >> 16) & 0xff; 172 a3 = (a1 >> 8) & 0xff; 173 a4 = a1 & 0xff; 174 a1 >>= 24; 175 olen = s - f->ftps_rptr;
| 113 size_t nlen, olen; 114 fr_info_t fi; 115 int inc, off; 116 nat_t *ipn; 117 mb_t *m; 118#if SOLARIS 119 mb_t *m1; 120#endif 121 122 tcp = (tcphdr_t *)fin->fin_dp; 123 /* 124 * Check for client sending out PORT message. 125 */ 126 if (dlen < IPF_MINPORTLEN) 127 return 0; 128 off = fin->fin_hlen + (tcp->th_off << 2); 129 /* 130 * Skip the PORT command + space 131 */ 132 s = f->ftps_rptr + 5; 133 /* 134 * Pick out the address components, two at a time. 135 */ 136 a1 = ippr_ftp_atoi(&s); 137 if (!s) 138 return 0; 139 a2 = ippr_ftp_atoi(&s); 140 if (!s) 141 return 0; 142 /* 143 * check that IP address in the PORT/PASV reply is the same as the 144 * sender of the command - prevents using PORT for port scanning. 145 */ 146 a1 <<= 16; 147 a1 |= a2; 148 if (a1 != ntohl(nat->nat_inip.s_addr)) 149 return 0; 150 151 a5 = ippr_ftp_atoi(&s); 152 if (!s) 153 return 0; 154 if (*s == ')') 155 s++; 156 157 /* 158 * check for CR-LF at the end. 159 */ 160 if (*s == '\n') 161 s--; 162 if ((*s == '\r') && (*(s + 1) == '\n')) { 163 s += 2; 164 a6 = a5 & 0xff; 165 } else 166 return 0; 167 a5 >>= 8; 168 a5 &= 0xff; 169 /* 170 * Calculate new address parts for PORT command 171 */ 172 a1 = ntohl(ip->ip_src.s_addr); 173 a2 = (a1 >> 16) & 0xff; 174 a3 = (a1 >> 8) & 0xff; 175 a4 = a1 & 0xff; 176 a1 >>= 24; 177 olen = s - f->ftps_rptr;
|
176 /* DO NOT change this to sprintf! */
| 178 /* DO NOT change this to snprintf! */
|
177 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", 178 "PORT", a1, a2, a3, a4, a5, a6); 179 180 nlen = strlen(newbuf); 181 inc = nlen - olen; 182 if ((inc + ip->ip_len) > 65535) 183 return 0; 184 185#if SOLARIS 186 m = fin->fin_qfm; 187 for (m1 = m; m1->b_cont; m1 = m1->b_cont) 188 ; 189 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { 190 mblk_t *nm; 191 192 /* alloc enough to keep same trailer space for lower driver */ 193 nm = allocb(nlen, BPRI_MED); 194 PANIC((!nm),("ippr_ftp_out: allocb failed")); 195 196 nm->b_band = m1->b_band; 197 nm->b_wptr += nlen; 198 199 m1->b_wptr -= olen; 200 PANIC((m1->b_wptr < m1->b_rptr), 201 ("ippr_ftp_out: cannot handle fragmented data block")); 202 203 linkb(m1, nm); 204 } else { 205 if (m1->b_datap->db_struiolim == m1->b_wptr) 206 m1->b_datap->db_struiolim += inc; 207 m1->b_datap->db_struioflag &= ~STRUIO_IP; 208 m1->b_wptr += inc; 209 } 210 copyin_mblk(m, off, nlen, newbuf); 211#else 212 m = *((mb_t **)fin->fin_mp); 213 if (inc < 0) 214 m_adj(m, inc); 215 /* the mbuf chain will be extended if necessary by m_copyback() */ 216 m_copyback(m, off, nlen, newbuf); 217# ifdef M_PKTHDR 218 if (!(m->m_flags & M_PKTHDR)) 219 m->m_pkthdr.len += inc; 220# endif 221#endif 222 if (inc != 0) { 223#if SOLARIS || defined(__sgi) 224 register u_32_t sum1, sum2; 225 226 sum1 = ip->ip_len; 227 sum2 = ip->ip_len + inc; 228 229 /* Because ~1 == -2, We really need ~1 == -1 */ 230 if (sum1 > sum2) 231 sum2--; 232 sum2 -= sum1; 233 sum2 = (sum2 & 0xffff) + (sum2 >> 16); 234 235 fix_outcksum(fin, &ip->ip_sum, sum2); 236#endif 237 ip->ip_len += inc; 238 } 239 240 /* 241 * Add skeleton NAT entry for connection which will come back the 242 * other way. 243 */
| 179 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", 180 "PORT", a1, a2, a3, a4, a5, a6); 181 182 nlen = strlen(newbuf); 183 inc = nlen - olen; 184 if ((inc + ip->ip_len) > 65535) 185 return 0; 186 187#if SOLARIS 188 m = fin->fin_qfm; 189 for (m1 = m; m1->b_cont; m1 = m1->b_cont) 190 ; 191 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { 192 mblk_t *nm; 193 194 /* alloc enough to keep same trailer space for lower driver */ 195 nm = allocb(nlen, BPRI_MED); 196 PANIC((!nm),("ippr_ftp_out: allocb failed")); 197 198 nm->b_band = m1->b_band; 199 nm->b_wptr += nlen; 200 201 m1->b_wptr -= olen; 202 PANIC((m1->b_wptr < m1->b_rptr), 203 ("ippr_ftp_out: cannot handle fragmented data block")); 204 205 linkb(m1, nm); 206 } else { 207 if (m1->b_datap->db_struiolim == m1->b_wptr) 208 m1->b_datap->db_struiolim += inc; 209 m1->b_datap->db_struioflag &= ~STRUIO_IP; 210 m1->b_wptr += inc; 211 } 212 copyin_mblk(m, off, nlen, newbuf); 213#else 214 m = *((mb_t **)fin->fin_mp); 215 if (inc < 0) 216 m_adj(m, inc); 217 /* the mbuf chain will be extended if necessary by m_copyback() */ 218 m_copyback(m, off, nlen, newbuf); 219# ifdef M_PKTHDR 220 if (!(m->m_flags & M_PKTHDR)) 221 m->m_pkthdr.len += inc; 222# endif 223#endif 224 if (inc != 0) { 225#if SOLARIS || defined(__sgi) 226 register u_32_t sum1, sum2; 227 228 sum1 = ip->ip_len; 229 sum2 = ip->ip_len + inc; 230 231 /* Because ~1 == -2, We really need ~1 == -1 */ 232 if (sum1 > sum2) 233 sum2--; 234 sum2 -= sum1; 235 sum2 = (sum2 & 0xffff) + (sum2 >> 16); 236 237 fix_outcksum(fin, &ip->ip_sum, sum2); 238#endif 239 ip->ip_len += inc; 240 } 241 242 /* 243 * Add skeleton NAT entry for connection which will come back the 244 * other way. 245 */
|
244 sp = htons(a5 << 8 | a6);
| 246 sp = (a5 << 8 | a6);
|
245 /* 246 * Don't allow the PORT command to specify a port < 1024 due to 247 * security crap. 248 */
| 247 /* 248 * Don't allow the PORT command to specify a port < 1024 due to 249 * security crap. 250 */
|
249 if (ntohs(sp) < 1024)
| 251 if (sp < 1024)
|
250 return 0; 251 /* 252 * The server may not make the connection back from port 20, but 253 * it is the most likely so use it here to check for a conflicting 254 * mapping. 255 */
| 252 return 0; 253 /* 254 * The server may not make the connection back from port 20, but 255 * it is the most likely so use it here to check for a conflicting 256 * mapping. 257 */
|
256 dp = htons(fin->fin_data[1] - 1); 257 ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, 258 ip->ip_dst, (dp << 16) | sp, 0);
| 258 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 259 fi.fin_data[0] = sp; 260 fi.fin_data[1] = fin->fin_data[1] - 1; 261 ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip, 262 ip->ip_dst, 0);
|
259 if (ipn == NULL) { 260 int slen; 261 262 slen = ip->ip_len; 263 ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
| 263 if (ipn == NULL) { 264 int slen; 265 266 slen = ip->ip_len; 267 ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
|
264 bcopy((char *)fin, (char *)&fi, sizeof(fi));
| |
265 bzero((char *)tcp2, sizeof(*tcp2)); 266 tcp2->th_win = htons(8192);
| 268 bzero((char *)tcp2, sizeof(*tcp2)); 269 tcp2->th_win = htons(8192);
|
267 tcp2->th_sport = sp;
| 270 tcp2->th_sport = htons(sp);
|
268 tcp2->th_off = 5; 269 tcp2->th_dport = 0; /* XXX - don't specify remote port */
| 271 tcp2->th_off = 5; 272 tcp2->th_dport = 0; /* XXX - don't specify remote port */
|
270 fi.fin_data[0] = ntohs(sp);
| |
271 fi.fin_data[1] = 0; 272 fi.fin_dlen = sizeof(*tcp2); 273 fi.fin_dp = (char *)tcp2;
| 273 fi.fin_data[1] = 0; 274 fi.fin_dlen = sizeof(*tcp2); 275 fi.fin_dp = (char *)tcp2;
|
274 fi.fin_fr = &natfr;
| 276 fi.fin_fr = &ftppxyfr;
|
275 fi.fin_out = 1; 276 swip = ip->ip_src; 277 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 278 ip->ip_src = nat->nat_inip;
| 277 fi.fin_out = 1; 278 swip = ip->ip_src; 279 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 280 ip->ip_src = nat->nat_inip;
|
279 ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_DPORT,
| 281 ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_DPORT,
|
280 NAT_OUTBOUND); 281 if (ipn != NULL) { 282 ipn->nat_age = fr_defnatage;
| 282 NAT_OUTBOUND); 283 if (ipn != NULL) { 284 ipn->nat_age = fr_defnatage;
|
283 (void) fr_addstate(ip, &fi, FI_W_DPORT);
| 285 (void) fr_addstate(ip, &fi, NULL, 286 FI_W_DPORT|FI_IGNOREPKT);
|
284 } 285 ip->ip_len = slen; 286 ip->ip_src = swip; 287 } 288 return APR_INC(inc); 289} 290 291 292int ippr_ftp_client(fin, ip, nat, ftp, dlen) 293fr_info_t *fin; 294nat_t *nat; 295ftpinfo_t *ftp; 296ip_t *ip; 297int dlen; 298{ 299 char *rptr, *wptr, cmd[6], c; 300 ftpside_t *f; 301 int inc, i; 302 303 inc = 0; 304 f = &ftp->ftp_side[0]; 305 rptr = f->ftps_rptr; 306 wptr = f->ftps_wptr; 307 308 for (i = 0; (i < 5) && (i < dlen); i++) { 309 c = rptr[i]; 310 if (isalpha(c)) { 311 cmd[i] = toupper(c); 312 } else { 313 cmd[i] = c; 314 } 315 } 316 cmd[i] = '\0'; 317 318 ftp->ftp_incok = 0; 319 if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) { 320 if (ftp->ftp_passok == FTPXY_ADOK_1 || 321 ftp->ftp_passok == FTPXY_AUOK_1) { 322 ftp->ftp_passok = FTPXY_USER_2; 323 ftp->ftp_incok = 1; 324 } else { 325 ftp->ftp_passok = FTPXY_USER_1; 326 ftp->ftp_incok = 1; 327 } 328 } else if (!strncmp(cmd, "AUTH ", 5)) { 329 ftp->ftp_passok = FTPXY_AUTH_1; 330 ftp->ftp_incok = 1; 331 } else if (!strncmp(cmd, "PASS ", 5)) { 332 if (ftp->ftp_passok == FTPXY_USOK_1) { 333 ftp->ftp_passok = FTPXY_PASS_1; 334 ftp->ftp_incok = 1; 335 } else if (ftp->ftp_passok == FTPXY_USOK_2) { 336 ftp->ftp_passok = FTPXY_PASS_2; 337 ftp->ftp_incok = 1; 338 } 339 } else if ((ftp->ftp_passok == FTPXY_AUOK_1) && 340 !strncmp(cmd, "ADAT ", 5)) { 341 ftp->ftp_passok = FTPXY_ADAT_1; 342 ftp->ftp_incok = 1;
| 287 } 288 ip->ip_len = slen; 289 ip->ip_src = swip; 290 } 291 return APR_INC(inc); 292} 293 294 295int ippr_ftp_client(fin, ip, nat, ftp, dlen) 296fr_info_t *fin; 297nat_t *nat; 298ftpinfo_t *ftp; 299ip_t *ip; 300int dlen; 301{ 302 char *rptr, *wptr, cmd[6], c; 303 ftpside_t *f; 304 int inc, i; 305 306 inc = 0; 307 f = &ftp->ftp_side[0]; 308 rptr = f->ftps_rptr; 309 wptr = f->ftps_wptr; 310 311 for (i = 0; (i < 5) && (i < dlen); i++) { 312 c = rptr[i]; 313 if (isalpha(c)) { 314 cmd[i] = toupper(c); 315 } else { 316 cmd[i] = c; 317 } 318 } 319 cmd[i] = '\0'; 320 321 ftp->ftp_incok = 0; 322 if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) { 323 if (ftp->ftp_passok == FTPXY_ADOK_1 || 324 ftp->ftp_passok == FTPXY_AUOK_1) { 325 ftp->ftp_passok = FTPXY_USER_2; 326 ftp->ftp_incok = 1; 327 } else { 328 ftp->ftp_passok = FTPXY_USER_1; 329 ftp->ftp_incok = 1; 330 } 331 } else if (!strncmp(cmd, "AUTH ", 5)) { 332 ftp->ftp_passok = FTPXY_AUTH_1; 333 ftp->ftp_incok = 1; 334 } else if (!strncmp(cmd, "PASS ", 5)) { 335 if (ftp->ftp_passok == FTPXY_USOK_1) { 336 ftp->ftp_passok = FTPXY_PASS_1; 337 ftp->ftp_incok = 1; 338 } else if (ftp->ftp_passok == FTPXY_USOK_2) { 339 ftp->ftp_passok = FTPXY_PASS_2; 340 ftp->ftp_incok = 1; 341 } 342 } else if ((ftp->ftp_passok == FTPXY_AUOK_1) && 343 !strncmp(cmd, "ADAT ", 5)) { 344 ftp->ftp_passok = FTPXY_ADAT_1; 345 ftp->ftp_incok = 1;
|
343 } else if ((ftp->ftp_passok == FTPXY_PAOK_2) &&
| 346 } else if ((ftp->ftp_passok == FTPXY_PAOK_1 || 347 ftp->ftp_passok == FTPXY_PAOK_2) &&
|
344 !strncmp(cmd, "ACCT ", 5)) { 345 ftp->ftp_passok = FTPXY_ACCT_1; 346 ftp->ftp_incok = 1; 347 } else if ((ftp->ftp_passok == FTPXY_GO) && !ippr_ftp_pasvonly && 348 !strncmp(cmd, "PORT ", 5)) { 349 inc = ippr_ftp_port(fin, ip, nat, f, dlen); 350 } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly && 351 !strncmp(cmd, "PORT ", 5)) { 352 inc = ippr_ftp_port(fin, ip, nat, f, dlen); 353 } 354 355 while ((*rptr++ != '\n') && (rptr < wptr)) 356 ; 357 f->ftps_rptr = rptr; 358 return inc; 359} 360 361 362int ippr_ftp_pasv(fin, ip, nat, f, dlen) 363fr_info_t *fin; 364ip_t *ip; 365nat_t *nat; 366ftpside_t *f; 367int dlen; 368{ 369 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 370 struct in_addr swip, swip2;
| 348 !strncmp(cmd, "ACCT ", 5)) { 349 ftp->ftp_passok = FTPXY_ACCT_1; 350 ftp->ftp_incok = 1; 351 } else if ((ftp->ftp_passok == FTPXY_GO) && !ippr_ftp_pasvonly && 352 !strncmp(cmd, "PORT ", 5)) { 353 inc = ippr_ftp_port(fin, ip, nat, f, dlen); 354 } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly && 355 !strncmp(cmd, "PORT ", 5)) { 356 inc = ippr_ftp_port(fin, ip, nat, f, dlen); 357 } 358 359 while ((*rptr++ != '\n') && (rptr < wptr)) 360 ; 361 f->ftps_rptr = rptr; 362 return inc; 363} 364 365 366int ippr_ftp_pasv(fin, ip, nat, f, dlen) 367fr_info_t *fin; 368ip_t *ip; 369nat_t *nat; 370ftpside_t *f; 371int dlen; 372{ 373 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 374 struct in_addr swip, swip2;
|
371 u_short a5, a6, sp, dp;
| |
372 u_int a1, a2, a3, a4;
| 375 u_int a1, a2, a3, a4;
|
| 376 u_short a5, a6, dp;
|
373 fr_info_t fi; 374 nat_t *ipn; 375 int inc; 376 char *s; 377 378#define PASV_REPLEN 24 379 /* 380 * Check for PASV reply message. 381 */ 382 if (dlen < IPF_MIN227LEN) 383 return 0; 384 else if (strncmp(f->ftps_rptr, "227 Entering Passive Mod", PASV_REPLEN)) 385 return 0; 386 387 tcp = (tcphdr_t *)fin->fin_dp; 388 389 /* 390 * Skip the PORT command + space 391 */ 392 s = f->ftps_rptr + PASV_REPLEN; 393 while (*s && !isdigit(*s)) 394 s++; 395 /* 396 * Pick out the address components, two at a time. 397 */ 398 a1 = ippr_ftp_atoi(&s); 399 if (!s) 400 return 0; 401 a2 = ippr_ftp_atoi(&s); 402 if (!s) 403 return 0; 404 405 /* 406 * check that IP address in the PORT/PASV reply is the same as the 407 * sender of the command - prevents using PORT for port scanning. 408 */ 409 a1 <<= 16; 410 a1 |= a2; 411 if (a1 != ntohl(nat->nat_oip.s_addr)) 412 return 0; 413 414 a5 = ippr_ftp_atoi(&s); 415 if (!s) 416 return 0; 417 418 if (*s == ')') 419 s++; 420 if (*s == '.') 421 s++; 422 if (*s == '\n') 423 s--; 424 /* 425 * check for CR-LF at the end. 426 */ 427 if ((*s == '\r') && (*(s + 1) == '\n')) { 428 s += 2; 429 a6 = a5 & 0xff; 430 } else 431 return 0; 432 a5 >>= 8; 433 /* 434 * Calculate new address parts for 227 reply 435 */ 436 a1 = ntohl(ip->ip_src.s_addr); 437 a2 = (a1 >> 16) & 0xff; 438 a3 = (a1 >> 8) & 0xff; 439 a4 = a1 & 0xff; 440 a1 >>= 24; 441 inc = 0; 442#if 0 443 olen = s - f->ftps_rptr; 444 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", 445 "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6); 446 nlen = strlen(newbuf); 447 inc = nlen - olen; 448 if ((inc + ip->ip_len) > 65535) 449 return 0; 450 451#if SOLARIS 452 m = fin->fin_qfm; 453 for (m1 = m; m1->b_cont; m1 = m1->b_cont) 454 ; 455 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { 456 mblk_t *nm; 457 458 /* alloc enough to keep same trailer space for lower driver */ 459 nm = allocb(nlen, BPRI_MED); 460 PANIC((!nm),("ippr_ftp_out: allocb failed")); 461 462 nm->b_band = m1->b_band; 463 nm->b_wptr += nlen; 464 465 m1->b_wptr -= olen; 466 PANIC((m1->b_wptr < m1->b_rptr), 467 ("ippr_ftp_out: cannot handle fragmented data block")); 468 469 linkb(m1, nm); 470 } else { 471 m1->b_wptr += inc; 472 } 473 /*copyin_mblk(m, off, nlen, newbuf);*/ 474#else /* SOLARIS */ 475 m = *((mb_t **)fin->fin_mp); 476 if (inc < 0) 477 m_adj(m, inc); 478 /* the mbuf chain will be extended if necessary by m_copyback() */ 479 /*m_copyback(m, off, nlen, newbuf);*/ 480#endif /* SOLARIS */ 481 if (inc != 0) { 482#if SOLARIS || defined(__sgi) 483 register u_32_t sum1, sum2; 484 485 sum1 = ip->ip_len; 486 sum2 = ip->ip_len + inc; 487 488 /* Because ~1 == -2, We really need ~1 == -1 */ 489 if (sum1 > sum2) 490 sum2--; 491 sum2 -= sum1; 492 sum2 = (sum2 & 0xffff) + (sum2 >> 16); 493 494 fix_outcksum(fin, &ip->ip_sum, sum2); 495#endif /* SOLARIS || defined(__sgi) */ 496 ip->ip_len += inc; 497 } 498#endif /* 0 */ 499 500 /* 501 * Add skeleton NAT entry for connection which will come back the 502 * other way. 503 */
| 377 fr_info_t fi; 378 nat_t *ipn; 379 int inc; 380 char *s; 381 382#define PASV_REPLEN 24 383 /* 384 * Check for PASV reply message. 385 */ 386 if (dlen < IPF_MIN227LEN) 387 return 0; 388 else if (strncmp(f->ftps_rptr, "227 Entering Passive Mod", PASV_REPLEN)) 389 return 0; 390 391 tcp = (tcphdr_t *)fin->fin_dp; 392 393 /* 394 * Skip the PORT command + space 395 */ 396 s = f->ftps_rptr + PASV_REPLEN; 397 while (*s && !isdigit(*s)) 398 s++; 399 /* 400 * Pick out the address components, two at a time. 401 */ 402 a1 = ippr_ftp_atoi(&s); 403 if (!s) 404 return 0; 405 a2 = ippr_ftp_atoi(&s); 406 if (!s) 407 return 0; 408 409 /* 410 * check that IP address in the PORT/PASV reply is the same as the 411 * sender of the command - prevents using PORT for port scanning. 412 */ 413 a1 <<= 16; 414 a1 |= a2; 415 if (a1 != ntohl(nat->nat_oip.s_addr)) 416 return 0; 417 418 a5 = ippr_ftp_atoi(&s); 419 if (!s) 420 return 0; 421 422 if (*s == ')') 423 s++; 424 if (*s == '.') 425 s++; 426 if (*s == '\n') 427 s--; 428 /* 429 * check for CR-LF at the end. 430 */ 431 if ((*s == '\r') && (*(s + 1) == '\n')) { 432 s += 2; 433 a6 = a5 & 0xff; 434 } else 435 return 0; 436 a5 >>= 8; 437 /* 438 * Calculate new address parts for 227 reply 439 */ 440 a1 = ntohl(ip->ip_src.s_addr); 441 a2 = (a1 >> 16) & 0xff; 442 a3 = (a1 >> 8) & 0xff; 443 a4 = a1 & 0xff; 444 a1 >>= 24; 445 inc = 0; 446#if 0 447 olen = s - f->ftps_rptr; 448 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", 449 "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6); 450 nlen = strlen(newbuf); 451 inc = nlen - olen; 452 if ((inc + ip->ip_len) > 65535) 453 return 0; 454 455#if SOLARIS 456 m = fin->fin_qfm; 457 for (m1 = m; m1->b_cont; m1 = m1->b_cont) 458 ; 459 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { 460 mblk_t *nm; 461 462 /* alloc enough to keep same trailer space for lower driver */ 463 nm = allocb(nlen, BPRI_MED); 464 PANIC((!nm),("ippr_ftp_out: allocb failed")); 465 466 nm->b_band = m1->b_band; 467 nm->b_wptr += nlen; 468 469 m1->b_wptr -= olen; 470 PANIC((m1->b_wptr < m1->b_rptr), 471 ("ippr_ftp_out: cannot handle fragmented data block")); 472 473 linkb(m1, nm); 474 } else { 475 m1->b_wptr += inc; 476 } 477 /*copyin_mblk(m, off, nlen, newbuf);*/ 478#else /* SOLARIS */ 479 m = *((mb_t **)fin->fin_mp); 480 if (inc < 0) 481 m_adj(m, inc); 482 /* the mbuf chain will be extended if necessary by m_copyback() */ 483 /*m_copyback(m, off, nlen, newbuf);*/ 484#endif /* SOLARIS */ 485 if (inc != 0) { 486#if SOLARIS || defined(__sgi) 487 register u_32_t sum1, sum2; 488 489 sum1 = ip->ip_len; 490 sum2 = ip->ip_len + inc; 491 492 /* Because ~1 == -2, We really need ~1 == -1 */ 493 if (sum1 > sum2) 494 sum2--; 495 sum2 -= sum1; 496 sum2 = (sum2 & 0xffff) + (sum2 >> 16); 497 498 fix_outcksum(fin, &ip->ip_sum, sum2); 499#endif /* SOLARIS || defined(__sgi) */ 500 ip->ip_len += inc; 501 } 502#endif /* 0 */ 503 504 /* 505 * Add skeleton NAT entry for connection which will come back the 506 * other way. 507 */
|
504 sp = 0;
| 508 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 509 fi.fin_data[0] = 0;
|
505 dp = htons(fin->fin_data[1] - 1);
| 510 dp = htons(fin->fin_data[1] - 1);
|
506 ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, 507 ip->ip_dst, (dp << 16) | sp, 0);
| 511 fi.fin_data[1] = ntohs(dp); 512 ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip, 513 ip->ip_dst, 0);
|
508 if (ipn == NULL) { 509 int slen; 510 511 slen = ip->ip_len; 512 ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
| 514 if (ipn == NULL) { 515 int slen; 516 517 slen = ip->ip_len; 518 ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
|
513 bcopy((char *)fin, (char *)&fi, sizeof(fi));
| |
514 bzero((char *)tcp2, sizeof(*tcp2)); 515 tcp2->th_win = htons(8192); 516 tcp2->th_sport = 0; /* XXX - fake it for nat_new */ 517 tcp2->th_off = 5;
| 519 bzero((char *)tcp2, sizeof(*tcp2)); 520 tcp2->th_win = htons(8192); 521 tcp2->th_sport = 0; /* XXX - fake it for nat_new */ 522 tcp2->th_off = 5;
|
518 fi.fin_data[0] = a5 << 8 | a6;
| 523 fi.fin_data[1] = a5 << 8 | a6;
|
519 fi.fin_dlen = sizeof(*tcp2);
| 524 fi.fin_dlen = sizeof(*tcp2);
|
520 tcp2->th_dport = htons(fi.fin_data[0]); 521 fi.fin_data[1] = 0;
| 525 tcp2->th_dport = htons(fi.fin_data[1]); 526 fi.fin_data[0] = 0;
|
522 fi.fin_dp = (char *)tcp2;
| 527 fi.fin_dp = (char *)tcp2;
|
523 fi.fin_fr = &natfr;
| 528 fi.fin_fr = &ftppxyfr;
|
524 fi.fin_out = 1; 525 swip = ip->ip_src; 526 swip2 = ip->ip_dst; 527 fi.fin_fi.fi_daddr = ip->ip_src.s_addr; 528 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 529 ip->ip_dst = ip->ip_src; 530 ip->ip_src = nat->nat_inip;
| 529 fi.fin_out = 1; 530 swip = ip->ip_src; 531 swip2 = ip->ip_dst; 532 fi.fin_fi.fi_daddr = ip->ip_src.s_addr; 533 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 534 ip->ip_dst = ip->ip_src; 535 ip->ip_src = nat->nat_inip;
|
531 ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_SPORT,
| 536 ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_SPORT,
|
532 NAT_OUTBOUND); 533 if (ipn != NULL) { 534 ipn->nat_age = fr_defnatage;
| 537 NAT_OUTBOUND); 538 if (ipn != NULL) { 539 ipn->nat_age = fr_defnatage;
|
535 (void) fr_addstate(ip, &fi, FI_W_SPORT);
| 540 (void) fr_addstate(ip, &fi, NULL, 541 FI_W_SPORT|FI_IGNOREPKT);
|
536 } 537 ip->ip_len = slen; 538 ip->ip_src = swip; 539 ip->ip_dst = swip2; 540 } 541 return inc; 542} 543 544 545int ippr_ftp_server(fin, ip, nat, ftp, dlen) 546fr_info_t *fin; 547ip_t *ip; 548nat_t *nat; 549ftpinfo_t *ftp; 550int dlen; 551{ 552 char *rptr, *wptr; 553 ftpside_t *f; 554 int inc; 555 556 inc = 0; 557 f = &ftp->ftp_side[1]; 558 rptr = f->ftps_rptr; 559 wptr = f->ftps_wptr; 560 561 if (!isdigit(*rptr) || !isdigit(*(rptr + 1)) || !isdigit(*(rptr + 2))) 562 return inc; 563 if (ftp->ftp_passok == FTPXY_GO) { 564 if (!strncmp(rptr, "227 ", 4)) 565 inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); 566 } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) { 567 inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); 568 } else if (*rptr == '5' || *rptr == '4') 569 ftp->ftp_passok = FTPXY_INIT; 570 else if (ftp->ftp_incok) { 571 if (*rptr == '3') { 572 if (ftp->ftp_passok == FTPXY_ACCT_1) 573 ftp->ftp_passok = FTPXY_GO; 574 else 575 ftp->ftp_passok++; 576 } else if (*rptr == '2') { 577 switch (ftp->ftp_passok) 578 { 579 case FTPXY_USER_1 : 580 case FTPXY_USER_2 : 581 case FTPXY_PASS_1 : 582 case FTPXY_PASS_2 : 583 case FTPXY_ACCT_1 : 584 ftp->ftp_passok = FTPXY_GO; 585 break; 586 default : 587 ftp->ftp_passok += 3; 588 break; 589 } 590 } 591 } 592 ftp->ftp_incok = 0; 593 while ((*rptr++ != '\n') && (rptr < wptr)) 594 ; 595 f->ftps_rptr = rptr; 596 return inc; 597} 598 599 600/* 601 * Look to see if the buffer starts with something which we recognise as 602 * being the correct syntax for the FTP protocol. 603 */
| 542 } 543 ip->ip_len = slen; 544 ip->ip_src = swip; 545 ip->ip_dst = swip2; 546 } 547 return inc; 548} 549 550 551int ippr_ftp_server(fin, ip, nat, ftp, dlen) 552fr_info_t *fin; 553ip_t *ip; 554nat_t *nat; 555ftpinfo_t *ftp; 556int dlen; 557{ 558 char *rptr, *wptr; 559 ftpside_t *f; 560 int inc; 561 562 inc = 0; 563 f = &ftp->ftp_side[1]; 564 rptr = f->ftps_rptr; 565 wptr = f->ftps_wptr; 566 567 if (!isdigit(*rptr) || !isdigit(*(rptr + 1)) || !isdigit(*(rptr + 2))) 568 return inc; 569 if (ftp->ftp_passok == FTPXY_GO) { 570 if (!strncmp(rptr, "227 ", 4)) 571 inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); 572 } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) { 573 inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); 574 } else if (*rptr == '5' || *rptr == '4') 575 ftp->ftp_passok = FTPXY_INIT; 576 else if (ftp->ftp_incok) { 577 if (*rptr == '3') { 578 if (ftp->ftp_passok == FTPXY_ACCT_1) 579 ftp->ftp_passok = FTPXY_GO; 580 else 581 ftp->ftp_passok++; 582 } else if (*rptr == '2') { 583 switch (ftp->ftp_passok) 584 { 585 case FTPXY_USER_1 : 586 case FTPXY_USER_2 : 587 case FTPXY_PASS_1 : 588 case FTPXY_PASS_2 : 589 case FTPXY_ACCT_1 : 590 ftp->ftp_passok = FTPXY_GO; 591 break; 592 default : 593 ftp->ftp_passok += 3; 594 break; 595 } 596 } 597 } 598 ftp->ftp_incok = 0; 599 while ((*rptr++ != '\n') && (rptr < wptr)) 600 ; 601 f->ftps_rptr = rptr; 602 return inc; 603} 604 605 606/* 607 * Look to see if the buffer starts with something which we recognise as 608 * being the correct syntax for the FTP protocol. 609 */
|
604int ippr_ftp_valid(buf, len)
| 610int ippr_ftp_client_valid(buf, len)
|
605char *buf; 606size_t len; 607{ 608 register char *s, c; 609 register size_t i = len; 610 611 if (i < 5) 612 return 2; 613 s = buf; 614 c = *s++; 615 i--; 616
| 611char *buf; 612size_t len; 613{ 614 register char *s, c; 615 register size_t i = len; 616 617 if (i < 5) 618 return 2; 619 s = buf; 620 c = *s++; 621 i--; 622
|
617 if (isdigit(c)) {
| 623 if (isalpha(c)) {
|
618 c = *s++; 619 i--;
| 624 c = *s++; 625 i--;
|
620 if (isdigit(c)) {
| 626 if (isalpha(c)) {
|
621 c = *s++; 622 i--;
| 627 c = *s++; 628 i--;
|
623 if (isdigit(c)) {
| 629 if (isalpha(c)) {
|
624 c = *s++; 625 i--;
| 630 c = *s++; 631 i--;
|
626 if ((c != '-') && (c != ' '))
| 632 if (isalpha(c)) { 633 c = *s++; 634 i--; 635 if ((c != ' ') && (c != '\r')) 636 return 1; 637 } else if ((c != ' ') && (c != '\r'))
|
627 return 1; 628 } else 629 return 1; 630 } else 631 return 1;
| 638 return 1; 639 } else 640 return 1; 641 } else 642 return 1;
|
632 } else if (isalpha(c)) {
| 643 } else 644 return 1; 645 for (; i; i--) {
|
633 c = *s++;
| 646 c = *s++;
|
| 647 if (c == '\n') 648 return 0; 649 } 650 return 2; 651} 652 653 654int ippr_ftp_server_valid(buf, len) 655char *buf; 656size_t len; 657{ 658 register char *s, c; 659 register size_t i = len; 660 661 if (i < 5) 662 return 2; 663 s = buf; 664 c = *s++; 665 i--; 666 667 if (isdigit(c)) { 668 c = *s++;
|
634 i--;
| 669 i--;
|
635 if (isalpha(c)) {
| 670 if (isdigit(c)) {
|
636 c = *s++; 637 i--;
| 671 c = *s++; 672 i--;
|
638 if (isalpha(c)) {
| 673 if (isdigit(c)) {
|
639 c = *s++; 640 i--;
| 674 c = *s++; 675 i--;
|
641 if (isalpha(c)) { 642 c = *s++; 643 i--; 644 if ((c != ' ') && (c != '\r')) 645 return 1; 646 } else if ((c != ' ') && (c != '\r'))
| 676 if ((c != '-') && (c != ' '))
|
647 return 1; 648 } else 649 return 1; 650 } else 651 return 1; 652 } else 653 return 1; 654 for (; i; i--) { 655 c = *s++; 656 if (c == '\n') 657 return 0; 658 } 659 return 2; 660} 661 662
| 677 return 1; 678 } else 679 return 1; 680 } else 681 return 1; 682 } else 683 return 1; 684 for (; i; i--) { 685 c = *s++; 686 if (c == '\n') 687 return 0; 688 } 689 return 2; 690} 691 692
|
| 693int ippr_ftp_valid(side, buf, len) 694int side; 695char *buf; 696size_t len; 697{ 698 int ret; 699 700 if (side == 0) 701 ret = ippr_ftp_client_valid(buf, len); 702 else 703 ret = ippr_ftp_server_valid(buf, len); 704 return ret; 705} 706 707
|
663int ippr_ftp_process(fin, ip, nat, ftp, rv) 664fr_info_t *fin; 665ip_t *ip; 666nat_t *nat; 667ftpinfo_t *ftp; 668int rv; 669{ 670 int mlen, len, off, inc, i, sel; 671 char *rptr, *wptr; 672 ftpside_t *f, *t; 673 tcphdr_t *tcp; 674 mb_t *m; 675 676 tcp = (tcphdr_t *)fin->fin_dp; 677 off = fin->fin_hlen + (tcp->th_off << 2); 678 679#if SOLARIS 680 m = fin->fin_qfm; 681#else 682 m = *((mb_t **)fin->fin_mp); 683#endif 684 685#if SOLARIS 686 mlen = msgdsize(m) - off; 687#else 688 mlen = mbufchainlen(m) - off; 689#endif 690 691 t = &ftp->ftp_side[1 - rv]; 692 f = &ftp->ftp_side[rv]; 693 if (!mlen) { 694 if (!t->ftps_seq || 695 (int)ntohl(tcp->th_ack) - (int)t->ftps_seq > 0) 696 t->ftps_seq = ntohl(tcp->th_ack); 697 f->ftps_len = 0; 698 return 0; 699 } 700 701 inc = 0; 702 rptr = f->ftps_rptr; 703 wptr = f->ftps_wptr; 704 705 sel = nat->nat_aps->aps_sel[1 - rv]; 706 if (rv) 707 i = nat->nat_aps->aps_ackoff[sel]; 708 else 709 i = nat->nat_aps->aps_seqoff[sel]; 710 /* 711 * XXX - Ideally, this packet should get dropped because we now know 712 * that it is out of order (and there is no real danger in doing so 713 * apart from causing packets to go through here ordered). 714 */ 715 if (f->ftps_len + f->ftps_seq == ntohl(tcp->th_seq)) 716 f->ftps_seq = ntohl(tcp->th_seq); 717 else if (ntohl(tcp->th_seq) + i != f->ftps_seq) {
| 708int ippr_ftp_process(fin, ip, nat, ftp, rv) 709fr_info_t *fin; 710ip_t *ip; 711nat_t *nat; 712ftpinfo_t *ftp; 713int rv; 714{ 715 int mlen, len, off, inc, i, sel; 716 char *rptr, *wptr; 717 ftpside_t *f, *t; 718 tcphdr_t *tcp; 719 mb_t *m; 720 721 tcp = (tcphdr_t *)fin->fin_dp; 722 off = fin->fin_hlen + (tcp->th_off << 2); 723 724#if SOLARIS 725 m = fin->fin_qfm; 726#else 727 m = *((mb_t **)fin->fin_mp); 728#endif 729 730#if SOLARIS 731 mlen = msgdsize(m) - off; 732#else 733 mlen = mbufchainlen(m) - off; 734#endif 735 736 t = &ftp->ftp_side[1 - rv]; 737 f = &ftp->ftp_side[rv]; 738 if (!mlen) { 739 if (!t->ftps_seq || 740 (int)ntohl(tcp->th_ack) - (int)t->ftps_seq > 0) 741 t->ftps_seq = ntohl(tcp->th_ack); 742 f->ftps_len = 0; 743 return 0; 744 } 745 746 inc = 0; 747 rptr = f->ftps_rptr; 748 wptr = f->ftps_wptr; 749 750 sel = nat->nat_aps->aps_sel[1 - rv]; 751 if (rv) 752 i = nat->nat_aps->aps_ackoff[sel]; 753 else 754 i = nat->nat_aps->aps_seqoff[sel]; 755 /* 756 * XXX - Ideally, this packet should get dropped because we now know 757 * that it is out of order (and there is no real danger in doing so 758 * apart from causing packets to go through here ordered). 759 */ 760 if (f->ftps_len + f->ftps_seq == ntohl(tcp->th_seq)) 761 f->ftps_seq = ntohl(tcp->th_seq); 762 else if (ntohl(tcp->th_seq) + i != f->ftps_seq) {
|
718 return APR_ERR(-1);
| 763 return APR_ERR(1);
|
719 } 720 f->ftps_len = mlen; 721 722 while (mlen > 0) { 723 len = MIN(mlen, FTP_BUFSZ / 2); 724 725#if SOLARIS 726 copyout_mblk(m, off, len, wptr); 727#else 728 m_copydata(m, off, len, wptr); 729#endif 730 mlen -= len; 731 off += len; 732 wptr += len; 733 f->ftps_wptr = wptr; 734 if (f->ftps_junk == 2)
| 764 } 765 f->ftps_len = mlen; 766 767 while (mlen > 0) { 768 len = MIN(mlen, FTP_BUFSZ / 2); 769 770#if SOLARIS 771 copyout_mblk(m, off, len, wptr); 772#else 773 m_copydata(m, off, len, wptr); 774#endif 775 mlen -= len; 776 off += len; 777 wptr += len; 778 f->ftps_wptr = wptr; 779 if (f->ftps_junk == 2)
|
735 f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr);
| 780 f->ftps_junk = ippr_ftp_valid(rv, rptr, wptr - rptr);
|
736 737 while ((f->ftps_junk == 0) && (wptr > rptr)) {
| 781 782 while ((f->ftps_junk == 0) && (wptr > rptr)) {
|
738 f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr);
| 783 f->ftps_junk = ippr_ftp_valid(rv, rptr, wptr - rptr);
|
739 if (f->ftps_junk == 0) {
| 784 if (f->ftps_junk == 0) {
|
| 785 f->ftps_cmds++;
|
740 len = wptr - rptr; 741 f->ftps_rptr = rptr; 742 if (rv) 743 inc += ippr_ftp_server(fin, ip, nat, 744 ftp, len); 745 else 746 inc += ippr_ftp_client(fin, ip, nat, 747 ftp, len); 748 rptr = f->ftps_rptr;
| 786 len = wptr - rptr; 787 f->ftps_rptr = rptr; 788 if (rv) 789 inc += ippr_ftp_server(fin, ip, nat, 790 ftp, len); 791 else 792 inc += ippr_ftp_client(fin, ip, nat, 793 ftp, len); 794 rptr = f->ftps_rptr;
|
| 795 wptr = f->ftps_wptr;
|
749 } 750 } 751
| 796 } 797 } 798
|
| 799 /* 800 * Off to a bad start so lets just forget about using the 801 * ftp proxy for this connection. 802 */ 803 if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) 804 return APR_ERR(2); 805
|
752 while ((f->ftps_junk == 1) && (rptr < wptr)) { 753 while ((rptr < wptr) && (*rptr != '\r')) 754 rptr++; 755 756 if (*rptr == '\r') { 757 if (rptr + 1 < wptr) { 758 if (*(rptr + 1) == '\n') { 759 rptr += 2; 760 f->ftps_junk = 0; 761 } else 762 rptr++; 763 } else 764 break; 765 } 766 } 767 f->ftps_rptr = rptr; 768 769 if (rptr == wptr) { 770 rptr = wptr = f->ftps_buf; 771 } else { 772 if ((wptr > f->ftps_buf + FTP_BUFSZ / 2)) { 773 i = wptr - rptr; 774 if ((rptr == f->ftps_buf) || 775 (wptr - rptr > FTP_BUFSZ / 2)) { 776 f->ftps_junk = 1; 777 rptr = wptr = f->ftps_buf; 778 } else { 779 bcopy(rptr, f->ftps_buf, i); 780 wptr = f->ftps_buf + i; 781 rptr = f->ftps_buf; 782 } 783 } 784 f->ftps_rptr = rptr; 785 f->ftps_wptr = wptr; 786 } 787 } 788 789 t->ftps_seq = ntohl(tcp->th_ack); 790 f->ftps_rptr = rptr; 791 f->ftps_wptr = wptr; 792 return APR_INC(inc); 793} 794 795 796int ippr_ftp_out(fin, ip, aps, nat) 797fr_info_t *fin; 798ip_t *ip; 799ap_session_t *aps; 800nat_t *nat; 801{ 802 ftpinfo_t *ftp; 803 804 ftp = aps->aps_data; 805 if (ftp == NULL) 806 return 0; 807 return ippr_ftp_process(fin, ip, nat, ftp, 0); 808} 809 810 811int ippr_ftp_in(fin, ip, aps, nat) 812fr_info_t *fin; 813ip_t *ip; 814ap_session_t *aps; 815nat_t *nat; 816{ 817 ftpinfo_t *ftp; 818 819 ftp = aps->aps_data; 820 if (ftp == NULL) 821 return 0; 822 return ippr_ftp_process(fin, ip, nat, ftp, 1); 823} 824 825 826/* 827 * ippr_ftp_atoi - implement a version of atoi which processes numbers in 828 * pairs separated by commas (which are expected to be in the range 0 - 255), 829 * returning a 16 bit number combining either side of the , as the MSB and 830 * LSB. 831 */ 832u_short ippr_ftp_atoi(ptr) 833char **ptr; 834{ 835 register char *s = *ptr, c; 836 register u_char i = 0, j = 0; 837 838 while ((c = *s++) && isdigit(c)) { 839 i *= 10; 840 i += c - '0'; 841 } 842 if (c != ',') { 843 *ptr = NULL; 844 return 0; 845 } 846 while ((c = *s++) && isdigit(c)) { 847 j *= 10; 848 j += c - '0'; 849 } 850 *ptr = s; 851 i &= 0xff; 852 j &= 0xff; 853 return (i << 8) | j; 854}
| 806 while ((f->ftps_junk == 1) && (rptr < wptr)) { 807 while ((rptr < wptr) && (*rptr != '\r')) 808 rptr++; 809 810 if (*rptr == '\r') { 811 if (rptr + 1 < wptr) { 812 if (*(rptr + 1) == '\n') { 813 rptr += 2; 814 f->ftps_junk = 0; 815 } else 816 rptr++; 817 } else 818 break; 819 } 820 } 821 f->ftps_rptr = rptr; 822 823 if (rptr == wptr) { 824 rptr = wptr = f->ftps_buf; 825 } else { 826 if ((wptr > f->ftps_buf + FTP_BUFSZ / 2)) { 827 i = wptr - rptr; 828 if ((rptr == f->ftps_buf) || 829 (wptr - rptr > FTP_BUFSZ / 2)) { 830 f->ftps_junk = 1; 831 rptr = wptr = f->ftps_buf; 832 } else { 833 bcopy(rptr, f->ftps_buf, i); 834 wptr = f->ftps_buf + i; 835 rptr = f->ftps_buf; 836 } 837 } 838 f->ftps_rptr = rptr; 839 f->ftps_wptr = wptr; 840 } 841 } 842 843 t->ftps_seq = ntohl(tcp->th_ack); 844 f->ftps_rptr = rptr; 845 f->ftps_wptr = wptr; 846 return APR_INC(inc); 847} 848 849 850int ippr_ftp_out(fin, ip, aps, nat) 851fr_info_t *fin; 852ip_t *ip; 853ap_session_t *aps; 854nat_t *nat; 855{ 856 ftpinfo_t *ftp; 857 858 ftp = aps->aps_data; 859 if (ftp == NULL) 860 return 0; 861 return ippr_ftp_process(fin, ip, nat, ftp, 0); 862} 863 864 865int ippr_ftp_in(fin, ip, aps, nat) 866fr_info_t *fin; 867ip_t *ip; 868ap_session_t *aps; 869nat_t *nat; 870{ 871 ftpinfo_t *ftp; 872 873 ftp = aps->aps_data; 874 if (ftp == NULL) 875 return 0; 876 return ippr_ftp_process(fin, ip, nat, ftp, 1); 877} 878 879 880/* 881 * ippr_ftp_atoi - implement a version of atoi which processes numbers in 882 * pairs separated by commas (which are expected to be in the range 0 - 255), 883 * returning a 16 bit number combining either side of the , as the MSB and 884 * LSB. 885 */ 886u_short ippr_ftp_atoi(ptr) 887char **ptr; 888{ 889 register char *s = *ptr, c; 890 register u_char i = 0, j = 0; 891 892 while ((c = *s++) && isdigit(c)) { 893 i *= 10; 894 i += c - '0'; 895 } 896 if (c != ',') { 897 *ptr = NULL; 898 return 0; 899 } 900 while ((c = *s++) && isdigit(c)) { 901 j *= 10; 902 j += c - '0'; 903 } 904 *ptr = s; 905 i &= 0xff; 906 j &= 0xff; 907 return (i << 8) | j; 908}
|