undns 0.4.0a

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.
@@ -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
+ }