undns 0.4.0a

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,70 @@
1
+ /*
2
+ * Copyright (c) 2002
3
+ * Neil Spring and the University of Washington.
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions
8
+ * are met:
9
+ * 1. Redistributions of source code must retain the above copyright
10
+ * notice, this list of conditions and the following disclaimer.
11
+ * 2. Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ * 3. The name of the author(s) may not be used to endorse or promote
15
+ * products derived from this software without specific prior
16
+ * written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
19
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
22
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+ #ifndef _queue_h
31
+ #define _queue_h
32
+ #include "nscommon.h"
33
+ typedef struct queue_struct *queue;
34
+ typedef struct queue_element_struct *q_element;
35
+
36
+ /* q_comparator returns like strcmp. */
37
+ typedef int (*q_comparator)(const void *v1, const void *v2);
38
+ #define q_strcmp ((q_comparator)strcmp)
39
+ /*@only@*/
40
+ queue q_new(/*@null@*/ q_comparator compare,
41
+ /*@null@*/ void (*release)(void *v));
42
+ void q_delete(/*@only@*/ queue q);
43
+ q_element q_insert(queue q, /*@only@*/ const void *v);
44
+ q_element q_insert_fromdir(queue q, /*@only@*/ const void *v, boolean start_at_end);
45
+ void q_append(queue q, /*@only@*/ const void *v);
46
+
47
+ /* if expunge fails, you crash. don't expunge something not in the queue. */
48
+ void q_expunge(queue q, q_element elt_removed);
49
+ /* removeme is a pointer to the element in the queue, not
50
+ something that compares equal. */
51
+ /* returns true if found and removed. */
52
+ boolean q_remove(queue q, void * removeme);
53
+ /*@null@*/ /*@only@*/ const void *q_pop(queue q);
54
+ /*@null@*/ /*@dependent@*/ const void *q_top(const queue q);
55
+
56
+ /* returns TRUE if it wishes to go on */
57
+ typedef boolean (*q_iterator_q)(queue q, const void *value, void *user);
58
+ typedef boolean (*q_iterator)(const void *value, void *user);
59
+ /* q_iterate returns TRUE if it reached the end, FALSE if
60
+ interrupted by iterator returning FALSE */
61
+ boolean q_iterate(queue q,
62
+ q_iterator iterator,
63
+ /*@out@*/ void *user);
64
+ boolean q_iterate_q(queue q,
65
+ q_iterator_q iterator,
66
+ /*@out@*/ void *user);
67
+
68
+ unsigned long q_length(queue q);
69
+ void *q_find(queue q, const void *findme);
70
+ #endif
@@ -0,0 +1,517 @@
1
+ /* Copyright 1999-2002 Eric Hoffman, Neil Spring,
2
+ and the University of Washington */
3
+ #include "radix.h"
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <sys/types.h>
7
+ #ifdef WIN32
8
+ #include <fcntl.h>
9
+ #include <io.h>
10
+ #else
11
+ #include <netinet/in.h>
12
+ #endif
13
+ #ifdef HAVE_UNISTD_H
14
+ #include <unistd.h>
15
+ #endif
16
+ #include "buffer.h"
17
+ #include "fcntl.h"
18
+ #include <assert.h>
19
+
20
+ #undef DEBUG_INSERTION
21
+ #define DEBUG_LOOKUP(x...)
22
+
23
+ /* ugly global variable, which gets updated on entry from new
24
+ functions */
25
+ static struct patricia_table *current_table;
26
+ extern boolean want_debug;
27
+ boolean really_want_debug = FALSE;
28
+ boolean really_want_protection = FALSE;
29
+
30
+ #ifdef __ASSERT_VOID_CAST
31
+ /* we can, non-portably, define something that looks like assert and
32
+ works like assert, but aldo dumps the table */
33
+ #define radix_assert(expr) \
34
+ do { if(!(expr) && current_table != NULL) \
35
+ patricia_dump(current_table, "assert.dot"); \
36
+ (__ASSERT_VOID_CAST ((expr) ? 0 : \
37
+ (__assert_fail (__STRING(expr), __FILE__, __LINE__, \
38
+ __ASSERT_FUNCTION), 0))); } while(0)
39
+ #else
40
+ #define radix_assert(expr) assert(expr)
41
+ #endif
42
+
43
+
44
+ static char *
45
+ label_of_dest(address dest, prefixlen_t prefix,
46
+ /*@out@*//*@returned@*/char *buf);
47
+ static char *
48
+ label_of_node(const struct patricia_entry *r,
49
+ /*@out@*//*@returned@*/char *buf);
50
+
51
+ void *get_data(const struct patricia_entry *r){
52
+ return(r->data);
53
+ }
54
+ void set_data(struct patricia_entry *r, void *data) {
55
+ r->data = data;
56
+ }
57
+
58
+ /* exported for testing */
59
+ address
60
+ radix_mask(address addr, prefixlen_t prefix)
61
+ {
62
+ address m;
63
+ unsigned int shift = 32U - (unsigned int)prefix;
64
+ if(prefix==(prefixlen_t)0) return 0;
65
+ if(really_want_protection) assert(shift <= 32);
66
+ m=(1<<(shift))-1;
67
+ m=htonl(~m);
68
+ return(addr&m);
69
+ }
70
+
71
+ static unsigned int testmasks[33];
72
+ void radix_init_testmasks(void) {
73
+ unsigned int i;
74
+ for(i=1; i<=32; i++) {
75
+ testmasks[i] = htonl( 1 << (32U - i) );
76
+ }
77
+ }
78
+
79
+ static inline boolean radix_test(address addr, prefixlen_t x) {
80
+ return( x == (prefixlen_t) 0 || ((addr & testmasks[x]) != 0));
81
+ }
82
+
83
+ boolean radix_test_export(address addr, prefixlen_t x) {
84
+ return radix_test(addr,x);
85
+ }
86
+
87
+
88
+ #if 0
89
+ /* test bit 1..32 */
90
+ /* if testing bit zero, return true; consider that an implicit match. */
91
+ unsigned int
92
+ radix_test(address addr, prefixlen_t x)
93
+ {
94
+ address g;
95
+ unsigned int ret;
96
+ unsigned int shift = 32U - (unsigned int)x;
97
+ if((int)x==0) return 1;
98
+ g=htonl(addr);
99
+ ret = g&(1<<(shift));
100
+ if(ret && !radix_test_fast(addr, x)) {
101
+ exit(EXIT_FAILURE);
102
+ } else if(!ret && radix_test_fast(addr, x)) {
103
+ exit(EXIT_FAILURE);
104
+ }
105
+ return ret;
106
+ }
107
+ #endif
108
+
109
+
110
+ /*@null@*//*@dependent@*/
111
+ static struct patricia_entry *
112
+ find_route_internal(/*@null@*/struct patricia_entry *r,
113
+ address destination, prefixlen_t prefix)
114
+ {
115
+ if (!r) return(0);
116
+ if ((r->destination==destination) && (r->prefixlen ==prefix))
117
+ return(r);
118
+ if(r->position <= 32) {
119
+ if (radix_test(destination,r->position) != 0) {
120
+ return(find_route_internal(r->on,destination,prefix));
121
+ } else {
122
+ return(find_route_internal(r->off,destination,prefix));
123
+ }
124
+ } else {
125
+ return(NULL);
126
+ }
127
+ }
128
+
129
+ /*@null@*//*@dependent@*/
130
+ struct patricia_entry *
131
+ radix_resolve_route(/*@null@*/ struct patricia_entry * top,
132
+ address destination) {
133
+ struct patricia_entry * here=top;
134
+ struct patricia_entry * best=NULL;
135
+ prefixlen_t length=0;
136
+ char la[25] __attribute__((unused));
137
+
138
+ DEBUG_LOOKUP("looking for %s: ", label_of_dest(destination, 32, la));
139
+ while(here){
140
+ if ((here->prefixlen >= length)&&
141
+ (radix_mask(destination,here->prefixlen) == here->destination)){
142
+ best=here;
143
+ length=here->prefixlen;
144
+ DEBUG_LOOKUP("+%s ", label_of_node(here, la));
145
+ } else {
146
+ DEBUG_LOOKUP("-%s ", label_of_node(here, la));
147
+ }
148
+ if (here->position <= 32)
149
+ if( radix_test(destination,here->position) != 0)
150
+ here=here->on;
151
+ else
152
+ here=here->off;
153
+ else
154
+ here=NULL;
155
+ }
156
+ DEBUG_LOOKUP("result: %s\n", best? label_of_node(best, la): "none");
157
+ return(best);
158
+ }
159
+
160
+ static prefixlen_t find_difference(address a, address b, prefixlen_t maxbits){
161
+ prefixlen_t difference;
162
+ if(really_want_protection) assert(maxbits <= 33);
163
+ for (difference=(prefixlen_t)1;
164
+ (difference<maxbits &&
165
+ (radix_test(a,difference) ==
166
+ radix_test(b,difference))); ) {
167
+
168
+ difference += 1; /* the post-increment of the for loop can be done here, just to simplify. */
169
+ }
170
+ return(difference);
171
+ }
172
+ #ifdef DEBUG_INSERTION
173
+ static void radix_insert_debug(struct patricia_entry * new, const char * as,
174
+ struct patricia_entry * old) {
175
+ char buf[50], buf2[50];
176
+ VERBAL("radix_insert_debug %s %s %s-%d\n",
177
+ label_of_node(new, buf),
178
+ as,
179
+ label_of_node(old, buf2), old->position);
180
+ }
181
+ #else
182
+ static void radix_insert_debug(struct patricia_entry * new __attribute__((unused)),
183
+ const char * as __attribute__((unused)),
184
+ struct patricia_entry * old __attribute__((unused))) {
185
+ return;
186
+ }
187
+ #endif
188
+
189
+ void radix_insert(struct patricia_entry **p,
190
+ /*@owned@*//*@partial@*/struct patricia_entry *new)
191
+ {
192
+ prefixlen_t difference;
193
+ struct patricia_entry * old=*p;
194
+ int commonprefixlen;
195
+
196
+ /* a little piece of mind */
197
+ if(really_want_protection) {
198
+ assert(new->position == 0);
199
+ assert(new->on == NULL);
200
+ assert(new->off == NULL);
201
+
202
+ radix_assert(old== NULL || old->on == NULL ||
203
+ (old->on->on == NULL && old->on->off == NULL) ||
204
+ old->position <= old->on->position);
205
+ radix_assert(old== NULL || old->off == NULL||
206
+ (old->off->on == NULL && old->off->off == NULL) ||
207
+ old->position <= old->off->position);
208
+ }
209
+
210
+ /* an empty table or subtree */
211
+ if (old == NULL) {
212
+ new->position = new->prefixlen + 1;
213
+ *p = new;
214
+ radix_insert_debug (new, "in empty table", new);
215
+ return;
216
+ }
217
+
218
+ /* a duplicate */
219
+ if(old->destination == new->destination &&
220
+ old->prefixlen == new->prefixlen) {
221
+ /* NON-ROUTING-TABLE behavior: assume oldest, not newest, is right. */
222
+ radix_insert_debug (new, "is duplicate of", old);
223
+ return;
224
+ }
225
+
226
+ difference = find_difference(old->destination, new->destination,
227
+ min(new->prefixlen, old->prefixlen));
228
+ commonprefixlen = max((int)0, ((int)old->position)-1);
229
+
230
+ /* attempt to handle a strange case:
231
+ we're inserting something that shouldn't go further down
232
+ in the tree, because of prefix < position requirements. */
233
+ if(difference >= old->position &&
234
+ new->prefixlen <= old->position &&
235
+ old->position < old->prefixlen) {
236
+ struct patricia_entry * *child;
237
+ new->position = old->position;
238
+ new->on = old->on;
239
+ new->off = old->off;
240
+ old->on = old->off = NULL;
241
+ *p = new;
242
+
243
+ child = (radix_test(old->destination,new->position)!=0)
244
+ ? &new->on : &new->off;
245
+ radix_insert_debug (old, "as pushdown of", new);
246
+ old->position=0;
247
+ radix_insert(child, old);
248
+
249
+ return;
250
+ }
251
+
252
+ /* if new is contained in old/prefix; at least what old/position */
253
+ if( difference >= old->position ||
254
+ ((radix_mask(new->destination,commonprefixlen) ==
255
+ radix_mask(old->destination,commonprefixlen) )
256
+ && new->prefixlen > old->prefixlen )){
257
+
258
+ struct patricia_entry * *child = (radix_test(new->destination,old->position)!=0)
259
+ ? &old->on : &old->off;
260
+ radix_insert_debug (new, "as child of", old);
261
+ radix_insert(child, new);
262
+ if(really_want_protection) radix_assert(new->position > old->position ||
263
+ (new->position >= old->position &&
264
+ new->destination == old->destination));
265
+ return;
266
+ }
267
+
268
+ /* if old is contained in new */
269
+ /* if( (radix_mask(new->destination,old->prefixlen) == old->destination)
270
+ && new->prefixlen > old->prefixlen ){ */
271
+ do {
272
+ radix_insert_debug (new, "as parent of", old);
273
+ if(difference < old->position-1) {
274
+ if(radix_test(old->destination, difference) !=
275
+ radix_test(new->destination, difference)) {
276
+ new->position = difference;
277
+ } else {
278
+ new->position = difference + 1;
279
+ }
280
+ } else {
281
+ new->position = old->position - 1;
282
+ }
283
+ // new->position = min((int)difference, (int)old->position-1);
284
+ if(radix_test(old->destination, new->position)!=0) {
285
+ new->on = old;
286
+ } else {
287
+ new->off = old;
288
+ }
289
+ *p = new;
290
+ } while(0);
291
+
292
+ return;
293
+ }
294
+
295
+ static char *
296
+ label_of_dest(address dest, prefixlen_t prefixlen, /*@out@*//*@returned@*/char *buf) {
297
+ address a=ntohl(dest);
298
+ assert(prefixlen <= 32);
299
+ sprintf(buf,"%u.%u.%u.%u/%u",
300
+ a>>24, (a>>16)&255, (a>>8)&255, a&255,
301
+ prefixlen);
302
+ return(buf);
303
+ }
304
+
305
+ static char *
306
+ label_of_node(const struct patricia_entry *r,
307
+ /*@out@*//*@returned@*/char *dest)
308
+ {
309
+ return(label_of_dest(r->destination, r->prefixlen, dest));
310
+ }
311
+
312
+ static void
313
+ print_routing_table_internal(const struct patricia_entry *r,
314
+ buffer b,
315
+ unsigned int *max)
316
+ {
317
+ char here[255];
318
+
319
+ if (r){
320
+ if (r->position > *max) *max=r->position;
321
+ (void)label_of_node(r,here);
322
+ /*bprintf (b," {rank = same; %d ; \"%s\"}\n",r->position,here);*/
323
+ bprintf (b," \"%s\" [label = \"{<h> %s | {<off> 0 |bit %d |<on> 1}}\"];\n",
324
+ here, here, r->position);
325
+
326
+ if (r->off){
327
+ char off[255];
328
+ bprintf (b," \"%s\":off -> \"%s\"[label=\"%d=0\"];\n",
329
+ here,label_of_node(r->off,off),r->position);
330
+ print_routing_table_internal(r->off,b,max);
331
+ }
332
+ if (r->on){
333
+ char on[255];
334
+ bprintf (b," \"%s\":on -> \"%s\"[label=\"%d=1\"];\n",
335
+ here, label_of_node(r->on,on), r->position);
336
+ print_routing_table_internal(r->on,b,max);
337
+ }
338
+ }
339
+ }
340
+
341
+ void radix_print_routing_table_dot(const struct patricia_entry *top, int fd)
342
+ {
343
+ unsigned max=0;
344
+ buffer b=create_buffer(100);
345
+ buffer base=create_buffer(100);
346
+
347
+ bprintf (base,"digraph radix {\n");
348
+ bprintf (base," size=\"10,7.5\"; ratio=auto; ordering=out\n");
349
+ bprintf (base," node [shape=record,width=.3,height=.3]\n");
350
+ if (top) {
351
+ // char z[90];
352
+ // eh. bprintf (b," root -> \"%s\";\n",label_of_node(top,z));
353
+ print_routing_table_internal(top,b,&max);
354
+ }
355
+ assert(write(fd,base->contents,(size_t)base->fill)>0);
356
+ assert(write(fd,b->contents,(size_t)b->fill)>0);
357
+ assert(write(fd,"}\n",2));
358
+ free_buffer(b);
359
+ free_buffer(base);
360
+ }
361
+
362
+ static void remove_route_internal(struct patricia_entry * *place,
363
+ address destination,
364
+ unsigned int prefixlen)
365
+ {
366
+ struct patricia_entry * r=*place;
367
+ if (r){
368
+ if ((r->destination!=destination) || (r->prefixlen!=prefixlen)){
369
+ if (radix_test(destination,r->position) != 0)
370
+ remove_route_internal(&r->on,destination,prefixlen);
371
+ else
372
+ remove_route_internal(&r->off,destination,prefixlen);
373
+ } else {
374
+ /* found it */
375
+ if (r->on) {
376
+ struct patricia_entry * q=r->on;
377
+ if (r->off) {
378
+ /* the rotation case*/
379
+ remove_route_internal(&r->on,q->destination,q->prefixlen);
380
+ q->position=r->position;
381
+ q->off=r->off;
382
+ q->on=r->on;
383
+ }
384
+ *place=q;
385
+ } else *place=r->off;
386
+ }
387
+ }
388
+ }
389
+
390
+ void radix_remove_route(struct patricia_table * n,
391
+ address destination,
392
+ prefixlen_t prefixlen)
393
+ {
394
+ if(n->routes) /* cheap check keeps lclint happy */
395
+ remove_route_internal(&n->routes,destination,prefixlen);
396
+ }
397
+
398
+ static void
399
+ print_routing_table_text_internal(const struct patricia_entry *r,
400
+ FILE *fdout) {
401
+ if (r){
402
+ char here[25];
403
+ fprintf(fdout, " %s via --\n", label_of_node(r,here));
404
+ print_routing_table_text_internal(r->off,fdout);
405
+ print_routing_table_text_internal(r->on,fdout);
406
+ }
407
+ }
408
+
409
+ void radix_print_routing_table_text(const struct patricia_entry *top,
410
+ FILE *fdout) {
411
+ fprintf(fdout, "Routing table:\n");
412
+ if(top)
413
+ print_routing_table_text_internal(top, fdout);
414
+ }
415
+
416
+
417
+ struct patricia_table * patricia_new(void){
418
+ NEWPTR(struct patricia_table, p);
419
+ radix_init_testmasks(); /* can overwrite */
420
+ p->routes = NULL;
421
+ p->default_route = NULL;
422
+ return(p);
423
+ }
424
+
425
+ static void recursive_delete(struct patricia_entry *e,
426
+ /*@null@*/ void (*data_free)(void *)) {
427
+ if(e != NULL) {
428
+ if(e->on != NULL) recursive_delete(e->on, data_free);
429
+ if(e->off != NULL) recursive_delete(e->off, data_free);
430
+ if(data_free != NULL) data_free(e->data);
431
+ free(e);
432
+ }
433
+ }
434
+
435
+ void patricia_delete(struct patricia_table * p,
436
+ /*@null@*/ void (*data_free)(void *)) {
437
+ recursive_delete(p->routes, data_free);
438
+ recursive_delete(p->default_route, data_free);
439
+ p->routes = NULL;
440
+ p->default_route = NULL;
441
+ free(p);
442
+ }
443
+
444
+ void patricia_insert(struct patricia_table * pt,
445
+ address a,
446
+ prefixlen_t prefixlen,
447
+ void *data) {
448
+ /* really try to avoid duplication; I'd rather do that
449
+ in the radix_insert(), but that seems like a pain atm.*/
450
+ // if(find_route_internal(pt->routes, a, prefixlen) == NULL) {
451
+ NEWPTR(struct patricia_entry, pe); /* this allocated memory may be leaked by scriptroute 1/14/07 */
452
+ current_table = pt; /* icky */
453
+ assert(pe != NULL);
454
+ assert(prefixlen <=32);
455
+ assert(pt != NULL);
456
+ pe->destination = a;
457
+ if(radix_mask(a, prefixlen) != a) {
458
+ // VERBAL("dropping errant 0x%x/%u\n", a, prefixlen);
459
+ free(pe);
460
+ return;
461
+ }
462
+ pe->prefixlen = prefixlen;
463
+ pe->data = data;
464
+ pe->position = 0;
465
+ pe->on = NULL;
466
+ pe->off = NULL;
467
+ if(really_want_debug) {
468
+ // VERBAL("patricia_insert(pt, 0x%x, %u, (void *)0x%p);\n", a, prefixlen, data);
469
+ }
470
+ radix_insert(&pt->routes, pe);
471
+ if(really_want_protection) assert(find_route_internal(pt->routes, a, prefixlen) != NULL);
472
+ //}
473
+ }
474
+ /*@null@*/
475
+ void *patricia_lookup(struct patricia_table * pt, address a) {
476
+ struct patricia_entry * pe;
477
+ // char buf[256];
478
+ current_table = pt;
479
+ pe = radix_resolve_route(pt->routes, a);
480
+ if(pe == NULL) {
481
+ pe = pt->default_route;
482
+ }
483
+ if(pe == NULL) {
484
+ return NULL;
485
+ }
486
+ // printf("foundl %s\n", label_of_node(pe, buf));
487
+ return(pe->data);
488
+ }
489
+
490
+ boolean
491
+ patricia_lookup_all(struct patricia_table * pt,
492
+ address a,
493
+ /*@out@*/ address *prefix,
494
+ /*@out@*/ prefixlen_t *prefixlen,
495
+ /*@out@*/ void **data) {
496
+ struct patricia_entry * pe;
497
+ // char buf[256];
498
+ current_table = pt;
499
+ pe = radix_resolve_route(pt->routes, a);
500
+ if(pe == NULL) {
501
+ pe = pt->default_route;
502
+ }
503
+ if(pe == NULL) {
504
+ return FALSE;
505
+ }
506
+ // printf("found %s\n", label_of_node(pe, buf));
507
+ *prefix = pe->destination;
508
+ *prefixlen = pe->prefixlen;
509
+ *data = pe->data;
510
+ return TRUE;
511
+ }
512
+
513
+ void patricia_dump(struct patricia_table * pt, const char *filename) {
514
+ int f = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0644);
515
+ radix_print_routing_table_dot(pt->routes, f);
516
+ close(f);
517
+ }