1 /* $NetBSD: ip_htable.c,v 1.1.1.1 2004/03/28 08:56:43 martti Exp $ */
2
3 /*
4 * Copyright (C) 1993-2001, 2003 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef _KERNEL
11 # define KERNEL 1
12 # define _KERNEL 1
13 #endif
14 #include <sys/param.h>
15 #include <sys/types.h>
16 #include <sys/errno.h>
17 #include <sys/time.h>
18 #include <sys/file.h>
19 #if !defined(_KERNEL)
20 # include <stdlib.h>
21 # include <string.h>
22 # define _KERNEL
23 # ifdef __OpenBSD__
24 struct file;
25 # endif
26 # include <sys/uio.h>
27 # undef _KERNEL
28 #endif
29 #include <sys/socket.h>
30 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
31 # include <sys/malloc.h>
32 #endif
33 #if defined(__FreeBSD__)
34 # include <sys/cdefs.h>
35 # include <sys/proc.h>
36 #endif
37 #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
38 !defined(linux)
39 # include <sys/mbuf.h>
40 #endif
41 #if defined(_KERNEL)
42 # include <sys/systm.h>
43 #else
44 # include <stdio.h>
45 #endif
46 #include <netinet/in.h>
47 #include <net/if.h>
48
49 #include "netinet/ip_compat.h"
50 #include "netinet/ip_fil.h"
51 #include "netinet/ip_lookup.h"
52 #include "netinet/ip_htable.h"
53 /* END OF INCLUDES */
54
55 #if !defined(lint)
56 static const char rcsid[] = "@(#)Id: ip_htable.c,v 2.34.2.1 2004/03/06 14:32:58 darrenr Exp";
57 #endif
58
59 #ifdef IPFILTER_LOOKUP
60 static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *));
61 static u_long ipht_nomem[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
62 static u_long ipf_nhtables[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
63 static u_long ipf_nhtnodes[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
64
65 iphtable_t *ipf_htables[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
66 NULL, NULL, NULL, NULL };
67
68
69 void fr_htable_unload()
70 {
71 iplookupflush_t fop;
72
73 fop.iplf_unit = IPL_LOGALL;
74 (void)fr_flushhtable(&fop);
75 }
76
77
78 int fr_gethtablestat(op)
79 iplookupop_t *op;
80 {
81 iphtstat_t stats;
82
83 if (op->iplo_size != sizeof(stats))
84 return EINVAL;
85
86 stats.iphs_tables = ipf_htables[op->iplo_unit];
87 stats.iphs_numtables = ipf_nhtables[op->iplo_unit];
88 stats.iphs_numnodes = ipf_nhtnodes[op->iplo_unit];
89 stats.iphs_nomem = ipht_nomem[op->iplo_unit];
90
91 return COPYOUT(&stats, op->iplo_struct, sizeof(stats));
92
93 }
94
95
96 /*
97 * Create a new hash table using the template passed.
98 */
99 int fr_newhtable(op)
100 iplookupop_t *op;
101 {
102 iphtable_t *iph, *oiph;
103 char name[FR_GROUPLEN];
104 int err, i, unit;
105
106 KMALLOC(iph, iphtable_t *);
107 if (iph == NULL)
108 return ENOMEM;
109
110 err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
111 if (err != 0) {
112 KFREE(iph);
113 return EFAULT;
114 }
115
116 unit = op->iplo_unit;
117 if (iph->iph_unit != unit) {
118 KFREE(iph);
119 return EINVAL;
120 }
121
122 if ((op->iplo_arg & IPHASH_ANON) == 0) {
123 if (fr_findhtable(op->iplo_unit, op->iplo_name) != NULL) {
124 KFREE(iph);
125 return EEXIST;
126 }
127 } else {
128 i = IPHASH_ANON;
129 do {
130 i++;
131 #if defined(SNPRINTF) && defined(_KERNEL)
132 SNPRINTF(name, sizeof(name), "%u", i);
133 #else
134 (void)sprintf(name, "%u", i);
135 #endif
136 for (oiph = ipf_htables[unit]; oiph != NULL;
137 oiph = oiph->iph_next)
138 if (strncmp(oiph->iph_name, name,
139 sizeof(oiph->iph_name)) == 0)
140 break;
141 } while (oiph != NULL);
142 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
143 err = COPYOUT(iph, op->iplo_struct, sizeof(*iph));
144 if (err != 0) {
145 KFREE(iph);
146 return EFAULT;
147 }
148 iph->iph_type |= IPHASH_ANON;
149 }
150
151 KMALLOCS(iph->iph_table, iphtent_t **,
152 iph->iph_size * sizeof(*iph->iph_table));
153 if (iph->iph_table == NULL) {
154 KFREE(iph);
155 ipht_nomem[unit]++;
156 return ENOMEM;
157 }
158
159 bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
160 iph->iph_masks = 0;
161
162 iph->iph_next = ipf_htables[unit];
163 iph->iph_pnext = &ipf_htables[unit];
164 if (ipf_htables[unit] != NULL)
165 ipf_htables[unit]->iph_pnext = &iph->iph_next;
166 ipf_htables[unit] = iph;
167
168 ipf_nhtables[unit]++;
169
170 return 0;
171 }
172
173
174 /*
175 */
176 int fr_removehtable(op)
177 iplookupop_t *op;
178 {
179 iphtable_t *iph;
180
181
182 iph = fr_findhtable(op->iplo_unit, op->iplo_name);
183 if (iph == NULL)
184 return ESRCH;
185
186 if (iph->iph_unit != op->iplo_unit) {
187 return EINVAL;
188 }
189
190 if (iph->iph_ref != 0) {
191 return EBUSY;
192 }
193
194 fr_delhtable(iph);
195
196 return 0;
197 }
198
199
200 void fr_delhtable(iph)
201 iphtable_t *iph;
202 {
203 iphtent_t *ipe;
204 int i;
205
206 for (i = 0; i < iph->iph_size; i++)
207 while ((ipe = iph->iph_table[i]) != NULL)
208 if (fr_delhtent(iph, ipe) != 0)
209 return;
210
211 *iph->iph_pnext = iph->iph_next;
212 if (iph->iph_next != NULL)
213 iph->iph_next->iph_pnext = iph->iph_pnext;
214
215 ipf_nhtables[iph->iph_unit]--;
216
217 if (iph->iph_ref == 0) {
218 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
219 KFREE(iph);
220 }
221 }
222
223
224 void fr_derefhtable(iph)
225 iphtable_t *iph;
226 {
227 iph->iph_ref--;
228 if (iph->iph_ref == 0)
229 fr_delhtable(iph);
230 }
231
232
233 iphtable_t *fr_findhtable(unit, name)
234 int unit;
235 char *name;
236 {
237 iphtable_t *iph;
238
239 for (iph = ipf_htables[unit]; iph != NULL; iph = iph->iph_next)
240 if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0)
241 break;
242 return iph;
243 }
244
245
246 size_t fr_flushhtable(op)
247 iplookupflush_t *op;
248 {
249 iphtable_t *iph;
250 size_t freed;
251 int i;
252
253 freed = 0;
254
255 for (i = 0; i <= IPL_LOGMAX; i++) {
256 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
257 while ((iph = ipf_htables[i]) != NULL) {
258 fr_delhtable(iph);
259 freed++;
260 }
261 }
262 }
263
264 return freed;
265 }
266
267
268 /*
269 * Add an entry to a hash table.
270 */
271 int fr_addhtent(iph, ipeo)
272 iphtable_t *iph;
273 iphtent_t *ipeo;
274 {
275 iphtent_t *ipe;
276 u_int hv;
277 int bits;
278
279 KMALLOC(ipe, iphtent_t *);
280 if (ipe == NULL)
281 return -1;
282
283 bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
284 ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr;
285 ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr);
286 bits = count4bits(ipe->ipe_mask.in4_addr);
287 ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr);
288
289 hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr,
290 iph->iph_size);
291 ipe->ipe_ref = 0;
292 ipe->ipe_next = iph->iph_table[hv];
293 ipe->ipe_pnext = iph->iph_table + hv;
294
295 if (iph->iph_table[hv] != NULL)
296 iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next;
297 iph->iph_table[hv] = ipe;
298 if ((bits >= 0) && (bits != 32))
299 iph->iph_masks |= 1 << bits;
300
301 switch (iph->iph_type & ~IPHASH_ANON)
302 {
303 case IPHASH_GROUPMAP :
304 ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL,
305 iph->iph_flags, IPL_LOGIPF,
306 fr_active);
307 break;
308
309 default :
310 ipe->ipe_ptr = NULL;
311 ipe->ipe_value = 0;
312 break;
313 }
314
315 ipf_nhtnodes[iph->iph_unit]++;
316
317 return 0;
318 }
319
320
321 /*
322 * Delete an entry from a hash table.
323 */
324 int fr_delhtent(iph, ipe)
325 iphtable_t *iph;
326 iphtent_t *ipe;
327 {
328
329 if (ipe->ipe_ref != 0)
330 return EBUSY;
331
332
333 *ipe->ipe_pnext = ipe->ipe_next;
334 if (ipe->ipe_next != NULL)
335 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
336
337 switch (iph->iph_type & ~IPHASH_ANON)
338 {
339 case IPHASH_GROUPMAP :
340 if (ipe->ipe_group != NULL)
341 fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active);
342 break;
343
344 default :
345 ipe->ipe_ptr = NULL;
346 ipe->ipe_value = 0;
347 break;
348 }
349
350 KFREE(ipe);
351
352 ipf_nhtnodes[iph->iph_unit]--;
353
354 return 0;
355 }
356
357
358 void *fr_iphmfindgroup(tptr, aptr)
359 void *tptr, *aptr;
360 {
361 struct in_addr *addr;
362 iphtable_t *iph;
363 iphtent_t *ipe;
364 void *rval;
365
366 READ_ENTER(&ip_poolrw);
367 iph = tptr;
368 addr = aptr;
369
370 ipe = fr_iphmfind(iph, addr);
371 if (ipe != NULL)
372 rval = ipe->ipe_ptr;
373 else
374 rval = NULL;
375 RWLOCK_EXIT(&ip_poolrw);
376 return rval;
377 }
378
379
380 int fr_iphmfindip(tptr, version, aptr)
381 void *tptr, *aptr;
382 int version;
383 {
384 struct in_addr *addr;
385 iphtable_t *iph;
386 iphtent_t *ipe;
387 int rval;
388
389 if (version != 4)
390 return 1;
391
392 if (tptr == NULL || aptr == NULL)
393 return 1;
394
395 iph = tptr;
396 addr = aptr;
397
398 READ_ENTER(&ip_poolrw);
399 ipe = fr_iphmfind(iph, addr);
400 if (ipe != NULL)
401 rval = 0;
402 else
403 rval = 1;
404 RWLOCK_EXIT(&ip_poolrw);
405 return rval;
406 }
407
408
409 /* Locks: ip_poolrw */
410 static iphtent_t *fr_iphmfind(iph, addr)
411 iphtable_t *iph;
412 struct in_addr *addr;
413 {
414 u_32_t hmsk, msk, ips;
415 iphtent_t *ipe;
416 u_int hv;
417
418 hmsk = iph->iph_masks;
419 msk = 0xffffffff;
420 maskloop:
421 ips = ntohl(addr->s_addr) & msk;
422 hv = IPE_HASH_FN(ips, msk, iph->iph_size);
423 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
424 if (ipe->ipe_mask.in4_addr != msk ||
425 ipe->ipe_addr.in4_addr != ips) {
426 continue;
427 }
428 break;
429 }
430
431 if ((ipe == NULL) && (hmsk != 0)) {
432 while (hmsk != 0) {
433 msk <<= 1;
434 if (hmsk & 0x80000000)
435 break;
436 hmsk <<= 1;
437 }
438 if (hmsk != 0) {
439 hmsk <<= 1;
440 goto maskloop;
441 }
442 }
443 return ipe;
444 }
445
446 #endif /* IPFILTER_LOOKUP */
Cache object: 0f97b24c2c9edd66b39fdf51f43f3e81
|