Deleted Added
full compact
ip_ftp_pxy.c (80482) ip_ftp_pxy.c (92685)
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}