undns 0.4.0a
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/undns_decode +29 -0
- data/ext/undns/buffer.c +247 -0
- data/ext/undns/buffer.h +59 -0
- data/ext/undns/config.h +2 -0
- data/ext/undns/conventions.c +1813 -0
- data/ext/undns/conventions.h +89 -0
- data/ext/undns/conventlex.c +2808 -0
- data/ext/undns/earth.c +180 -0
- data/ext/undns/earth.h +4 -0
- data/ext/undns/exception.h +12 -0
- data/ext/undns/extconf.rb +44 -0
- data/ext/undns/filetest.c +90 -0
- data/ext/undns/filetest.h +7 -0
- data/ext/undns/hashes.c +104 -0
- data/ext/undns/hashes.h +48 -0
- data/ext/undns/hashtable.c +518 -0
- data/ext/undns/hashtable.h +103 -0
- data/ext/undns/my_ruby.h +3 -0
- data/ext/undns/nscommon.h +207 -0
- data/ext/undns/originAS.c +134 -0
- data/ext/undns/originAS.h +17 -0
- data/ext/undns/progress.c +285 -0
- data/ext/undns/progress.h +45 -0
- data/ext/undns/queue.c +346 -0
- data/ext/undns/queue.h +70 -0
- data/ext/undns/radix.c +517 -0
- data/ext/undns/radix.h +72 -0
- data/ext/undns/ruleset.c +603 -0
- data/ext/undns/ruleset.h +108 -0
- data/ext/undns/swig-undns_wrap-rb.c +2995 -0
- data/ext/undns/typed_hashtable.h +158 -0
- data/ext/undns/typed_queue.h +112 -0
- data/ext/undns/xmalloc.c +153 -0
- data/ext/undns/xmalloc.h +14 -0
- data/lib/undns.rb +5 -0
- metadata +84 -0
data/ext/undns/radix.h
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#include "nscommon.h"
|
2
|
+
#include <sys/types.h>
|
3
|
+
#include <sys/socket.h>
|
4
|
+
#include <netinet/in.h>
|
5
|
+
#ifndef __LCLINT__
|
6
|
+
#include <arpa/inet.h>
|
7
|
+
#endif
|
8
|
+
#include <stdio.h>
|
9
|
+
|
10
|
+
// #ifdef __linux__
|
11
|
+
// #define ADDR_T in_addr_t
|
12
|
+
// #else
|
13
|
+
#define ADDR_T u_int32_t
|
14
|
+
// #endif
|
15
|
+
|
16
|
+
typedef ADDR_T address;
|
17
|
+
typedef unsigned char prefixlen_t;
|
18
|
+
/* typedef struct patricia_entry *patricia_entry; */
|
19
|
+
/* typedef struct patricia_table *patricia_table; */
|
20
|
+
|
21
|
+
struct patricia_entry {
|
22
|
+
address destination;
|
23
|
+
prefixlen_t prefixlen;
|
24
|
+
unsigned char position;
|
25
|
+
void *data;
|
26
|
+
struct patricia_entry *on,*off;
|
27
|
+
};
|
28
|
+
|
29
|
+
struct patricia_table {
|
30
|
+
/*@null@*/ struct patricia_entry *routes;
|
31
|
+
/*@null@*/ struct patricia_entry *default_route;
|
32
|
+
};
|
33
|
+
|
34
|
+
/* externally useful bits */
|
35
|
+
struct patricia_table *patricia_new(void);
|
36
|
+
void patricia_delete(/*@only@*/ struct patricia_table * p, void (*data_free)(void *));
|
37
|
+
void patricia_insert(struct patricia_table *pt, address a,
|
38
|
+
unsigned char prefixlen, /*@owned@*/void *data);
|
39
|
+
/*@null@*//* just get the data *//*@dependent@*/
|
40
|
+
void *patricia_lookup(struct patricia_table *pt, address a);
|
41
|
+
/* get it all */
|
42
|
+
boolean patricia_lookup_all(struct patricia_table * pt,
|
43
|
+
address a,
|
44
|
+
/*@out@*/ address *prefix,
|
45
|
+
/*@out@*/ prefixlen_t *prefixlen,
|
46
|
+
/*@out@*/ void **data);
|
47
|
+
void patricia_dump(struct patricia_table *pt, const char *filename);
|
48
|
+
|
49
|
+
/* slightly less useful */
|
50
|
+
/*@null@*//*@dependent@*/
|
51
|
+
struct patricia_entry *
|
52
|
+
radix_resolve_route(/*@null@*/
|
53
|
+
struct patricia_entry *top,
|
54
|
+
address destination);
|
55
|
+
void *get_data(const struct patricia_entry *r);
|
56
|
+
|
57
|
+
/* somewhat useful bits */
|
58
|
+
void set_data(struct patricia_entry *r, void *data);
|
59
|
+
|
60
|
+
void radix_insert(struct patricia_entry **p, /*@owned@*//*@partial@*/struct patricia_entry *r);
|
61
|
+
|
62
|
+
void radix_remove_route(struct patricia_table *n,
|
63
|
+
address destination,
|
64
|
+
unsigned char prefixlen);
|
65
|
+
|
66
|
+
void radix_print_routing_table_text(/*@null@*/const struct patricia_entry *r,
|
67
|
+
FILE *fdout);
|
68
|
+
void radix_print_routing_table_dot(/*@null@*/const struct patricia_entry *r,
|
69
|
+
int fd);
|
70
|
+
|
71
|
+
address radix_mask(address addr, prefixlen_t prefix);
|
72
|
+
boolean radix_test_export(address addr, prefixlen_t x); // used by check_radix, real thing is static so as to be inlined.
|
data/ext/undns/ruleset.c
ADDED
@@ -0,0 +1,603 @@
|
|
1
|
+
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <string.h>
|
5
|
+
#include <sys/stat.h>
|
6
|
+
#include <assert.h>
|
7
|
+
#include <errno.h>
|
8
|
+
#include "ruleset.h"
|
9
|
+
#include "exception.h"
|
10
|
+
#include "filetest.h"
|
11
|
+
|
12
|
+
const char *input_filename;
|
13
|
+
extern boolean want_debug;
|
14
|
+
extern boolean want_conventions_debug;
|
15
|
+
boolean Had_an_error = FALSE;
|
16
|
+
|
17
|
+
void set_conventions_debug(boolean v) {
|
18
|
+
want_conventions_debug = v;
|
19
|
+
}
|
20
|
+
static void tally_asnc(struct asnc *matched);
|
21
|
+
|
22
|
+
extern FILE *conv_yyin;
|
23
|
+
extern int conv_yyparse(void);
|
24
|
+
|
25
|
+
asnc_hashtable Ruleset;
|
26
|
+
|
27
|
+
#define DM(args...) if(want_debug) { fprintf(stderr, args); }
|
28
|
+
|
29
|
+
boolean is_nonempty(FILE *fp) {
|
30
|
+
struct stat st;
|
31
|
+
if( fstat(fileno(fp), &st) < 0) return FALSE;
|
32
|
+
return(st.st_size > 0);
|
33
|
+
}
|
34
|
+
|
35
|
+
#ifndef PKGDATADIR
|
36
|
+
#define PKGDATADIR DATADIR "/" PACKAGE_NAME
|
37
|
+
#endif
|
38
|
+
|
39
|
+
const char *ruleset_path = ".:..:" PKGDATADIR ":/usr/local/share/undns:/usr/share/undns";
|
40
|
+
|
41
|
+
extern void set_file_and_line(struct instrumentation *inst, const char *file, unsigned int line) {
|
42
|
+
memset(inst, 0, sizeof(struct instrumentation));
|
43
|
+
|
44
|
+
inst->file = strdup(file); /* might be leaky, worse is very space inefficient. but let's see that
|
45
|
+
it works firs before using string bindings to make it fast */
|
46
|
+
inst->line = line;
|
47
|
+
inst->dynamic_match_count = 0; /* shouldn't need this with the memset above... but wtf? I do! crap.*/
|
48
|
+
inst->doubt_count = 0; /* shouldn't need this with the memset above... but wtf? I do! crap.*/
|
49
|
+
|
50
|
+
}
|
51
|
+
extern const char *inst_get_filename(const struct instrumentation *inst) {
|
52
|
+
return inst->file; /* because I might reorganize this to use string bindings to compress. */
|
53
|
+
}
|
54
|
+
static const char *inst_format_stats(char *buf, unsigned int buflen, const struct instrumentation *inst) {
|
55
|
+
assert(inst);
|
56
|
+
assert(inst->file);
|
57
|
+
assert(buf);
|
58
|
+
assert(buflen > 20); /* sanity, not safety */
|
59
|
+
if (inst->dynamic_match_count > 0) {
|
60
|
+
if (inst->doubt_count > 0) {
|
61
|
+
snprintf(buf, buflen-1, "%s:%d - matches: %d, doubts: %d", inst_get_filename(inst), inst->line, inst->dynamic_match_count, inst->doubt_count);
|
62
|
+
} else {
|
63
|
+
snprintf(buf, buflen-1, "%s:%d - matches: %d", inst_get_filename(inst), inst->line, inst->dynamic_match_count);
|
64
|
+
}
|
65
|
+
} else {
|
66
|
+
snprintf(buf, buflen-1, "%s:%d - unmatched", inst_get_filename(inst), inst->line);
|
67
|
+
}
|
68
|
+
return buf;
|
69
|
+
}
|
70
|
+
|
71
|
+
/* also invoked by originAS.c */
|
72
|
+
/*@null@*/ FILE *
|
73
|
+
fopen_path_r(const char *filename) {
|
74
|
+
char *fullpath = searchPath(ruleset_path, filename);
|
75
|
+
if(fullpath != NULL) {
|
76
|
+
FILE * ret;
|
77
|
+
if(!fileExists(fullpath)) {
|
78
|
+
fprintf(stderr, "bug! path lookup failed. path: '%s', file '%s'\n",
|
79
|
+
ruleset_path, filename);
|
80
|
+
}
|
81
|
+
/*
|
82
|
+
if(want_debug) {
|
83
|
+
fprintf(stderr, "found %s at %s %s\n",
|
84
|
+
filename, fullpath, fileExists(fullpath) ? "!" : "not.");
|
85
|
+
}
|
86
|
+
*/
|
87
|
+
ret = fopen(fullpath, "r");
|
88
|
+
free(fullpath);
|
89
|
+
return ret;
|
90
|
+
} else {
|
91
|
+
errno = ENOENT;
|
92
|
+
return NULL;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
/* returns true if all good, false if there was a parse error */
|
97
|
+
void load_ruleset(const char *filename) {
|
98
|
+
FILE *fp;
|
99
|
+
if(filename == NULL) {
|
100
|
+
throw_void("load_ruleset: no filename to load\n");
|
101
|
+
}
|
102
|
+
fp=fopen_path_r(filename);
|
103
|
+
if(fp != NULL) {
|
104
|
+
if(is_nonempty(fp)) {
|
105
|
+
input_filename = filename;
|
106
|
+
conv_yyin=fp;
|
107
|
+
(void)conv_yyparse();
|
108
|
+
}
|
109
|
+
(void)fclose(fp);
|
110
|
+
} else {
|
111
|
+
char err[255];
|
112
|
+
sprintf(err, "ruleset '%s': %s\n", filename, strerror(errno));
|
113
|
+
throw_void(err);
|
114
|
+
}
|
115
|
+
if(Had_an_error) {
|
116
|
+
throw_void("undns is aborting due to previous errors\n");
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
#define REGS_LEN 10
|
121
|
+
struct fmr {
|
122
|
+
const char *hostname;
|
123
|
+
struct convention *match; /* not const, since we will increment stats. */
|
124
|
+
#ifdef DEPRECATED_GNU_REGEX
|
125
|
+
struct re_registers regs;
|
126
|
+
#else
|
127
|
+
regmatch_t posix_regs[REGS_LEN];
|
128
|
+
#endif
|
129
|
+
};
|
130
|
+
|
131
|
+
/* returns TRUE if we need to continue trying rules
|
132
|
+
returns FALSE if we found our match */
|
133
|
+
static boolean
|
134
|
+
try_rule(const struct convention *c, void *fmr) {
|
135
|
+
struct fmr *f = fmr;
|
136
|
+
/* int matchedchars; */
|
137
|
+
#ifdef DEPRECATED_GNU_REGEX
|
138
|
+
int matchoffset;
|
139
|
+
#endif
|
140
|
+
assert(f->match == NULL);
|
141
|
+
assert(f->hostname != NULL);
|
142
|
+
assert(c != NULL);
|
143
|
+
|
144
|
+
/* f->regs.num_regs = REGS_UNALLOCATED; */
|
145
|
+
/* matchedchars = re_match(&((struct convention *)c)->rpbuf,
|
146
|
+
f->hostname, strlen(f->hostname), 0, &f->regs); */
|
147
|
+
#ifdef DEPRECATED_GNU_REGEX
|
148
|
+
matchoffset = re_search(&((struct convention *)c)->rpbuf,
|
149
|
+
f->hostname, strlen(f->hostname), 0, strlen(f->hostname), &f->regs);
|
150
|
+
DM("matching %s to %s: %d\n", c->regex, f->hostname, matchoffset);
|
151
|
+
/* if(matchedchars > 0) { */
|
152
|
+
if(matchoffset >= 0) {
|
153
|
+
DM("matched!\n");
|
154
|
+
f->match = c;
|
155
|
+
return FALSE;
|
156
|
+
} else {
|
157
|
+
return TRUE;
|
158
|
+
}
|
159
|
+
#else
|
160
|
+
{
|
161
|
+
int reg_ret = regexec(&((struct convention *)c)->rpbuf, f->hostname,
|
162
|
+
REGS_LEN, f->posix_regs, 0);
|
163
|
+
if(reg_ret == REG_NOMATCH) {
|
164
|
+
return TRUE;
|
165
|
+
} else {
|
166
|
+
f->match = (struct convention *)c; /* de-const. */
|
167
|
+
return FALSE;
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
#endif
|
172
|
+
}
|
173
|
+
|
174
|
+
static void copy_substring(char *destination,
|
175
|
+
long long startidx, long long endidx, const char *source) {
|
176
|
+
if (startidx > -1) {
|
177
|
+
strncpy(destination, source + startidx, endidx - startidx);
|
178
|
+
destination[endidx - startidx] = '\0';
|
179
|
+
}
|
180
|
+
}
|
181
|
+
|
182
|
+
static struct stringpair *extract_key_and_find_binding(struct key_decl *kd,
|
183
|
+
#ifdef DEPRECATED_GNU_REGEX
|
184
|
+
struct re_registers *regs,
|
185
|
+
#else
|
186
|
+
regmatch_t *posix_regs,
|
187
|
+
#endif
|
188
|
+
const char *hostname,
|
189
|
+
char *key /* out */) {
|
190
|
+
assert(kd->bindings); /* expects that the caller has already ensured that there are bindings involved. */
|
191
|
+
|
192
|
+
/* extract the "key" portion of the hostname from the regex match, which only identifies the substring range. */
|
193
|
+
#ifdef DEPRECATED_GNU_REGEX
|
194
|
+
assert(regs->start[kd->regex_index] > -1);
|
195
|
+
copy_substring(key, regs->start[kd->regex_index],
|
196
|
+
regs->end[kd->regex_index],
|
197
|
+
hostname);
|
198
|
+
#else
|
199
|
+
if( posix_regs[kd->regex_index].rm_so == -1) {
|
200
|
+
fprintf(stderr, "%s:%d Problem in ruleset found for hostname '%s' where the index of the match is out of range\n", __FILE__, __LINE__, hostname);
|
201
|
+
abort();
|
202
|
+
}
|
203
|
+
copy_substring(key, posix_regs[kd->regex_index].rm_so,
|
204
|
+
posix_regs[kd->regex_index].rm_eo,
|
205
|
+
hostname);
|
206
|
+
#endif
|
207
|
+
|
208
|
+
DM("matched %s %skey %s in %s\n",
|
209
|
+
(kd->id ==attr_loc) ? "loc" : "type",
|
210
|
+
(kd->isDefault) ? "default " : "",
|
211
|
+
key, hostname);
|
212
|
+
DM("seeking in %lu entries\n", key_ht_count(kd->bindings));
|
213
|
+
return key_ht_lookup_k(kd->bindings, &key);
|
214
|
+
|
215
|
+
}
|
216
|
+
|
217
|
+
static void tally_stringpair(struct key_decl *kd, struct stringpair *matched);
|
218
|
+
static void count_incomplete_keydecl(struct key_decl *matched);
|
219
|
+
const char *kdlookup(struct key_decl *kd,
|
220
|
+
#ifdef DEPRECATED_GNU_REGEX
|
221
|
+
struct re_registers *regs,
|
222
|
+
#else
|
223
|
+
regmatch_t *regs,
|
224
|
+
#endif
|
225
|
+
const char *hostname) {
|
226
|
+
char key[128];
|
227
|
+
struct stringpair *found_binding;
|
228
|
+
|
229
|
+
if(kd == NULL) { return NULL; }
|
230
|
+
if(kd->constant != NULL) { return(kd->constant); }
|
231
|
+
|
232
|
+
found_binding = extract_key_and_find_binding(kd, regs, hostname, key);
|
233
|
+
|
234
|
+
if(found_binding != NULL) {
|
235
|
+
DM("returning found %s\n", found_binding->value);
|
236
|
+
tally_stringpair(kd, found_binding);
|
237
|
+
return(found_binding -> value);
|
238
|
+
} else if(kd->isDefault) {
|
239
|
+
DM("returning %s\n", key);
|
240
|
+
return(strdup(key));
|
241
|
+
} else {
|
242
|
+
/* not found; although we have a key_decl and this pattern matched, the keys
|
243
|
+
don't include what we have. */
|
244
|
+
count_incomplete_keydecl(kd); /* tally it as a doubt on the keydecl as a whole. */
|
245
|
+
|
246
|
+
if(want_conventions_debug) {
|
247
|
+
if(kd->id == attr_loc) {
|
248
|
+
DM("undns: Unknown location tag %s in %s\n",
|
249
|
+
key, hostname);
|
250
|
+
if(want_conventions_debug) {
|
251
|
+
return "Unknown Location with Hash";
|
252
|
+
}
|
253
|
+
}
|
254
|
+
return NULL;
|
255
|
+
} else {
|
256
|
+
DM("returning null\n");
|
257
|
+
return NULL;
|
258
|
+
}
|
259
|
+
}
|
260
|
+
}
|
261
|
+
|
262
|
+
boolean find_matching_rule(const struct asnc *ac, void *fmr) {
|
263
|
+
struct fmr *f = fmr;
|
264
|
+
assert(ac != NULL);
|
265
|
+
/* zero is an okay special case, neg 1 is a special case. */
|
266
|
+
assert((ac->asn >= 0 && ac->asn <40000) || ac->asn==65535);
|
267
|
+
if(ac->prefilter_regex != NULL) {
|
268
|
+
#ifdef DEPRECATED_GNU_REGEX
|
269
|
+
size_t len = strlen(f->hostname);
|
270
|
+
int matchoffset = re_search(&((struct asnc *)ac)->prefilter_rpbuf,
|
271
|
+
f->hostname, len, 0, len, NULL);
|
272
|
+
if(matchoffset >= 0) {
|
273
|
+
/* matched. */
|
274
|
+
tally_asnc((struct asnc *)ac); /* de-const. */
|
275
|
+
return(conv_q_iterate( ac->conventions, try_rule, f ));
|
276
|
+
} else {
|
277
|
+
return(TRUE); /* keep looking */
|
278
|
+
}
|
279
|
+
#else
|
280
|
+
int reg_ret = regexec(&((struct asnc *)ac)->prefilter_rpbuf,
|
281
|
+
f->hostname, 0, NULL, 0);
|
282
|
+
if(reg_ret == REG_NOMATCH) {
|
283
|
+
return TRUE;
|
284
|
+
} else {
|
285
|
+
/* matched. */
|
286
|
+
tally_asnc((struct asnc *)ac); /* de-const. */
|
287
|
+
return(conv_q_iterate( ac->conventions, try_rule, f ));
|
288
|
+
}
|
289
|
+
#endif
|
290
|
+
}
|
291
|
+
/* no prefilter. tally if conv_q_iterate returns false (found) */
|
292
|
+
if (conv_q_iterate( ac->conventions, try_rule, f )) {
|
293
|
+
return TRUE; /* not found, keep looking */
|
294
|
+
} else {
|
295
|
+
tally_asnc((struct asnc *)ac); /* de-const. */
|
296
|
+
return FALSE;
|
297
|
+
}
|
298
|
+
// return(conv_q_iterate( ac->conventions, try_rule, f ));
|
299
|
+
}
|
300
|
+
|
301
|
+
boolean find_matching_rule_nonzero(const struct asnc *ac, void *fmr) {
|
302
|
+
assert(ac != NULL);
|
303
|
+
if( ac->asn == 0 ) return TRUE; /* keep looking */
|
304
|
+
else return find_matching_rule(ac, fmr);
|
305
|
+
}
|
306
|
+
|
307
|
+
static void doubt_tally(struct convention *matched) {
|
308
|
+
DM("increment doubt count for convention %s:%d\n", inst_get_filename(&matched->inst), matched->inst.line);
|
309
|
+
matched->inst.dynamic_match_count -= 1; /* because we had to find it again */
|
310
|
+
matched->inst.doubt_count += 1;
|
311
|
+
}
|
312
|
+
static void tally(struct convention *matched) {
|
313
|
+
DM("increment match count for convention %s:%d\n", inst_get_filename(&matched->inst), matched->inst.line);
|
314
|
+
matched->inst.dynamic_match_count += 1;
|
315
|
+
}
|
316
|
+
static void count_incomplete_keydecl(struct key_decl *matched) {
|
317
|
+
matched->inst.doubt_count += 1;
|
318
|
+
}
|
319
|
+
static void tally_asnc(struct asnc *matched) {
|
320
|
+
DM("increment match count for asn %s:%d\n", inst_get_filename(&matched->inst), matched->inst.line);
|
321
|
+
matched->inst.dynamic_match_count += 1;
|
322
|
+
}
|
323
|
+
static void tally_stringpair(struct key_decl *kd, struct stringpair *matched) {
|
324
|
+
DM("increment match count for stringpair %s:%d\n", inst_get_filename(&matched->inst), matched->inst.line);
|
325
|
+
matched->inst.dynamic_match_count += 1;
|
326
|
+
kd->inst.dynamic_match_count += 1;
|
327
|
+
}
|
328
|
+
static void doubt_stringpair(struct stringpair *matched) {
|
329
|
+
DM("increment match count for stringpair %s:%d\n", inst_get_filename(&matched->inst), matched->inst.line);
|
330
|
+
matched->inst.doubt_count += 1;
|
331
|
+
}
|
332
|
+
|
333
|
+
/* const before the * means we don't mess with the pointer value, just what it points to. */
|
334
|
+
boolean find_host_convention(/*@out@*/ struct fmr *f, int asn,
|
335
|
+
/*@notnull@*/ const char *hostname) {
|
336
|
+
assert(f);
|
337
|
+
memset(f,0,sizeof(struct fmr));
|
338
|
+
f->hostname = hostname;
|
339
|
+
if(Ruleset == NULL) load_ruleset("Conventions.dat");
|
340
|
+
if(Ruleset == NULL) {
|
341
|
+
fprintf(stderr, "ERROR: find_host_convention failed to load Conventions.dat.\n");
|
342
|
+
return (FALSE);
|
343
|
+
}
|
344
|
+
if(asn == 0) {
|
345
|
+
/* only search nonzero ASes first, */
|
346
|
+
(void) asnc_ht_iterate(Ruleset, find_matching_rule_nonzero, f);
|
347
|
+
if(f->match == NULL) {
|
348
|
+
int zero = 0;
|
349
|
+
const struct asnc *ac = asnc_ht_lookup_k(Ruleset, &zero);
|
350
|
+
/* then it's okay to look at the default rules (as 0) */
|
351
|
+
if( ac != NULL) find_matching_rule(ac, f);
|
352
|
+
}
|
353
|
+
} else {
|
354
|
+
const struct asnc *ac = asnc_ht_lookup_k(Ruleset, &asn);
|
355
|
+
if (ac == NULL) {
|
356
|
+
fprintf(stderr,
|
357
|
+
"ERROR: find_host_convention called, but failed to find an asn "
|
358
|
+
"convention for asn %d among %lu asns\n",
|
359
|
+
asn, asnc_ht_count(Ruleset));
|
360
|
+
return(FALSE);
|
361
|
+
}
|
362
|
+
find_matching_rule(ac, f);
|
363
|
+
}
|
364
|
+
if(f->match) {
|
365
|
+
tally(f->match);
|
366
|
+
}
|
367
|
+
|
368
|
+
return(f->match != NULL);
|
369
|
+
}
|
370
|
+
|
371
|
+
void doubt_location(int asn, const char *hostname) {
|
372
|
+
struct fmr f;
|
373
|
+
assert(hostname);
|
374
|
+
if(find_host_convention(&f, asn, hostname)) {
|
375
|
+
char key[128];
|
376
|
+
doubt_tally(f.match);
|
377
|
+
if(f.match->loc) {
|
378
|
+
if(f.match->loc->constant == NULL) {
|
379
|
+
struct stringpair *found_binding = extract_key_and_find_binding(f.match->loc, f.posix_regs, hostname, key);
|
380
|
+
if(found_binding) {
|
381
|
+
doubt_stringpair(found_binding);
|
382
|
+
}
|
383
|
+
}
|
384
|
+
}
|
385
|
+
}
|
386
|
+
}
|
387
|
+
|
388
|
+
const char *get_attribute(int asn, const char *hostname, enum attributetype attr) {
|
389
|
+
struct fmr f;
|
390
|
+
assert(hostname != NULL);
|
391
|
+
memset(&f, 0, sizeof(f)); /* needed when debugging. */
|
392
|
+
if(find_host_convention(&f, asn, hostname)) {
|
393
|
+
DM("found match for %s\n", hostname);
|
394
|
+
const char *returnme = kdlookup((attr == attr_loc) ? f.match->loc : f.match->type,
|
395
|
+
f.posix_regs,
|
396
|
+
hostname);
|
397
|
+
if(returnme == NULL) {
|
398
|
+
}
|
399
|
+
return returnme;
|
400
|
+
} else {
|
401
|
+
/* there was no convention matching this hostname in that asn. */
|
402
|
+
DM("no match for %s\n", hostname);
|
403
|
+
return NULL;
|
404
|
+
}
|
405
|
+
}
|
406
|
+
|
407
|
+
const char *get_loc(int asn, const char *hostname) {
|
408
|
+
return(get_attribute(asn, hostname, attr_loc));
|
409
|
+
}
|
410
|
+
int get_asn_bydns(const char *hostname) {
|
411
|
+
struct fmr f;
|
412
|
+
if(hostname != NULL && find_host_convention(&f, 0, hostname)) {
|
413
|
+
return((int)(f.match->asn));
|
414
|
+
} else {
|
415
|
+
return 0;
|
416
|
+
}
|
417
|
+
}
|
418
|
+
const char *get_role(int asn, const char *hostname) {
|
419
|
+
return(get_attribute(asn, hostname, attr_type));
|
420
|
+
}
|
421
|
+
|
422
|
+
static char *get_a_tag(struct fmr *f, const char *hostname, const char *tag) {
|
423
|
+
char buf[255];
|
424
|
+
unsigned int i;
|
425
|
+
buf[0] = '\0';
|
426
|
+
if(tag != NULL) {
|
427
|
+
DM("found tag match for %s\n", hostname);
|
428
|
+
for (i = 1;
|
429
|
+
i < REGS_LEN;
|
430
|
+
i++) {
|
431
|
+
if(strcmp(tag, "all") == 0 ||
|
432
|
+
index(tag, '0' + i) != NULL) {
|
433
|
+
|
434
|
+
if(f->posix_regs[i].rm_so >= 0) {
|
435
|
+
strncat(buf, &hostname[f->posix_regs[i].rm_so],
|
436
|
+
(f->posix_regs[i].rm_eo - f->posix_regs[i].rm_so));
|
437
|
+
}
|
438
|
+
}
|
439
|
+
}
|
440
|
+
}
|
441
|
+
return strdup(buf);
|
442
|
+
}
|
443
|
+
|
444
|
+
char *get_poptag(int asn, const char *hostname) {
|
445
|
+
struct fmr f;
|
446
|
+
if(find_host_convention(&f, asn, hostname)) {
|
447
|
+
if(f.match->poptag != NULL) {
|
448
|
+
return get_a_tag(&f, hostname, f.match->poptag->constant);
|
449
|
+
}
|
450
|
+
}
|
451
|
+
return NULL;
|
452
|
+
}
|
453
|
+
|
454
|
+
char *get_identifier(int asn, const char *hostname) {
|
455
|
+
struct fmr f;
|
456
|
+
if(find_host_convention(&f, asn, hostname)) {
|
457
|
+
if(f.match->unique != NULL) {
|
458
|
+
return get_a_tag(&f, hostname, f.match->unique->constant);
|
459
|
+
}
|
460
|
+
}
|
461
|
+
return NULL;
|
462
|
+
}
|
463
|
+
|
464
|
+
const char *get_loc_list(int asn, const char **hostname_list) {
|
465
|
+
int i;
|
466
|
+
for(i=0; hostname_list[i]!=NULL; i++) {
|
467
|
+
get_loc(asn, hostname_list[i]);
|
468
|
+
/* find some way to compute the majority without much fuss. */
|
469
|
+
}
|
470
|
+
return NULL;
|
471
|
+
}
|
472
|
+
|
473
|
+
struct key_decl *new_key_decl(/*@owned@*/ char *id, int regex_index,
|
474
|
+
boolean isDefault,
|
475
|
+
key_hashtable bindings) {
|
476
|
+
NEWPTR(struct key_decl, ret);
|
477
|
+
if(strcmp(id, "loc") == 0) ret->id = attr_loc;
|
478
|
+
else if(strcmp(id, "type") == 0) ret->id = attr_type;
|
479
|
+
else { printf("bad type: '%s'\n", id); return NULL; }
|
480
|
+
ret->regex_index = regex_index;
|
481
|
+
ret->isDefault = isDefault;
|
482
|
+
ret->bindings = bindings;
|
483
|
+
ret->constant = NULL;
|
484
|
+
free(id);
|
485
|
+
return ret;
|
486
|
+
}
|
487
|
+
struct key_decl *new_key_decl_const(/*@owned@*/ char *id, char *constant){
|
488
|
+
NEWPTR(struct key_decl, ret);
|
489
|
+
if(strcmp(id, "loc") == 0) ret->id = attr_loc;
|
490
|
+
else if(strcmp(id, "type") == 0) ret->id = attr_type;
|
491
|
+
else if(strcmp(id, "unique") == 0) ret->id = attr_unique;
|
492
|
+
else if(strcmp(id, "poptag") == 0) ret->id = attr_poptag;
|
493
|
+
else { printf("bad type: '%s'\n", id); return NULL; }
|
494
|
+
ret->regex_index = 0;
|
495
|
+
ret->isDefault = FALSE;
|
496
|
+
ret->bindings = NULL;
|
497
|
+
ret->constant = constant;
|
498
|
+
free(id);
|
499
|
+
return ret;
|
500
|
+
}
|
501
|
+
|
502
|
+
#define SET_IF_UNSET(x, y) if(ret->x) { printf("warning: %s attribute is already set for %s!\n", #x, ret->regex); } else { ret->x = y;;;;;;;; }
|
503
|
+
static void add_key_decl(struct convention *ret, struct key_decl *a) {
|
504
|
+
if(a != NULL) {
|
505
|
+
switch(a->id) {
|
506
|
+
case attr_loc: SET_IF_UNSET(loc, a); break;
|
507
|
+
case attr_type: SET_IF_UNSET(type, a); break;
|
508
|
+
case attr_unique: SET_IF_UNSET(unique, a); break;
|
509
|
+
case attr_poptag: SET_IF_UNSET(poptag, a); break;
|
510
|
+
default: fprintf(stderr, "bogus attribute!\n");
|
511
|
+
}
|
512
|
+
}
|
513
|
+
}
|
514
|
+
|
515
|
+
struct convention *new_convention(char *regex,
|
516
|
+
struct key_decl *a,
|
517
|
+
struct key_decl *b,
|
518
|
+
struct key_decl *c,
|
519
|
+
struct key_decl *d,
|
520
|
+
const char *filename,
|
521
|
+
int linenum) {
|
522
|
+
NEWPTR(struct convention, ret);
|
523
|
+
int errcode;
|
524
|
+
ret->regex = regex;
|
525
|
+
|
526
|
+
ret->loc = NULL;
|
527
|
+
ret->type = NULL;
|
528
|
+
ret->unique = NULL;
|
529
|
+
ret->poptag = NULL;
|
530
|
+
add_key_decl(ret, a);
|
531
|
+
add_key_decl(ret, b);
|
532
|
+
add_key_decl(ret, c);
|
533
|
+
add_key_decl(ret, d);
|
534
|
+
|
535
|
+
if ((errcode = regcomp(&ret->rpbuf, regex, REG_EXTENDED)) != 0) {
|
536
|
+
char errbuf[256];
|
537
|
+
regerror(errcode, &ret->rpbuf, errbuf, 256);
|
538
|
+
fprintf(stderr, "error in compiling regular expression '%s': %s\n",
|
539
|
+
regex, errbuf);
|
540
|
+
exit(EXIT_FAILURE);
|
541
|
+
}
|
542
|
+
|
543
|
+
set_file_and_line(&ret->inst, filename, linenum);
|
544
|
+
return(ret);
|
545
|
+
}
|
546
|
+
|
547
|
+
static boolean dump_stringpair(const struct stringpair *sp, void *file_pointer) {
|
548
|
+
FILE *fp = file_pointer;
|
549
|
+
char buffy[255];
|
550
|
+
assert(fp);
|
551
|
+
assert(sp);
|
552
|
+
fprintf(fp, " %s->%s %s\n", sp->key, sp->value, inst_format_stats(buffy, 255, &sp->inst));
|
553
|
+
return TRUE;
|
554
|
+
}
|
555
|
+
|
556
|
+
static boolean dump_conventions(const struct convention *conv, void *file_pointer) {
|
557
|
+
FILE *fp = file_pointer;
|
558
|
+
char buffy[255];
|
559
|
+
assert(fp);
|
560
|
+
assert(conv);
|
561
|
+
assert(conv->asn < 100000); /* sanity */
|
562
|
+
fprintf(fp, " %ld, %s, %s\n", conv->asn, conv->regex, inst_format_stats(buffy, 255, &conv->inst));
|
563
|
+
if(conv->loc && conv->loc->bindings && conv->inst.dynamic_match_count > 0) {
|
564
|
+
fprintf(fp, " incomplete keys: %s\n", inst_format_stats(buffy, 255, &conv->loc->inst));
|
565
|
+
key_ht_iterate(conv->loc->bindings, dump_stringpair, fp);
|
566
|
+
}
|
567
|
+
/* TODO: there's more to dump: key declarations and such. */
|
568
|
+
return TRUE;
|
569
|
+
}
|
570
|
+
|
571
|
+
static boolean dump_asns(const struct asnc *as, void *file_pointer ) {
|
572
|
+
FILE *fp = file_pointer;
|
573
|
+
char buffy[255];
|
574
|
+
assert(fp);
|
575
|
+
assert(as);
|
576
|
+
fprintf(fp, "AS%d, %s, %s\n", as->asn, as->prefilter_regex, inst_format_stats(buffy, 255, &as->inst));
|
577
|
+
if(as->conventions) {
|
578
|
+
conv_q_iterate(as->conventions, dump_conventions, fp);
|
579
|
+
}
|
580
|
+
return TRUE;
|
581
|
+
}
|
582
|
+
|
583
|
+
void dump_parsed_conventions_to_file(const char * filename) {
|
584
|
+
FILE *dump = fopen(filename, "w");
|
585
|
+
assert(filename);
|
586
|
+
assert(dump);
|
587
|
+
|
588
|
+
asnc_ht_iterate(Ruleset, dump_asns, dump);
|
589
|
+
|
590
|
+
fclose(dump);
|
591
|
+
}
|
592
|
+
|
593
|
+
void dump_single_asn_conventions_to_file(int asn, const char * filename) {
|
594
|
+
FILE *dump = fopen(filename, "w");
|
595
|
+
const struct asnc *ac = asnc_ht_lookup_k(Ruleset, &asn);
|
596
|
+
|
597
|
+
assert(filename);
|
598
|
+
assert(dump);
|
599
|
+
|
600
|
+
dump_asns(ac, dump);
|
601
|
+
|
602
|
+
fclose(dump);
|
603
|
+
}
|