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