undns 0.4.0a

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