]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/ip_ftp_pxy.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Simple FTP transparent proxy for in-kernel use. For use with the NAT
28 #define isdigit(x) ((x) >= '0' && (x) <= '9')
32 #define IPF_MINPORTLEN 18
33 #define IPF_MAXPORTLEN 30
36 int ippr_ftp_init
__P((fr_info_t
*, ip_t
*, tcphdr_t
*,
37 ap_session_t
*, nat_t
*));
38 int ippr_ftp_in
__P((fr_info_t
*, ip_t
*, tcphdr_t
*,
39 ap_session_t
*, nat_t
*));
40 int ippr_ftp_out
__P((fr_info_t
*, ip_t
*, tcphdr_t
*,
41 ap_session_t
*, nat_t
*));
42 u_short ipf_ftp_atoi
__P((char **));
46 * FTP application proxy initialization.
48 int ippr_ftp_init(fin
, ip
, tcp
, aps
, nat
)
55 aps
->aps_sport
= tcp
->th_sport
;
56 aps
->aps_dport
= tcp
->th_dport
;
61 int ippr_ftp_in(fin
, ip
, tcp
, aps
, nat
)
71 if (tcp
->th_sport
== aps
->aps_dport
) {
72 sum2
= (u_32_t
)ntohl(tcp
->th_ack
);
74 if ((aps
->aps_after
[!sel
] > aps
->aps_after
[sel
]) &&
75 (sum2
> aps
->aps_after
[!sel
])) {
76 sel
= aps
->aps_sel
= !sel
; /* switch to other set */
78 if (aps
->aps_seqoff
[sel
] && (sum2
> aps
->aps_after
[sel
])) {
79 sum1
= (u_32_t
)aps
->aps_seqoff
[sel
];
80 tcp
->th_ack
= htonl(sum2
- sum1
);
89 * ipf_ftp_atoi - implement a version of atoi which processes numbers in
90 * pairs separated by commas (which are expected to be in the range 0 - 255),
91 * returning a 16 bit number combining either side of the , as the MSB and
94 u_short
ipf_ftp_atoi(ptr
)
97 register char *s
= *ptr
, c
;
98 register u_char i
= 0, j
= 0;
100 while ((c
= *s
++) && isdigit(c
)) {
108 while ((c
= *s
++) && isdigit(c
)) {
117 int ippr_ftp_out(fin
, ip
, tcp
, aps
, nat
)
124 register u_32_t sum1
, sum2
;
125 char newbuf
[IPF_MAXPORTLEN
+1];
126 char portbuf
[IPF_MAXPORTLEN
+1], *s
;
127 int ch
= 0, off
= (ip
->ip_hl
<< 2) + (tcp
->th_off
<< 2);
128 u_int a1
, a2
, a3
, a4
;
130 int olen
, dlen
, nlen
= 0, inc
= 0;
131 tcphdr_t tcph
, *tcp2
= &tcph
;
135 mb_t
*m
= *(mb_t
**)fin
->fin_mp
;
140 /* skip any leading M_PROTOs */
141 while(m
&& (MTYPE(m
) != M_DATA
))
143 PANIC((!m
),("ippr_ftp_out: no M_DATA"));
145 dlen
= msgdsize(m
) - off
;
146 bzero(portbuf
, sizeof(portbuf
));
147 copyout_mblk(m
, off
, MIN(sizeof(portbuf
), dlen
), portbuf
);
149 dlen
= mbufchainlen(m
) - off
;
150 bzero(portbuf
, sizeof(portbuf
));
151 m_copydata(m
, off
, MIN(sizeof(portbuf
), dlen
), portbuf
);
153 portbuf
[IPF_MAXPORTLEN
] = '\0';
155 if ((dlen
< IPF_MINPORTLEN
) || strncmp(portbuf
, "PORT ", 5))
159 * Skip the PORT command + space
163 * Pick out the address components, two at a time.
165 (void) ipf_ftp_atoi(&s
);
168 (void) ipf_ftp_atoi(&s
);
171 a5
= ipf_ftp_atoi(&s
);
175 * check for CR-LF at the end.
177 if (*s
!= '\n' || *(s
- 1) != '\r')
182 * Calculate new address parts for PORT command
184 a1
= ntohl(ip
->ip_src
.s_addr
);
185 a2
= (a1
>> 16) & 0xff;
186 a3
= (a1
>> 8) & 0xff;
189 olen
= s
- portbuf
+ 1;
190 (void) snprintf(newbuf
, sizeof(newbuf
), "PORT %d,%d,%d,%d,%d,%d\r\n",
191 a1
, a2
, a3
, a4
, a5
, a6
);
192 nlen
= strlen(newbuf
);
195 for (m1
= m
; m1
->b_cont
; m1
= m1
->b_cont
)
200 /* alloc enough to keep same trailer space for lower driver */
201 nm
= allocb(nlen
+ m1
->b_datap
->db_lim
- m1
->b_wptr
, BPRI_MED
);
202 PANIC((!nm
),("ippr_ftp_out: allocb failed"));
204 nm
->b_band
= m1
->b_band
;
208 PANIC((m1
->b_wptr
< m1
->b_rptr
),("ippr_ftp_out: cannot handle fragmented data block"));
214 copyin_mblk(m
, off
, nlen
, newbuf
);
218 /* the mbuf chain will be extended if necessary by m_copyback() */
219 m_copyback(m
, off
, nlen
, newbuf
);
222 #if SOLARIS || defined(__sgi)
224 sum2
= ip
->ip_len
+ inc
;
226 /* Because ~1 == -2, We really need ~1 == -1 */
230 sum2
= (sum2
& 0xffff) + (sum2
>> 16);
232 fix_outcksum(&ip
->ip_sum
, sum2
);
239 * Add skeleton NAT entry for connection which will come back the
243 fin
->fin_dp
= (char *)tcp2
;
244 bzero((char *)tcp2
, sizeof(*tcp2
));
245 tcp2
->th_sport
= htons(a5
<< 8 | a6
);
246 tcp2
->th_dport
= htons(20);
248 ip
->ip_src
= nat
->nat_inip
;
249 if ((ipn
= nat_new(nat
->nat_ptr
, ip
, fin
, IPN_TCP
, NAT_OUTBOUND
)))
250 ipn
->nat_age
= fr_defnatage
;
251 (void) fr_addstate(ip
, fin
, FR_INQUE
|FR_PASS
|FR_QUICK
|FR_KEEPSTATE
);
253 fin
->fin_dp
= (char *)savep
;
256 if (tcp
->th_dport
== aps
->aps_dport
) {
257 sum2
= (u_32_t
)ntohl(tcp
->th_seq
);
259 if ((aps
->aps_after
[!off
] > aps
->aps_after
[off
]) &&
260 (sum2
> aps
->aps_after
[!off
])) {
261 off
= aps
->aps_sel
= !off
; /* switch to other set */
263 if (aps
->aps_seqoff
[off
]) {
264 sum1
= (u_32_t
)aps
->aps_after
[off
] -
265 aps
->aps_seqoff
[off
];
267 sum1
= (u_32_t
)aps
->aps_seqoff
[off
];
269 tcp
->th_seq
= htonl(sum2
);
274 if (inc
&& (sum2
> aps
->aps_after
[!off
])) {
275 aps
->aps_after
[!off
] = sum2
+ nlen
- 1;
276 aps
->aps_seqoff
[!off
] = aps
->aps_seqoff
[off
] + inc
;