1 /* $FreeBSD$ */
2
3 /*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 *
8 * Simple FTP transparent proxy for in-kernel use. For use with the NAT
9 * code.
10 *
11 * $FreeBSD$
12 * Id: ip_ftp_pxy.c,v 2.88.2.19 2006/04/01 10:14:53 darrenr Exp $
13 */
14
15 #define IPF_FTP_PROXY
16
17 #define IPF_MINPORTLEN 18
18 #define IPF_MINEPRTLEN 20
19 #define IPF_MAXPORTLEN 30
20 #define IPF_MIN227LEN 39
21 #define IPF_MAX227LEN 51
22 #define IPF_MIN229LEN 47
23 #define IPF_MAX229LEN 51
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
42 #define FTPXY_JUNK_OK 0
43 #define FTPXY_JUNK_BAD 1 /* Ignore all commands for this connection */
44 #define FTPXY_JUNK_EOL 2 /* consume the rest of this line only */
45 #define FTPXY_JUNK_CONT 3 /* Saerching for next numeric */
46
47 /*
48 * Values for FTP commands. Numerics cover 0-999
49 */
50 #define FTPXY_C_PASV 1000
51 #define FTPXY_C_PORT 1001
52 #define FTPXY_C_EPSV 1002
53 #define FTPXY_C_EPRT 1003
54
55
56 typedef struct ipf_ftp_softc_s {
57 int ipf_p_ftp_pasvonly;
58 /* Do not require logins before transfers */
59 int ipf_p_ftp_insecure;
60 int ipf_p_ftp_pasvrdr;
61 /* PASV must be last command prior to 227 */
62 int ipf_p_ftp_forcepasv;
63 int ipf_p_ftp_debug;
64 int ipf_p_ftp_single_xfer;
65 void *ipf_p_ftp_tune;
66 } ipf_ftp_softc_t;
67
68
69 void ipf_p_ftp_main_load(void);
70 void ipf_p_ftp_main_unload(void);
71 void *ipf_p_ftp_soft_create(ipf_main_softc_t *);
72 void ipf_p_ftp_soft_destroy(ipf_main_softc_t *, void *);
73
74 int ipf_p_ftp_client(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
75 ftpinfo_t *, int);
76 int ipf_p_ftp_complete(char *, size_t);
77 int ipf_p_ftp_in(void *, fr_info_t *, ap_session_t *, nat_t *);
78 int ipf_p_ftp_new(void *, fr_info_t *, ap_session_t *, nat_t *);
79 void ipf_p_ftp_del(ipf_main_softc_t *, ap_session_t *);
80 int ipf_p_ftp_out(void *, fr_info_t *, ap_session_t *, nat_t *);
81 int ipf_p_ftp_pasv(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
82 ftpinfo_t *, int);
83 int ipf_p_ftp_epsv(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
84 ftpinfo_t *, int);
85 int ipf_p_ftp_port(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
86 ftpinfo_t *, int);
87 int ipf_p_ftp_process(ipf_ftp_softc_t *, fr_info_t *, nat_t *,
88 ftpinfo_t *, int);
89 int ipf_p_ftp_server(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
90 ftpinfo_t *, int);
91 int ipf_p_ftp_valid(ipf_ftp_softc_t *, ftpinfo_t *, int, char *, size_t);
92 int ipf_p_ftp_server_valid(ipf_ftp_softc_t *, ftpside_t *, char *,
93 size_t);
94 int ipf_p_ftp_client_valid(ipf_ftp_softc_t *, ftpside_t *, char *,
95 size_t);
96 u_short ipf_p_ftp_atoi(char **);
97 int ipf_p_ftp_pasvreply(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
98 ftpinfo_t *, u_int, char *, char *);
99 int ipf_p_ftp_eprt(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
100 ftpinfo_t *, int);
101 int ipf_p_ftp_eprt4(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
102 ftpinfo_t *, int);
103 int ipf_p_ftp_eprt6(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
104 ftpinfo_t *, int);
105 int ipf_p_ftp_addport(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
106 ftpinfo_t *, int, int, int);
107 void ipf_p_ftp_setpending(ipf_main_softc_t *, ftpinfo_t *);
108
109 /*
110 * Debug levels
111 */
112 #define DEBUG_SECURITY 0x01
113 #define DEBUG_ERROR 0x02
114 #define DEBUG_INFO 0x04
115 #define DEBUG_PARSE_ERR 0x08
116 #define DEBUG_PARSE_INFO 0x10
117 #define DEBUG_PARSE 0x20
118
119 static int ipf_p_ftp_proxy_init = 0;
120 static frentry_t ftppxyfr;
121 static ipftuneable_t ipf_ftp_tuneables[] = {
122 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_debug) },
123 "ftp_debug", 0, 0x7f,
124 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_debug),
125 0, NULL, NULL },
126 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_pasvonly) },
127 "ftp_pasvonly", 0, 1,
128 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_pasvonly),
129 0, NULL, NULL },
130 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_insecure) },
131 "ftp_insecure", 0, 1,
132 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_insecure),
133 0, NULL, NULL },
134 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_pasvrdr) },
135 "ftp_pasvrdr", 0, 1,
136 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_pasvrdr),
137 0, NULL, NULL },
138 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_forcepasv) },
139 "ftp_forcepasv", 0, 1,
140 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_forcepasv),
141 0, NULL, NULL },
142 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_single_xfer) },
143 "ftp_single_xfer", 0, 1,
144 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_single_xfer),
145 0, NULL, NULL },
146 { { NULL }, NULL, 0, 0, 0, 0, NULL, NULL }
147 };
148
149
150 void
151 ipf_p_ftp_main_load(void)
152 {
153 bzero((char *)&ftppxyfr, sizeof(ftppxyfr));
154 ftppxyfr.fr_ref = 1;
155 ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
156
157 MUTEX_INIT(&ftppxyfr.fr_lock, "FTP Proxy Mutex");
158 ipf_p_ftp_proxy_init = 1;
159 }
160
161
162 void
163 ipf_p_ftp_main_unload(void)
164 {
165
166 if (ipf_p_ftp_proxy_init == 1) {
167 MUTEX_DESTROY(&ftppxyfr.fr_lock);
168 ipf_p_ftp_proxy_init = 0;
169 }
170 }
171
172
173 /*
174 * Initialize local structures.
175 */
176 void *
177 ipf_p_ftp_soft_create(ipf_main_softc_t *softc)
178 {
179 ipf_ftp_softc_t *softf;
180
181 KMALLOC(softf, ipf_ftp_softc_t *);
182 if (softf == NULL)
183 return (NULL);
184
185 bzero((char *)softf, sizeof(*softf));
186 #if defined(_KERNEL)
187 softf->ipf_p_ftp_debug = 0;
188 #else
189 softf->ipf_p_ftp_debug = DEBUG_PARSE_ERR;
190 #endif
191 softf->ipf_p_ftp_forcepasv = 1;
192
193 softf->ipf_p_ftp_tune = ipf_tune_array_copy(softf,
194 sizeof(ipf_ftp_tuneables),
195 ipf_ftp_tuneables);
196 if (softf->ipf_p_ftp_tune == NULL) {
197 ipf_p_ftp_soft_destroy(softc, softf);
198 return (NULL);
199 }
200 if (ipf_tune_array_link(softc, softf->ipf_p_ftp_tune) == -1) {
201 ipf_p_ftp_soft_destroy(softc, softf);
202 return (NULL);
203 }
204
205 return (softf);
206 }
207
208
209 void
210 ipf_p_ftp_soft_destroy(ipf_main_softc_t *softc, void *arg)
211 {
212 ipf_ftp_softc_t *softf = arg;
213
214 if (softf->ipf_p_ftp_tune != NULL) {
215 ipf_tune_array_unlink(softc, softf->ipf_p_ftp_tune);
216 KFREES(softf->ipf_p_ftp_tune, sizeof(ipf_ftp_tuneables));
217 softf->ipf_p_ftp_tune = NULL;
218 }
219
220 KFREE(softf);
221 }
222
223
224 int
225 ipf_p_ftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
226 {
227 ftpinfo_t *ftp;
228 ftpside_t *f;
229
230 KMALLOC(ftp, ftpinfo_t *);
231 if (ftp == NULL)
232 return (-1);
233
234 nat = nat; /* LINT */
235
236 aps->aps_data = ftp;
237 aps->aps_psiz = sizeof(ftpinfo_t);
238 aps->aps_sport = htons(fin->fin_sport);
239 aps->aps_dport = htons(fin->fin_dport);
240
241 bzero((char *)ftp, sizeof(*ftp));
242 f = &ftp->ftp_side[0];
243 f->ftps_rptr = f->ftps_buf;
244 f->ftps_wptr = f->ftps_buf;
245 f = &ftp->ftp_side[1];
246 f->ftps_rptr = f->ftps_buf;
247 f->ftps_wptr = f->ftps_buf;
248 ftp->ftp_passok = FTPXY_INIT;
249 ftp->ftp_incok = 0;
250 return (0);
251 }
252
253
254 void
255 ipf_p_ftp_setpending(ipf_main_softc_t *softc, ftpinfo_t *ftp)
256 {
257 if (ftp->ftp_pendnat != NULL)
258 ipf_nat_setpending(softc, ftp->ftp_pendnat);
259
260 if (ftp->ftp_pendstate != NULL) {
261 READ_ENTER(&softc->ipf_state);
262 ipf_state_setpending(softc, ftp->ftp_pendstate);
263 RWLOCK_EXIT(&softc->ipf_state);
264 }
265 }
266
267
268 void
269 ipf_p_ftp_del(softc, aps)
270 ipf_main_softc_t *softc;
271 ap_session_t *aps;
272 {
273 ftpinfo_t *ftp;
274
275 ftp = aps->aps_data;
276 if (ftp != NULL)
277 ipf_p_ftp_setpending(softc, ftp);
278 }
279
280
281 int
282 ipf_p_ftp_port(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat,
283 ftpinfo_t *ftp, int dlen)
284 {
285 char newbuf[IPF_FTPBUFSZ], *s;
286 u_int a1, a2, a3, a4;
287 u_short a5, a6, sp;
288 size_t nlen, olen;
289 tcphdr_t *tcp;
290 int inc, off;
291 ftpside_t *f;
292 mb_t *m;
293
294 m = fin->fin_m;
295 f = &ftp->ftp_side[0];
296 tcp = (tcphdr_t *)fin->fin_dp;
297 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
298
299 /*
300 * Check for client sending out PORT message.
301 */
302 if (dlen < IPF_MINPORTLEN) {
303 DT3(ftp_PORT_error_dlen, nat_t *, nat, ftpside_t *, f,
304 u_int, dlen);
305 if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
306 printf("ipf_p_ftp_port:dlen(%d) < IPF_MINPORTLEN\n",
307 dlen);
308 return (0);
309 }
310 /*
311 * Skip the PORT command + space
312 */
313 s = f->ftps_rptr + 5;
314 /*
315 * Pick out the address components, two at a time.
316 */
317 a1 = ipf_p_ftp_atoi(&s);
318 if (s == NULL) {
319 DT2(ftp_PORT_error_atoi_1, nat_t *, nat, ftpside_t *, f);
320 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
321 printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 1);
322 return (0);
323 }
324 a2 = ipf_p_ftp_atoi(&s);
325 if (s == NULL) {
326 DT2(ftp_PORT_error_atoi_2, nat_t *, nat, ftpside_t *, f);
327 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
328 printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 2);
329 return (0);
330 }
331
332 /*
333 * Check that IP address in the PORT/PASV reply is the same as the
334 * sender of the command - prevents using PORT for port scanning.
335 */
336 a1 <<= 16;
337 a1 |= a2;
338 if (((nat->nat_dir == NAT_OUTBOUND) &&
339 (a1 != ntohl(nat->nat_osrcaddr))) ||
340 ((nat->nat_dir == NAT_INBOUND) &&
341 (a1 != ntohl(nat->nat_nsrcaddr)))) {
342 DT3(ftp_PORT_error_address, nat_t *, nat, ftpside_t *, f,
343 u_int, a1);
344 if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
345 printf("ipf_p_ftp_port:%s != nat->nat_inip\n", "a1");
346 return (APR_ERR(1));
347 }
348
349 a5 = ipf_p_ftp_atoi(&s);
350 if (s == NULL) {
351 DT2(ftp_PORT_error_atoi_3, nat_t *, nat, ftpside_t *, f);
352 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
353 printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 3);
354 return (0);
355 }
356 if (*s == ')')
357 s++;
358
359 /*
360 * check for CR-LF at the end.
361 */
362 if (*s == '\n')
363 s--;
364 if ((*s != '\r') || (*(s + 1) != '\n')) {
365 DT2(ftp_PORT_error_no_crlf, nat_t *, nat, ftpside_t *, f);
366 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
367 printf("ipf_p_ftp_port:missing %s\n", "cr-lf");
368 return (0);
369 }
370 s += 2;
371 a6 = a5 & 0xff;
372
373 /*
374 * Calculate the source port. Verification of > 1024 is in
375 * ipf_p_ftp_addport.
376 */
377 a5 >>= 8;
378 a5 &= 0xff;
379 sp = a5 << 8 | a6;
380
381 /*
382 * Calculate new address parts for PORT command
383 */
384 if (nat->nat_dir == NAT_INBOUND)
385 a1 = ntohl(nat->nat_ndstaddr);
386 else
387 a1 = ntohl(ip->ip_src.s_addr);
388 a1 = ntohl(ip->ip_src.s_addr);
389 a2 = (a1 >> 16) & 0xff;
390 a3 = (a1 >> 8) & 0xff;
391 a4 = a1 & 0xff;
392 a1 >>= 24;
393 olen = s - f->ftps_rptr;
394 (void) snprintf(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n",
395 "PORT", a1, a2, a3, a4, a5, a6);
396
397 nlen = strlen(newbuf);
398 inc = nlen - olen;
399 if ((inc + fin->fin_plen) > 65535) {
400 DT3(ftp_PORT_error_inc, nat_t *, nat, ftpside_t *, f,
401 int, inc);
402 if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
403 printf("ipf_p_ftp_port:inc(%d) + ip->ip_len > 65535\n",
404 inc);
405 return (0);
406 }
407
408 #if !defined(_KERNEL)
409 M_ADJ(m, inc);
410 #else
411 /*
412 * m_adj takes care of pkthdr.len, if required and treats inc<0 to
413 * mean remove -len bytes from the end of the packet.
414 * The mbuf chain will be extended if necessary by m_copyback().
415 */
416 if (inc < 0)
417 M_ADJ(m, inc);
418 #endif /* !defined(_KERNEL) */
419 COPYBACK(m, off, nlen, newbuf);
420 fin->fin_flx |= FI_DOCKSUM;
421
422 if (inc != 0) {
423 fin->fin_plen += inc;
424 ip->ip_len = htons(fin->fin_plen);
425 fin->fin_dlen += inc;
426 }
427
428 f->ftps_cmd = FTPXY_C_PORT;
429 return (ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, sp, inc));
430 }
431
432
433 int
434 ipf_p_ftp_addport(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat,
435 ftpinfo_t *ftp, int dlen, int nport, int inc)
436 {
437 tcphdr_t tcph, *tcp2 = &tcph;
438 ipf_main_softc_t *softc;
439 ipf_nat_softc_t *softn;
440 int direction;
441 fr_info_t fi;
442 ipnat_t *ipn;
443 nat_t *nat2;
444 u_short sp;
445 int flags;
446
447 softc = fin->fin_main_soft;
448 softn = softc->ipf_nat_soft;
449
450 if ((ftp->ftp_pendnat != NULL) || (ftp->ftp_pendstate != NULL)) {
451 if (softf->ipf_p_ftp_single_xfer != 0) {
452 DT2(ftp_PORT_error_add_active, nat_t *, nat,
453 ftpinfo_t *, ftp);
454 if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
455 printf("ipf_p_ftp_addport:xfer active %p/%p\n",
456 ftp->ftp_pendnat, ftp->ftp_pendstate);
457 return (0);
458 }
459 ipf_p_ftp_setpending(softc, ftp);
460 }
461
462 /*
463 * Add skeleton NAT entry for connection which will come back the
464 * other way.
465 */
466 sp = nport;
467 /*
468 * Don't allow the PORT command to specify a port < 1024 due to
469 * security risks.
470 */
471 if (sp < 1024) {
472 DT3(ftp_PORT_error_port, nat_t *, nat, ftpinfo_t *, ftp,
473 u_int, sp);
474 if (softf->ipf_p_ftp_debug & DEBUG_SECURITY)
475 printf("ipf_p_ftp_addport:sp(%d) < 1024\n", sp);
476 return (0);
477 }
478 /*
479 * The server may not make the connection back from port 20, but
480 * it is the most likely so use it here to check for a conflicting
481 * mapping.
482 */
483 bcopy((char *)fin, (char *)&fi, sizeof(fi));
484 fi.fin_flx |= FI_IGNORE;
485 fi.fin_data[0] = sp;
486 fi.fin_data[1] = fin->fin_data[1] - 1;
487 fi.fin_src6 = nat->nat_ndst6;
488 fi.fin_dst6 = nat->nat_nsrc6;
489
490 #ifndef USE_INET6
491 if (nat->nat_v[0] == 6)
492 return (APR_INC(inc));
493 #endif
494
495 /*
496 * If an existing entry already exists, use it instead.
497 */
498 #ifdef USE_INET6
499 if (nat->nat_v[0] == 6) {
500 if (nat->nat_dir == NAT_OUTBOUND) {
501 nat2 = ipf_nat6_outlookup(&fi, IPN_TCP|NAT_SEARCH,
502 nat->nat_pr[1],
503 &nat->nat_osrc6.in6,
504 &nat->nat_odst6.in6);
505 } else {
506 nat2 = ipf_nat6_inlookup(&fi, IPN_TCP|NAT_SEARCH,
507 nat->nat_pr[0],
508 &nat->nat_odst6.in6,
509 &nat->nat_osrc6.in6);
510 }
511 } else
512 #endif
513 {
514 if (nat->nat_dir == NAT_OUTBOUND) {
515 nat2 = ipf_nat_outlookup(&fi, IPN_TCP|NAT_SEARCH,
516 nat->nat_pr[1],
517 nat->nat_osrcip,
518 nat->nat_odstip);
519 } else {
520 nat2 = ipf_nat_inlookup(&fi, IPN_TCP|NAT_SEARCH,
521 nat->nat_pr[0],
522 nat->nat_odstip,
523 nat->nat_osrcip);
524 }
525 }
526 if (nat2 != NULL)
527 return (APR_INC(inc));
528
529 /*
530 * An existing entry doesn't exist. Let's make one.
531 */
532 ipn = ipf_proxy_rule_rev(nat);
533 if (ipn == NULL)
534 return (APR_ERR(1));
535 ipn->in_use = 0;
536
537 fi.fin_fr = &ftppxyfr;
538 fi.fin_dp = (char *)tcp2;
539 fi.fin_dlen = sizeof(*tcp2);
540 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
541 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
542 fi.fin_data[1] = sp;
543 fi.fin_data[0] = 0;
544
545 bzero((char *)tcp2, sizeof(*tcp2));
546 tcp2->th_sport = 0;
547 tcp2->th_dport = htons(sp);
548
549 tcp2->th_win = htons(8192);
550 TCP_OFF_A(tcp2, 5);
551 tcp2->th_flags = TH_SYN;
552
553 if (nat->nat_dir == NAT_INBOUND) {
554 fi.fin_out = 1;
555 direction = NAT_OUTBOUND;
556 } else {
557 fi.fin_out = 0;
558 direction = NAT_INBOUND;
559 }
560 flags = SI_W_SPORT|NAT_SLAVE|IPN_TCP;
561
562 MUTEX_ENTER(&softn->ipf_nat_new);
563 #ifdef USE_INET6
564 if (nat->nat_v[0] == 6)
565 nat2 = ipf_nat6_add(&fi, ipn, &ftp->ftp_pendnat, flags,
566 direction);
567 else
568 #endif
569 nat2 = ipf_nat_add(&fi, ipn, &ftp->ftp_pendnat, flags,
570 direction);
571 MUTEX_EXIT(&softn->ipf_nat_new);
572
573 if (nat2 == NULL) {
574 KFREES(ipn, ipn->in_size);
575 return (APR_ERR(1));
576 }
577
578 (void) ipf_nat_proto(&fi, nat2, IPN_TCP);
579 MUTEX_ENTER(&nat2->nat_lock);
580 ipf_nat_update(&fi, nat2);
581 MUTEX_EXIT(&nat2->nat_lock);
582 fi.fin_ifp = NULL;
583 if (nat2->nat_dir == NAT_INBOUND)
584 fi.fin_dst6 = nat->nat_osrc6;
585 if (ipf_state_add(softc, &fi, (ipstate_t **)&ftp->ftp_pendstate,
586 SI_W_SPORT) != 0)
587 ipf_nat_setpending(softc, nat2);
588
589 return (APR_INC(inc));
590 }
591
592
593 int
594 ipf_p_ftp_client(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip,
595 nat_t *nat, ftpinfo_t *ftp, int dlen)
596 {
597 char *rptr, *wptr, cmd[6], c;
598 ftpside_t *f;
599 int inc, i;
600
601 inc = 0;
602 f = &ftp->ftp_side[0];
603 rptr = f->ftps_rptr;
604 wptr = f->ftps_wptr;
605
606 for (i = 0; (i < 5) && (i < dlen); i++) {
607 c = rptr[i];
608 if (ISALPHA(c)) {
609 cmd[i] = TOUPPER(c);
610 } else {
611 cmd[i] = c;
612 }
613 }
614 cmd[i] = '\0';
615
616 ftp->ftp_incok = 0;
617 DT2(ftp_client_command, char [], cmd, int, ftp->ftp_passok);
618 if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) {
619 if (ftp->ftp_passok == FTPXY_ADOK_1 ||
620 ftp->ftp_passok == FTPXY_AUOK_1) {
621 ftp->ftp_passok = FTPXY_USER_2;
622 ftp->ftp_incok = 1;
623 } else {
624 ftp->ftp_passok = FTPXY_USER_1;
625 ftp->ftp_incok = 1;
626 }
627 } else if (!strncmp(cmd, "AUTH ", 5)) {
628 ftp->ftp_passok = FTPXY_AUTH_1;
629 ftp->ftp_incok = 1;
630 } else if (!strncmp(cmd, "PASS ", 5)) {
631 if (ftp->ftp_passok == FTPXY_USOK_1) {
632 ftp->ftp_passok = FTPXY_PASS_1;
633 ftp->ftp_incok = 1;
634 } else if (ftp->ftp_passok == FTPXY_USOK_2) {
635 ftp->ftp_passok = FTPXY_PASS_2;
636 ftp->ftp_incok = 1;
637 }
638 } else if ((ftp->ftp_passok == FTPXY_AUOK_1) &&
639 !strncmp(cmd, "ADAT ", 5)) {
640 ftp->ftp_passok = FTPXY_ADAT_1;
641 ftp->ftp_incok = 1;
642 } else if ((ftp->ftp_passok == FTPXY_PAOK_1 ||
643 ftp->ftp_passok == FTPXY_PAOK_2) &&
644 !strncmp(cmd, "ACCT ", 5)) {
645 ftp->ftp_passok = FTPXY_ACCT_1;
646 ftp->ftp_incok = 1;
647 } else if ((ftp->ftp_passok == FTPXY_GO) &&
648 !softf->ipf_p_ftp_pasvonly &&
649 !strncmp(cmd, "PORT ", 5)) {
650 inc = ipf_p_ftp_port(softf, fin, ip, nat, ftp, dlen);
651 } else if ((ftp->ftp_passok == FTPXY_GO) &&
652 !softf->ipf_p_ftp_pasvonly &&
653 !strncmp(cmd, "EPRT ", 5)) {
654 inc = ipf_p_ftp_eprt(softf, fin, ip, nat, ftp, dlen);
655 } else if (softf->ipf_p_ftp_insecure &&
656 !softf->ipf_p_ftp_pasvonly &&
657 !strncmp(cmd, "PORT ", 5)) {
658 inc = ipf_p_ftp_port(softf, fin, ip, nat, ftp, dlen);
659 }
660 if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
661 printf("ipf_p_ftp_client: cmd[%s] passok %d incok %d inc %d\n",
662 cmd, ftp->ftp_passok, ftp->ftp_incok, inc);
663
664 DT2(ftp_client_passok, char *, cmd, int, ftp->ftp_passok);
665 while ((*rptr++ != '\n') && (rptr < wptr))
666 ;
667 f->ftps_rptr = rptr;
668 return (inc);
669 }
670
671
672 int
673 ipf_p_ftp_pasv(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat,
674 ftpinfo_t *ftp, int dlen)
675 {
676 u_int a1, a2, a3, a4, data_ip;
677 char newbuf[IPF_FTPBUFSZ];
678 const char *brackets[2];
679 u_short a5, a6;
680 ftpside_t *f;
681 char *s;
682
683 if ((softf->ipf_p_ftp_forcepasv != 0) &&
684 (ftp->ftp_side[0].ftps_cmd != FTPXY_C_PASV)) {
685 DT2(ftp_PASV_error_state, nat_t *, nat, ftpinfo_t *, ftp);
686 if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
687 printf("ipf_p_ftp_pasv:ftps_cmd(%d) != FTPXY_C_PASV\n",
688 ftp->ftp_side[0].ftps_cmd);
689 return (0);
690 }
691
692 f = &ftp->ftp_side[1];
693
694 #define PASV_REPLEN 24
695 /*
696 * Check for PASV reply message.
697 */
698 if (dlen < IPF_MIN227LEN) {
699 DT3(ftp_PASV_error_short, nat_t *, nat, ftpinfo_t *, ftp,
700 int, dlen);
701 if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
702 printf("ipf_p_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n",
703 dlen);
704 return (0);
705 } else if (strncmp(f->ftps_rptr,
706 "227 Entering Passive Mod", PASV_REPLEN)) {
707 DT2(ftp_PASV_error_string, nat_t *, nat, ftpinfo_t *, ftp);
708 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
709 printf("ipf_p_ftp_pasv:%d reply wrong\n", 227);
710 return (0);
711 }
712
713 brackets[0] = "";
714 brackets[1] = "";
715 /*
716 * Skip the PASV reply + space
717 */
718 s = f->ftps_rptr + PASV_REPLEN;
719 while (*s && !ISDIGIT(*s)) {
720 if (*s == '(') {
721 brackets[0] = "(";
722 brackets[1] = ")";
723 }
724 s++;
725 }
726
727 /*
728 * Pick out the address components, two at a time.
729 */
730 a1 = ipf_p_ftp_atoi(&s);
731 if (s == NULL) {
732 DT2(ftp_PASV_error_atoi_1, nat_t *, nat, ftpside_t *, f);
733 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
734 printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 1);
735 return (0);
736 }
737 a2 = ipf_p_ftp_atoi(&s);
738 if (s == NULL) {
739 DT2(ftp_PASV_error_atoi_2, nat_t *, nat, ftpside_t *, f);
740 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
741 printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 2);
742 return (0);
743 }
744
745 /*
746 * check that IP address in the PASV reply is the same as the
747 * sender of the command - prevents using PASV for port scanning.
748 */
749 a1 <<= 16;
750 a1 |= a2;
751
752 if (((nat->nat_dir == NAT_INBOUND) &&
753 (a1 != ntohl(nat->nat_ndstaddr))) ||
754 ((nat->nat_dir == NAT_OUTBOUND) &&
755 (a1 != ntohl(nat->nat_odstaddr)))) {
756 DT3(ftp_PASV_error_address, nat_t *, nat, ftpside_t *, f,
757 u_int, a1);
758 if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
759 printf("ipf_p_ftp_pasv:%s != nat->nat_oip\n", "a1");
760 return (0);
761 }
762
763 a5 = ipf_p_ftp_atoi(&s);
764 if (s == NULL) {
765 DT2(ftp_PASV_error_atoi_3, nat_t *, nat, ftpside_t *, f);
766 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
767 printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 3);
768 return (0);
769 }
770
771 if (*s == ')')
772 s++;
773 if (*s == '.')
774 s++;
775 if (*s == '\n')
776 s--;
777 /*
778 * check for CR-LF at the end.
779 */
780 if ((*s != '\r') || (*(s + 1) != '\n')) {
781 DT(pasv_missing_crlf);
782 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
783 printf("ipf_p_ftp_pasv:missing %s", "cr-lf\n");
784 return (0);
785 }
786 s += 2;
787
788 a6 = a5 & 0xff;
789 a5 >>= 8;
790 /*
791 * Calculate new address parts for 227 reply
792 */
793 if (nat->nat_dir == NAT_INBOUND) {
794 data_ip = nat->nat_odstaddr;
795 a1 = ntohl(data_ip);
796 } else
797 data_ip = htonl(a1);
798
799 a2 = (a1 >> 16) & 0xff;
800 a3 = (a1 >> 8) & 0xff;
801 a4 = a1 & 0xff;
802 a1 >>= 24;
803
804 (void) snprintf(newbuf, sizeof(newbuf), "%s %s%u,%u,%u,%u,%u,%u%s\r\n",
805 "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4,
806 a5, a6, brackets[1]);
807 return (ipf_p_ftp_pasvreply(softf, fin, ip, nat, ftp, (a5 << 8 | a6),
808 newbuf, s));
809 }
810
811 int
812 ipf_p_ftp_pasvreply(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip,
813 nat_t *nat, ftpinfo_t *ftp, u_int port, char *newmsg, char *s)
814 {
815 int inc, off, nflags;
816 tcphdr_t *tcp, tcph, *tcp2;
817 ipf_main_softc_t *softc;
818 ipf_nat_softc_t *softn;
819 size_t nlen, olen;
820 #ifdef USE_INET6
821 ip6_t *ip6;
822 #endif
823 ipnat_t *ipn;
824 fr_info_t fi;
825 ftpside_t *f;
826 nat_t *nat2;
827 mb_t *m;
828
829 softc = fin->fin_main_soft;
830 softn = softc->ipf_nat_soft;
831
832 if ((ftp->ftp_pendnat != NULL) || (ftp->ftp_pendstate != NULL))
833 ipf_p_ftp_setpending(softc, ftp);
834
835 m = fin->fin_m;
836 tcp = (tcphdr_t *)fin->fin_dp;
837 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
838
839 tcp2 = &tcph;
840 inc = 0;
841
842 f = &ftp->ftp_side[1];
843 olen = s - f->ftps_rptr;
844 nlen = strlen(newmsg);
845 inc = nlen - olen;
846 if ((inc + fin->fin_plen) > 65535) {
847 DT3(ftp_PASV_error_inc, nat_t *, nat, ftpside_t *, f,
848 int, inc);
849 if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
850 printf("ipf_p_ftp_pasv:inc(%d) + ip->ip_len > 65535\n",
851 inc);
852 return (0);
853 }
854
855 ipn = ipf_proxy_rule_fwd(nat);
856 if (ipn == NULL)
857 return (APR_ERR(1));
858 ipn->in_use = 0;
859
860 /*
861 * Add skeleton NAT entry for connection which will come back the
862 * other way.
863 */
864 bzero((char *)tcp2, sizeof(*tcp2));
865 bcopy((char *)fin, (char *)&fi, sizeof(fi));
866 fi.fin_flx |= FI_IGNORE;
867 fi.fin_data[0] = 0;
868 fi.fin_data[1] = port;
869 nflags = IPN_TCP|SI_W_SPORT;
870
871 fi.fin_fr = &ftppxyfr;
872 fi.fin_dp = (char *)tcp2;
873 fi.fin_out = 1 - fin->fin_out;
874 fi.fin_dlen = sizeof(*tcp2);
875 fi.fin_src6 = nat->nat_osrc6;
876 fi.fin_dst6 = nat->nat_odst6;
877 fi.fin_plen = fi.fin_hlen + sizeof(*tcp);
878 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
879
880 TCP_OFF_A(tcp2, 5);
881 tcp2->th_flags = TH_SYN;
882 tcp2->th_win = htons(8192);
883 tcp2->th_dport = htons(port);
884
885 MUTEX_ENTER(&softn->ipf_nat_new);
886 #ifdef USE_INET6
887 if (nat->nat_v[0] == 6)
888 nat2 = ipf_nat6_add(&fi, ipn, &ftp->ftp_pendnat,
889 nflags, nat->nat_dir);
890 else
891 #endif
892 nat2 = ipf_nat_add(&fi, ipn, &ftp->ftp_pendnat,
893 nflags, nat->nat_dir);
894 MUTEX_EXIT(&softn->ipf_nat_new);
895
896 if (nat2 == NULL) {
897 KFREES(ipn, ipn->in_size);
898 return (APR_ERR(1));
899 }
900
901 (void) ipf_nat_proto(&fi, nat2, IPN_TCP);
902 MUTEX_ENTER(&nat2->nat_lock);
903 ipf_nat_update(&fi, nat2);
904 MUTEX_EXIT(&nat2->nat_lock);
905 fi.fin_ifp = NULL;
906 if (nat->nat_dir == NAT_INBOUND) {
907 #ifdef USE_INET6
908 if (nat->nat_v[0] == 6)
909 fi.fin_dst6 = nat->nat_ndst6;
910 else
911 #endif
912 fi.fin_daddr = nat->nat_ndstaddr;
913 }
914 if (ipf_state_add(softc, &fi, (ipstate_t **)&ftp->ftp_pendstate,
915 SI_W_SPORT) != 0)
916 ipf_nat_setpending(softc, nat2);
917
918 #if !defined(_KERNEL)
919 M_ADJ(m, inc);
920 #else
921 /*
922 * m_adj takes care of pkthdr.len, if required and treats inc<0 to
923 * mean remove -len bytes from the end of the packet.
924 * The mbuf chain will be extended if necessary by m_copyback().
925 */
926 if (inc < 0)
927 M_ADJ(m, inc);
928 #endif /* !defined(_KERNEL) */
929 COPYBACK(m, off, nlen, newmsg);
930 fin->fin_flx |= FI_DOCKSUM;
931
932 if (inc != 0) {
933 fin->fin_plen += inc;
934 fin->fin_dlen += inc;
935 #ifdef USE_INET6
936 if (nat->nat_v[0] == 6) {
937 ip6 = (ip6_t *)fin->fin_ip;
938 u_short len = ntohs(ip6->ip6_plen) + inc;
939 ip6->ip6_plen = htons(len);
940 } else
941 #endif
942 ip->ip_len = htons(fin->fin_plen);
943 }
944
945 return (APR_INC(inc));
946 }
947
948
949 int
950 ipf_p_ftp_server(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat,
951 ftpinfo_t *ftp, int dlen)
952 {
953 char *rptr, *wptr;
954 ftpside_t *f;
955 int inc;
956
957 inc = 0;
958 f = &ftp->ftp_side[1];
959 rptr = f->ftps_rptr;
960 wptr = f->ftps_wptr;
961
962 DT2(ftp_server_response, char *, rptr, int, ftp->ftp_passok);
963 if (*rptr == ' ')
964 goto server_cmd_ok;
965 if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2)))
966 return (0);
967 if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
968 printf("ipf_p_ftp_server_1: cmd[%4.4s] passok %d\n",
969 rptr, ftp->ftp_passok);
970 if (ftp->ftp_passok == FTPXY_GO) {
971 if (!strncmp(rptr, "227 ", 4))
972 inc = ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen);
973 else if (!strncmp(rptr, "229 ", 4))
974 inc = ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen);
975 else if (strncmp(rptr, "200", 3)) {
976 /*
977 * 200 is returned for a successful command.
978 */
979 ;
980 }
981 } else if (softf->ipf_p_ftp_insecure && !strncmp(rptr, "227 ", 4)) {
982 inc = ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen);
983 } else if (softf->ipf_p_ftp_insecure && !strncmp(rptr, "229 ", 4)) {
984 inc = ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen);
985 } else if (*rptr == '5' || *rptr == '4')
986 ftp->ftp_passok = FTPXY_INIT;
987 else if (ftp->ftp_incok) {
988 if (*rptr == '3') {
989 if (ftp->ftp_passok == FTPXY_ACCT_1)
990 ftp->ftp_passok = FTPXY_GO;
991 else
992 ftp->ftp_passok++;
993 } else if (*rptr == '2') {
994 switch (ftp->ftp_passok)
995 {
996 case FTPXY_USER_1 :
997 case FTPXY_USER_2 :
998 case FTPXY_PASS_1 :
999 case FTPXY_PASS_2 :
1000 case FTPXY_ACCT_1 :
1001 ftp->ftp_passok = FTPXY_GO;
1002 break;
1003 default :
1004 ftp->ftp_passok += 3;
1005 break;
1006 }
1007 }
1008 }
1009 ftp->ftp_incok = 0;
1010 server_cmd_ok:
1011 if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
1012 printf("ipf_p_ftp_server_2: cmd[%4.4s] passok %d\n",
1013 rptr, ftp->ftp_passok);
1014 DT3(ftp_server_passok, char *,rptr, int, ftp->ftp_incok,
1015 int, ftp->ftp_passok);
1016
1017 while ((*rptr++ != '\n') && (rptr < wptr))
1018 ;
1019 f->ftps_rptr = rptr;
1020 return (inc);
1021 }
1022
1023
1024 /*
1025 * 0 FTPXY_JUNK_OK
1026 * 1 FTPXY_JUNK_BAD
1027 * 2 FTPXY_JUNK_EOL
1028 * 3 FTPXY_JUNK_CONT
1029 *
1030 * Look to see if the buffer starts with something which we recognise as
1031 * being the correct syntax for the FTP protocol.
1032 */
1033 int
1034 ipf_p_ftp_client_valid(ipf_ftp_softc_t *softf, ftpside_t *ftps, char *buf,
1035 size_t len)
1036 {
1037 register char *s, c, pc;
1038 register size_t i = len;
1039 char cmd[5];
1040
1041 s = buf;
1042
1043 if (ftps->ftps_junk == FTPXY_JUNK_BAD)
1044 return (FTPXY_JUNK_BAD);
1045
1046 if (i < 5) {
1047 DT1(client_valid, int, i);
1048 if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
1049 printf("ipf_p_ftp_client_valid:i(%d) < 5\n", (int)i);
1050 return (2);
1051 }
1052
1053 i--;
1054 c = *s++;
1055
1056 if (ISALPHA(c)) {
1057 cmd[0] = TOUPPER(c);
1058 c = *s++;
1059 i--;
1060 if (ISALPHA(c)) {
1061 cmd[1] = TOUPPER(c);
1062 c = *s++;
1063 i--;
1064 if (ISALPHA(c)) {
1065 cmd[2] = TOUPPER(c);
1066 c = *s++;
1067 i--;
1068 if (ISALPHA(c)) {
1069 cmd[3] = TOUPPER(c);
1070 c = *s++;
1071 i--;
1072 if ((c != ' ') && (c != '\r'))
1073 goto bad_client_command;
1074 } else if ((c != ' ') && (c != '\r'))
1075 goto bad_client_command;
1076 } else
1077 goto bad_client_command;
1078 } else
1079 goto bad_client_command;
1080 } else {
1081 bad_client_command:
1082 DT4(client_junk, int, len, int, i, int, c, char *, buf);
1083 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
1084 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n",
1085 "ipf_p_ftp_client_valid",
1086 ftps->ftps_junk, (int)len, (int)i, c,
1087 (int)len, (int)len, buf);
1088 return (FTPXY_JUNK_BAD);
1089 }
1090
1091 for (; i; i--) {
1092 pc = c;
1093 c = *s++;
1094 if ((pc == '\r') && (c == '\n')) {
1095 cmd[4] = '\0';
1096 if (!strcmp(cmd, "PASV")) {
1097 ftps->ftps_cmd = FTPXY_C_PASV;
1098 } else if (!strcmp(cmd, "EPSV")) {
1099 ftps->ftps_cmd = FTPXY_C_EPSV;
1100 } else {
1101 ftps->ftps_cmd = 0;
1102 }
1103 return (0);
1104 }
1105 }
1106 #if !defined(_KERNEL)
1107 printf("ipf_p_ftp_client_valid:junk after cmd[%*.*s]\n",
1108 (int)len, (int)len, buf);
1109 #endif
1110 return (FTPXY_JUNK_EOL);
1111 }
1112
1113
1114 int
1115 ipf_p_ftp_server_valid(ipf_ftp_softc_t *softf, ftpside_t *ftps, char *buf,
1116 size_t len)
1117 {
1118 register char *s, c, pc;
1119 register size_t i = len;
1120 int cmd;
1121
1122 s = buf;
1123 cmd = 0;
1124
1125 if (ftps->ftps_junk == FTPXY_JUNK_BAD)
1126 return (FTPXY_JUNK_BAD);
1127
1128 if (i < 5) {
1129 DT1(server_valid, int, i);
1130 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
1131 printf("ipf_p_ftp_servert_valid:i(%d) < 5\n", (int)i);
1132 return (2);
1133 }
1134
1135 c = *s++;
1136 i--;
1137 if (c == ' ') {
1138 cmd = -1;
1139 goto search_eol;
1140 }
1141
1142 if (ISDIGIT(c)) {
1143 cmd = (c - '') * 100;
1144 c = *s++;
1145 i--;
1146 if (ISDIGIT(c)) {
1147 cmd += (c - '') * 10;
1148 c = *s++;
1149 i--;
1150 if (ISDIGIT(c)) {
1151 cmd += (c - '');
1152 c = *s++;
1153 i--;
1154 if ((c != '-') && (c != ' '))
1155 goto bad_server_command;
1156 if (c == '-')
1157 return (FTPXY_JUNK_CONT);
1158 } else
1159 goto bad_server_command;
1160 } else
1161 goto bad_server_command;
1162 } else {
1163 bad_server_command:
1164 DT4(server_junk, int len, buf, int, i, int, c, char *, buf);
1165 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO)
1166 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n",
1167 "ipf_p_ftp_server_valid",
1168 ftps->ftps_junk, (int)len, (int)i,
1169 c, (int)len, (int)len, buf);
1170 if (ftps->ftps_junk == FTPXY_JUNK_CONT)
1171 return (FTPXY_JUNK_CONT);
1172 return (FTPXY_JUNK_BAD);
1173 }
1174 search_eol:
1175 for (; i; i--) {
1176 pc = c;
1177 c = *s++;
1178 if ((pc == '\r') && (c == '\n')) {
1179 if (cmd == -1) {
1180 if (ftps->ftps_junk == FTPXY_JUNK_CONT)
1181 return (FTPXY_JUNK_CONT);
1182 } else {
1183 ftps->ftps_cmd = cmd;
1184 }
1185 return (FTPXY_JUNK_OK);
1186 }
1187 }
1188
1189 DT2(junk_eol, int, len, char *, buf);
1190 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO)
1191 printf("ipf_p_ftp_server_valid:junk after cmd[%*.*s]\n",
1192 (int)len, (int)len, buf);
1193 return (FTPXY_JUNK_EOL);
1194 }
1195
1196
1197 int
1198 ipf_p_ftp_valid(ipf_ftp_softc_t *softf, ftpinfo_t *ftp, int side, char *buf,
1199 size_t len)
1200 {
1201 ftpside_t *ftps;
1202
1203 ftps = &ftp->ftp_side[side];
1204
1205 if (side == 0)
1206 return (ipf_p_ftp_client_valid(softf, ftps, buf, len));
1207 else
1208 return (ipf_p_ftp_server_valid(softf, ftps, buf, len));
1209 }
1210
1211
1212 /*
1213 * For map rules, the following applies:
1214 * rv == 0 for outbound processing,
1215 * rv == 1 for inbound processing.
1216 * For rdr rules, the following applies:
1217 * rv == 0 for inbound processing,
1218 * rv == 1 for outbound processing.
1219 */
1220 int
1221 ipf_p_ftp_process(ipf_ftp_softc_t *softf, fr_info_t *fin, nat_t *nat,
1222 ftpinfo_t *ftp, int rv)
1223 {
1224 int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff, retry;
1225 char *rptr, *wptr, *s;
1226 u_32_t thseq, thack;
1227 ap_session_t *aps;
1228 ftpside_t *f, *t;
1229 tcphdr_t *tcp;
1230 ip_t *ip;
1231 mb_t *m;
1232
1233 m = fin->fin_m;
1234 ip = fin->fin_ip;
1235 tcp = (tcphdr_t *)fin->fin_dp;
1236 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
1237
1238 f = &ftp->ftp_side[rv];
1239 t = &ftp->ftp_side[1 - rv];
1240 thseq = ntohl(tcp->th_seq);
1241 thack = ntohl(tcp->th_ack);
1242 mlen = MSGDSIZE(m) - off;
1243
1244 DT3(process_debug, tcphdr_t *, tcp, int, off, int, mlen);
1245 if (softf->ipf_p_ftp_debug & DEBUG_INFO)
1246 printf("ipf_p_ftp_process: %d:%d,%d, mlen %d flags %x\n",
1247 fin->fin_out, fin->fin_sport, fin->fin_dport,
1248 mlen, tcp->th_flags);
1249
1250 if ((mlen == 0) && ((tcp->th_flags & TH_OPENING) == TH_OPENING)) {
1251 f->ftps_seq[0] = thseq + 1;
1252 t->ftps_seq[0] = thack;
1253 return (0);
1254 } else if (mlen < 0) {
1255 return (0);
1256 }
1257
1258 aps = nat->nat_aps;
1259
1260 sel = aps->aps_sel[1 - rv];
1261 sel2 = aps->aps_sel[rv];
1262 if (rv == 1) {
1263 seqoff = aps->aps_seqoff[sel];
1264 if (aps->aps_seqmin[sel] > seqoff + thseq)
1265 seqoff = aps->aps_seqoff[!sel];
1266 ackoff = aps->aps_ackoff[sel2];
1267 if (aps->aps_ackmin[sel2] > ackoff + thack)
1268 ackoff = aps->aps_ackoff[!sel2];
1269 } else {
1270 seqoff = aps->aps_ackoff[sel];
1271 if (softf->ipf_p_ftp_debug & DEBUG_INFO)
1272 printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq,
1273 aps->aps_ackmin[sel]);
1274 if (aps->aps_ackmin[sel] > seqoff + thseq)
1275 seqoff = aps->aps_ackoff[!sel];
1276
1277 ackoff = aps->aps_seqoff[sel2];
1278 if (softf->ipf_p_ftp_debug & DEBUG_INFO)
1279 printf("ackoff %d thack %x seqmin %x\n", ackoff, thack,
1280 aps->aps_seqmin[sel2]);
1281 if (ackoff > 0) {
1282 if (aps->aps_seqmin[sel2] > ackoff + thack)
1283 ackoff = aps->aps_seqoff[!sel2];
1284 } else {
1285 if (aps->aps_seqmin[sel2] > thack)
1286 ackoff = aps->aps_seqoff[!sel2];
1287 }
1288 }
1289 if (softf->ipf_p_ftp_debug & DEBUG_INFO) {
1290 printf("%s: %x seq %x/%d ack %x/%d len %d/%d off %d\n",
1291 rv ? "IN" : "OUT", tcp->th_flags, thseq, seqoff,
1292 thack, ackoff, mlen, fin->fin_plen, off);
1293 printf("sel %d seqmin %x/%x offset %d/%d\n", sel,
1294 aps->aps_seqmin[sel], aps->aps_seqmin[sel2],
1295 aps->aps_seqoff[sel], aps->aps_seqoff[sel2]);
1296 printf("sel %d ackmin %x/%x offset %d/%d\n", sel2,
1297 aps->aps_ackmin[sel], aps->aps_ackmin[sel2],
1298 aps->aps_ackoff[sel], aps->aps_ackoff[sel2]);
1299 }
1300
1301 /*
1302 * XXX - Ideally, this packet should get dropped because we now know
1303 * that it is out of order (and there is no real danger in doing so
1304 * apart from causing packets to go through here ordered).
1305 */
1306 if (softf->ipf_p_ftp_debug & DEBUG_INFO) {
1307 printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n",
1308 rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff);
1309 }
1310
1311 ok = 0;
1312 if (t->ftps_seq[0] == 0) {
1313 t->ftps_seq[0] = thack;
1314 ok = 1;
1315 } else {
1316 if (ackoff == 0) {
1317 if (t->ftps_seq[0] == thack)
1318 ok = 1;
1319 else if (t->ftps_seq[1] == thack) {
1320 t->ftps_seq[0] = thack;
1321 ok = 1;
1322 }
1323 } else {
1324 if (t->ftps_seq[0] + ackoff == thack) {
1325 t->ftps_seq[0] = thack;
1326 ok = 1;
1327 } else if (t->ftps_seq[0] == thack + ackoff) {
1328 t->ftps_seq[0] = thack + ackoff;
1329 ok = 1;
1330 } else if (t->ftps_seq[1] + ackoff == thack) {
1331 t->ftps_seq[0] = thack;
1332 ok = 1;
1333 } else if (t->ftps_seq[1] == thack + ackoff) {
1334 t->ftps_seq[0] = thack + ackoff;
1335 ok = 1;
1336 }
1337 }
1338 }
1339
1340 if (softf->ipf_p_ftp_debug & DEBUG_INFO) {
1341 if (!ok)
1342 printf("%s ok\n", "not");
1343 }
1344
1345 if (!mlen) {
1346 if (t->ftps_seq[0] + ackoff != thack &&
1347 t->ftps_seq[1] + ackoff != thack) {
1348 DT3(thack, ftpside_t *t, t, int, ackoff, u_32_t, thack);
1349 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) {
1350 printf("%s:seq[0](%u) + (%d) != (%u)\n",
1351 "ipf_p_ftp_process", t->ftps_seq[0],
1352 ackoff, thack);
1353 printf("%s:seq[1](%u) + (%d) != (%u)\n",
1354 "ipf_p_ftp_process", t->ftps_seq[1],
1355 ackoff, thack);
1356 }
1357 return (APR_ERR(1));
1358 }
1359
1360 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) {
1361 printf("ipf_p_ftp_process:f:seq[0] %x seq[1] %x\n",
1362 f->ftps_seq[0], f->ftps_seq[1]);
1363 }
1364
1365 if (tcp->th_flags & TH_FIN) {
1366 if (thseq == f->ftps_seq[1]) {
1367 f->ftps_seq[0] = f->ftps_seq[1] - seqoff;
1368 f->ftps_seq[1] = thseq + 1 - seqoff;
1369 } else {
1370 DT2(thseq, ftpside_t *t, t, u_32_t, thseq);
1371 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) {
1372 printf("FIN: thseq %x seqoff %d ftps_seq %x\n",
1373 thseq, seqoff, f->ftps_seq[0]);
1374 }
1375 return (APR_ERR(1));
1376 }
1377 }
1378 f->ftps_len = 0;
1379 return (0);
1380 }
1381
1382 ok = 0;
1383 if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) {
1384 ok = 1;
1385 /*
1386 * Retransmitted data packet.
1387 */
1388 } else if ((thseq + mlen == f->ftps_seq[0]) ||
1389 (thseq + mlen == f->ftps_seq[1])) {
1390 ok = 1;
1391 }
1392
1393 if (ok == 0) {
1394 DT3(ok_0, ftpside_t *, f, u_32_t, thseq, int, mlen);
1395 inc = thseq - f->ftps_seq[0];
1396 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) {
1397 printf("inc %d sel %d rv %d\n", inc, sel, rv);
1398 printf("th_seq %x ftps_seq %x/%x\n",
1399 thseq, f->ftps_seq[0], f->ftps_seq[1]);
1400 printf("ackmin %x ackoff %d\n", aps->aps_ackmin[sel],
1401 aps->aps_ackoff[sel]);
1402 printf("seqmin %x seqoff %d\n", aps->aps_seqmin[sel],
1403 aps->aps_seqoff[sel]);
1404 }
1405
1406 return (APR_ERR(1));
1407 }
1408
1409 inc = 0;
1410 rptr = f->ftps_rptr;
1411 wptr = f->ftps_wptr;
1412 f->ftps_seq[0] = thseq;
1413 f->ftps_seq[1] = f->ftps_seq[0] + mlen;
1414 f->ftps_len = mlen;
1415
1416 while (mlen > 0) {
1417 len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr));
1418 if (len == 0)
1419 break;
1420 COPYDATA(m, off, len, wptr);
1421 mlen -= len;
1422 off += len;
1423 wptr += len;
1424
1425 whilemore:
1426 if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
1427 printf("%s:len %d/%d off %d wptr %lx junk %d [%*.*s]\n",
1428 "ipf_p_ftp_process",
1429 len, mlen, off, (u_long)wptr, f->ftps_junk,
1430 len, len, rptr);
1431
1432 f->ftps_wptr = wptr;
1433 if (f->ftps_junk != FTPXY_JUNK_OK) {
1434 i = f->ftps_junk;
1435 f->ftps_junk = ipf_p_ftp_valid(softf, ftp, rv, rptr,
1436 wptr - rptr);
1437 DT2(junk_transit, int, i, int, f->ftps_junk);
1438
1439 if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
1440 printf("%s:junk %d -> %d\n",
1441 "ipf_p_ftp_process", i, f->ftps_junk);
1442
1443 if (f->ftps_junk == FTPXY_JUNK_BAD) {
1444 DT(buffer_full);
1445 if (wptr - rptr == sizeof(f->ftps_buf)) {
1446 if (softf->ipf_p_ftp_debug &
1447 DEBUG_PARSE_INFO)
1448 printf("%s:full buffer\n",
1449 "ipf_p_ftp_process");
1450 f->ftps_rptr = f->ftps_buf;
1451 f->ftps_wptr = f->ftps_buf;
1452 rptr = f->ftps_rptr;
1453 wptr = f->ftps_wptr;
1454 continue;
1455 }
1456 }
1457 }
1458
1459 while ((f->ftps_junk == FTPXY_JUNK_OK) && (wptr > rptr)) {
1460 len = wptr - rptr;
1461 f->ftps_junk = ipf_p_ftp_valid(softf, ftp, rv,
1462 rptr, len);
1463 DT5(junk_ftp_valid, int, len, int, rv, u_long, rptr,
1464 u_long, wptr, int, f->ftps_junk);
1465
1466 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) {
1467 printf("%s=%d len %d rv %d ptr %lx/%lx ",
1468 "ipf_p_ftp_valid",
1469 f->ftps_junk, len, rv, (u_long)rptr,
1470 (u_long)wptr);
1471 printf("buf [%*.*s]\n", len, len, rptr);
1472 }
1473
1474 if (f->ftps_junk == FTPXY_JUNK_OK) {
1475 f->ftps_cmds++;
1476 f->ftps_rptr = rptr;
1477 if (rv)
1478 inc += ipf_p_ftp_server(softf, fin, ip,
1479 nat, ftp, len);
1480 else
1481 inc += ipf_p_ftp_client(softf, fin, ip,
1482 nat, ftp, len);
1483 rptr = f->ftps_rptr;
1484 wptr = f->ftps_wptr;
1485 }
1486 }
1487
1488 /*
1489 * Off to a bad start so lets just forget about using the
1490 * ftp proxy for this connection.
1491 */
1492 if ((f->ftps_cmds == 0) && (f->ftps_junk == FTPXY_JUNK_BAD)) {
1493 /* f->ftps_seq[1] += inc; */
1494
1495 DT(ftp_junk_cmd);
1496 if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
1497 printf("%s:cmds == 0 junk == 1\n",
1498 "ipf_p_ftp_process");
1499 return (APR_ERR(2));
1500 }
1501
1502 retry = 0;
1503 if ((f->ftps_junk != FTPXY_JUNK_OK) && (rptr < wptr)) {
1504 for (s = rptr; s < wptr; s++) {
1505 if ((*s == '\r') && (s + 1 < wptr) &&
1506 (*(s + 1) == '\n')) {
1507 rptr = s + 2;
1508 retry = 1;
1509 if (f->ftps_junk != FTPXY_JUNK_CONT)
1510 f->ftps_junk = FTPXY_JUNK_OK;
1511 break;
1512 }
1513 }
1514 }
1515
1516 if (rptr == wptr) {
1517 rptr = wptr = f->ftps_buf;
1518 } else {
1519 /*
1520 * Compact the buffer back to the start. The junk
1521 * flag should already be set and because we're not
1522 * throwing away any data, it is preserved from its
1523 * current state.
1524 */
1525 if (rptr > f->ftps_buf) {
1526 bcopy(rptr, f->ftps_buf, wptr - rptr);
1527 wptr -= rptr - f->ftps_buf;
1528 rptr = f->ftps_buf;
1529 }
1530 }
1531 f->ftps_rptr = rptr;
1532 f->ftps_wptr = wptr;
1533 if (retry)
1534 goto whilemore;
1535 }
1536
1537 /* f->ftps_seq[1] += inc; */
1538 if (tcp->th_flags & TH_FIN)
1539 f->ftps_seq[1]++;
1540 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO) {
1541 mlen = MSGDSIZE(m);
1542 mlen -= off;
1543 printf("ftps_seq[1] = %x inc %d len %d\n",
1544 f->ftps_seq[1], inc, mlen);
1545 }
1546
1547 f->ftps_rptr = rptr;
1548 f->ftps_wptr = wptr;
1549 return (APR_INC(inc));
1550 }
1551
1552
1553 int
1554 ipf_p_ftp_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
1555 {
1556 ipf_ftp_softc_t *softf = arg;
1557 ftpinfo_t *ftp;
1558 int rev;
1559
1560 ftp = aps->aps_data;
1561 if (ftp == NULL)
1562 return (0);
1563
1564 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1;
1565 if (ftp->ftp_side[1 - rev].ftps_ifp == NULL)
1566 ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp;
1567
1568 return (ipf_p_ftp_process(softf, fin, nat, ftp, rev));
1569 }
1570
1571
1572 int
1573 ipf_p_ftp_in(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
1574 {
1575 ipf_ftp_softc_t *softf = arg;
1576 ftpinfo_t *ftp;
1577 int rev;
1578
1579 ftp = aps->aps_data;
1580 if (ftp == NULL)
1581 return (0);
1582
1583 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1;
1584 if (ftp->ftp_side[rev].ftps_ifp == NULL)
1585 ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp;
1586
1587 return (ipf_p_ftp_process(softf, fin, nat, ftp, 1 - rev));
1588 }
1589
1590
1591 /*
1592 * ipf_p_ftp_atoi - implement a version of atoi which processes numbers in
1593 * pairs separated by commas (which are expected to be in the range 0 - 255),
1594 * returning a 16 bit number combining either side of the , as the MSB and
1595 * LSB.
1596 */
1597 u_short
1598 ipf_p_ftp_atoi(char **ptr)
1599 {
1600 register char *s = *ptr, c;
1601 register u_char i = 0, j = 0;
1602
1603 while (((c = *s++) != '\0') && ISDIGIT(c)) {
1604 i *= 10;
1605 i += c - '';
1606 }
1607 if (c != ',') {
1608 *ptr = NULL;
1609 return (0);
1610 }
1611 while (((c = *s++) != '\0') && ISDIGIT(c)) {
1612 j *= 10;
1613 j += c - '';
1614 }
1615 *ptr = s;
1616 i &= 0xff;
1617 j &= 0xff;
1618 return (i << 8) | j;
1619 }
1620
1621
1622 int
1623 ipf_p_ftp_eprt(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat,
1624 ftpinfo_t *ftp, int dlen)
1625 {
1626 ftpside_t *f;
1627
1628 /*
1629 * Check for client sending out EPRT message.
1630 */
1631 if (dlen < IPF_MINEPRTLEN) {
1632 DT1(epert_dlen, int, dlen);
1633 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
1634 printf("ipf_p_ftp_eprt:dlen(%d) < IPF_MINEPRTLEN\n",
1635 dlen);
1636 return (0);
1637 }
1638
1639 /*
1640 * Parse the EPRT command. Format is:
1641 * "EPRT |1|1.2.3.4|2000|" for IPv4 and
1642 * "EPRT |2|ef00::1:2|2000|" for IPv6
1643 */
1644 f = &ftp->ftp_side[0];
1645 if (f->ftps_rptr[5] != '|')
1646 return (0);
1647 if (f->ftps_rptr[5] == f->ftps_rptr[7]) {
1648 if (f->ftps_rptr[6] == '1' && nat->nat_v[0] == 4)
1649 return (ipf_p_ftp_eprt4(softf, fin, ip, nat, ftp, dlen));
1650 #ifdef USE_INET6
1651 if (f->ftps_rptr[6] == '2' && nat->nat_v[0] == 6)
1652 return (ipf_p_ftp_eprt6(softf, fin, ip, nat, ftp, dlen));
1653 #endif
1654 }
1655 return (0);
1656 }
1657
1658
1659 int
1660 ipf_p_ftp_eprt4(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat,
1661 ftpinfo_t *ftp, int dlen)
1662 {
1663 int a1, a2, a3, a4, port, olen, nlen, inc, off;
1664 char newbuf[IPF_FTPBUFSZ];
1665 char *s, c, delim;
1666 u_32_t addr, i;
1667 tcphdr_t *tcp;
1668 ftpside_t *f;
1669 mb_t *m;
1670
1671 m = fin->fin_m;
1672 tcp = (tcphdr_t *)fin->fin_dp;
1673 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
1674 f = &ftp->ftp_side[0];
1675 delim = f->ftps_rptr[5];
1676 s = f->ftps_rptr + 8;
1677
1678 /*
1679 * get the IP address.
1680 */
1681 i = 0;
1682 while (((c = *s++) != '\0') && ISDIGIT(c)) {
1683 i *= 10;
1684 i += c - '';
1685 }
1686 if (i > 255)
1687 return (0);
1688 if (c != '.')
1689 return (0);
1690 addr = (i << 24);
1691
1692 i = 0;
1693 while (((c = *s++) != '\0') && ISDIGIT(c)) {
1694 i *= 10;
1695 i += c - '';
1696 }
1697 if (i > 255)
1698 return (0);
1699 if (c != '.')
1700 return (0);
1701 addr |= (addr << 16);
1702
1703 i = 0;
1704 while (((c = *s++) != '\0') && ISDIGIT(c)) {
1705 i *= 10;
1706 i += c - '';
1707 }
1708 if (i > 255)
1709 return (0);
1710 if (c != '.')
1711 return (0);
1712 addr |= (addr << 8);
1713
1714 i = 0;
1715 while (((c = *s++) != '\0') && ISDIGIT(c)) {
1716 i *= 10;
1717 i += c - '';
1718 }
1719 if (i > 255)
1720 return (0);
1721 if (c != delim)
1722 return (0);
1723 addr |= addr;
1724
1725 /*
1726 * Get the port number
1727 */
1728 i = 0;
1729 while (((c = *s++) != '\0') && ISDIGIT(c)) {
1730 i *= 10;
1731 i += c - '';
1732 }
1733 if (i > 65535)
1734 return (0);
1735 if (c != delim)
1736 return (0);
1737 port = i;
1738
1739 /*
1740 * Check for CR-LF at the end of the command string.
1741 */
1742 if ((*s != '\r') || (*(s + 1) != '\n')) {
1743 DT(eprt4_no_crlf);
1744 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
1745 printf("ipf_p_ftp_eprt4:missing %s\n", "cr-lf");
1746 return (0);
1747 }
1748 s += 2;
1749
1750 /*
1751 * Calculate new address parts for PORT command
1752 */
1753 if (nat->nat_dir == NAT_INBOUND)
1754 a1 = ntohl(nat->nat_odstaddr);
1755 else
1756 a1 = ntohl(ip->ip_src.s_addr);
1757 a2 = (a1 >> 16) & 0xff;
1758 a3 = (a1 >> 8) & 0xff;
1759 a4 = a1 & 0xff;
1760 a1 >>= 24;
1761 olen = s - f->ftps_rptr;
1762 /* DO NOT change this to snprintf! */
1763 /*
1764 * While we could force the use of | as a delimiter here, it makes
1765 * sense to preserve whatever character is being used by the systems
1766 * involved in the communication.
1767 */
1768 (void) snprintf(newbuf, sizeof(newbuf), "%s %c1%c%u.%u.%u.%u%c%u%c\r\n",
1769 "EPRT", delim, delim, a1, a2, a3, a4, delim, port,
1770 delim);
1771
1772 nlen = strlen(newbuf);
1773 inc = nlen - olen;
1774 if ((inc + fin->fin_plen) > 65535) {
1775 DT2(eprt4_len, int, inc, int, fin->fin_plen);
1776 if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
1777 printf("ipf_p_ftp_eprt4:inc(%d) + ip->ip_len > 65535\n",
1778 inc);
1779 return (0);
1780 }
1781
1782 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
1783 #if !defined(_KERNEL)
1784 M_ADJ(m, inc);
1785 #else
1786 if (inc < 0)
1787 M_ADJ(m, inc);
1788 #endif
1789 /* the mbuf chain will be extended if necessary by m_copyback() */
1790 COPYBACK(m, off, nlen, newbuf);
1791 fin->fin_flx |= FI_DOCKSUM;
1792
1793 if (inc != 0) {
1794 fin->fin_plen += inc;
1795 ip->ip_len = htons(fin->fin_plen);
1796 fin->fin_dlen += inc;
1797 }
1798
1799 f->ftps_cmd = FTPXY_C_EPRT;
1800 return (ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, port, inc));
1801 }
1802
1803
1804 int
1805 ipf_p_ftp_epsv(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat,
1806 ftpinfo_t *ftp, int dlen)
1807 {
1808 char newbuf[IPF_FTPBUFSZ];
1809 u_short ap = 0;
1810 ftpside_t *f;
1811 char *s;
1812
1813 if ((softf->ipf_p_ftp_forcepasv != 0) &&
1814 (ftp->ftp_side[0].ftps_cmd != FTPXY_C_EPSV)) {
1815 DT1(epsv_cmd, int, ftp->ftp_side[0].ftps_cmd);
1816 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
1817 printf("ipf_p_ftp_epsv:ftps_cmd(%d) != FTPXY_C_EPSV\n",
1818 ftp->ftp_side[0].ftps_cmd);
1819 return (0);
1820 }
1821 f = &ftp->ftp_side[1];
1822
1823 #define EPSV_REPLEN 33
1824 /*
1825 * Check for EPSV reply message.
1826 */
1827 if (dlen < IPF_MIN229LEN) {
1828 return (0);
1829 } else if (strncmp(f->ftps_rptr,
1830 "229 Entering Extended Passive Mode", EPSV_REPLEN)) {
1831 return (0);
1832 }
1833
1834 /*
1835 * Skip the EPSV command + space
1836 */
1837 s = f->ftps_rptr + 33;
1838 while (*s && !ISDIGIT(*s))
1839 s++;
1840
1841 /*
1842 * As per RFC 2428, there are no addres components in the EPSV
1843 * response. So we'll go straight to getting the port.
1844 */
1845 while (*s && ISDIGIT(*s)) {
1846 ap *= 10;
1847 ap += *s++ - '';
1848 }
1849
1850 if (*s == '|')
1851 s++;
1852 if (*s == ')')
1853 s++;
1854 if (*s == '\n')
1855 s--;
1856 /*
1857 * check for CR-LF at the end.
1858 */
1859 if ((*s != '\r') || (*(s + 1) != '\n')) {
1860 return (0);
1861 }
1862 s += 2;
1863
1864 (void) snprintf(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n",
1865 "229 Entering Extended Passive Mode", ap);
1866
1867 return (ipf_p_ftp_pasvreply(softf, fin, ip, nat, ftp, (u_int)ap,
1868 newbuf, s));
1869 }
1870
1871 #ifdef USE_INET6
1872 int
1873 ipf_p_ftp_eprt6(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat,
1874 ftpinfo_t *ftp, int dlen)
1875 {
1876 int port, olen, nlen, inc, off, left, i;
1877 char newbuf[IPF_FTPBUFSZ];
1878 char *s, c;
1879 i6addr_t addr, *a6;
1880 tcphdr_t *tcp;
1881 ip6_t *ip6;
1882 char delim;
1883 u_short whole;
1884 u_short part;
1885 ftpside_t *f;
1886 u_short *t;
1887 int fwd;
1888 mb_t *m;
1889 u_32_t a;
1890
1891 m = fin->fin_m;
1892 ip6 = (ip6_t *)ip;
1893 f = &ftp->ftp_side[0];
1894 s = f->ftps_rptr + 8;
1895 f = &ftp->ftp_side[0];
1896 delim = f->ftps_rptr[5];
1897 tcp = (tcphdr_t *)fin->fin_dp;
1898 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
1899
1900 addr.i6[0] = 0;
1901 addr.i6[1] = 0;
1902 addr.i6[2] = 0;
1903 addr.i6[3] = 0;
1904 /*
1905 * Parse an IPv6 address.
1906 * Go forward until either :: or | is found. If :: is found,
1907 * reverse direction. Direction change is performed to ease
1908 * parsing an unknown number of 0s in the middle.
1909 */
1910 whole = 0;
1911 t = (u_short *)&addr;
1912 fwd = 1;
1913 for (part = 0; (c = *s) != '\0'; ) {
1914 if (c == delim) {
1915 *t = htons((u_short)whole);
1916 break;
1917 }
1918 if (c == ':') {
1919 *t = part;
1920 if (fwd) {
1921 *t = htons((u_short)whole);
1922 t++;
1923 } else {
1924 *t = htons((u_short)(whole >> 16));
1925 t--;
1926 }
1927 whole = 0;
1928 if (fwd == 1 && s[1] == ':') {
1929 while (*s && *s != '|')
1930 s++;
1931 if ((c = *s) != delim)
1932 break;
1933 t = (u_short *)&addr.i6[3];
1934 t++;
1935 fwd = 0;
1936 } else if (fwd == 0 && s[-1] == ':') {
1937 break;
1938 }
1939 } else {
1940 if (c >= '' && c <= '9') {
1941 c -= '';
1942 } else if (c >= 'a' && c <= 'f') {
1943 c -= 'a' + 10;
1944 } else if (c >= 'A' && c <= 'F') {
1945 c -= 'A' + 10;
1946 }
1947 if (fwd) {
1948 whole <<= 8;
1949 whole |= c;
1950 } else {
1951 whole >>= 8;
1952 whole |= ((u_32_t)c) << 24;
1953 }
1954 }
1955 if (fwd)
1956 s++;
1957 else
1958 s--;
1959 }
1960 if (c != ':' && c != delim)
1961 return (0);
1962
1963 while (*s != '|')
1964 s++;
1965 s++;
1966
1967 /*
1968 * Get the port number
1969 */
1970 i = 0;
1971 while (((c = *s++) != '\0') && ISDIGIT(c)) {
1972 i *= 10;
1973 i += c - '';
1974 }
1975 if (i > 65535)
1976 return (0);
1977 if (c != delim)
1978 return (0);
1979 port = (u_short)(i & 0xffff);
1980
1981 /*
1982 * Check for CR-LF at the end of the command string.
1983 */
1984 if ((*s != '\r') || (*(s + 1) != '\n')) {
1985 DT(eprt6_no_crlf);
1986 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
1987 printf("ipf_p_ftp_eprt6:missing %s\n", "cr-lf");
1988 return (0);
1989 }
1990 s += 2;
1991
1992 /*
1993 * Calculate new address parts for PORT command
1994 */
1995 a6 = (i6addr_t *)&ip6->ip6_src;
1996 olen = s - f->ftps_rptr;
1997 /* DO NOT change this to snprintf! */
1998 /*
1999 * While we could force the use of | as a delimiter here, it makes
2000 * sense to preserve whatever character is being used by the systems
2001 * involved in the communication.
2002 */
2003 s = newbuf;
2004 left = sizeof(newbuf);
2005 (void) snprintf(s, left, "EPRT %c2%c", delim, delim);
2006 s += strlen(s);
2007 a = ntohl(a6->i6[0]);
2008 snprintf(s, left, "%x:%x:", a >> 16, a & 0xffff);
2009 left -= strlen(s);
2010 s += strlen(s);
2011 a = ntohl(a6->i6[1]);
2012 snprintf(s, left, "%x:%x:", a >> 16, a & 0xffff);
2013 left -= strlen(s);
2014 s += strlen(s);
2015 a = ntohl(a6->i6[2]);
2016 snprintf(s, left,"%x:%x:", a >> 16, a & 0xffff);
2017 left -= strlen(s);
2018 s += strlen(s);
2019 a = ntohl(a6->i6[3]);
2020 snprintf(s, left, "%x:%x", a >> 16, a & 0xffff);
2021 left -= strlen(s);
2022 s += strlen(s);
2023 snprintf(s, left, "|%d|\r\n", port);
2024 nlen = strlen(newbuf);
2025 inc = nlen - olen;
2026 if ((inc + fin->fin_plen) > 65535) {
2027 DT2(eprt6_len, int, inc, int, fin->fin_plen);
2028 if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
2029 printf("ipf_p_ftp_eprt6:inc(%d) + ip->ip_len > 65535\n",
2030 inc);
2031 return (0);
2032 }
2033
2034 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
2035 #if !defined(_KERNEL)
2036 M_ADJ(m, inc);
2037 #else
2038 if (inc < 0)
2039 M_ADJ(m, inc);
2040 #endif
2041 /* the mbuf chain will be extended if necessary by m_copyback() */
2042 COPYBACK(m, off, nlen, newbuf);
2043 fin->fin_flx |= FI_DOCKSUM;
2044
2045 if (inc != 0) {
2046 fin->fin_plen += inc;
2047 ip6->ip6_plen = htons(fin->fin_plen - fin->fin_hlen);
2048 fin->fin_dlen += inc;
2049 }
2050
2051 f->ftps_cmd = FTPXY_C_EPRT;
2052 return (ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, port, inc));
2053 }
2054 #endif
Cache object: 744612e9fe258646af26ea7cc4d355d5
|