]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | } |