comparison src/routeconfig.cpp @ 0:48d06780cf77

initial version
author Carl Byington <carl@five-ten-sg.com>
date Tue, 13 May 2008 14:03:10 -0700
parents
children bb3f804f13a0
comparison
equal deleted inserted replaced
-1:000000000000 0:48d06780cf77
1 /*
2
3 Copyright (c) 2007 Carl Byington - 510 Software Group, released under
4 the GPL version 3 or any later version at your choice available at
5 http://www.gnu.org/licenses/gpl-3.0.txt
6
7 */
8
9 #include "includes.h"
10 #include <fcntl.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <netdb.h>
15 #include <limits.h>
16 #include <set>
17 #include <vector>
18 #include <map>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <time.h>
22
23 char *token_announce;
24 char *token_file;
25 char *token_include;
26 char *token_index_ip;
27 char *token_index_length;
28 char *token_index_path;
29 char *token_index_value;
30 char *token_ip;
31 char *token_lbrace;
32 char *token_path;
33 char *token_rbrace;
34 char *token_reset;
35 char *token_semi;
36 char *token_slash;
37 char *token_withdraw;
38
39 const int training = 100; // need 100 hours uptime before using the statistics
40 const float origin_threshold = 2.9; // a bit less than 1 + decay + decay^2
41 const float adjacent_threshold = 2.9; // ""
42 const float decay = 0.99; // hourly exponential decay
43 const float threshold = 0.01; // when counts have decayed below threshold, discard the item
44 const int ancient_smtp = 3*3600;// suspicious smtp connections over 3 hours old are ignored
45
46 string_set all_strings; // owns all the strings, only modified by the config loader thread
47 const int maxlen = 1000; // used for snprintf buffers
48 typedef pair<int,int> adjacent;
49 typedef vector<int> aspath;
50 typedef map<int,float> o_history; // as origin history
51 typedef map<adjacent,float> a_history; // as adjacency history
52 typedef set<adjacent> a_set; // set of current adjacency pairs
53 typedef map<uint32_t,time_t> m_connect; // smtp connections
54
55 class route_prefix {
56 uint32_t prefix_value;
57 bool announced;
58 bool trusted; // cannot be suspicious
59 aspath path;
60 o_history origin_history;
61 m_connect smtp_connections;
62 public:
63 route_prefix(uint32_t value);
64 void add_route(aspath path_, a_history &adj_history);
65 void remove_route(int prefix_length);
66 uint32_t prefix() const { return prefix_value; };
67 bool active() const { return announced; };
68 adjacent aspair(int i) const { return adjacent(path[i], path[i+1]); };
69 bool empty() const { return !announced && origin_history.empty(); };
70 void update_history(a_set &adj_set);
71 suspicion suspicious(a_history &adj_history, bool debug = false, int prefix_length = 0, uint32_t ip = 0);
72 void record_smtp(uint32_t ip);
73 string name(int length) const;
74 };
75
76 struct ltrouteprefix {
77 bool operator()(const route_prefix* r1, const route_prefix* r2) const {
78 return r1->prefix() < r2->prefix();
79 }
80 };
81
82 typedef set<route_prefix*, ltrouteprefix> route_prefixes;
83
84 class RIB {
85 pthread_mutex_t rib_mutex;
86 int uptime;
87 bool stable;
88 route_prefixes prefixes[33]; // /0 to /32
89 a_history history;
90 aspath path;
91 public:
92 RIB();
93 void set_path(aspath path_) {path = path_;};
94 void add_route(int prefix_length, uint32_t prefix_value);
95 void remove_route(int prefix_length, uint32_t prefix_value);
96 void update_history();
97 suspicion suspicious(route_prefix *r, bool debug = false, int prefix_length = 0, uint32_t ip = 0);
98 suspicion suspicious(uint32_t ip);
99 void clear();
100 void reset();
101 };
102
103
104 RIB route_base;
105
106 const uint32_t masks[33] = {
107 0x00000000,
108 0x80000000,
109 0xc0000000,
110 0xe0000000,
111 0xf0000000,
112 0xf8000000,
113 0xfc000000,
114 0xfe000000,
115 0xff000000,
116 0xff800000,
117 0xffc00000,
118 0xffe00000,
119 0xfff00000,
120 0xfff80000,
121 0xfffc0000,
122 0xfffe0000,
123 0xffff0000,
124 0xffff8000,
125 0xffffc000,
126 0xffffe000,
127 0xfffff000,
128 0xfffff800,
129 0xfffffc00,
130 0xfffffe00,
131 0xffffff00,
132 0xffffff80,
133 0xffffffc0,
134 0xffffffe0,
135 0xfffffff0,
136 0xfffffff8,
137 0xfffffffc,
138 0xfffffffe,
139 0xffffffff};
140
141
142 ////////////////////////////////////////////////
143 //
144 char *suspicious_name(suspicion s)
145 {
146 char *ss = "";
147 switch (s) {
148 case suspicious_none: ss = "none"; break;
149 case suspicious_origin: ss = "origin"; break;
150 case suspicious_adjacency: ss = "adjacency"; break;
151 default: break;
152 }
153 return ss;
154 }
155
156
157 ////////////////////////////////////////////////
158 //
159 route_prefix::route_prefix(uint32_t value)
160 {
161 prefix_value = value;
162 announced = false;
163 trusted = false;
164 }
165
166
167 void route_prefix::add_route(aspath path_, a_history &adj_history)
168 {
169 suspicion s = suspicious(adj_history);
170 trusted = announced && (s == suspicious_none);
171 announced = true;
172 path = path_;
173 }
174
175
176 void route_prefix::remove_route(int prefix_length)
177 {
178 if (announced) {
179 for (m_connect::iterator i = smtp_connections.begin(); i != smtp_connections.end(); i++) {
180 const uint32_t &ip = (*i).first;
181 time_t &t = (*i).second;
182 uint32_t nip = htonl(ip);
183 char buf[maxlen];
184 char adr[sizeof "255.255.255.255 "];
185 adr[0] = '\0';
186 inet_ntop(AF_INET, (const u_char *)&nip, adr, sizeof(adr));
187 char ctbuf[maxlen];
188 ctime_r(&t, ctbuf);
189 int ii = strlen(ctbuf);
190 if (ii > 1) ctbuf[ii-1] = '\0'; // remove trailing newline
191 snprintf(buf, sizeof(buf), "*** smtp connection at %s from %s via prefix %s/%d being removed", ctbuf, adr, name(prefix_length).c_str(), prefix_length);
192 my_syslog(buf);
193 }
194 }
195 announced = false;
196 smtp_connections.clear();
197 }
198
199
200 void route_prefix::update_history(a_set &adj_set)
201 {
202 // decay origin history
203 for (o_history::iterator i = origin_history.begin(); i != origin_history.end(); i++) {
204 float &count = (*i).second;
205 count *= decay;
206 }
207 if (announced) {
208 // remove old suspicious smtp connections
209 time_t cutoff = time(NULL) - ancient_smtp;
210 for (m_connect::iterator i = smtp_connections.begin(); i != smtp_connections.end(); ) {
211 time_t &t = (*i).second;
212 if (t > cutoff) i++;
213 else smtp_connections.erase(i++);
214 }
215
216 // update origin history
217 int n = path.size() - 1;
218 int origin = path[n];
219 o_history::iterator j = origin_history.find(origin);
220 if (j == origin_history.end()) {
221 origin_history[origin] = 1.0;
222 }
223 else {
224 float &count = (*j).second;
225 count++;
226 }
227 // update current adjacency set
228 for (int k=0; k<n; k++) {
229 adj_set.insert(aspair(k));
230 }
231 }
232
233 // remove origin history entries below the threshold
234 for (o_history::iterator i = origin_history.begin(); i != origin_history.end();) {
235 float &count = (*i).second;
236 if (count > threshold) i++;
237 else origin_history.erase(i++);
238 }
239 }
240
241
242 suspicion route_prefix::suspicious(a_history &adj_history, bool debug, int prefix_length, uint32_t ip)
243 {
244 if (!announced || trusted) return suspicious_none;
245 debug &= (debug_syslog > 2);
246
247 // check origin stability
248 int n = path.size() - 1;
249 int origin = path[n];
250 o_history::const_iterator o = origin_history.find(origin);
251 if (o == origin_history.end()) {
252 if (debug) {
253 char buf[maxlen];
254 snprintf(buf, sizeof(buf), "debug suspicious origin %d missing count %s",
255 origin, name(prefix_length).c_str());
256 my_syslog(buf);
257 }
258 record_smtp(ip);
259 return suspicious_origin;
260 }
261 const float &count = (*o).second;
262 if (count < origin_threshold) {
263 if (debug) {
264 char buf[maxlen];
265 snprintf(buf, sizeof(buf), "debug suspicious origin %d count %5.2f vs %5.2f %s",
266 origin, count, origin_threshold, name(prefix_length).c_str());
267 my_syslog(buf);
268 }
269 record_smtp(ip);
270 return suspicious_origin;
271 }
272
273 // check as adjacency stability
274 for (int k=0; k<n; k++) {
275 adjacent aa = aspair(k);
276 a_history::iterator a = adj_history.find(aa);
277 if (a == adj_history.end()) {
278 if (debug) {
279 char buf[maxlen];
280 snprintf(buf, sizeof(buf), "debug suspicious adjacency (%d,%d) missing count %s",
281 aa.first, aa.second, name(prefix_length).c_str());
282 my_syslog(buf);
283 }
284 record_smtp(ip);
285 return suspicious_adjacency;
286 }
287 float &count = (*a).second;
288 if (count < adjacent_threshold) {
289 if (debug) {
290 char buf[maxlen];
291 snprintf(buf, sizeof(buf), "debug suspicious adjacency (%d,%d) count %5.2f vs %5.2f %s",
292 aa.first, aa.second, count, adjacent_threshold, name(prefix_length).c_str());
293 my_syslog(buf);
294 }
295 record_smtp(ip);
296 return suspicious_adjacency;
297 }
298 }
299 return suspicious_none;
300 }
301
302
303 void route_prefix::record_smtp(uint32_t ip)
304 {
305 if (ip) smtp_connections[ip] = time(NULL);
306 }
307
308
309 string route_prefix::name(int length) const
310 {
311 char buf[maxlen];
312 char adr[sizeof "255.255.255.255 "];
313 adr[0] = '\0';
314 uint32_t nip = htonl(prefix_value);
315 inet_ntop(AF_INET, (const u_char *)&nip, adr, sizeof(adr));
316 snprintf(buf, sizeof(buf), "%s/%d", adr, length);
317 int n = path.size();
318 for (int i=0; i<n; i++) {
319 snprintf(adr, sizeof(adr), " %d", path[i]);
320 strncat(buf, adr, max(0, maxlen-1-(int)strlen(adr)));
321 }
322 return string(buf);
323 }
324
325
326 ////////////////////////////////////////////////
327 //
328
329 RIB::RIB()
330 {
331 pthread_mutex_init(&rib_mutex, 0);
332 uptime = 0;
333 stable = false;
334 }
335
336
337 void RIB::add_route(int prefix_length, uint32_t prefix_value)
338 {
339 if (prefix_length < 0) return;
340 if (prefix_length > 32) return;
341 pthread_mutex_lock(&rib_mutex);
342 prefix_value &= masks[prefix_length];
343 route_prefix rr(prefix_value);
344 route_prefixes &p = prefixes[prefix_length];
345 route_prefixes::iterator i = p.find(&rr);
346 route_prefix *r = NULL;
347 if (i == p.end()) {
348 // new prefix
349 r = new route_prefix(prefix_value);
350 p.insert(r);
351 }
352 else {
353 // existing prefix
354 r = *i;
355 }
356 r->add_route(path, history);
357 suspicion s;
358 if (debug_syslog > 2) s = suspicious(r);
359 if ((debug_syslog > 2) && (s != suspicious_none) && (prefix_length < 22)) {
360 char buf[maxlen];
361 snprintf(buf, sizeof(buf), "add suspicious %s route %s", suspicious_name(s), r->name(prefix_length).c_str());
362 my_syslog(buf);
363 }
364 else if (debug_syslog > 3) {
365 char buf[maxlen];
366 snprintf(buf, sizeof(buf), "add route %s", r->name(prefix_length).c_str());
367 my_syslog(buf);
368 }
369 pthread_mutex_unlock(&rib_mutex);
370 }
371
372
373 void RIB::remove_route(int prefix_length, uint32_t prefix_value)
374 {
375 if (prefix_length < 0) return;
376 if (prefix_length > 32) return;
377 pthread_mutex_lock(&rib_mutex);
378 uint32_t mask = masks[prefix_length];
379 prefix_value &= mask;
380 route_prefix r(prefix_value);
381 route_prefixes &p = prefixes[prefix_length];
382 route_prefixes::iterator i = p.find(&r);
383 if (i != p.end()) {
384 // existing prefix
385 route_prefix* r = *i;
386 if (debug_syslog > 3) {
387 char buf[maxlen];
388 snprintf(buf, sizeof(buf), "remove route %s", r->name(prefix_length).c_str());
389 my_syslog(buf);
390 }
391 r->remove_route(prefix_length);
392 if (r->empty()) {
393 p.erase(r);
394 delete r;
395 };
396 }
397 pthread_mutex_unlock(&rib_mutex);
398 }
399
400
401 void RIB::update_history()
402 {
403 pthread_mutex_lock(&rib_mutex);
404 a_set adj_set;
405 uptime++;
406 stable = (uptime > training);
407 int total = 0;
408 int inactive = 0;
409 int suspic = 0;
410 for (int i=0; i<=32; i++) {
411 bool debug = true; // show first suspicious prefix
412 route_prefixes &p = prefixes[i];
413 for (route_prefixes::iterator j = p.begin(); j != p.end();) {
414 route_prefix *r = *j;
415 r->update_history(adj_set);
416 total++;
417 if (r->active()) {
418 if (suspicious(r, debug, i) != suspicious_none) {
419 suspic++;
420 debug = false;
421 }
422 }
423 else {
424 inactive++;
425 }
426 if (r->empty()) {
427 p.erase(j++);
428 delete r;
429 }
430 else j++;
431 }
432 }
433 if (debug_syslog > 2) {
434 char buf[maxlen];
435 snprintf(buf, sizeof(buf), "total %d inactive %d suspicious %d", total, inactive, suspic);
436 my_syslog(buf);
437 }
438 // decay adjacency history
439 for (a_history::iterator i = history.begin(); i != history.end(); i++) {
440 float &count = (*i).second;
441 count *= decay;
442 }
443 // update adjacency history from the current adjacency set
444 for (a_set::iterator i = adj_set.begin(); i != adj_set.end(); i++) {
445 a_history::iterator a = history.find(*i);
446 if (a == history.end()) {
447 // new adjacency
448 history[*i] = 1.0;
449 }
450 else {
451 float &count = (*a).second;
452 count++;
453 }
454 }
455 // remove adjacency history entries below the threshold
456 for (a_history::iterator i = history.begin(); i != history.end();) {
457 float &count = (*i).second;
458 if (count > threshold) i++;
459 else history.erase(i++);
460 }
461 pthread_mutex_unlock(&rib_mutex);
462 }
463
464
465 suspicion RIB::suspicious(route_prefix *r, bool debug, int prefix_length, uint32_t ip)
466 {
467 if (!stable) return suspicious_none;
468 if (!r) return suspicious_none;
469 return r->suspicious(history, debug, prefix_length, ip);
470 }
471
472
473 suspicion RIB::suspicious(uint32_t ip)
474 {
475 if (!stable) return suspicious_none;
476 suspicion rc = suspicious_none;
477 route_prefix *r1 = NULL;
478 int pl;
479 pthread_mutex_lock(&rib_mutex);
480 for (int i=32; i>=0; i--) {
481 route_prefixes &p = prefixes[i];
482 uint32_t network = ip & masks[i];
483 route_prefix r(network);
484 route_prefixes::iterator j = p.find(&r);
485 if (j != p.end()) {
486 // existing prefix
487 route_prefix* r = *j;
488 if (r->active()) {
489 r1 = r;
490 pl = i;
491 break;
492 }
493 }
494 }
495 rc = suspicious(r1, true, pl, ip);
496 pthread_mutex_unlock(&rib_mutex);
497 return rc;
498 }
499
500
501 void RIB::clear()
502 {
503 pthread_mutex_lock(&rib_mutex);
504 for (int i=0; i<=32; i++) {
505 route_prefixes &p = prefixes[i];
506 for (route_prefixes::iterator j = p.begin(); j != p.end();) {
507 route_prefix *r = *j;
508 p.erase(j++);
509 delete r;
510 }
511 }
512 history.clear();
513 pthread_mutex_unlock(&rib_mutex);
514 }
515
516
517 void RIB::reset()
518 {
519 pthread_mutex_lock(&rib_mutex);
520 for (int i=0; i<=32; i++) {
521 route_prefixes &p = prefixes[i];
522 for (route_prefixes::iterator j = p.begin(); j != p.end(); j++) {
523 route_prefix *r = *j;
524 r->remove_route(i);
525 }
526 }
527 pthread_mutex_unlock(&rib_mutex);
528 }
529
530
531 ////////////////////////////////////////////////
532 //
533 CONFIG::CONFIG() {
534 reference_count = 0;
535 generation = 0;
536 load_time = 0;
537 }
538
539
540 CONFIG::~CONFIG() {
541 for (routeconfig_list::iterator i=routeconfigs.begin(); i!=routeconfigs.end(); i++) {
542 ROUTECONFIG *c = *i;
543 delete c;
544 }
545 }
546
547
548 void CONFIG::dump() {
549 for (routeconfig_list::iterator i=routeconfigs.begin(); i!=routeconfigs.end(); i++) {
550 ROUTECONFIG *c = *i;
551 c->dump(0);
552 }
553 }
554
555
556 void CONFIG::read() {
557 while (true) {
558 bool have = false;
559 for (routeconfig_list::iterator i=routeconfigs.begin(); i!=routeconfigs.end(); i++) {
560 ROUTECONFIGP c = *i;
561 have |= c->read(*this);
562 }
563 if (!have) break;
564 }
565 }
566
567
568
569 ////////////////////////////////////////////////
570 //
571 ROUTECONFIG::ROUTECONFIG(TOKEN &tok, char *file_name_) {
572 tokp = &tok;
573 file_name = file_name_;
574 open(true);
575 }
576
577
578 ROUTECONFIG::~ROUTECONFIG() {
579 close();
580 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) {
581 PATTERN *p = *i;
582 delete p;
583 }
584 }
585
586
587 void ROUTECONFIG::open(bool msg) {
588 fd = ::open(file_name, O_RDONLY);
589 len = 0;
590 if (fd == -1) {
591 if (msg) {
592 char buf[maxlen];
593 snprintf(buf, sizeof(buf), "syslog file %s not readable", file_name);
594 tokp->token_error(buf);
595 }
596 }
597 else {
598 if (debug_syslog > 1) {
599 snprintf(buf, sizeof(buf), "syslog file %s opened", file_name);
600 my_syslog(buf);
601 }
602 if (msg) lseek(fd, 0, SEEK_END);
603 if (fstat(fd, &openfdstat)) {
604 close();
605 snprintf(buf, sizeof(buf), "syslog file %s cannot stat after open", file_name);
606 tokp->token_error(buf);
607 }
608 // specify that this fd gets closed on exec, so that selinux
609 // won't complain
610 int oldflags = fcntl(fd, F_GETFD, 0);
611 if (oldflags >= 0) {
612 fcntl(fd, F_SETFD, oldflags | FD_CLOEXEC);
613 }
614 }
615 }
616
617
618 bool ROUTECONFIG::read(CONFIG &con) {
619 if (failed()) {
620 open(false);
621 if (failed()) return false;
622 }
623 int n = ::read(fd, buf+len, buflen-len);
624 bool have = (n > 0);
625 if (have) {
626 len += n;
627 while (true) {
628 char *p = (char*)memchr(buf, '\n', len);
629 if (!p) break;
630 n = p-buf;
631 *p = '\0';
632 process(con); // process null terminated string
633 len -= n+1;
634 memmove(buf, p+1, len);
635 }
636 // no <lf> in a full buffer
637 if (len == buflen) len = 0;
638 }
639 else {
640 // check for file close
641 struct stat filenamest;
642 if (0 == stat(file_name, &filenamest)) {
643 if ((filenamest.st_dev != openfdstat.st_dev) ||
644 (filenamest.st_ino != openfdstat.st_ino)) {
645 close();
646 }
647 }
648 else {
649 // filename no longer exists
650 close();
651 }
652 }
653 return have;
654 }
655
656
657 void ROUTECONFIG::close() {
658 if (debug_syslog > 1) {
659 snprintf(buf, sizeof(buf), "syslog file %s closed", file_name);
660 my_syslog(buf);
661 }
662 if (fd != -1) ::close(fd);
663 fd = -1;
664 }
665
666
667 void ROUTECONFIG::add_pattern(PATTERNP pat) {
668 patterns.push_back(pat);
669 }
670
671
672 void ROUTECONFIG::process(CONFIG &con) {
673 int pi=0;
674 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) {
675 PATTERN *p = *i;
676 if (p->process(buf, con, file_name, pi)) break;
677 pi++;
678 }
679 }
680
681
682 void ROUTECONFIG::dump(int level) {
683 char indent[maxlen];
684 int i = min(maxlen-1, level*4);
685 memset(indent, ' ', i);
686 indent[i] = '\0';
687 printf("%s file \"%s\" {\n", indent, file_name);
688 for (pattern_list::iterator i=patterns.begin(); i!=patterns.end(); i++) {
689 PATTERN *p = *i;
690 p->dump(level+1);
691 }
692 printf("%s }; \n", indent);
693 }
694
695
696 ////////////////////////////////////////////////
697 //
698 int ip_address(char *have);
699 int ip_address(char *have) {
700 int ipaddr = 0;
701 in_addr ip;
702 if (inet_aton(have, &ip)) ipaddr = ip.s_addr;
703 else {
704 struct hostent *host = gethostbyname(have);
705 if (host && host->h_addrtype == AF_INET) memcpy(&ipaddr, host->h_addr, sizeof(ipaddr));
706 }
707 return ntohl(ipaddr);
708 }
709
710
711 ////////////////////////////////////////////////
712 //
713
714 PATTERN::PATTERN(TOKEN &tok, pattern_style style_, char *pattern_, int index1_, int index2_)
715 {
716 style = style_;
717 pattern = pattern_;
718 index1 = index1_;
719 index2 = index2_;
720 if (pattern) {
721 int rc = regcomp(&re, pattern, REG_ICASE | REG_EXTENDED);
722 if (rc) {
723 char bu[maxlen];
724 regerror(rc, &re, bu, maxlen);
725 char buf[maxlen];
726 snprintf(buf, sizeof(buf), "pattern %s not valid - %s", pattern, bu);
727 tok.token_error(buf);
728 pattern = NULL;
729 }
730 }
731 }
732
733
734 PATTERN::~PATTERN() {
735 regfree(&re);
736 }
737
738
739 bool PATTERN::process(char *buf, CONFIG &con, char *file_name, int pattern_index)
740 {
741 if (pattern) {
742 const int nmatch = max(index1, index2) + 1;
743 regmatch_t match[nmatch];
744 if (0 == regexec(&re, buf, nmatch, match, 0)) {
745 int sp1 = match[index1].rm_so;
746 int ep1 = match[index1].rm_eo;
747 int sp2 = match[index2].rm_so;
748 int ep2 = match[index2].rm_eo;
749 if ((sp1 != -1) && (sp2 != -1)) {
750 if (debug_syslog > 13) {
751 my_syslog(buf); // show lines with matches
752 }
753 buf[ep1] = '\0';
754 buf[ep2] = '\0';
755 uint32_t ip;
756 int pl;
757 suspicion s;
758 switch (style) {
759 case style_reset:
760 route_base.reset();
761 break;
762 case style_path:
763 {
764 aspath path;
765 char *p = buf+sp1;
766 char *e;
767 long l;
768 while (true) {
769 l = strtol(p, &e, 10);
770 if (e == p) break;
771 p = e;
772 path.push_back((int)l);
773 }
774 route_base.set_path(path);
775 }
776 break;
777 case style_announce:
778 ip = ip_address(buf+sp1);
779 pl = atoi(buf+sp2);
780 if (ip) route_base.add_route(pl, ip);
781 break;
782 case style_withdraw:
783 ip = ip_address(buf+sp1);
784 pl = atoi(buf+sp2);
785 if (ip) route_base.remove_route(pl, ip);
786 break;
787 case style_ip:
788 ip = ip_address(buf+sp1);
789 s = route_base.suspicious(ip);
790 if (s != suspicious_none) {
791 char adr[sizeof "255.255.255.255 "];
792 adr[0] = '\0';
793 uint32_t nip = htonl(ip);
794 inet_ntop(AF_INET, (const u_char *)&nip, adr, sizeof(adr));
795 char buf[maxlen];
796 snprintf(buf, sizeof(buf), "*** suspicious %s ip %s", suspicious_name(s), adr);
797 my_syslog(buf);
798 }
799 break;
800 }
801 return true;
802 }
803 }
804 }
805 return false;
806 }
807
808
809 void PATTERN::dump(int level, int index, char *token)
810 {
811 char indent[maxlen];
812 int i = min(maxlen-1, level*4);
813 memset(indent, ' ', i);
814 indent[i] = '\0';
815 printf("%s %s %d; \n", indent, token, index);
816 }
817
818
819 void PATTERN::dump(int level)
820 {
821 char indent[maxlen];
822 int i = min(maxlen-1, level*4);
823 memset(indent, ' ', i);
824 indent[i] = '\0';
825 switch (style) {
826 case style_reset:
827 printf("%s %s \"%s\" { \n", indent, token_reset, pattern);
828 break;
829 case style_path:
830 printf("%s %s \"%s\" { \n", indent, token_path, pattern);
831 dump(level+1, index1, token_index_path);
832 break;
833 case style_announce:
834 printf("%s %s \"%s\" { \n", indent, token_announce, pattern);
835 dump(level+1, index1, token_index_value);
836 dump(level+1, index2, token_index_length);
837 break;
838 case style_withdraw:
839 printf("%s %s \"%s\" { \n", indent, token_withdraw, pattern);
840 dump(level+1, index1, token_index_value);
841 dump(level+1, index2, token_index_length);
842 break;
843 case style_ip:
844 printf("%s %s \"%s\" { \n", indent, token_ip, pattern);
845 dump(level+1, index1, token_index_ip);
846 break;
847 }
848 printf("%s }; \n", indent);
849 }
850
851
852 ////////////////////////////////////////////////
853 // helper to discard the strings held by a string_set
854 //
855 void discard(string_set &s) {
856 for (string_set::iterator i=s.begin(); i!=s.end(); i++) {
857 free(*i);
858 }
859 s.clear();
860 }
861
862
863 ////////////////////////////////////////////////
864 // helper to register a string in a string set
865 //
866 char* register_string(string_set &s, char *name) {
867 string_set::iterator i = s.find(name);
868 if (i != s.end()) return *i;
869 char *x = strdup(name);
870 s.insert(x);
871 return x;
872 }
873
874
875 ////////////////////////////////////////////////
876 // register a global string
877 //
878 char* register_string(char *name) {
879 return register_string(all_strings, name);
880 }
881
882
883 ////////////////////////////////////////////////
884 // clear all global strings, helper for valgrind checking
885 //
886 void clear_strings() {
887 discard(all_strings);
888 }
889
890
891 ////////////////////////////////////////////////
892 // clear the rib, helper for valgrind checking
893 //
894 void clear_rib() {
895 route_base.clear();
896 }
897
898
899 ////////////////////////////////////////////////
900 //
901 bool tsa(TOKEN &tok, char *token);
902 bool tsa(TOKEN &tok, char *token) {
903 char *have = tok.next();
904 if (have == token) return true;
905 tok.token_error(token, have);
906 return false;
907 }
908
909
910 ////////////////////////////////////////////////
911 //
912 bool parse_path(TOKEN &tok, ROUTECONFIG &con, char *tokk, pattern_style style);
913 bool parse_path(TOKEN &tok, ROUTECONFIG &con, char *tokk, pattern_style style) {
914 char *pattern = tok.next();
915 int index = 0;
916 if (!tsa(tok, token_lbrace)) return false;
917 while (true) {
918 char *have = tok.next();
919 if (!have) break;
920 if (have == token_rbrace) break;
921 if (have == tokk) {
922 index = tok.nextint();
923 if (!tsa(tok, token_semi)) return false;
924 }
925 else return false;
926 }
927 if (!tsa(tok, token_semi)) return false;
928 PATTERNP p = new PATTERN(tok, style, pattern, index, 0);
929 con.add_pattern(p);
930 return true;
931 }
932
933
934 bool parse_announce_withdraw(TOKEN &tok, ROUTECONFIG &con, pattern_style style);
935 bool parse_announce_withdraw(TOKEN &tok, ROUTECONFIG &con, pattern_style style) {
936 char *pattern = tok.next();
937 int index1 = 0;
938 int index2 = 0;
939 if (!tsa(tok, token_lbrace)) return false;
940 while (true) {
941 char *have = tok.next();
942 if (!have) break;
943 if (have == token_rbrace) break;
944 if (have == token_index_value) {
945 index1 = tok.nextint();
946 if (!tsa(tok, token_semi)) return false;
947 }
948 else if (have == token_index_length) {
949 index2 = tok.nextint();
950 if (!tsa(tok, token_semi)) return false;
951 }
952 else return false;
953 }
954 if (!tsa(tok, token_semi)) return false;
955 PATTERNP p = new PATTERN(tok, style, pattern, index1, index2);
956 con.add_pattern(p);
957 return true;
958 }
959
960
961 bool parse_routeconfig(TOKEN &tok, CONFIG &dc);
962 bool parse_routeconfig(TOKEN &tok, CONFIG &dc) {
963 char *name = tok.next();
964 if (!tsa(tok, token_lbrace)) return false;
965 ROUTECONFIGP con = new ROUTECONFIG(tok, name);
966 if (con->failed()) {
967 delete con;
968 return false;
969 }
970 dc.add_routeconfig(con);
971 while (true) {
972 char *have = tok.next();
973 if (!have) break;
974 if (have == token_rbrace) break;
975 if (have == token_reset) {
976 if (!parse_path(tok, *con, NULL, style_reset)) return false;
977 }
978 else if (have == token_path) {
979 if (!parse_path(tok, *con, token_index_path, style_path)) return false;
980 }
981 else if (have == token_ip) {
982 if (!parse_path(tok, *con, token_index_ip, style_ip)) return false;
983 }
984 else if (have == token_announce) {
985 if (!parse_announce_withdraw(tok, *con, style_announce)) return false;
986 }
987 else if (have == token_withdraw) {
988 if (!parse_announce_withdraw(tok, *con, style_withdraw)) return false;
989 }
990 else {
991 tok.token_error("path/announce/withdraw", have);
992 return false;
993 }
994 }
995 if (!tsa(tok, token_semi)) return false;
996 return true;
997 }
998
999
1000 ////////////////////////////////////////////////
1001 // parse a config file
1002 //
1003 bool load_conf(CONFIG &dc, char *fn) {
1004 int count = 0;
1005 TOKEN tok(fn, &dc.config_files);
1006 while (true) {
1007 char *have = tok.next();
1008 if (!have) break;
1009 if (have == token_file) {
1010 if (!parse_routeconfig(tok, dc)) return false;
1011 count++;
1012 }
1013 else {
1014 tok.token_error("file", have);
1015 return false;
1016 }
1017 }
1018 tok.token_error("load_conf() found %d syslog files in %s", count, fn);
1019 return (!dc.routeconfigs.empty());
1020 }
1021
1022
1023 ////////////////////////////////////////////////
1024 //
1025 void routing_hourly_update() {
1026 route_base.update_history();
1027 }
1028
1029
1030 ////////////////////////////////////////////////
1031 // init the tokens
1032 //
1033 void token_init() {
1034 token_announce = register_string("announce");
1035 token_file = register_string("file");
1036 token_include = register_string("include");
1037 token_index_ip = register_string("index_ip");
1038 token_index_length = register_string("index_length");
1039 token_index_path = register_string("index_path");
1040 token_index_value = register_string("index_value");
1041 token_ip = register_string("ip");
1042 token_lbrace = register_string("{");
1043 token_path = register_string("path");
1044 token_rbrace = register_string("}");
1045 token_reset = register_string("reset");
1046 token_semi = register_string(";");
1047 token_slash = register_string("/");
1048 token_withdraw = register_string("withdraw");
1049 }