]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/ip_proxy.c
8d645eb400a725c3d2f7e3847f230aa08c2221fb
[apple/xnu.git] / bsd / netinet / ip_proxy.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (C) 1997 by Darren Reed.
24 *
25 * Redistribution and use in source and binary forms are permitted
26 * provided that this notice is preserved and due credit is given
27 * to the original author and the contributors.
28 */
29 #if !defined(lint)
30 #endif
31
32 #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL)
33 # define _KERNEL
34 #endif
35
36 #if !defined(_KERNEL) && !defined(KERNEL)
37 # include <stdio.h>
38 # include <string.h>
39 # include <stdlib.h>
40 #endif
41 #include <sys/errno.h>
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/time.h>
45 #include <sys/file.h>
46 #if !defined(__FreeBSD__)
47 # include <sys/ioctl.h>
48 #endif
49 #include <sys/fcntl.h>
50 #include <sys/uio.h>
51 #ifndef linux
52 # include <sys/protosw.h>
53 #endif
54 #include <sys/socket.h>
55 #if defined(_KERNEL)
56 # if !defined(linux)
57 # include <sys/systm.h>
58 # else
59 # include <linux/string.h>
60 # endif
61 #endif
62 #if !defined(__SVR4) && !defined(__svr4__)
63 # ifndef linux
64 # include <sys/mbuf.h>
65 # endif
66 #else
67 # include <sys/byteorder.h>
68 # include <sys/dditypes.h>
69 # include <sys/stream.h>
70 # include <sys/kmem.h>
71 #endif
72 #if __FreeBSD__ > 2
73 # include <sys/queue.h>
74 # include <sys/malloc.h>
75 #endif
76 #include <net/if.h>
77 #ifdef sun
78 # include <net/af.h>
79 #endif
80 #include <net/route.h>
81 #include <netinet/in.h>
82 #include <netinet/in_systm.h>
83 #include <netinet/ip.h>
84 #ifndef linux
85 # include <netinet/ip_var.h>
86 #endif
87 #include <netinet/tcp.h>
88 #include <netinet/udp.h>
89 #include <netinet/ip_icmp.h>
90 #include "netinet/ip_compat.h"
91 #include <netinet/tcpip.h>
92 #include "netinet/ip_fil.h"
93 #include "netinet/ip_proxy.h"
94 #include "netinet/ip_nat.h"
95 #include "netinet/ip_state.h"
96
97 #ifndef MIN
98 #define MIN(a,b) (((a)<(b))?(a):(b))
99 #endif
100
101 static ap_session_t *ap_find __P((ip_t *, tcphdr_t *));
102 static ap_session_t *ap_new_session __P((aproxy_t *, ip_t *, tcphdr_t *,
103 fr_info_t *, nat_t *));
104
105 static int ap_matchsrcdst __P((ap_session_t *aps, struct in_addr src,
106 struct in_addr dst, void *tcp, u_short sport,
107 u_short dport));
108
109 #define AP_SESS_SIZE 53
110
111 #if defined(_KERNEL) && !defined(linux)
112 #include "netinet/ip_ftp_pxy.c"
113 #endif
114
115 ap_session_t *ap_sess_tab[AP_SESS_SIZE];
116 aproxy_t ap_proxies[] = {
117 #if IPF_FTP_PROXY
118 { "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_in, ippr_ftp_out },
119 #endif
120 { "", '\0', 0, 0, NULL, NULL }
121 };
122
123
124 int ap_ok(ip, tcp, nat)
125 ip_t *ip;
126 tcphdr_t *tcp;
127 ipnat_t *nat;
128 {
129 aproxy_t *apr = nat->in_apr;
130 u_short dport = nat->in_dport;
131
132 if (!apr || (apr && (apr->apr_flags & APR_DELETE)) ||
133 (ip->ip_p != apr->apr_p))
134 return 0;
135 if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport))
136 return 0;
137 return 1;
138 }
139
140
141 static int
142 ap_matchsrcdst(aps, src, dst, tcp, sport, dport)
143 ap_session_t *aps;
144 struct in_addr src, dst;
145 void *tcp;
146 u_short sport, dport;
147 {
148 if (aps->aps_dst.s_addr == dst.s_addr) {
149 if ((aps->aps_src.s_addr == src.s_addr) &&
150 (!tcp || (sport == aps->aps_sport) &&
151 (dport == aps->aps_dport)))
152 return 1;
153 } else if (aps->aps_dst.s_addr == src.s_addr) {
154 if ((aps->aps_src.s_addr == dst.s_addr) &&
155 (!tcp || (sport == aps->aps_dport) &&
156 (dport == aps->aps_sport)))
157 return 1;
158 }
159 return 0;
160 }
161
162
163 static ap_session_t *ap_find(ip, tcp)
164 ip_t *ip;
165 tcphdr_t *tcp;
166 {
167 register u_char p = ip->ip_p;
168 register ap_session_t *aps;
169 register u_short sp, dp;
170 register u_long hv;
171 struct in_addr src, dst;
172
173 src = ip->ip_src, dst = ip->ip_dst;
174 sp = dp = 0; /* XXX gcc -Wunitialized */
175
176 hv = ip->ip_src.s_addr ^ ip->ip_dst.s_addr;
177 hv *= 651733;
178 if (tcp) {
179 sp = tcp->th_sport;
180 dp = tcp->th_dport;
181 hv ^= (sp + dp);
182 hv *= 5;
183 }
184 hv %= AP_SESS_SIZE;
185
186 for (aps = ap_sess_tab[hv]; aps; aps = aps->aps_next)
187 if ((aps->aps_p == p) &&
188 ap_matchsrcdst(aps, src, dst, tcp, sp, dp))
189 break;
190 return aps;
191 }
192
193
194 /*
195 * Allocate a new application proxy structure and fill it in with the
196 * relevant details. call the init function once complete, prior to
197 * returning.
198 */
199 static ap_session_t *ap_new_session(apr, ip, tcp, fin, nat)
200 aproxy_t *apr;
201 ip_t *ip;
202 tcphdr_t *tcp;
203 fr_info_t *fin;
204 nat_t *nat;
205 {
206 register ap_session_t *aps;
207 u_short dport;
208 u_long hv;
209
210 if (!apr || (apr && (apr->apr_flags & APR_DELETE)) ||
211 (ip->ip_p != apr->apr_p))
212 return NULL;
213 dport = nat->nat_ptr->in_dport;
214 if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport))
215 return NULL;
216
217 hv = ip->ip_src.s_addr ^ ip->ip_dst.s_addr;
218 hv *= 651733;
219 if (tcp) {
220 hv ^= (tcp->th_sport + tcp->th_dport);
221 hv *= 5;
222 }
223 hv %= AP_SESS_SIZE;
224
225 KMALLOC(aps, ap_session_t *, sizeof(*aps));
226 if (!aps)
227 return NULL;
228 bzero((char *)aps, sizeof(*aps));
229 aps->aps_apr = apr;
230 aps->aps_src = ip->ip_src;
231 aps->aps_dst = ip->ip_dst;
232 aps->aps_p = ip->ip_p;
233 aps->aps_tout = 1200; /* XXX */
234 if (tcp) {
235 aps->aps_sport = tcp->th_sport;
236 aps->aps_dport = tcp->th_dport;
237 }
238 aps->aps_data = NULL;
239 aps->aps_psiz = 0;
240 aps->aps_next = ap_sess_tab[hv];
241 ap_sess_tab[hv] = aps;
242 (void) (*apr->apr_init)(fin, ip, tcp, aps, nat);
243 return aps;
244 }
245
246
247 /*
248 * check to see if a packet should be passed through an active proxy routine
249 * if one has been setup for it.
250 */
251 int ap_check(ip, tcp, fin, nat)
252 ip_t *ip;
253 tcphdr_t *tcp;
254 fr_info_t *fin;
255 nat_t *nat;
256 {
257 ap_session_t *aps;
258 aproxy_t *apr;
259 int err;
260
261 if (!(fin->fin_fi.fi_fl & FI_TCPUDP))
262 tcp = NULL;
263
264 if ((aps = ap_find(ip, tcp)) ||
265 (aps = ap_new_session(nat->nat_ptr->in_apr, ip, tcp, fin, nat))) {
266 if (ip->ip_p == IPPROTO_TCP) {
267 /*
268 * verify that the checksum is correct. If not, then
269 * don't do anything with this packet.
270 */
271 if (tcp->th_sum != fr_tcpsum(*(mb_t **)fin->fin_mp,
272 ip, tcp, ip->ip_len)) {
273 frstats[fin->fin_out].fr_tcpbad++;
274 return -1;
275 }
276 fr_tcp_age(&aps->aps_tout, aps->aps_state, ip, fin,
277 tcp->th_sport == aps->aps_sport);
278 }
279
280 apr = aps->aps_apr;
281 err = 0;
282 if (fin->fin_out) {
283 if (apr->apr_outpkt)
284 err = (*apr->apr_outpkt)(fin, ip, tcp,
285 aps, nat);
286 } else {
287 if (apr->apr_inpkt)
288 err = (*apr->apr_inpkt)(fin, ip, tcp,
289 aps, nat);
290 }
291 if (err == 2) {
292 tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip,
293 tcp, ip->ip_len);
294 err = 0;
295 }
296 return err;
297 }
298 return -1;
299 }
300
301
302 aproxy_t *ap_match(pr, name)
303 u_char pr;
304 char *name;
305 {
306 aproxy_t *ap;
307
308 for (ap = ap_proxies; ap->apr_p; ap++)
309 if ((ap->apr_p == pr) &&
310 !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) {
311 ap->apr_ref++;
312 return ap;
313 }
314 return NULL;
315 }
316
317
318 void ap_free(ap)
319 aproxy_t *ap;
320 {
321 ap->apr_ref--;
322 }
323
324
325 void aps_free(aps)
326 ap_session_t *aps;
327 {
328 if (aps->aps_data && aps->aps_psiz)
329 KFREES(aps->aps_data, aps->aps_psiz);
330 KFREE(aps);
331 }
332
333
334 void ap_unload()
335 {
336 ap_session_t *aps;
337 int i;
338
339 for (i = 0; i < AP_SESS_SIZE; i++)
340 while ((aps = ap_sess_tab[i])) {
341 ap_sess_tab[i] = aps->aps_next;
342 aps_free(aps);
343 }
344 }
345
346
347 void ap_expire()
348 {
349 ap_session_t *aps, **apsp;
350 int i;
351
352 for (i = 0; i < AP_SESS_SIZE; i++)
353 for (apsp = &ap_sess_tab[i]; (aps = *apsp); ) {
354 aps->aps_tout--;
355 if (!aps->aps_tout) {
356 ap_sess_tab[i] = aps->aps_next;
357 aps_free(aps);
358 *apsp = aps->aps_next;
359 } else
360 apsp = &aps->aps_next;
361 }
362 }