]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/ip_auth.c
xnu-123.5.tar.gz
[apple/xnu.git] / bsd / netinet / ip_auth.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 & 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