]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet/ip_proxy.c
xnu-124.13.tar.gz
[apple/xnu.git] / bsd / netinet / ip_proxy.c
CommitLineData
1c79356b
A
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
101static ap_session_t *ap_find __P((ip_t *, tcphdr_t *));
102static ap_session_t *ap_new_session __P((aproxy_t *, ip_t *, tcphdr_t *,
103 fr_info_t *, nat_t *));
104
105static 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
115ap_session_t *ap_sess_tab[AP_SESS_SIZE];
116aproxy_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
124int ap_ok(ip, tcp, nat)
125ip_t *ip;
126tcphdr_t *tcp;
127ipnat_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
141static int
142ap_matchsrcdst(aps, src, dst, tcp, sport, dport)
143ap_session_t *aps;
144struct in_addr src, dst;
145void *tcp;
146u_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
163static ap_session_t *ap_find(ip, tcp)
164ip_t *ip;
165tcphdr_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 */
199static ap_session_t *ap_new_session(apr, ip, tcp, fin, nat)
200aproxy_t *apr;
201ip_t *ip;
202tcphdr_t *tcp;
203fr_info_t *fin;
204nat_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 */
251int ap_check(ip, tcp, fin, nat)
252ip_t *ip;
253tcphdr_t *tcp;
254fr_info_t *fin;
255nat_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
302aproxy_t *ap_match(pr, name)
303u_char pr;
304char *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
318void ap_free(ap)
319aproxy_t *ap;
320{
321 ap->apr_ref--;
322}
323
324
325void aps_free(aps)
326ap_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
334void 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
347void 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}