forked from Skinza/ExaRTBH
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ExaRTBH.php
executable file
·141 lines (122 loc) · 4.42 KB
/
ExaRTBH.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/php
<?php
/********
* Author: Bas van Elburg ([email protected]
*/
// config
$config = array(
'running' => true,
'debug' => false, // warning, this will produce debug data to stdout!
'blackholeipfile' => '/home/bas/ExaRTBH/blackholeips',
'filecheckinterval' => 5,
'blackhole_bgp_community' => "65001:666",
'blackhole_nexthop' => '192.6.6.6'
);
// "internal" list of active blackhole routes
$blackholes = array();
logstr("Booting....");
while($config['running']) {
// does the file exist? no? write memory to file, else parse
if(!file_exists($config['blackholeipfile'])) {
// file does not exist, create one and write known blackhole entries to file!
logstr2("WARNING","blackhole ip file not found, (re)creating file [" . $config['blackholeipfile'] . "]");
generateBlackholeFile();
} else {
// load entries from blackhole file
$newBlackholeEntries = loadBlackholesFromFile($config['blackholeipfile']);
// loop trough new blackhole entries to see what action is needed
foreach($newBlackholeEntries as $newBlackhole) {
// loop trough new set of prefixes
$prefixFound = false;
foreach($blackholes as $key => $blackhole) {
if($blackhole == $newBlackhole) {
// blackhole is allready active, no action required
unset($blackholes[$key]); // remove from current list, will be replaced when new list is processed
$prefixFound = true;
break;
}
}
if(!$prefixFound) {
echo $newBlackhole->announceString() . "\n";
}
}
//process prefixes in current list to withdrawel these routes
foreach($blackholes as $blackhole) {
echo $blackhole->withdrawString()."\n";
}
//processing complete, replace old list with the new one
$blackholes = $newBlackholeEntries;
}
// generate hash of file
$config['blackholiphash'] = md5_file($config['blackholeipfile']);
logstr("generated hash: " . $config['blackholiphash']);
// wait for change of file
logstr("waiting...");
while(@md5_file($config['blackholeipfile']) == $config['blackholiphash']) {
sleep($config['filecheckinterval']);
}
logstr("file changed, reloading!");
}
/* support fuctions */
function logstr($str_msg) {
logstr2("INFO",$str_msg);
}
function logstr2($loglevel,$str_msg) {
global $config;
if($config['debug']) {
echo "[".date("Y-m-d H:i:s")."] [".$loglevel."] ".$str_msg . "\n";
}
}
// load blackholes from file and return them als an array of BlackHoleEntries
function loadBlackholesFromFile($file) {
global $config;
$newBlackholes = array();
// tbd: yes i know this should have error / input checking
foreach(file($file) as $row) {
$row = trim($row); // trim the line
// if it is not a comment
if(substr($row,0,1) != "#") {
// parse the row, it is 1 of the following formats:
// network/prefixlen (127.0.0.1/32) (only /32 supported right now)
// more formats will be supported in the future
if(preg_match("/(.*)\/(32)$/",$row)) {
$newBlackholes[] = new BlackholeEntry(trim($row),$config['blackhole_bgp_community'],$config['blackhole_nexthop']);
} else {
logstr2("WARNING", "Ignoring entry (unexpected format) [".$row."]");
}
}
}
return $newBlackholes;
}
// generateBlackhole file content en write to file
function generateBlackholeFile()
{
global $blackholes,$config;
$string2write = "";
foreach($blackholes as $bhEntry) {
$string2write .= $bhEntry->toBlackholeFileString();
}
file_put_contents($config['blackholeipfile'],$string2write);
logstr("blackholes written to new file");
}
/* data classes */
class BlackholeEntry {
public $prefix;
public $bgp_community;
public $nexthop;
public $localpref = 4000;
function __construct($_prefix,$_bgp_community,$_nexthop) {
$this->prefix = $_prefix;
$this->bgp_community = $_bgp_community;
$this->nexthop = $_nexthop;
}
// returns the string to add to the blackhole file (including trailing \n)
function toBlackholeFileString() {
return $this->prefix . "\n";
}
// tbd add local pref to data class
// tbd better checks
function announceString() { return "announce route $this->prefix next-hop $this->nexthop local-preference $this->localpref community [$this->bgp_community]"; }
function withdrawString() { return "withdraw route $this->prefix next-hop $this->nexthop local-preference $this->localpref community [$this->bgp_community]"; }
}
?>