]>
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 & Guido van Rooij. | |
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 | ||
30 | #define __FreeBSD_version 300000 /* just a hack - no <sys/osreldate.h> */ | |
31 | ||
32 | #if !defined(KERNEL) | |
33 | # include <stdlib.h> | |
34 | # include <string.h> | |
35 | #endif | |
36 | #include <sys/errno.h> | |
37 | #include <sys/types.h> | |
38 | #include <sys/param.h> | |
39 | #include <sys/time.h> | |
40 | #include <sys/file.h> | |
41 | #if defined(KERNEL) && (__FreeBSD_version >= 220000) | |
42 | # include <sys/filio.h> | |
43 | # include <sys/fcntl.h> | |
44 | #else | |
45 | # include <sys/ioctl.h> | |
46 | #endif | |
47 | #include <sys/uio.h> | |
48 | #ifndef linux | |
49 | # include <sys/protosw.h> | |
50 | #endif | |
51 | #include <sys/socket.h> | |
52 | #if defined(KERNEL) | |
53 | # include <sys/systm.h> | |
54 | #endif | |
55 | #if !defined(__SVR4) && !defined(__svr4__) | |
56 | # ifndef linux | |
57 | # include <sys/mbuf.h> | |
58 | # endif | |
59 | #else | |
60 | # include <sys/filio.h> | |
61 | # include <sys/byteorder.h> | |
62 | # include <sys/dditypes.h> | |
63 | # include <sys/stream.h> | |
64 | # include <sys/kmem.h> | |
65 | #endif | |
66 | #if defined(KERNEL) && (__FreeBSD_version >= 300000) | |
67 | # include <sys/malloc.h> | |
68 | #endif | |
69 | #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) | |
70 | # include <kern/cpu_number.h> | |
71 | #endif | |
72 | #include <net/if.h> | |
73 | #ifdef sun | |
74 | #include <net/af.h> | |
75 | #endif | |
76 | #if !defined(KERNEL) && (__FreeBSD_version >= 300000) | |
77 | # include <net/if_var.h> | |
78 | #endif | |
79 | #include <net/route.h> | |
80 | #include <netinet/in.h> | |
81 | #include <netinet/in_systm.h> | |
82 | #include <netinet/ip.h> | |
83 | #ifndef KERNEL | |
84 | #define KERNEL | |
85 | #define NOT_KERNEL | |
86 | #endif | |
87 | #ifndef linux | |
88 | # include <netinet/ip_var.h> | |
89 | #endif | |
90 | #ifdef NOT_KERNEL | |
91 | #undef KERNEL | |
92 | #endif | |
93 | #ifdef __sgi | |
94 | # ifdef IFF_DRVRLOCK /* IRIX6 */ | |
95 | #include <sys/hashing.h> | |
96 | # endif | |
97 | #endif | |
98 | #include <netinet/tcp.h> | |
99 | #if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */ | |
100 | extern struct ifqueue ipintrq; /* ip packet input queue */ | |
101 | #else | |
102 | # ifndef linux | |
103 | # include <netinet/in_var.h> | |
104 | # include <netinet/tcp_fsm.h> | |
105 | # endif | |
106 | #endif | |
107 | #include <netinet/udp.h> | |
108 | #include <netinet/ip_icmp.h> | |
109 | #include "netinet/ip_compat.h" | |
110 | #include <netinet/tcpip.h> | |
111 | #include "netinet/ip_fil.h" | |
112 | #include "netinet/ip_auth.h" | |
113 | #if !SOLARIS && !defined(linux) | |
114 | # include <net/netisr.h> | |
115 | # ifdef __FreeBSD__ | |
116 | # include <machine/cpufunc.h> | |
117 | # endif | |
118 | #endif | |
119 | ||
120 | ||
121 | #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) | |
122 | extern kmutex_t ipf_auth; | |
123 | # if SOLARIS | |
124 | extern kcondvar_t ipfauthwait; | |
125 | # endif | |
126 | #endif | |
127 | #ifdef linux | |
128 | static struct wait_queue *ipfauthwait = NULL; | |
129 | #endif | |
130 | ||
131 | int fr_authsize = FR_NUMAUTH; | |
132 | int fr_authused = 0; | |
133 | int fr_defaultauthage = 600; | |
134 | fr_authstat_t fr_authstats; | |
135 | static frauth_t fr_auth[FR_NUMAUTH]; | |
136 | mb_t *fr_authpkts[FR_NUMAUTH]; | |
137 | static int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; | |
138 | static frauthent_t *fae_list = NULL; | |
139 | frentry_t *ipauth = NULL; | |
140 | ||
141 | ||
142 | /* | |
143 | * Check if a packet has authorization. If the packet is found to match an | |
144 | * authorization result and that would result in a feedback loop (i.e. it | |
145 | * will end up returning FR_AUTH) then return FR_BLOCK instead. | |
146 | */ | |
147 | int fr_checkauth(ip, fin) | |
148 | ip_t *ip; | |
149 | fr_info_t *fin; | |
150 | { | |
151 | u_short id = ip->ip_id; | |
152 | u_32_t pass; | |
153 | int i; | |
154 | ||
155 | MUTEX_ENTER(&ipf_auth); | |
156 | for (i = fr_authstart; i != fr_authend; ) { | |
157 | /* | |
158 | * index becomes -2 only after an SIOCAUTHW. Check this in | |
159 | * case the same packet gets sent again and it hasn't yet been | |
160 | * auth'd. | |
161 | */ | |
162 | if ((fr_auth[i].fra_index == -2) && | |
163 | (id == fr_auth[i].fra_info.fin_id) && | |
164 | !bcmp((char *)fin,(char *)&fr_auth[i].fra_info,FI_CSIZE)) { | |
165 | /* | |
166 | * Avoid feedback loop. | |
167 | */ | |
168 | if (!(pass = fr_auth[i].fra_pass) || (pass & FR_AUTH)) | |
169 | pass = FR_BLOCK; | |
170 | fr_authstats.fas_hits++; | |
171 | fr_auth[i].fra_index = -1; | |
172 | fr_authused--; | |
173 | if (i == fr_authstart) { | |
174 | while (fr_auth[i].fra_index == -1) { | |
175 | i++; | |
176 | if (i == FR_NUMAUTH) | |
177 | i = 0; | |
178 | fr_authstart = i; | |
179 | if (i == fr_authend) | |
180 | break; | |
181 | } | |
182 | if (fr_authstart == fr_authend) { | |
183 | fr_authnext = 0; | |
184 | fr_authstart = fr_authend = 0; | |
185 | } | |
186 | } | |
187 | MUTEX_EXIT(&ipf_auth); | |
188 | return pass; | |
189 | } | |
190 | i++; | |
191 | if (i == FR_NUMAUTH) | |
192 | i = 0; | |
193 | } | |
194 | fr_authstats.fas_miss++; | |
195 | MUTEX_EXIT(&ipf_auth); | |
196 | return 0; | |
197 | } | |
198 | ||
199 | ||
200 | /* | |
201 | * Check if we have room in the auth array to hold details for another packet. | |
202 | * If we do, store it and wake up any user programs which are waiting to | |
203 | * hear about these events. | |
204 | */ | |
205 | int fr_newauth(m, fin, ip | |
206 | #if defined(_KERNEL) && SOLARIS | |
207 | , qif) | |
208 | qif_t *qif; | |
209 | #else | |
210 | ) | |
211 | #endif | |
212 | mb_t *m; | |
213 | fr_info_t *fin; | |
214 | ip_t *ip; | |
215 | { | |
216 | int i; | |
217 | ||
218 | MUTEX_ENTER(&ipf_auth); | |
219 | if ((fr_authstart > fr_authend) && (fr_authstart - fr_authend == -1)) { | |
220 | fr_authstats.fas_nospace++; | |
221 | MUTEX_EXIT(&ipf_auth); | |
222 | return 0; | |
223 | } | |
224 | if (fr_authend - fr_authstart == FR_NUMAUTH - 1) { | |
225 | fr_authstats.fas_nospace++; | |
226 | MUTEX_EXIT(&ipf_auth); | |
227 | return 0; | |
228 | } | |
229 | ||
230 | fr_authstats.fas_added++; | |
231 | fr_authused++; | |
232 | i = fr_authend++; | |
233 | if (fr_authend == FR_NUMAUTH) | |
234 | fr_authend = 0; | |
235 | MUTEX_EXIT(&ipf_auth); | |
236 | fr_auth[i].fra_index = i; | |
237 | fr_auth[i].fra_pass = 0; | |
238 | fr_auth[i].fra_age = fr_defaultauthage; | |
239 | bcopy((char *)fin, (char *)&fr_auth[i].fra_info, sizeof(*fin)); | |
240 | #if !defined(sparc) && !defined(m68k) | |
241 | /* | |
242 | * No need to copyback here as we want to undo the changes, not keep | |
243 | * them. | |
244 | */ | |
245 | # if SOLARIS && defined(KERNEL) | |
246 | if (ip == (ip_t *)m->b_rptr) | |
247 | # endif | |
248 | { | |
249 | register u_short bo; | |
250 | ||
251 | bo = ip->ip_len; | |
252 | ip->ip_len = htons(bo); | |
253 | # if !SOLARIS /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */ | |
254 | bo = ip->ip_id; | |
255 | ip->ip_id = htons(bo); | |
256 | # endif | |
257 | bo = ip->ip_off; | |
258 | ip->ip_off = htons(bo); | |
259 | } | |
260 | #endif | |
261 | #if SOLARIS && defined(KERNEL) | |
262 | m->b_rptr -= qif->qf_off; | |
263 | fr_authpkts[i] = *(mblk_t **)fin->fin_mp; | |
264 | fr_auth[i].fra_q = qif->qf_q; | |
265 | cv_signal(&ipfauthwait); | |
266 | #else | |
267 | fr_authpkts[i] = m; | |
268 | # if defined(linux) && defined(KERNEL) | |
269 | wake_up_interruptible(&ipfauthwait); | |
270 | # else | |
271 | WAKEUP(&fr_authnext); | |
272 | # endif | |
273 | #endif | |
274 | return 1; | |
275 | } | |
276 | ||
277 | ||
278 | int fr_auth_ioctl(data, cmd, fr, frptr) | |
279 | caddr_t data; | |
280 | #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) | |
281 | u_long cmd; | |
282 | #else | |
283 | int cmd; | |
284 | #endif | |
285 | frentry_t *fr, **frptr; | |
286 | { | |
287 | mb_t *m; | |
288 | #if defined(KERNEL) | |
289 | # if !SOLARIS | |
290 | struct ifqueue *ifq; | |
291 | int s; | |
292 | # endif | |
293 | #endif | |
294 | frauth_t auth, *au = &auth; | |
295 | frauthent_t *fae, **faep; | |
296 | int i, error = 0; | |
297 | ||
298 | switch (cmd) | |
299 | { | |
300 | case SIOCINIFR : | |
301 | case SIOCRMIFR : | |
302 | case SIOCADIFR : | |
303 | error = EINVAL; | |
304 | break; | |
305 | case SIOCINAFR : | |
306 | case SIOCRMAFR : | |
307 | case SIOCADAFR : | |
308 | for (faep = &fae_list; (fae = *faep); ) | |
309 | if (&fae->fae_fr == fr) | |
310 | break; | |
311 | else | |
312 | faep = &fae->fae_next; | |
313 | if (cmd == SIOCRMAFR) { | |
314 | if (!fae) | |
315 | error = ESRCH; | |
316 | else { | |
317 | *faep = fae->fae_next; | |
318 | *frptr = fr->fr_next; | |
319 | KFREE(fae); | |
320 | } | |
321 | } else { | |
322 | KMALLOC(fae, frauthent_t *, sizeof(*fae)); | |
323 | if (fae != NULL) { | |
324 | IRCOPY((char *)data, (char *)&fae->fae_fr, | |
325 | sizeof(fae->fae_fr)); | |
326 | if (!fae->fae_age) | |
327 | fae->fae_age = fr_defaultauthage; | |
328 | fae->fae_fr.fr_hits = 0; | |
329 | fae->fae_fr.fr_next = *frptr; | |
330 | *frptr = &fae->fae_fr; | |
331 | fae->fae_next = *faep; | |
332 | *faep = fae; | |
333 | } else | |
334 | error = ENOMEM; | |
335 | } | |
336 | break; | |
337 | case SIOCATHST: | |
338 | IWCOPY((char *)&fr_authstats, data, sizeof(fr_authstats)); | |
339 | break; | |
340 | case SIOCAUTHW: | |
341 | fr_authioctlloop: | |
342 | MUTEX_ENTER(&ipf_auth); | |
343 | if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { | |
344 | IWCOPY((char *)&fr_auth[fr_authnext++], data, | |
345 | sizeof(fr_info_t)); | |
346 | if (fr_authnext == FR_NUMAUTH) | |
347 | fr_authnext = 0; | |
348 | MUTEX_EXIT(&ipf_auth); | |
349 | return 0; | |
350 | } | |
351 | #ifdef KERNEL | |
352 | # if SOLARIS | |
353 | if (!cv_wait_sig(&ipfauthwait, &ipf_auth)) { | |
354 | mutex_exit(&ipf_auth); | |
355 | return EINTR; | |
356 | } | |
357 | # else | |
358 | # ifdef linux | |
359 | interruptible_sleep_on(&ipfauthwait); | |
360 | if (current->signal & ~current->blocked) | |
361 | error = -EINTR; | |
362 | # else | |
363 | error = SLEEP(&fr_authnext, "fr_authnext"); | |
364 | # endif | |
365 | # endif | |
366 | #endif | |
367 | MUTEX_EXIT(&ipf_auth); | |
368 | if (!error) | |
369 | goto fr_authioctlloop; | |
370 | break; | |
371 | case SIOCAUTHR: | |
372 | IRCOPY(data, (caddr_t)&auth, sizeof(auth)); | |
373 | MUTEX_ENTER(&ipf_auth); | |
374 | i = au->fra_index; | |
375 | if ((i < 0) || (i > FR_NUMAUTH) || | |
376 | (fr_auth[i].fra_info.fin_id != au->fra_info.fin_id)) { | |
377 | MUTEX_EXIT(&ipf_auth); | |
378 | return EINVAL; | |
379 | } | |
380 | m = fr_authpkts[i]; | |
381 | fr_auth[i].fra_index = -2; | |
382 | fr_auth[i].fra_pass = au->fra_pass; | |
383 | fr_authpkts[i] = NULL; | |
384 | #ifdef KERNEL | |
385 | MUTEX_EXIT(&ipf_auth); | |
386 | SPL_NET(s); | |
387 | # ifndef linux | |
388 | if (m && au->fra_info.fin_out) { | |
389 | # if SOLARIS | |
390 | error = fr_qout(fr_auth[i].fra_q, m); | |
391 | # else /* SOLARIS */ | |
392 | #if IPSEC | |
393 | m->m_pkthdr.rcvif = NULL; | |
394 | #endif /*IPSEC*/ | |
395 | ||
396 | error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); | |
397 | # endif /* SOLARIS */ | |
398 | if (error) | |
399 | fr_authstats.fas_sendfail++; | |
400 | else | |
401 | fr_authstats.fas_sendok++; | |
402 | } else if (m) { | |
403 | # if SOLARIS | |
404 | error = fr_qin(fr_auth[i].fra_q, m); | |
405 | # else /* SOLARIS */ | |
406 | ifq = &ipintrq; | |
407 | if (IF_QFULL(ifq)) { | |
408 | IF_DROP(ifq); | |
409 | m_freem(m); | |
410 | error = ENOBUFS; | |
411 | } else { | |
412 | IF_ENQUEUE(ifq, m); | |
413 | schednetisr(NETISR_IP); | |
414 | } | |
415 | # endif /* SOLARIS */ | |
416 | if (error) | |
417 | fr_authstats.fas_quefail++; | |
418 | else | |
419 | fr_authstats.fas_queok++; | |
420 | } else | |
421 | error = EINVAL; | |
422 | # endif | |
423 | # if SOLARIS | |
424 | if (error) | |
425 | error = EINVAL; | |
426 | # else | |
427 | /* | |
428 | * If we experience an error which will result in the packet | |
429 | * not being processed, make sure we advance to the next one. | |
430 | */ | |
431 | if (error == ENOBUFS) { | |
432 | fr_authused--; | |
433 | fr_auth[i].fra_index = -1; | |
434 | fr_auth[i].fra_pass = 0; | |
435 | if (i == fr_authstart) { | |
436 | while (fr_auth[i].fra_index == -1) { | |
437 | i++; | |
438 | if (i == FR_NUMAUTH) | |
439 | i = 0; | |
440 | fr_authstart = i; | |
441 | if (i == fr_authend) | |
442 | break; | |
443 | } | |
444 | if (fr_authstart == fr_authend) { | |
445 | fr_authnext = 0; | |
446 | fr_authstart = fr_authend = 0; | |
447 | } | |
448 | } | |
449 | } | |
450 | # endif | |
451 | SPL_X(s); | |
452 | #endif /* KERNEL */ | |
453 | break; | |
454 | default : | |
455 | error = EINVAL; | |
456 | break; | |
457 | } | |
458 | return error; | |
459 | } | |
460 | ||
461 | ||
462 | #ifdef KERNEL | |
463 | /* | |
464 | * Free all network buffer memory used to keep saved packets. | |
465 | */ | |
466 | void fr_authunload() | |
467 | { | |
468 | register int i; | |
469 | register frauthent_t *fae, **faep; | |
470 | mb_t *m; | |
471 | ||
472 | MUTEX_ENTER(&ipf_auth); | |
473 | for (i = 0; i < FR_NUMAUTH; i++) { | |
474 | if ((m = fr_authpkts[i])) { | |
475 | FREE_MB_T(m); | |
476 | fr_authpkts[i] = NULL; | |
477 | fr_auth[i].fra_index = -1; | |
478 | } | |
479 | } | |
480 | ||
481 | ||
482 | for (faep = &fae_list; (fae = *faep); ) { | |
483 | *faep = fae->fae_next; | |
484 | KFREE(fae); | |
485 | } | |
486 | MUTEX_EXIT(&ipf_auth); | |
487 | } | |
488 | ||
489 | ||
490 | /* | |
491 | * Slowly expire held auth records. Timeouts are set | |
492 | * in expectation of this being called twice per second. | |
493 | */ | |
494 | void fr_authexpire() | |
495 | { | |
496 | register int i; | |
497 | register frauth_t *fra; | |
498 | register frauthent_t *fae, **faep; | |
499 | mb_t *m; | |
500 | #if !SOLARIS | |
501 | int s; | |
502 | #endif | |
503 | ||
504 | SPL_NET(s); | |
505 | MUTEX_ENTER(&ipf_auth); | |
506 | for (i = 0, fra = fr_auth; i < FR_NUMAUTH; i++, fra++) { | |
507 | if ((!--fra->fra_age) && (m = fr_authpkts[i])) { | |
508 | FREE_MB_T(m); | |
509 | fr_authpkts[i] = NULL; | |
510 | fr_auth[i].fra_index = -1; | |
511 | fr_authstats.fas_expire++; | |
512 | fr_authused--; | |
513 | } | |
514 | } | |
515 | ||
516 | for (faep = &fae_list; (fae = *faep); ) { | |
517 | if (!--fra->fra_age) { | |
518 | *faep = fae->fae_next; | |
519 | KFREE(fae); | |
520 | fr_authstats.fas_expire++; | |
521 | } else | |
522 | faep = &fae->fae_next; | |
523 | } | |
524 | MUTEX_EXIT(&ipf_auth); | |
525 | SPL_X(s); | |
526 | } | |
527 | #endif |