undns 0.4.0a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }