Skip to content

Commit 134542a

Browse files
committed
Initial commit of Dynamic IP distribution list for PA firewalls
country list in all.csv cron.entry for example cron entry convert.php for converting RIR databases into country and ASN files feed.php used as the url in the firewall for the feed
1 parent f0982b8 commit 134542a

File tree

9 files changed

+630
-0
lines changed

9 files changed

+630
-0
lines changed

README

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
This is a dynamic IP list generator.
2+
Depending on the arguments you get the IP4/IP6 addresses listed for countries or ASN numbers
3+
4+
Usage: Valid arguments are: asn, country. Seperate multiple values with Semicolon.
5+
Do note that platforms limits might be easily exceeded with this.
6+
7+
ASN
8+
feed.php?asn=1136;33915
9+
Country
10+
feed.php?country=NL;DE
11+
Both
12+
feed.php?country=NL;DE&asn=1136;33915
13+
14+
You can peruse the raw input data https://iserv.nl/files/edl/in/ directory and see what came https://iserv.nl/files/edl/out/, although the feed script is probably easier to integrate.
15+
This script came about after missing IPv6 GEO location functionality in Palo Alto (=<10.1.11) which is ... weird.
16+
It is also way easier to setup a ASN blocklist for questionable hosting such as "Limenet" https://bgp.tools/as/394711
17+

all.csv

+250
Large diffs are not rendered by default.

convert.php

+309
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
<?php
2+
3+
// print_r($_SERVER);
4+
// Exit when not on shell
5+
if(isset($_SERVER['REMOTE_ADDR'])) {
6+
echo "This should be run from the CLI\n";
7+
exit(0);
8+
}
9+
$regs = array("ripencc", "apnic", "arin", "afrinic", "lacnic");
10+
$indir = "in";
11+
$outdir = "out";
12+
13+
echo "Time: ". date("Y-m-d H:i:s") ."\n";
14+
15+
$dbs = array();
16+
$dbs['ripe']['serial'] = "https://ftp.ripe.net/ripe/dbase/RIPE.CURRENTSERIAL";
17+
$dbs['ripe']['db'] = "https://ftp.ripe.net/ripe/dbase/ripe.db.gz";
18+
$dbs['apnic']['serial'] = "https://ftp.apnic.net/apnic/whois/APNIC.CURRENTSERIAL";
19+
$dbs['apnic']['db'] = "https://ftp.apnic.net/apnic/whois/apnic.db.route.gz";
20+
$dbs['apnic6']['serial'] = "https://ftp.apnic.net/apnic/whois/APNIC.CURRENTSERIAL";
21+
$dbs['apnic6']['db'] = "https://ftp.apnic.net/apnic/whois/apnic.db.route6.gz";
22+
$dbs['lacnic']['serial'] = "https://ftp.lacnic.net/lacnic/irr/LACNIC.CURRENTSERIAL";
23+
$dbs['lacnic']['db'] = "https://ftp.lacnic.net/lacnic/irr/lacnic.db.gz";
24+
$dbs['arin']['serial'] = "https://ftp.arin.net/pub/rr/ARIN.CURRENTSERIAL";
25+
$dbs['arin']['db'] = "https://ftp.arin.net/pub/rr/arin.db.gz";
26+
$dbs['afrinic']['serial'] = "https://ftp.afrinic.net/dbase/AFRINIC.CURRENTSERIAL";
27+
$dbs['afrinic']['db'] = "https://ftp.afrinic.net/dbase/afrinic.db.gz";
28+
29+
$cdbs['ripe']['hash'] = "https://ftp.ripe.net/ripe/stats/delegated-ripencc-extended-latest.md5";
30+
$cdbs['ripe']['db'] = "https://ftp.ripe.net/ripe/stats/delegated-ripencc-extended-latest";
31+
$cdbs['apnic']['hash'] = "https://ftp.apnic.net/stats/apnic/delegated-apnic-extended-latest.md5";
32+
$cdbs['apnic']['db'] = "https://ftp.apnic.net/stats/apnic/delegated-apnic-extended-latest";
33+
$cdbs['lacnic']['hash'] = "https://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-extended-latest.md5";
34+
$cdbs['lacnic']['db'] = "https://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-extended-latest";
35+
$cdbs['arin']['hash'] = "https://ftp.arin.net/pub/stats/arin/delegated-arin-extended-latest.md5";
36+
$cdbs['arin']['db'] = "https://ftp.arin.net/pub/stats/arin/delegated-arin-extended-latest";
37+
$cdbs['afrinic']['hash'] = "https://ftp.afrinic.net/stats/afrinic/delegated-afrinic-extended-latest.md5";
38+
$cdbs['afrinic']['db'] = "https://ftp.afrinic.net/stats/afrinic/delegated-afrinic-extended-latest";
39+
40+
// Download current DB
41+
foreach($dbs as $rir => $db) {
42+
echo "Check serial for RIR {$rir}\n";
43+
$onlineserial = "";
44+
$localserial = "";
45+
46+
$onlineserial = file_get_contents($db['serial']);
47+
$dbfile = basename($db['db']);
48+
if(is_readable("{$indir}/{$dbfile}.serial"))
49+
$localserial = file_get_contents("{$indir}/{$dbfile}.serial");
50+
51+
if((floatval($onlineserial) > floatval($localserial)) || (empty($localserial))) {
52+
echo "Download file {$db['db']}\n";
53+
if (file_put_contents("{$indir}/{$dbfile}", file_get_contents($db['db']))) {
54+
echo "File {$dbfile} downloaded successfully\n";
55+
file_put_contents("{$indir}/{$dbfile}.serial", $onlineserial);
56+
} else {
57+
echo "Failed to download {$dbfile}\n";
58+
}
59+
}
60+
}
61+
62+
// Download current DB
63+
foreach($cdbs as $rir => $db) {
64+
echo "Check hash for RIR {$rir}\n";
65+
$onlineserial = "";
66+
$localserial = "";
67+
68+
$onlineserial = file_get_contents($db['hash']);
69+
$dbfile = basename($db['db']);
70+
if(is_readable("{$indir}/{$dbfile}.hash"))
71+
$localserial = file_get_contents("{$indir}/{$dbfile}.hash");
72+
73+
if((floatval($onlineserial) != floatval($localserial)) || (empty($localserial))) {
74+
echo "Download file {$db['db']}\n";
75+
if (file_put_contents("{$indir}/{$dbfile}", file_get_contents($db['db']))) {
76+
echo "File {$dbfile} downloaded successfully\n";
77+
file_put_contents("{$indir}/{$dbfile}.hash", $onlineserial);
78+
} else {
79+
echo "Failed to download {$dbfile}\n";
80+
}
81+
}
82+
}
83+
84+
$rirs = array();
85+
foreach($regs as $reg){
86+
if(is_readable("{$indir}/delegated-{$reg}-extended-latest"))
87+
$rirs[$reg]['file'] = "{$indir}/delegated-{$reg}-extended-latest";
88+
}
89+
90+
$iso3166 = file("all.csv");
91+
array_shift($iso3166);
92+
93+
// keep dividing number of hosts by until we have 1
94+
function calc_snbits($nr) {
95+
$sn = 0;
96+
while($nr > 1) {
97+
$nr = $nr /2;
98+
$sn++;
99+
}
100+
return $sn;
101+
}
102+
103+
104+
/**
105+
* Validates the format of a CIDR notation string
106+
*
107+
* @param string $cidr
108+
* @return bool
109+
*/
110+
function validateCidr($cidr)
111+
{
112+
$parts = explode('/', $cidr);
113+
if(count($parts) != 2) {
114+
return false;
115+
}
116+
117+
$ip = $parts[0];
118+
$netmask = $parts[1];
119+
120+
if (!preg_match("/^\d+$/", $netmask)){
121+
return false;
122+
}
123+
124+
$netmask = intval($parts[1]);
125+
126+
if($netmask < 0) {
127+
return false;
128+
}
129+
130+
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
131+
return $netmask <= 32;
132+
}
133+
134+
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
135+
return $netmask <= 128;
136+
}
137+
138+
return false;
139+
}
140+
141+
142+
$cip = array();
143+
$guid = array();
144+
$asn = array();
145+
$asroutes = array();
146+
147+
echo "Parse RIR allocations\n";
148+
foreach($rirs as $rir => $info) {
149+
if (is_readable($info['file'])) {
150+
echo "Parsing file {$info['file']}\n";
151+
$arr = array();
152+
$arr = file($info['file']);
153+
foreach($arr as $entry) {
154+
$el = preg_split("/\|/", $entry);
155+
if(!isset($el[2]))
156+
continue;
157+
if(!isset($el[7]))
158+
continue;
159+
160+
$el[3] = trim($el[3]);
161+
$el[7] = trim($el[7]);
162+
switch($el[2]) {
163+
case "asn":
164+
// 7 is guid
165+
// 3 is asn
166+
// 2 is country
167+
$asn[$el[3]] = $el[7];
168+
$asguid[$el[7]] = $el[3];
169+
// echo "Found AS {$el[3]} RIR {$rir} guid {$el[7]}\n";
170+
// print_r($el);
171+
break;
172+
case "ipv6":
173+
case "ipv4":
174+
// Only output the useful info
175+
if(preg_match("/(assigned|allocated)/", $el[6])) {
176+
// calculate subnet mask
177+
$bits = 32 - calc_snbits($el[4]);
178+
if($el[2] == "ipv6")
179+
$bits = $el[4];
180+
181+
182+
$cidr = "{$el[3]}/{$bits}";
183+
if(!validateCidr($cidr)) {
184+
echo "Address '{$el[3]}/{$bits}' is not valid in {$info['file']}, skipping\n";
185+
continue;
186+
} else {
187+
$cip[$el[1]][] = $cidr;
188+
// echo "{$el[3]}/{$bits} \n";
189+
// also save by guid for ASN lookup
190+
$guid[$el[7]][] = $cidr;
191+
}
192+
193+
}
194+
// print_r($asn);
195+
// print_r($ip6);
196+
// print_r($el);
197+
// exit;
198+
break;
199+
default:
200+
// noop
201+
break;
202+
}
203+
}
204+
}
205+
206+
echo "Parse RIR {$rir} GUID ASN routes\n";
207+
foreach($asn as $as => $id) {
208+
if(isset($guid[$id])) {
209+
// $arr = $guid[$id];
210+
// echo "Found AS {$as} on {$rir} with {$id}\n";
211+
if(!isset($asroutes[$as]))
212+
$asroutes[$as] = $guid[$id];
213+
else
214+
$asroutes[$as] = array_merge($asroutes[$as], $guid[$id]);
215+
// file_put_contents("{$outdir}/asn/AS{$as}.txt", implode("\n", $arr));
216+
}
217+
}
218+
// print_r($asroutes);
219+
// exit();
220+
$guid = array();
221+
$asn = array();
222+
$asguid = array();
223+
224+
225+
}
226+
227+
228+
$regions = array();
229+
foreach($iso3166 as $country) {
230+
$el = str_getcsv($country);
231+
if($el[6] == "")
232+
continue;
233+
$region[$el[6]][] = $el[1];
234+
235+
}
236+
237+
// print_r($region);
238+
// exit(0);
239+
240+
// print_r($res);
241+
echo "Write Aggregate country lists from all RIRs\n";
242+
foreach($cip as $country => $arr) {
243+
file_put_contents("{$outdir}/country/{$country}.txt", implode("\n", $arr));
244+
245+
}
246+
247+
248+
249+
echo "Parse RIR DB for ASN routes\n";
250+
foreach($dbs as $rir => $db) {
251+
$i = 0;
252+
$k = 0;
253+
$db = "{$indir}/". basename($db['db']);
254+
if (is_readable($db)) {
255+
echo "Parsing $db \n";
256+
// $arr = file('compress.zlib://'.$db);
257+
$arr = array();
258+
$ret = null;
259+
$cmd = "zgrep -E \"(^route|^origin)\" $db";
260+
exec($cmd, $arr, $ret);
261+
// print_r($arr);
262+
263+
foreach($arr as $line) {
264+
unset($matches);
265+
if(preg_match("/^(route|route6):[ ]+([0-9a-f\:\.\/]+)/", $line, $matches))
266+
$route = trim($matches[2]);
267+
268+
if(preg_match("/^origin:[ ]+AS([0-9]+)/", $line, $matches))
269+
$asnum = round($matches[1]);
270+
271+
if((isset($route)) && (isset($asnum))) {
272+
$asroutes[$asnum][] = trim($route);
273+
// echo "Add route {$route} for AS {$asnum}\n";
274+
unset($route);
275+
unset($asnum);
276+
}
277+
278+
$i++;
279+
if($i > 49999) {
280+
$k++;;
281+
echo ($k*5) ."0k.";
282+
$i = 0;
283+
}
284+
}
285+
echo "\n";
286+
287+
}
288+
}
289+
290+
// exit(0);
291+
292+
echo "Write ". count($asroutes) ." ASN files\n";
293+
$i = 0;
294+
$k = 0;
295+
foreach($asroutes as $as => $routes) {
296+
// echo "Write file for {$as} ". count($routes) . "entries\n";
297+
if(!empty($routes)) {
298+
file_put_contents("{$outdir}/asn/AS{$as}.txt", implode("\n", array_unique($routes)));
299+
}
300+
$i++;
301+
if($i > 9999) {
302+
$k++;;
303+
echo "{$k}0k.";
304+
$i = 0;
305+
}
306+
}
307+
echo "\n";
308+
309+
echo "Time: ". date("Y-m-d H:i:s") ."\n";

cron.entry

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
13 13 * * * cd somepath;php convert.php > update.log

feed.php

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
4+
5+
$outdir = "out";
6+
7+
if((!isset($_GET['asn'])) && (!isset($_GET['country']))) {
8+
header("Content-Type: text/plain");
9+
echo file_get_contents("README");
10+
exit(0);
11+
12+
}
13+
14+
function climit($cl) {
15+
return substr($cl, 0, 2);
16+
}
17+
18+
function aslimit($as) {
19+
return substr($as, 0, 6);
20+
}
21+
22+
// Process Country value
23+
if(isset($_GET['country'])) {
24+
$val = strtoupper(strip_tags($_GET['country']));
25+
$items = preg_split("/;/", $val);
26+
$items = array_map('trim', $items);
27+
$items = array_map('climit', $items);
28+
// print_r($items);
29+
30+
foreach($items as $country) {
31+
if(is_readable("{$outdir}/country/{$country}.txt")) {
32+
echo file_get_contents("{$outdir}/country/{$country}.txt");
33+
}
34+
}
35+
36+
}
37+
38+
// Process Country value
39+
if(isset($_GET['asn'])) {
40+
$val = strtoupper(strip_tags($_GET['asn']));
41+
$items = preg_split("/;/", $val);
42+
$items = array_filter($items, 'is_numeric');
43+
$items = array_map('aslimit', $items);
44+
//print_r($items);
45+
46+
foreach($items as $as) {
47+
if(is_readable("{$outdir}/asn/AS{$as}.txt")) {
48+
echo file_get_contents("{$outdir}/asn/AS{$as}.txt");
49+
}
50+
}
51+
52+
}
53+

in/input_files_here

Whitespace-only changes.

out/asn/asn_output

Whitespace-only changes.

out/country/country_output

Whitespace-only changes.

out/output_files_here

Whitespace-only changes.

0 commit comments

Comments
 (0)