undns 0.4.0f → 0.4.0h

Sign up to get free protection for your applications and to get access to all the features.
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
+ }