undns 0.4.0f → 0.4.0h

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0a0427aa879826016674018308678c320e467f9c
4
- data.tar.gz: e8bcfd6dd560ae8a0b7a34528a6e7d387e9a7598
3
+ metadata.gz: 0d4a8579ec7c425c5f34a5fd44afbcc9938c253b
4
+ data.tar.gz: 5587a5805eafb34b46c1060392e3850612df9980
5
5
  SHA512:
6
- metadata.gz: c0b86b92710a6bd58e686b2398dc4834ca17c38b8df40c990126354b9472c170c764aa42c14b561eae0a750b4c520edb31b6fee2fa98f7e24c89e54b4faabaf9
7
- data.tar.gz: df932b28a3a90474baadc01ce6e15cb120173ea823be22ea5fade45dc5c9a4ae6f7e1e18df7cbf2be61a1465c028c0a192d175c64c6c56e10da3f6c867932816
6
+ metadata.gz: 8644cba6f0761564bdb4435e44e0881bd331e541d49be7856593e59a528cf46e14b3eb4dff94f5c4f8903e1824a3afafcb6fb69eaa0044ac9be565f118039bc9
7
+ data.tar.gz: 40f2db5a09a506e73e584a247f1615038903c2bec73dc88b8c64a4bd4d81652e14ad1037c7922de71bf75b29d83bbf2d1bdeae0ea698f117a7f7ea7955099f32
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'undns'
4
+
5
+ if ARGV.empty? then
6
+ puts "usage: '#{$0} address' where address is a v4 or v6 address"
7
+ end
8
+
9
+ puts Undns.origin_for_address_str(ARGV[0])
@@ -0,0 +1,127 @@
1
+ #! /usr/bin/ruby
2
+
3
+ require 'undns'
4
+
5
+ ZebraDumpParser = Undns::Path::origins6_dat.gsub(/origins6.dat/, 'zebra-dump-parser.pl')
6
+ unless test(?e, ZebraDumpParser)
7
+ $stderr.puts "Expected to find #{ZebraDumpParser}, which is missing"
8
+ exit 1
9
+ end
10
+
11
+
12
+ # TODO: check that bunzip2 exists
13
+
14
+ puts Undns::Path::origins6_dat
15
+ if test(?s,Undns::Path::origins6_dat) then
16
+ age = Time.now - File.stat(Undns::Path::origins6_dat).mtime
17
+ size = File.stat(Undns::Path::origins6_dat).size
18
+ if age > 14000 || size < 30000 then
19
+ puts "will *update* #{Undns::Path::origins6_dat}"
20
+ else
21
+ puts "will *not* update #{Undns::Path::origins6_dat}, which is only #{(age / 3600).to_i} hours old; aborting."
22
+ puts "remove #{Undns::Path::origins6_dat} if you really want to update."
23
+ exit
24
+ end
25
+ else
26
+ puts "will *create* #{Undns::Path::origins6_dat}"
27
+ end
28
+
29
+ # early open, in case lack permissions
30
+ o = File.open("%s-new" % Undns::Path::origins6_dat, "w")
31
+
32
+ URL = 'http://archive.routeviews.org/route-views6/bgpdata/%4d.%02d/RIBS/rib.%4d%02d%02d.0000.bz2' % [
33
+ Time.now.year, Time.now.month,
34
+ Time.now.year, Time.now.month, Time.now.day ]
35
+
36
+ def canonicalize(network)
37
+ octets = Array.new(4)
38
+ octets[0], octets[1], octets[2], octets[3], bits = network.split(/[\/\.]/)
39
+ if bits then
40
+ # octets = prefix.split('.')
41
+ bits_that_should_be_zero = (1 << (32-bits.to_i)) - 1
42
+ if (octets[3].to_i & bits_that_should_be_zero) != 0 then
43
+ $stderr.puts "bad prefix #{network}"
44
+ end
45
+ return network # not as written by ratul; he ensured that there were no stray bits.
46
+ else
47
+ # this part as written by Ratul, though not classful, which surprises me.
48
+ # octets = prefix.split('.')
49
+ if octets[3] != '0' then
50
+ if octets[2] != '0' then
51
+ if octets[1] != '0' then
52
+ bits = 8
53
+ else
54
+ bits = 16
55
+ end
56
+ else
57
+ bits = 24
58
+ end
59
+ else
60
+ $stderr.puts "unexpected."
61
+ end
62
+ return "%s/%d" % [ network, bits ]
63
+ end
64
+ end
65
+
66
+ # a difficult line, guess which.
67
+ #* 213.200.192.0/18 12.0.1.63 0 0 0 7018 3320 3303 44038 i
68
+ #* 213.200.196.144/29164.128.32.11 0 0 0 3303 ?
69
+ #* 213.200.197.80/30164.128.32.11 0 0 0 3303 ?
70
+ #* 213.200.208.16/29164.128.32.11 0 0 0 3303 ?
71
+
72
+ # IO.popen('curl %s | bunzip2' % URL).each { |ln|
73
+ started = false
74
+ networkPos = nil
75
+ pathPos = nil
76
+ lastline = nil
77
+ origins = Hash.new { |h,k| h[k] = Array.new }
78
+ i = 0
79
+
80
+ Kernel::system("mkdir -p /tmp/undns-update-origins-dat")
81
+ IntermediatePath = "/tmp/undns-update-origins-dat/rib.bz2"
82
+ if(!test(?s, IntermediatePath)) then
83
+ $stderr.puts "downloading #{URL} to #{IntermediatePath}"
84
+ unless Kernel::system("curl #{URL} -o #{IntermediatePath}") then
85
+ $stderr.puts "download failed\n"
86
+ exit 1
87
+ end
88
+ else
89
+ age = Time.now - File.stat(IntermediatePath).mtime
90
+ size = File.stat(IntermediatePath).size
91
+ if age > 3000 || size < 30000000 then # size check in case was incomplete once.
92
+ $stderr.puts "re-downloading #{URL} to #{IntermediatePath}"
93
+ unless Kernel::system("curl #{URL} -o #{IntermediatePath}") then
94
+ $stderr.puts "download failed\n"
95
+ exit 1
96
+ end
97
+ else
98
+ $stderr.puts "relying on cached #{IntermediatePath} for #{URL}; remove it if bad."
99
+ end
100
+ end
101
+ $stderr.puts "converting #{IntermediatePath} via zebra-dump-parser.pl"
102
+
103
+ last_ln = nil
104
+ last_prefix = nil
105
+ IO.popen("bunzip2 -c #{IntermediatePath} | perl #{ZebraDumpParser}", "r").each { |ln|
106
+ prefix, origin = ln.split(' ')
107
+ if last_prefix then
108
+ if last_prefix != prefix then
109
+ o.puts last_ln
110
+ else
111
+ last_ln = last_ln.chomp + ',' + origin
112
+ end
113
+ end
114
+ last_ln = ln
115
+ last_prefix = prefix
116
+ }
117
+
118
+ o.close
119
+ $stderr.puts "%d bytes" % [ File::stat("%s-new" % Undns::Path::origins6_dat).size ]
120
+
121
+ if(test(?e, Undns::Path::origins6_dat)) then
122
+ Kernel.system('diff -urb %s %s-new > %s.diff' % [ Undns::Path::origins6_dat, Undns::Path::origins6_dat, Undns::Path::origins6_dat ])
123
+ Kernel.system('mv %s %s-old' % [ Undns::Path::origins6_dat, Undns::Path::origins6_dat ])
124
+ end
125
+ Kernel.system('mv %s-new %s' % [ Undns::Path::origins6_dat, Undns::Path::origins6_dat ])
126
+
127
+
@@ -11,6 +11,7 @@
11
11
  #ifdef DEPRECATED_GNU_REGEX
12
12
  #include <gnuregex.h>
13
13
  #else
14
+ #include <sys/types.h>
14
15
  #include <regex.h>
15
16
  #endif
16
17
  #else
@@ -50,6 +51,18 @@ void init_earth(const char *LocationTableFilename) {
50
51
  FILE *ltfp = fopen(LocationTableFilename, "r");
51
52
  char regex[] = "^\"([^\"]+)\" *(-?[0-9\\.]+) *(-?[0-9\\.]+)";
52
53
  char linebuf[255];
54
+ #ifdef DEPRECATED_GNU_REGEX
55
+ struct re_pattern_buffer rpbuf;
56
+ struct re_registers regs;
57
+ #else
58
+ /* typical */
59
+ #ifndef REGS_LEN
60
+ #define REGS_LEN 10
61
+ #endif
62
+ regex_t rpbuf;
63
+ regmatch_t regs[REGS_LEN];
64
+ #endif
65
+
53
66
  if(ltfp == NULL) {
54
67
  printf("Unable to load %s as location table\n",
55
68
  LocationTableFilename);
@@ -57,8 +70,6 @@ void init_earth(const char *LocationTableFilename) {
57
70
  }
58
71
  #ifdef DEPRECATED_GNU_REGEX
59
72
  re_syntax_options = RE_SYNTAX_POSIX_EGREP;
60
- struct re_registers regs;
61
- struct re_pattern_buffer rpbuf;
62
73
  memset(&rpbuf, 0, sizeof(struct re_pattern_buffer));
63
74
  {
64
75
  const char *errstr =
@@ -71,11 +82,6 @@ void init_earth(const char *LocationTableFilename) {
71
82
  }
72
83
  regs.num_regs = REGS_UNALLOCATED;
73
84
  #else
74
- regex_t rpbuf;
75
- #ifndef REGS_LEN
76
- #define REGS_LEN 10
77
- #endif
78
- regmatch_t regs[REGS_LEN];
79
85
  {
80
86
  int error = regcomp(&rpbuf, regex, REG_EXTENDED);
81
87
  if(error) {
@@ -114,16 +120,21 @@ void init_earth(const char *LocationTableFilename) {
114
120
  }
115
121
  #else
116
122
  // printf("-- %s", linebuf);
117
- memset(regs, 0, sizeof(regs));
123
+ // memset(regs, 0, sizeof(regs));
118
124
  int reg_ret = regexec(&rpbuf, linebuf, REGS_LEN-1, regs, 0);
119
125
  if(reg_ret == REG_NOMATCH) {
120
126
  fprintf(stderr, "init_earth: Couldn't parse line: %s", linebuf);
121
127
  free(newlte);
122
128
  continue;
129
+ #ifdef REG_ILLSEQ
130
+ /* stanza only here while debugging the sys/types
131
+ needed before regex issue */
132
+ /* but why remove it. */
123
133
  } else if(reg_ret == REG_ILLSEQ) {
124
134
  fprintf(stderr, "init_earth: Illegal character sequence in (skipped) line: %s", linebuf);
125
135
  free(newlte);
126
136
  continue;
137
+ #endif
127
138
  } else if(reg_ret != 0) {
128
139
  fprintf(stderr, "init_earth: unexpected nonzero return from regexec: %d\n", reg_ret);
129
140
  exit(1);
@@ -89,8 +89,6 @@ hashtable ht_new(unsigned int size,
89
89
  ht->free_keyval = free_keyval;
90
90
  #ifdef _REENTRANT
91
91
  (void)pthread_mutexattr_init(&attrib);
92
- // (void)pthread_mutexattr_setkind_np(&attrib, PTHREAD_MUTEX_RECURSIVE_NP);
93
- // (void)pthread_mutexattr_setkind(&attrib, PTHREAD_MUTEX_RECURSIVE_NP);
94
92
  #ifdef PTHREAD_MUTEX_RECURSIVE_NP
95
93
  /* linux only */
96
94
  (void)pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE_NP);
@@ -318,9 +316,9 @@ boolean ht_iterate_pairs(hashtable ht, unsigned int nThreads, unsigned int chunk
318
316
  boolean ht_iterate_pairs(hashtable ht, unsigned int nThreads, unsigned int chunkSize,
319
317
  boolean (*callback)(const void *keyval, const void *keyval2)) {
320
318
  unsigned int threadId;
319
+ ht_iterate_pairs_pthread_struct * data;
321
320
  /* probably should make nThreads be 1 or abort if not 1.... */
322
321
  if(ht == NULL) return FALSE;
323
- ht_iterate_pairs_pthread_struct * data;
324
322
  assert(nThreads<100);
325
323
  assert(chunkSize < ht->table_size);
326
324
 
@@ -13,16 +13,20 @@
13
13
  #include "nscommon.h"
14
14
  #include "originAS.h"
15
15
  #include "radix.h"
16
+ #include "radix6.h"
16
17
  #include "exception.h"
17
18
  #include "ruleset.h" /* fopen_path_r */
18
19
 
19
20
  static struct patricia_table *origins;
21
+ static struct patricia6_table *origins6;
22
+
20
23
  static in_addr_t addr_from_octets(unsigned int o1, unsigned int o2,
21
24
  unsigned int o3, unsigned int o4){
22
25
  return (htonl((o1<<24) + (o2<<16) + (o3<<8) + o4));
23
26
  }
24
27
 
25
28
  const char *Origins_In_Use;
29
+ const char *Origins6_In_Use;
26
30
 
27
31
  void
28
32
  origins_init(const char *origins_dat) {
@@ -54,6 +58,41 @@ origins_init(const char *origins_dat) {
54
58
  }
55
59
  fclose(in);
56
60
  }
61
+ void
62
+ origins6_init(const char *origins6_dat) {
63
+ char linebuf[90];
64
+ // FILE *in = popen("./show_origins.pl | sort -u", "r");
65
+ const char *filename = (origins6_dat != NULL) ? origins6_dat : "origins6.dat";
66
+ FILE *in = fopen_path_r(filename, &Origins_In_Use);
67
+ if(in == NULL) {
68
+ char buf[255];
69
+ sprintf(buf, "can't open origins6.dat(%s): %s", filename, strerror(errno));
70
+ throw_void(buf);
71
+ }
72
+ origins6 = patricia6_new();
73
+ while(!feof(in) && fgets(linebuf, sizeof(linebuf), in) != NULL) {
74
+ char addrbuf[61];
75
+ unsigned int len, as;
76
+ if(sscanf(linebuf, "%60[a-f0-9A-F:]/%u %u",
77
+ addrbuf, &len, &as) == 3) {
78
+ struct in6_addr addr;
79
+ inet_pton(AF_INET6, addrbuf, &addr);
80
+ // fprintf(stderr, "inserting %s/%d\n", addrbuf, len);
81
+ patricia6_insert(origins6, addr, len, (void *)as);
82
+ } else if(sscanf(linebuf, "%60[a-f0-9A-F:]/%u {%u",
83
+ addrbuf, &len, &as) == 6) {
84
+ /* pick the first one from a multiple-origins line */
85
+ struct in6_addr addr;
86
+ inet_pton(AF_INET6, addrbuf, &addr);
87
+ patricia6_insert(origins6, addr, len, (void *)as);
88
+ } else {
89
+ /* this has never forced me to actually address this issue, it just clouds
90
+ up the output file. */
91
+ printf("originAS: recoverable error parsing '%s' in origins.dat\n", linebuf);
92
+ }
93
+ }
94
+ fclose(in);
95
+ }
57
96
 
58
97
  unsigned short origin_for_address(in_addr_t a) {
59
98
  if ( origins == NULL ) {
@@ -67,10 +106,29 @@ unsigned short origin_for_address(in_addr_t a) {
67
106
  }
68
107
  }
69
108
 
109
+ unsigned short origin6_for_address(struct in6_addr a) {
110
+ if ( origins6 == NULL ) {
111
+ origins6_init(NULL);
112
+ }
113
+ if ( origins6 != NULL ) {
114
+ return((unsigned short)(unsigned int)patricia6_lookup(origins6, a));
115
+ } else {
116
+ fprintf(stderr, "Origins6 failed to initialize\n"); /* shouldn't get here. */
117
+ return(0);
118
+ }
119
+ }
120
+
70
121
  unsigned short origin_for_address_str(const char *addrstring) {
71
122
  struct in_addr a;
123
+ struct in6_addr a6;
124
+
125
+ if(addrstring == NULL) return 0;
72
126
  if(inet_aton(addrstring, &a)) {
127
+ // fprintf(stderr, "parsing %s as v4\n", addrstring);
73
128
  return(origin_for_address(a.s_addr));
129
+ } else if(inet_pton(AF_INET6, addrstring, &a6)) {
130
+ // fprintf(stderr, "parsing %s as v6\n", addrstring);
131
+ return(origin6_for_address(a6));
74
132
  }
75
133
  return 0;
76
134
  }
@@ -101,7 +159,7 @@ origins_regression_test(const char *origins_dat) {
101
159
  FILE *in;
102
160
  char linebuf[60];
103
161
  origins_init(origins_dat);
104
- in = fopen_path_r(origins_dat, &Origins_In_Use);
162
+ in = fopen_path_r(origins_dat, NULL);
105
163
  while(!feof(in) && fgets(linebuf, sizeof(linebuf), in) != NULL) {
106
164
  unsigned int o1, o2, o3, o4, len, as;
107
165
  if(sscanf(linebuf, "%u.%u.%u.%u/%u %u",
@@ -111,7 +169,7 @@ origins_regression_test(const char *origins_dat) {
111
169
  radix_resolve_route(origins->routes,addr_from_octets(o1,o2,o3,o4+1));
112
170
  if((unsigned int)pe->data != as && pe->position <= len) {
113
171
  /* not the same and not a more specific */
114
- fprintf(stderr, "failed to verify %u == %u on line:\n%s",
172
+ fprintf(stderr, "failed to verify %u == %u on line: %s",
115
173
  as, (unsigned int) pe->data, linebuf);
116
174
  if(pe->prefixlen > len) {
117
175
  fprintf(stderr, " -- because a more specific was matched. (%u > %u)\n", pe->prefixlen, len);
@@ -134,3 +192,48 @@ origins_regression_test(const char *origins_dat) {
134
192
  }
135
193
  (void)fclose(in);
136
194
  }
195
+
196
+ void
197
+ origins6_regression_test(const char *origins6_dat) {
198
+ FILE *in;
199
+ char linebuf[60];
200
+ origins6_init(origins6_dat);
201
+ in = fopen_path_r(origins6_dat, NULL);
202
+ while(!feof(in) && fgets(linebuf, sizeof(linebuf), in) != NULL) {
203
+ char addrbuf[61];
204
+ unsigned int len, as;
205
+ if(sscanf(linebuf, "%60[a-fA-F0-9:]/%u %u", addrbuf, &len, &as) == 3) {
206
+ struct in6_addr addr;
207
+ inet_pton(AF_INET6, addrbuf, &addr);
208
+ struct patricia6_entry *pe = radix6_resolve_route(origins6->routes,addr);
209
+ assert(pe);
210
+ if((unsigned int)pe->data != as && pe->position <= len) {
211
+ /* not the same and not a more specific */
212
+ char buf[60];
213
+ fprintf(stderr, "failed to verify expected AS %u == found %u (%s/%d) on line: %s",
214
+ as, (unsigned int) pe->data,
215
+ inet_ntop(AF_INET6, &pe->destination, buf, 60), pe->prefixlen,
216
+ linebuf);
217
+ if(pe->prefixlen > len) {
218
+ fprintf(stderr, " -- because a more specific was matched. (%u > %u)\n", pe->prefixlen, len);
219
+ } else if(as == 0) {
220
+ patricia6_dump(origins6, "origins6_regression_failure.dot");
221
+ #if !defined(CHECK_ORIGINS_SHOULD_FAIL) || CHECK_ORIGINS_SHOULD_FAIL == 0
222
+ abort();
223
+ #else
224
+ exit(EXIT_SUCCESS);
225
+ #endif
226
+ } else {
227
+ /* meh. inconsistent origins happen. */
228
+ }
229
+ }
230
+ // unsigned int stored_as = (unsigned int) patricia_lookup(origins, addr_from_octets(o1,o2,o3,o4+1));
231
+ // if( stored_as != as) {
232
+ // fprintf(stderr, "failed to verify %u == %u on line:\n%s",
233
+ // as, stored_as, linebuf);
234
+ // abort();
235
+ // }
236
+ }
237
+ }
238
+ (void)fclose(in);
239
+ }
@@ -171,7 +171,7 @@ q_element q_insert_fromdir(queue q, const void *v, boolean scan_backwards) {
171
171
  /* <= there should append equal things. < should prepend equal things */
172
172
  iter = iter->next);
173
173
  if(iter) { // must insert in middle
174
- newelem = malloc(sizeof(struct queue_element_struct));
174
+ // newelem = malloc(sizeof(struct queue_element_struct));
175
175
  assert(newelem!=NULL);
176
176
  newelem->value = v;
177
177
  newelem->next = iter;
@@ -238,6 +238,8 @@ static /*@null@*/ const void *q_top_gotlock(const queue q) {
238
238
  else
239
239
  q->tail=NULL;
240
240
  free(freeme);
241
+ } else {
242
+ assert(retval == NULL);
241
243
  }
242
244
  check_invariants(q);
243
245
  UNLOCK;
@@ -24,8 +24,8 @@
24
24
  functions */
25
25
  static struct patricia_table *current_table;
26
26
  extern boolean want_debug;
27
- boolean really_want_debug = FALSE;
28
- boolean really_want_protection = FALSE;
27
+ static boolean really_want_debug = FALSE;
28
+ static boolean really_want_protection = FALSE;
29
29
 
30
30
  #ifdef __ASSERT_VOID_CAST
31
31
  /* we can, non-portably, define something that looks like assert and
@@ -0,0 +1,607 @@
1
+ /* Copyright 1999-2002 Eric Hoffman, Neil Spring,
2
+ and the University of Washington */
3
+ #define VERBOSE
4
+ #include "radix.h"
5
+ #include "radix6.h"
6
+ #include <stdio.h>
7
+ #include <stdlib.h>
8
+ #include <sys/types.h>
9
+ #ifdef WIN32
10
+ #include <fcntl.h>
11
+ #include <io.h>
12
+ #else
13
+ #include <netinet/in.h>
14
+ #endif
15
+ #ifdef HAVE_UNISTD_H
16
+ #include <unistd.h>
17
+ #endif
18
+ #include "buffer.h"
19
+ #include "fcntl.h"
20
+ #include <assert.h>
21
+
22
+ #undef DEBUG_INSERTION
23
+ // #define DEBUG_LOOKUP(x...) fprintf(stderr, x)
24
+ #define DEBUG_LOOKUP(x...)
25
+
26
+ /* ugly global variable, which gets updated on entry from new
27
+ functions */
28
+ static struct patricia6_table *current_table;
29
+ extern boolean want_debug;
30
+ static boolean really_want_debug = TRUE; /* means lots of stderr */
31
+ static boolean really_want_protection = TRUE; /* means lookups after insertion. */
32
+
33
+ #ifdef __ASSERT_VOID_CAST
34
+ /* we can, non-portably, define something that looks like assert and
35
+ works like assert, but aldo dumps the table */
36
+ #define radix6_assert(expr) \
37
+ do { if(!(expr) && current_table != NULL) \
38
+ patricia6_dump(current_table, "assert.dot"); \
39
+ (__ASSERT_VOID_CAST ((expr) ? 0 : \
40
+ (__assert_fail (__STRING(expr), __FILE__, __LINE__, \
41
+ __ASSERT_FUNCTION), 0))); } while(0)
42
+ #else
43
+ #define radix6_assert(expr) assert(expr)
44
+ #endif
45
+
46
+
47
+ static char *
48
+ label_of_dest(address6 dest, prefixlen_t prefix,
49
+ /*@out@*//*@returned@*/char *buf);
50
+ static char *
51
+ label_of_node(const struct patricia6_entry *r,
52
+ /*@out@*//*@returned@*/char *buf);
53
+
54
+ void *get_data6(const struct patricia6_entry *r){
55
+ return(r->data);
56
+ }
57
+ void set_data6(struct patricia6_entry *r, void *data) {
58
+ r->data = data;
59
+ }
60
+
61
+ /* exported for testing */
62
+ address6
63
+ radix6_mask(address6 addr, prefixlen_t prefix)
64
+ {
65
+ address6 m = IN6ADDR_ANY_INIT;
66
+ char *d = (char *)&m;
67
+ char *s = (char *)&addr;
68
+ int remaining_prefix = prefix;
69
+
70
+ assert(prefix <= 128);
71
+ if(prefix == (prefixlen_t)0) return m;
72
+ if(really_want_protection) assert(prefix <= 128);
73
+
74
+ while((remaining_prefix-=8) >= 0) {
75
+ *d++ = *s++;
76
+ }
77
+
78
+ if(remaining_prefix == -8) {
79
+ // fprintf(stderr, "reached zero\n");
80
+ return m;
81
+ }
82
+ // fprintf(stderr, "is %d\n", remaining_prefix);
83
+
84
+ *d = (*s) & ~((1<<(-remaining_prefix)) - 1);
85
+ return m;
86
+ }
87
+
88
+ static inline boolean radix6_test(address6 addr, prefixlen_t x);
89
+ static void check_radix6_mask(prefixlen_t len) {
90
+ int i;
91
+ address6 m = {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
92
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}};
93
+ address6 n = radix6_mask(m, len);
94
+ if(want_debug) {
95
+ char bufa[60];
96
+ fprintf(stderr, "mask test /%d = %s\n", len, inet_ntop(AF_INET6, &n, bufa, 60));
97
+ }
98
+ for(i=1;i<=len;i++) {
99
+ if(!radix6_test(n, i)) { fprintf(stderr, "failed mask test %d at %d\n", len, i); exit(1); }
100
+ }
101
+ for(;i<=128;i++) {
102
+ if(radix6_test(n, i)) { fprintf(stderr, "failed mask test %d at %d\n", len, i); exit(1); }
103
+ }
104
+ }
105
+
106
+ static unsigned int testmasks[9];
107
+ void radix6_init_testmasks(void) {
108
+ unsigned int i, p;
109
+ for(i=1; i<=8; i++) {
110
+ testmasks[i] = 1 << (8U - i);
111
+ if(want_debug) fprintf(stderr, "tm[%d] = 0x%x\n", i, testmasks[i]);
112
+ }
113
+ testmasks[0] = testmasks[8];
114
+
115
+ for(p = 1; p <= 128; p++) {
116
+ check_radix6_mask(p);
117
+ }
118
+ }
119
+ static inline boolean radix6_test(address6 addr, prefixlen_t x) {
120
+ char *s = (char *)&addr;
121
+ boolean ret = (x == (prefixlen_t)0 || s[(x-1)/8] & testmasks[x%8]);
122
+
123
+ #if 0
124
+ char bufa[60];
125
+ fprintf(stderr, "radix6_test %s @ %d is %s\n",
126
+ inet_ntop(AF_INET6, &addr, bufa, 60 ), x, ret ? "T" : "f");
127
+ #endif
128
+
129
+ return ret;
130
+ }
131
+
132
+ /*@null@*//*@dependent@*/
133
+ static struct patricia6_entry *
134
+ find_route_internal(/*@null@*/struct patricia6_entry *r,
135
+ address6 destination, prefixlen_t prefix)
136
+ {
137
+ if (!r) return(0);
138
+ if (memcmp(&r->destination, &destination, sizeof(address6)) == 0
139
+ && (r->prefixlen == prefix))
140
+ return(r);
141
+ if(r->position <= 128) {
142
+ if (radix6_test(destination,r->position) != 0) {
143
+ return(find_route_internal(r->on,destination,prefix));
144
+ } else {
145
+ return(find_route_internal(r->off,destination,prefix));
146
+ }
147
+ } else {
148
+ return(NULL);
149
+ }
150
+ }
151
+
152
+ /*@null@*//*@dependent@*/
153
+ struct patricia6_entry *
154
+ radix6_resolve_route(/*@null@*/ struct patricia6_entry * top,
155
+ address6 destination) {
156
+ struct patricia6_entry * here=top;
157
+ struct patricia6_entry * best=NULL;
158
+ prefixlen_t length=0;
159
+ char la[25] __attribute__((unused));
160
+
161
+ DEBUG_LOOKUP("looking for %s: ", label_of_dest(destination, 128, la));
162
+ while(here){
163
+ if (here->prefixlen >= length) {
164
+ address6 masked = radix6_mask(destination,here->prefixlen);
165
+ if(memcmp(&masked, &here->destination, sizeof(masked)) == 0){
166
+ best=here;
167
+ length=here->prefixlen;
168
+ DEBUG_LOOKUP("+%s ", label_of_node(here, la));
169
+ } else {
170
+ DEBUG_LOOKUP("-%s ", label_of_node(here, la));
171
+ }
172
+ } else {
173
+ DEBUG_LOOKUP("_%s ", label_of_node(here, la));
174
+ }
175
+ if (here->position <= 128)
176
+ if( radix6_test(destination,here->position) != 0)
177
+ here=here->on;
178
+ else
179
+ here=here->off;
180
+ else
181
+ here=NULL;
182
+ }
183
+ DEBUG_LOOKUP("result: %s\n", best? label_of_node(best, la): "none");
184
+ return(best);
185
+ }
186
+
187
+ static prefixlen_t find_difference(address6 a, address6 b, prefixlen_t maxbits){
188
+ prefixlen_t difference;
189
+ if(really_want_protection) assert(maxbits <= 129);
190
+ for (difference=(prefixlen_t)1;
191
+ (difference<maxbits &&
192
+ (radix6_test(a,difference) ==
193
+ radix6_test(b,difference))); ) {
194
+
195
+ difference += 1; /* the post-increment of the for loop can be done here, just to simplify. */
196
+ }
197
+ #if 0
198
+ char bufa[60], bufb[60];
199
+ fprintf(stderr, "diff %d of %d %s %s\n",
200
+ difference, maxbits,
201
+ inet_ntop(AF_INET6, &a, bufa, 60),
202
+ inet_ntop(AF_INET6, &b, bufb, 60));
203
+ #endif
204
+
205
+ return(difference);
206
+ }
207
+ #ifdef DEBUG_INSERTION
208
+ static void radix6_insert_debug(struct patricia6_entry * new, const char * as,
209
+ struct patricia6_entry * old) {
210
+ char buf[50], buf2[50];
211
+ VERBAL("radix6_insert_debug %s %s %s-%d\n",
212
+ label_of_node(new, buf),
213
+ as,
214
+ label_of_node(old, buf2), old->position);
215
+ }
216
+ #else
217
+ static void radix6_insert_debug(struct patricia6_entry * new __attribute__((unused)),
218
+ const char * as __attribute__((unused)),
219
+ struct patricia6_entry * old __attribute__((unused))) {
220
+ return;
221
+ }
222
+ #endif
223
+
224
+ void radix6_insert(struct patricia6_entry **p,
225
+ /*@owned@*//*@partial@*/struct patricia6_entry *new)
226
+ {
227
+ prefixlen_t difference;
228
+ struct patricia6_entry * old=*p;
229
+ int commonprefixlen;
230
+
231
+ /* a little piece of mind */
232
+ if(really_want_protection) {
233
+ assert(new->position == 0);
234
+ assert(new->on == NULL);
235
+ assert(new->off == NULL);
236
+
237
+ radix6_assert(old== NULL || old->on == NULL ||
238
+ (old->on->on == NULL && old->on->off == NULL) ||
239
+ old->position <= old->on->position);
240
+ radix6_assert(old== NULL || old->off == NULL||
241
+ (old->off->on == NULL && old->off->off == NULL) ||
242
+ old->position <= old->off->position);
243
+ }
244
+
245
+ /* an empty table or subtree */
246
+ if (old == NULL) {
247
+ new->position = new->prefixlen + 1;
248
+ *p = new;
249
+ radix6_insert_debug (new, "in empty table or subtree", new);
250
+ return;
251
+ }
252
+
253
+ /* a duplicate */
254
+ if(memcmp(&old->destination, &new->destination, sizeof(address6)) == 0 &&
255
+ old->prefixlen == new->prefixlen) {
256
+ /* NON-ROUTING-TABLE behavior: assume oldest, not newest, is right. */
257
+ char bufa[60];
258
+ radix6_insert_debug (new, "is duplicate of", old);
259
+ fprintf(stderr, "warning: discarding duplicate %s/%d\n", inet_ntop(AF_INET6, &new->destination, bufa, 60), new->prefixlen);
260
+ new->position = (prefixlen_t)-1; /* flag it for free() ing */
261
+ return;
262
+ }
263
+
264
+ difference = find_difference(old->destination, new->destination,
265
+ min(new->prefixlen, old->prefixlen));
266
+ commonprefixlen = max((int)0, ((int)old->position)-1);
267
+
268
+ /* attempt to handle a strange case:
269
+ we're inserting something that shouldn't go further down
270
+ in the tree, because of prefix < position requirements. */
271
+ if(difference >= old->position &&
272
+ new->prefixlen <= old->position &&
273
+ old->position < old->prefixlen) {
274
+ struct patricia6_entry * *child;
275
+ new->position = old->position;
276
+ new->on = old->on;
277
+ new->off = old->off;
278
+ old->on = old->off = NULL;
279
+ *p = new;
280
+
281
+ child = (radix6_test(old->destination,new->position)!=0)
282
+ ? &new->on : &new->off;
283
+ radix6_insert_debug (old, "as pushdown of", new);
284
+ old->position=0;
285
+ radix6_insert(child, old);
286
+
287
+ return;
288
+ }
289
+
290
+ /* if new is contained in old/prefix; at least what old/position */
291
+ address6 new_masked = radix6_mask(new->destination,commonprefixlen);
292
+ address6 old_masked = radix6_mask(old->destination,commonprefixlen);
293
+ if( difference >= old->position ||
294
+ (memcmp(&new_masked, &old_masked, sizeof(address6)) == 0
295
+ && new->prefixlen > old->prefixlen )){
296
+
297
+ struct patricia6_entry * *child = (radix6_test(new->destination,old->position)!=0)
298
+ ? &old->on : &old->off;
299
+ radix6_insert_debug (new, "as child of", old);
300
+ radix6_insert(child, new);
301
+
302
+ if(new->position == (prefixlen_t)-1) {
303
+ /* was a duplicate */
304
+ return;
305
+ }
306
+
307
+ if(really_want_protection) {
308
+ if(!(new->position > old->position ||
309
+ (new->position >= old->position &&
310
+ memcmp(&new->destination, &old->destination, sizeof(address6) == 0)))) {
311
+ char bufa[60], bufb[60];
312
+ fprintf(stderr, "diff %d cpl %d np %d op %d %s/%d %s/%d\n",
313
+ difference, commonprefixlen, new->position, old->position,
314
+ inet_ntop(AF_INET6, &new->destination, bufa, 60), new->prefixlen,
315
+ inet_ntop(AF_INET6, &old->destination, bufb, 60), old->prefixlen);
316
+ radix6_print_routing_table_dot(old, 2);
317
+ }
318
+
319
+ radix6_assert(new->position > old->position ||
320
+ (new->position >= old->position &&
321
+ memcmp(&new->destination, &old->destination, sizeof(address6) == 0)));
322
+ /*
323
+ fprintf(stderr, "cleared\n");
324
+ */
325
+ }
326
+
327
+ return;
328
+ }
329
+
330
+ /* if old is contained in new */
331
+ /* if( (radix6_mask(new->destination,old->prefixlen) == old->destination)
332
+ && new->prefixlen > old->prefixlen ){ */
333
+ do {
334
+ radix6_insert_debug (new, "as parent of", old);
335
+ if(difference < old->position-1) {
336
+ if(radix6_test(old->destination, difference) !=
337
+ radix6_test(new->destination, difference)) {
338
+ new->position = difference;
339
+ } else {
340
+ new->position = difference + 1;
341
+ }
342
+ } else {
343
+ new->position = old->position - 1;
344
+ }
345
+ // new->position = min((int)difference, (int)old->position-1);
346
+ if(radix6_test(old->destination, new->position)!=0) {
347
+ new->on = old;
348
+ } else {
349
+ new->off = old;
350
+ }
351
+ *p = new;
352
+ } while(0);
353
+
354
+ return;
355
+ }
356
+
357
+ static char *
358
+ label_of_dest(address6 dest, prefixlen_t prefixlen, /*@out@*//*@returned@*/char *buf) {
359
+ char minibuf[10];
360
+ assert(prefixlen <= 128);
361
+ inet_ntop(AF_INET6, &dest, buf, 44);
362
+ sprintf(minibuf,"/%u", prefixlen);
363
+ strcat(buf, minibuf);
364
+ return(buf);
365
+ }
366
+
367
+ static char *
368
+ label_of_node(const struct patricia6_entry *r,
369
+ /*@out@*//*@returned@*/char *dest)
370
+ {
371
+ return(label_of_dest(r->destination, r->prefixlen, dest));
372
+ }
373
+
374
+ static void
375
+ print_routing_table_internal(const struct patricia6_entry *r,
376
+ buffer b,
377
+ unsigned int *max)
378
+ {
379
+ char here[255];
380
+
381
+ if (r){
382
+ if (r->position > *max) *max=r->position;
383
+ (void)label_of_node(r,here);
384
+ /*bprintf (b," {rank = same; %d ; \"%s\"}\n",r->position,here);*/
385
+ bprintf (b," \"%s\" [label = \"{<h> %s | {<off> 0 |bit %d |<on> 1}}\"];\n",
386
+ here, here, r->position);
387
+
388
+ if (r->off){
389
+ char off[255];
390
+ bprintf (b," \"%s\":off -> \"%s\"[label=\"%d=0\"];\n",
391
+ here,label_of_node(r->off,off),r->position);
392
+ print_routing_table_internal(r->off,b,max);
393
+ }
394
+ if (r->on){
395
+ char on[255];
396
+ bprintf (b," \"%s\":on -> \"%s\"[label=\"%d=1\"];\n",
397
+ here, label_of_node(r->on,on), r->position);
398
+ print_routing_table_internal(r->on,b,max);
399
+ }
400
+ }
401
+ }
402
+
403
+ void radix6_print_routing_table_dot(const struct patricia6_entry *top, int fd)
404
+ {
405
+ unsigned max=0;
406
+ buffer b=create_buffer(100);
407
+ buffer base=create_buffer(100);
408
+
409
+ bprintf (base,"digraph radix {\n");
410
+ bprintf (base," size=\"10,7.5\"; ratio=auto; ordering=out\n");
411
+ bprintf (base," node [shape=record,width=.3,height=.3]\n");
412
+ if (top) {
413
+ // char z[90];
414
+ // eh. bprintf (b," root -> \"%s\";\n",label_of_node(top,z));
415
+ print_routing_table_internal(top,b,&max);
416
+ }
417
+ assert(write(fd,base->contents,(size_t)base->fill)>0);
418
+ assert(write(fd,b->contents,(size_t)b->fill)>0);
419
+ assert(write(fd,"}\n",2));
420
+ free_buffer(b);
421
+ free_buffer(base);
422
+ }
423
+
424
+ static void remove_route_internal(struct patricia6_entry * *place,
425
+ address6 destination,
426
+ unsigned int prefixlen)
427
+ {
428
+ struct patricia6_entry * r=*place;
429
+ if (r){
430
+ if ((memcmp(&r->destination, &destination, sizeof(address6)) != 0) ||
431
+ (r->prefixlen!=prefixlen)){
432
+ if (radix6_test(destination,r->position) != 0)
433
+ remove_route_internal(&r->on,destination,prefixlen);
434
+ else
435
+ remove_route_internal(&r->off,destination,prefixlen);
436
+ } else {
437
+ /* found it */
438
+ if (r->on) {
439
+ struct patricia6_entry * q=r->on;
440
+ if (r->off) {
441
+ /* the rotation case*/
442
+ remove_route_internal(&r->on,q->destination,q->prefixlen);
443
+ q->position=r->position;
444
+ q->off=r->off;
445
+ q->on=r->on;
446
+ }
447
+ *place=q;
448
+ } else *place=r->off;
449
+ }
450
+ }
451
+ }
452
+
453
+ void radix6_remove_route(struct patricia6_table * n,
454
+ address6 destination,
455
+ prefixlen_t prefixlen)
456
+ {
457
+ if(n->routes) /* cheap check keeps lclint happy */
458
+ remove_route_internal(&n->routes,destination,prefixlen);
459
+ }
460
+
461
+ static void
462
+ print_routing_table_text_internal(const struct patricia6_entry *r,
463
+ FILE *fdout) {
464
+ if (r){
465
+ char here[25];
466
+ fprintf(fdout, " %s via --\n", label_of_node(r,here));
467
+ print_routing_table_text_internal(r->off,fdout);
468
+ print_routing_table_text_internal(r->on,fdout);
469
+ }
470
+ }
471
+
472
+ void radix6_print_routing_table_text(const struct patricia6_entry *top,
473
+ FILE *fdout) {
474
+ fprintf(fdout, "Routing table:\n");
475
+ if(top)
476
+ print_routing_table_text_internal(top, fdout);
477
+ }
478
+
479
+
480
+ struct patricia6_table * patricia6_new(void){
481
+ NEWPTR(struct patricia6_table, p);
482
+ radix6_init_testmasks(); /* can overwrite */
483
+ p->routes = NULL;
484
+ p->default_route = NULL;
485
+ return(p);
486
+ }
487
+
488
+ static void recursive_delete(struct patricia6_entry *e,
489
+ /*@null@*/ void (*data_free)(void *)) {
490
+ if(e != NULL) {
491
+ if(e->on != NULL) recursive_delete(e->on, data_free);
492
+ if(e->off != NULL) recursive_delete(e->off, data_free);
493
+ if(data_free != NULL) data_free(e->data);
494
+ free(e);
495
+ }
496
+ }
497
+
498
+ void patricia6_delete(struct patricia6_table * p,
499
+ /*@null@*/ void (*data_free)(void *)) {
500
+ recursive_delete(p->routes, data_free);
501
+ recursive_delete(p->default_route, data_free);
502
+ p->routes = NULL;
503
+ p->default_route = NULL;
504
+ free(p);
505
+ }
506
+
507
+ void patricia6_insert(struct patricia6_table * pt,
508
+ address6 a,
509
+ prefixlen_t prefixlen,
510
+ void *data) {
511
+ /* really try to avoid duplication; I'd rather do that
512
+ in the radix6_insert(), but that seems like a pain atm.*/
513
+ // if(find_route_internal(pt->routes, a, prefixlen) == NULL) {
514
+ NEWPTR(struct patricia6_entry, pe); /* this allocated memory may be leaked by scriptroute 1/14/07 */
515
+ current_table = pt; /* icky */
516
+ assert(pe != NULL);
517
+ assert(prefixlen <= 128);
518
+ assert(pt != NULL);
519
+ pe->destination = a;
520
+ address6 mask_checked = radix6_mask(a, prefixlen);
521
+ if(memcmp(&a, &mask_checked, sizeof(address6)) != 0) {
522
+ VERBAL("dropping errant prefix\n");
523
+ free(pe);
524
+ return;
525
+ }
526
+ pe->prefixlen = prefixlen;
527
+ pe->data = data;
528
+ pe->position = 0;
529
+ pe->on = NULL;
530
+ pe->off = NULL;
531
+ if(really_want_debug) {
532
+ // VERBAL("patricia6_insert(pt, 0x%x, %u, (void *)0x%p);\n", a, prefixlen, data);
533
+ }
534
+
535
+ /* perhaps a /0 slipped through. */
536
+ if(prefixlen == 0) {
537
+ pt->default_route = pe;
538
+ return;
539
+ }
540
+
541
+ radix6_insert(&pt->routes, pe);
542
+
543
+ /* patricia6_dump(pt, "intst.dot"); */
544
+
545
+ /* check that it can be found once inserted. */
546
+ if(really_want_protection) {
547
+ if(find_route_internal(pt->routes, a, prefixlen) == NULL) {
548
+ char buf[60];
549
+ fprintf(stderr, "after inserting, couldn't find %s/%d\n",
550
+ inet_ntop(AF_INET6, &a, buf, 60), prefixlen);
551
+ radix6_print_routing_table_dot(pt->routes, 2);
552
+ assert(0);
553
+ }
554
+ }
555
+
556
+ if(pe->position == (prefixlen_t)-1) {
557
+ // fprintf(stderr, "freeing duplicate\n");
558
+ memset(pe, 0, sizeof(*pe));
559
+ free(pe);
560
+ }
561
+
562
+ //}
563
+ }
564
+ /*@null@*/
565
+ void *patricia6_lookup(struct patricia6_table * pt, address6 a) {
566
+ struct patricia6_entry * pe;
567
+ // char buf[256];
568
+ current_table = pt;
569
+ pe = radix6_resolve_route(pt->routes, a);
570
+ if(pe == NULL) {
571
+ pe = pt->default_route;
572
+ }
573
+ if(pe == NULL) {
574
+ return NULL;
575
+ }
576
+ // printf("foundl %s\n", label_of_node(pe, buf));
577
+ return(pe->data);
578
+ }
579
+
580
+ boolean
581
+ patricia6_lookup_all(struct patricia6_table * pt,
582
+ address6 a,
583
+ /*@out@*/ address6 *prefix,
584
+ /*@out@*/ prefixlen_t *prefixlen,
585
+ /*@out@*/ void **data) {
586
+ struct patricia6_entry * pe;
587
+ // char buf[256];
588
+ current_table = pt;
589
+ pe = radix6_resolve_route(pt->routes, a);
590
+ if(pe == NULL) {
591
+ pe = pt->default_route;
592
+ }
593
+ if(pe == NULL) {
594
+ return FALSE;
595
+ }
596
+ // printf("found %s\n", label_of_node(pe, buf));
597
+ *prefix = pe->destination;
598
+ *prefixlen = pe->prefixlen;
599
+ *data = pe->data;
600
+ return TRUE;
601
+ }
602
+
603
+ void patricia6_dump(struct patricia6_table * pt, const char *filename) {
604
+ int f = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0644);
605
+ radix6_print_routing_table_dot(pt->routes, f);
606
+ close(f);
607
+ }