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 +4 -4
- data/bin/undns_origin +9 -0
- data/bin/update_origins6_dat +127 -0
- data/ext/undns/earth.c +19 -8
- data/ext/undns/hashtable.c +1 -3
- data/ext/undns/originAS.c +105 -2
- data/ext/undns/queue.c +3 -1
- data/ext/undns/radix.c +2 -2
- data/ext/undns/radix6.c +607 -0
- data/ext/undns/radix6.h +72 -0
- data/ext/undns/ruleset.c +2 -1
- data/lib/undns.rb +54 -5
- data/lib/undns/zebra-dump-parser.pl +592 -0
- data/test/test_undns.rb +2 -0
- metadata +8 -2
- data/lib/undns/origins.dat +0 -517715
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d4a8579ec7c425c5f34a5fd44afbcc9938c253b
|
4
|
+
data.tar.gz: 5587a5805eafb34b46c1060392e3850612df9980
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8644cba6f0761564bdb4435e44e0881bd331e541d49be7856593e59a528cf46e14b3eb4dff94f5c4f8903e1824a3afafcb6fb69eaa0044ac9be565f118039bc9
|
7
|
+
data.tar.gz: 40f2db5a09a506e73e584a247f1615038903c2bec73dc88b8c64a4bd4d81652e14ad1037c7922de71bf75b29d83bbf2d1bdeae0ea698f117a7f7ea7955099f32
|
data/bin/undns_origin
ADDED
@@ -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
|
+
|
data/ext/undns/earth.c
CHANGED
@@ -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);
|
data/ext/undns/hashtable.c
CHANGED
@@ -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
|
|
data/ext/undns/originAS.c
CHANGED
@@ -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,
|
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
|
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
|
+
}
|
data/ext/undns/queue.c
CHANGED
@@ -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;
|
data/ext/undns/radix.c
CHANGED
@@ -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
|
data/ext/undns/radix6.c
ADDED
@@ -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
|
+
}
|