├── .coveragerc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── TODO.md ├── appconfig.cfg.dist ├── data ├── rfc-managed.txt ├── ripe-managed-space.txt └── schema.sql ├── db ├── README ├── bootstrap ├── create_bgp ├── create_irr_as_sets ├── create_irr_routes ├── create_managed ├── create_serials ├── create_source ├── fetch ├── refresh ├── refresh_ripe_managed └── sources.py ├── docs └── irrexplorer-logo.png ├── exabgp.conf ├── fetch_ripe_managed.py ├── irrexplorer ├── __init__.py ├── bgpupdate.py ├── irrparser.py ├── irrtest.data ├── irrupdate.py ├── nrtm.py ├── report.py ├── sqldb.py ├── utils.py └── www.py ├── irrexplorer_config.yml.dist ├── irrexwww ├── query ├── requirements.txt ├── setup.cfg ├── setup.py ├── static ├── img │ ├── false.png │ ├── loading.gif │ └── true.png ├── js │ └── table.js └── robots.txt ├── templates ├── index.html └── search.html ├── tests ├── REGRESSION.CURRENTSERIAL ├── irrtest.data ├── nrtm_server.py ├── nrtm_test.yml ├── test_nrtmclient.py ├── test_regression.py └── test_utils.py └── worker /.coveragerc: -------------------------------------------------------------------------------- 1 | # .coveragerc to control coverage.py 2 | [run] 3 | branch = True 4 | source = . 5 | 6 | [report] 7 | omit = 8 | setup.py 9 | irrexplorer/__init__.py 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .eggs/ 3 | irrexplorer.egg-info/ 4 | .coverage 5 | .venv/ 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - '2.7' 5 | 6 | install: 7 | - pip install coveralls 8 | - pip install -r requirements.txt 9 | - sudo cp tests/nrtm_test.yml irrexplorer_config.yml 10 | - python setup.py install 11 | # - sudo ip addr add 127.0.0.2/8 dev lo 12 | # - sudo env exabgp.tcp.bind="127.0.0.2" exabgp.tcp.port=179 exabgp.daemon.daemonize=true exabgp tests/bgp_injector.conf 13 | - python tests/nrtm_server.py & 14 | 15 | script: 16 | - python setup.py nosetests 17 | 18 | after_success: 19 | - coveralls 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Job Snijders, Peter van Dijk 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | IRR Explorer 2 | ============ 3 | 4 | [![Build Status](https://travis-ci.org/job/irrexplorer.svg?branch=master)](https://travis-ci.org/job/irrexplorer) 5 | [![Coverage Status](https://coveralls.io/repos/job/irrexplorer/badge.svg?branch=master)](https://coveralls.io/r/job/irrexplorer?branch=master) 6 | 7 | Note: IRR Explorer v2 8 | ===================== 9 | 10 | The NLNOG Foundation supported by RIPE NCC commissioned a complete rewrite of IRR Explorer: https://github.com/dashcare/irrexplorer 11 | 12 | This v1 repository has been archived. 13 | 14 | Explore IRR & BGP data in near real time 15 | ---------------------------------------- 16 | 17 |

18 | 19 |

20 | 21 | Background 22 | ---------- 23 | 24 | IRR Explorer was written to make it easier to debug data in the IRR 25 | system. An example is to verify whether you would be impacted by deployment 26 | if filtering strategies such as "IRR Lockdown". 27 | 28 | video: https://ripe70.ripe.net/archives/video/21/ 29 | pdf: https://ripe70.ripe.net/presentations/52-RIPE70_jobsnijders_irrlockdown.pdf 30 | 31 | 32 | Setup 33 | ----- 34 | 35 | Copy irrexplorer_config.yml.dist to irrexplorer_config.yml and edit it to your 36 | liking. 37 | 38 | Note that mirroring of many IRR databases is not possible without getting 39 | access granted. 40 | 41 | ``` 42 | ( cd db ; ./bootstrap ) 43 | ``` 44 | This will download IRR database snapshots and setup the database. It will take some time. 45 | 46 | Continously updating BGP and IRR sources: 47 | ``` 48 | ./worker 49 | ``` 50 | 51 | Finally start the web interface 52 | ``` 53 | ./irexwww 54 | ``` 55 | 56 | There is query tool as well: 57 | ``` 58 | ./query 1.2.3.0/24 59 | ``` 60 | It is rather basic and need some work though. 61 | 62 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | IRR Explorer 2 | ============ 3 | 4 | # TODO 5 | 6 | * exabgp 7 | * launch 8 | * feed it config 9 | * catch STDOUT from the 'run' process 10 | 11 | * Investigate issue with records going missing 12 | * Logging added, so debugging can actually be done 13 | 14 | * Database 15 | * Upgrade to PostgreSQL 9.5. 16 | * Has better query planner for gin indexes 17 | * Supports ON CONFLICT (UPSERT) which will save us trouble on mirror updates 18 | 19 | 20 | -------------------------------------------------------------------------------- /appconfig.cfg.dist: -------------------------------------------------------------------------------- 1 | # set this key to something random generated, flask need this 2 | # SECRET_KEY='ssshhh... I'm hunting rabbits' 3 | -------------------------------------------------------------------------------- /data/rfc-managed.txt: -------------------------------------------------------------------------------- 1 | 0.0.0.0/8 RFC1122 2 | 10.0.0.0/8 RFC1918 3 | 100.64.0.0/10 RFC6598 4 | 127.0.0.0/8 LOOPBACK 5 | 172.16.0.0/12 RFC1918 6 | 192.0.0.0/24 RFC5736 7 | 192.168.0.0/16 RFC1918 8 | 169.254.0.0/16 RFC3927 9 | 192.0.2.0/24 RFC5737 10 | 198.18.0.0/15 RFC2544 11 | 198.51.100.0/24 RFC5737 12 | 203.0.113.0/24 RFC5737 13 | 240.0.0.0/4 CLASS-E 14 | ::ffff:0:0/96 IPv4-mapped 15 | ::/96 IPv4-compatible 16 | fc00::/7 IPv6-ULA 17 | -------------------------------------------------------------------------------- /data/ripe-managed-space.txt: -------------------------------------------------------------------------------- 1 | 2.0.0.0/8 2 | 5.0.0.0/8 3 | 24.132.0.0/14 4 | 25.0.0.0/8 5 | 31.0.0.0/8 6 | 37.0.0.0/8 7 | 45.128.0.0/11 8 | 45.8.0.0/13 9 | 45.80.0.0/12 10 | 46.0.0.0/8 11 | 51.0.0.0/8 12 | 53.0.0.0/8 13 | 57.0.0.0/8 14 | 62.0.0.0/8 15 | 77.0.0.0/8 16 | 78.0.0.0/7 17 | 80.0.0.0/4 18 | 109.0.0.0/8 19 | 128.0.0.0/16 20 | 128.124.0.0/16 21 | 128.127.0.0/16 22 | 128.130.0.0/15 23 | 128.139.0.0/16 24 | 128.140.0.0/15 25 | 128.142.0.0/16 26 | 128.16.0.0/16 27 | 128.176.0.0/16 28 | 128.178.0.0/15 29 | 128.199.0.0/16 30 | 128.204.0.0/16 31 | 128.214.0.0/16 32 | 128.232.0.0/16 33 | 128.234.0.0/16 34 | 128.240.0.0/16 35 | 128.243.0.0/16 36 | 128.246.0.0/16 37 | 128.39.0.0/16 38 | 128.40.0.0/15 39 | 128.45.0.0/16 40 | 128.65.0.0/16 41 | 128.66.0.0/15 42 | 128.68.0.0/14 43 | 128.7.0.0/16 44 | 128.72.0.0/13 45 | 128.86.0.0/15 46 | 128.93.0.0/16 47 | 128.98.0.0/16 48 | 129.102.0.0/15 49 | 129.104.0.0/16 50 | 129.11.0.0/16 51 | 129.12.0.0/15 52 | 129.125.0.0/16 53 | 129.129.0.0/16 54 | 129.132.0.0/16 55 | 129.142.0.0/15 56 | 129.16.0.0/16 57 | 129.169.0.0/16 58 | 129.175.0.0/16 59 | 129.177.0.0/16 60 | 129.178.0.0/16 61 | 129.181.0.0/16 62 | 129.182.0.0/15 63 | 129.184.0.0/15 64 | 129.187.0.0/16 65 | 129.194.0.0/15 66 | 129.199.0.0/16 67 | 129.20.0.0/16 68 | 129.206.0.0/16 69 | 129.208.0.0/16 70 | 129.214.0.0/15 71 | 129.217.0.0/16 72 | 129.233.0.0/16 73 | 129.234.0.0/16 74 | 129.240.0.0/15 75 | 129.242.0.0/16 76 | 129.247.0.0/16 77 | 129.26.0.0/15 78 | 129.31.0.0/16 79 | 129.67.0.0/16 80 | 129.69.0.0/16 81 | 129.70.0.0/16 82 | 129.73.0.0/16 83 | 129.88.0.0/16 84 | 130.0.0.0/16 85 | 130.100.0.0/16 86 | 130.104.0.0/16 87 | 130.112.0.0/16 88 | 130.115.0.0/16 89 | 130.120.0.0/16 90 | 130.125.0.0/16 91 | 130.133.0.0/16 92 | 130.136.0.0/16 93 | 130.138.0.0/15 94 | 130.140.0.0/14 95 | 130.144.0.0/14 96 | 130.148.0.0/15 97 | 130.159.0.0/16 98 | 130.161.0.0/16 99 | 130.180.0.0/16 100 | 130.183.0.0/16 101 | 130.185.0.0/16 102 | 130.186.0.0/16 103 | 130.188.0.0/16 104 | 130.190.0.0/16 105 | 130.192.0.0/15 106 | 130.198.0.0/16 107 | 130.204.0.0/16 108 | 130.206.0.0/16 109 | 130.208.0.0/15 110 | 130.223.0.0/16 111 | 130.225.0.0/16 112 | 130.226.0.0/15 113 | 130.228.0.0/14 114 | 130.232.0.0/13 115 | 130.24.0.0/15 116 | 130.240.0.0/14 117 | 130.244.0.0/16 118 | 130.246.0.0/16 119 | 130.251.0.0/16 120 | 130.255.0.0/16 121 | 130.26.0.0/16 122 | 130.28.0.0/16 123 | 130.32.0.0/16 124 | 130.37.0.0/16 125 | 130.43.0.0/16 126 | 130.59.0.0/16 127 | 130.60.0.0/16 128 | 130.66.0.0/15 129 | 130.73.0.0/16 130 | 130.75.0.0/16 131 | 130.78.0.0/15 132 | 130.82.0.0/15 133 | 130.84.0.0/16 134 | 130.88.0.0/15 135 | 130.92.0.0/16 136 | 130.98.0.0/16 137 | 131.1.0.0/16 138 | 131.102.0.0/16 139 | 131.111.0.0/16 140 | 131.114.0.0/15 141 | 131.116.0.0/15 142 | 131.130.0.0/16 143 | 131.152.0.0/16 144 | 131.154.0.0/15 145 | 131.159.0.0/16 146 | 131.160.0.0/16 147 | 131.164.0.0/15 148 | 131.166.0.0/16 149 | 131.169.0.0/16 150 | 131.173.0.0/16 151 | 131.174.0.0/15 152 | 131.176.0.0/15 153 | 131.180.0.0/16 154 | 131.188.0.0/16 155 | 131.205.0.0/16 156 | 131.207.0.0/16 157 | 131.211.0.0/16 158 | 131.220.0.0/16 159 | 131.224.0.0/16 160 | 131.227.0.0/16 161 | 131.228.0.0/16 162 | 131.231.0.0/16 163 | 131.234.0.0/16 164 | 131.237.0.0/16 165 | 131.246.0.0/16 166 | 131.251.0.0/16 167 | 131.254.0.0/16 168 | 131.97.0.0/16 169 | 131.99.0.0/16 170 | 132.146.0.0/16 171 | 132.149.0.0/16 172 | 132.150.0.0/16 173 | 132.153.0.0/16 174 | 132.155.0.0/16 175 | 132.165.0.0/16 176 | 132.166.0.0/15 177 | 132.168.0.0/15 178 | 132.171.0.0/16 179 | 132.176.0.0/16 180 | 132.180.0.0/16 181 | 132.185.0.0/16 182 | 132.186.0.0/15 183 | 132.195.0.0/16 184 | 132.196.0.0/16 185 | 132.199.0.0/16 186 | 132.227.0.0/16 187 | 132.229.0.0/16 188 | 132.230.0.0/15 189 | 132.232.0.0/16 190 | 132.244.0.0/16 191 | 132.252.0.0/16 192 | 132.64.0.0/13 193 | 132.72.0.0/14 194 | 132.76.0.0/15 195 | 132.78.0.0/16 196 | 134.0.0.0/14 197 | 134.104.0.0/14 198 | 134.108.0.0/15 199 | 134.110.0.0/16 200 | 134.119.0.0/16 201 | 134.130.0.0/16 202 | 134.138.0.0/16 203 | 134.142.0.0/15 204 | 134.145.0.0/16 205 | 134.146.0.0/15 206 | 134.151.0.0/16 207 | 134.155.0.0/16 208 | 134.157.0.0/16 209 | 134.158.0.0/16 210 | 134.169.0.0/16 211 | 134.17.0.0/16 212 | 134.171.0.0/16 213 | 134.176.0.0/16 214 | 134.183.0.0/16 215 | 134.184.0.0/16 216 | 134.188.0.0/16 217 | 134.19.0.0/16 218 | 134.191.0.0/16 219 | 134.203.0.0/16 220 | 134.206.0.0/16 221 | 134.21.0.0/16 222 | 134.212.0.0/15 223 | 134.214.0.0/16 224 | 134.219.0.0/16 225 | 134.220.0.0/15 226 | 134.222.0.0/16 227 | 134.225.0.0/16 228 | 134.226.0.0/15 229 | 134.239.0.0/16 230 | 134.245.0.0/16 231 | 134.246.0.0/15 232 | 134.249.0.0/16 233 | 134.25.0.0/16 234 | 134.255.0.0/16 235 | 134.27.0.0/16 236 | 134.28.0.0/16 237 | 134.30.0.0/16 238 | 134.34.0.0/16 239 | 134.36.0.0/15 240 | 134.47.0.0/16 241 | 134.54.0.0/16 242 | 134.58.0.0/15 243 | 134.60.0.0/15 244 | 134.76.0.0/16 245 | 134.81.0.0/16 246 | 134.83.0.0/16 247 | 134.90.0.0/15 248 | 134.92.0.0/14 249 | 134.96.0.0/13 250 | 135.196.0.0/16 251 | 136.148.0.0/16 252 | 136.155.0.0/16 253 | 136.156.0.0/15 254 | 136.158.0.0/16 255 | 136.163.0.0/16 256 | 136.164.0.0/16 257 | 136.169.0.0/16 258 | 136.170.0.0/16 259 | 136.172.0.0/15 260 | 136.199.0.0/16 261 | 136.201.0.0/16 262 | 136.206.0.0/16 263 | 136.225.0.0/16 264 | 136.230.0.0/15 265 | 136.243.0.0/16 266 | 137.101.0.0/16 267 | 137.105.0.0/16 268 | 137.108.0.0/16 269 | 137.120.0.0/15 270 | 137.129.0.0/16 271 | 137.133.0.0/16 272 | 137.138.0.0/16 273 | 137.156.0.0/16 274 | 137.163.0.0/16 275 | 137.17.0.0/16 276 | 137.174.0.0/16 277 | 137.191.0.0/16 278 | 137.193.0.0/16 279 | 137.194.0.0/15 280 | 137.204.0.0/15 281 | 137.208.0.0/16 282 | 137.213.0.0/16 283 | 137.217.0.0/16 284 | 137.218.0.0/16 285 | 137.221.0.0/16 286 | 137.222.0.0/15 287 | 137.224.0.0/16 288 | 137.226.0.0/16 289 | 137.248.0.0/16 290 | 137.250.0.0/15 291 | 137.253.0.0/16 292 | 137.33.0.0/16 293 | 137.34.0.0/16 294 | 137.43.0.0/16 295 | 137.44.0.0/16 296 | 137.47.0.0/16 297 | 137.50.0.0/16 298 | 137.55.0.0/16 299 | 137.56.0.0/16 300 | 137.58.0.0/16 301 | 137.60.0.0/15 302 | 137.62.0.0/16 303 | 137.73.0.0/16 304 | 137.93.0.0/16 305 | 137.96.0.0/16 306 | 138.100.0.0/16 307 | 138.102.0.0/15 308 | 138.104.0.0/16 309 | 138.106.0.0/16 310 | 138.124.0.0/16 311 | 138.131.0.0/16 312 | 138.132.0.0/16 313 | 138.134.0.0/16 314 | 138.14.0.0/16 315 | 138.187.0.0/16 316 | 138.188.0.0/14 317 | 138.195.0.0/16 318 | 138.198.0.0/15 319 | 138.200.0.0/15 320 | 138.203.0.0/16 321 | 138.205.0.0/16 322 | 138.206.0.0/16 323 | 138.21.0.0/16 324 | 138.215.0.0/16 325 | 138.216.0.0/16 326 | 138.22.0.0/16 327 | 138.221.0.0/16 328 | 138.222.0.0/15 329 | 138.224.0.0/14 330 | 138.228.0.0/16 331 | 138.231.0.0/16 332 | 138.232.0.0/15 333 | 138.244.0.0/15 334 | 138.246.0.0/16 335 | 138.248.0.0/14 336 | 138.253.0.0/16 337 | 138.3.0.0/16 338 | 138.37.0.0/16 339 | 138.38.0.0/16 340 | 138.4.0.0/16 341 | 138.40.0.0/15 342 | 138.48.0.0/16 343 | 138.6.0.0/16 344 | 138.62.0.0/15 345 | 138.66.0.0/16 346 | 138.70.0.0/16 347 | 138.81.0.0/16 348 | 138.96.0.0/16 349 | 139.1.0.0/16 350 | 139.10.0.0/15 351 | 139.100.0.0/16 352 | 139.105.0.0/16 353 | 139.106.0.0/15 354 | 139.108.0.0/14 355 | 139.112.0.0/13 356 | 139.12.0.0/14 357 | 139.120.0.0/16 358 | 139.122.0.0/15 359 | 139.124.0.0/16 360 | 139.128.0.0/16 361 | 139.133.0.0/16 362 | 139.141.0.0/16 363 | 139.143.0.0/16 364 | 139.145.0.0/16 365 | 139.149.0.0/16 366 | 139.153.0.0/16 367 | 139.156.0.0/15 368 | 139.158.0.0/16 369 | 139.16.0.0/13 370 | 139.160.0.0/16 371 | 139.162.0.0/16 372 | 139.164.0.0/15 373 | 139.166.0.0/16 374 | 139.174.0.0/16 375 | 139.178.0.0/15 376 | 139.184.0.0/16 377 | 139.191.0.0/16 378 | 139.2.0.0/15 379 | 139.222.0.0/16 380 | 139.24.0.0/15 381 | 139.27.0.0/16 382 | 139.29.0.0/16 383 | 139.30.0.0/16 384 | 139.4.0.0/16 385 | 139.50.0.0/16 386 | 139.54.0.0/16 387 | 139.58.0.0/16 388 | 139.6.0.0/15 389 | 139.63.0.0/16 390 | 139.66.0.0/16 391 | 139.74.0.0/15 392 | 139.79.0.0/16 393 | 139.8.0.0/16 394 | 139.83.0.0/16 395 | 139.89.0.0/16 396 | 139.90.0.0/15 397 | 139.92.0.0/16 398 | 139.96.0.0/15 399 | 139.98.0.0/16 400 | 140.105.0.0/16 401 | 140.150.0.0/15 402 | 140.164.0.0/16 403 | 140.166.0.0/16 404 | 140.181.0.0/16 405 | 140.203.0.0/16 406 | 140.231.0.0/16 407 | 140.77.0.0/16 408 | 140.78.0.0/16 409 | 140.84.0.0/15 410 | 140.86.0.0/16 411 | 140.93.0.0/16 412 | 140.94.0.0/16 413 | 140.97.0.0/16 414 | 141.0.0.0/8 415 | 143.117.0.0/16 416 | 143.118.0.0/16 417 | 143.121.0.0/16 418 | 143.126.0.0/16 419 | 143.129.0.0/16 420 | 143.130.0.0/16 421 | 143.161.0.0/16 422 | 143.163.0.0/16 423 | 143.164.0.0/16 424 | 143.167.0.0/16 425 | 143.169.0.0/16 426 | 143.176.0.0/14 427 | 143.180.0.0/16 428 | 143.196.0.0/16 429 | 143.205.0.0/16 430 | 143.210.0.0/16 431 | 143.217.0.0/16 432 | 143.224.0.0/15 433 | 143.233.0.0/16 434 | 143.234.0.0/16 435 | 143.237.0.0/16 436 | 143.239.0.0/16 437 | 143.245.0.0/16 438 | 143.252.0.0/16 439 | 143.41.0.0/16 440 | 143.47.0.0/16 441 | 143.50.0.0/15 442 | 143.52.0.0/15 443 | 143.65.0.0/16 444 | 143.93.0.0/16 445 | 143.97.0.0/16 446 | 143.99.0.0/16 447 | 144.119.0.0/16 448 | 144.122.0.0/16 449 | 144.124.0.0/16 450 | 144.127.0.0/16 451 | 144.145.0.0/16 452 | 144.164.0.0/15 453 | 144.173.0.0/16 454 | 144.176.0.0/14 455 | 144.180.0.0/15 456 | 144.193.0.0/16 457 | 144.2.0.0/16 458 | 144.20.0.0/15 459 | 144.200.0.0/16 460 | 144.204.0.0/16 461 | 144.206.0.0/16 462 | 144.209.0.0/16 463 | 144.24.0.0/16 464 | 144.248.0.0/16 465 | 144.27.0.0/16 466 | 144.32.0.0/16 467 | 144.4.0.0/16 468 | 144.41.0.0/16 469 | 144.43.0.0/16 470 | 144.44.0.0/16 471 | 144.54.0.0/16 472 | 144.56.0.0/15 473 | 144.63.0.0/16 474 | 144.64.0.0/15 475 | 144.76.0.0/16 476 | 144.82.0.0/16 477 | 144.84.0.0/15 478 | 144.87.0.0/16 479 | 144.95.0.0/16 480 | 144.98.0.0/16 481 | 145.0.0.0/8 482 | 146.0.0.0/16 483 | 146.100.0.0/14 484 | 146.104.0.0/14 485 | 146.108.0.0/15 486 | 146.110.0.0/16 487 | 146.112.0.0/16 488 | 146.119.0.0/16 489 | 146.120.0.0/16 490 | 146.124.0.0/16 491 | 146.133.0.0/16 492 | 146.136.0.0/16 493 | 146.140.0.0/16 494 | 146.158.0.0/15 495 | 146.161.0.0/16 496 | 146.162.0.0/16 497 | 146.169.0.0/16 498 | 146.172.0.0/15 499 | 146.175.0.0/16 500 | 146.176.0.0/15 501 | 146.179.0.0/16 502 | 146.185.0.0/16 503 | 146.188.0.0/16 504 | 146.19.0.0/16 505 | 146.191.0.0/16 506 | 146.192.0.0/15 507 | 146.194.0.0/16 508 | 146.2.0.0/15 509 | 146.21.0.0/16 510 | 146.210.0.0/15 511 | 146.212.0.0/15 512 | 146.216.0.0/16 513 | 146.219.0.0/16 514 | 146.220.0.0/16 515 | 146.224.0.0/16 516 | 146.227.0.0/16 517 | 146.228.0.0/16 518 | 146.234.0.0/16 519 | 146.247.0.0/16 520 | 146.248.0.0/15 521 | 146.251.0.0/16 522 | 146.253.0.0/16 523 | 146.254.0.0/15 524 | 146.4.0.0/16 525 | 146.48.0.0/16 526 | 146.50.0.0/16 527 | 146.52.0.0/16 528 | 146.59.0.0/16 529 | 146.60.0.0/16 530 | 146.66.0.0/15 531 | 146.70.0.0/16 532 | 146.72.0.0/16 533 | 146.75.0.0/16 534 | 146.77.0.0/16 535 | 146.80.0.0/15 536 | 146.87.0.0/16 537 | 146.90.0.0/16 538 | 146.97.0.0/16 539 | 147.100.0.0/16 540 | 147.102.0.0/16 541 | 147.111.0.0/16 542 | 147.112.0.0/16 543 | 147.119.0.0/16 544 | 147.12.0.0/15 545 | 147.122.0.0/15 546 | 147.125.0.0/16 547 | 147.127.0.0/16 548 | 147.14.0.0/16 549 | 147.142.0.0/15 550 | 147.147.0.0/16 551 | 147.148.0.0/14 552 | 147.152.0.0/16 553 | 147.156.0.0/16 554 | 147.161.0.0/16 555 | 147.162.0.0/15 556 | 147.167.0.0/16 557 | 147.171.0.0/16 558 | 147.172.0.0/15 559 | 147.175.0.0/16 560 | 147.180.0.0/15 561 | 147.184.0.0/16 562 | 147.186.0.0/16 563 | 147.188.0.0/15 564 | 147.193.0.0/16 565 | 147.196.0.0/15 566 | 147.201.0.0/16 567 | 147.204.0.0/16 568 | 147.210.0.0/16 569 | 147.213.0.0/16 570 | 147.214.0.0/15 571 | 147.220.0.0/16 572 | 147.228.0.0/14 573 | 147.232.0.0/14 574 | 147.236.0.0/15 575 | 147.243.0.0/16 576 | 147.250.0.0/15 577 | 147.252.0.0/16 578 | 147.27.0.0/16 579 | 147.29.0.0/16 580 | 147.30.0.0/16 581 | 147.32.0.0/15 582 | 147.44.0.0/15 583 | 147.52.0.0/16 584 | 147.54.0.0/16 585 | 147.60.0.0/16 586 | 147.67.0.0/16 587 | 147.68.0.0/16 588 | 147.7.0.0/16 589 | 147.75.0.0/16 590 | 147.77.0.0/16 591 | 147.83.0.0/16 592 | 147.84.0.0/16 593 | 147.86.0.0/15 594 | 147.88.0.0/15 595 | 147.91.0.0/16 596 | 147.93.0.0/16 597 | 147.94.0.0/15 598 | 147.96.0.0/16 599 | 147.98.0.0/15 600 | 148.110.0.0/16 601 | 148.118.0.0/15 602 | 148.120.0.0/14 603 | 148.135.0.0/16 604 | 148.136.0.0/16 605 | 148.138.0.0/16 606 | 148.140.0.0/16 607 | 148.143.0.0/16 608 | 148.148.0.0/16 609 | 148.151.0.0/16 610 | 148.160.0.0/16 611 | 148.169.0.0/16 612 | 148.176.0.0/16 613 | 148.181.0.0/16 614 | 148.185.0.0/16 615 | 148.187.0.0/16 616 | 148.196.0.0/15 617 | 148.198.0.0/16 618 | 148.2.0.0/15 619 | 148.200.0.0/16 620 | 148.251.0.0/16 621 | 148.252.0.0/15 622 | 148.54.0.0/16 623 | 148.56.0.0/16 624 | 148.6.0.0/16 625 | 148.60.0.0/16 626 | 148.79.0.0/16 627 | 148.81.0.0/16 628 | 148.82.0.0/15 629 | 148.88.0.0/16 630 | 149.0.0.0/16 631 | 149.126.0.0/16 632 | 149.132.0.0/15 633 | 149.134.0.0/16 634 | 149.139.0.0/16 635 | 149.140.0.0/16 636 | 149.146.0.0/15 637 | 149.148.0.0/16 638 | 149.153.0.0/16 639 | 149.154.0.0/15 640 | 149.156.0.0/15 641 | 149.170.0.0/16 642 | 149.172.0.0/16 643 | 149.177.0.0/16 644 | 149.178.0.0/15 645 | 149.180.0.0/14 646 | 149.184.0.0/13 647 | 149.192.0.0/14 648 | 149.196.0.0/15 649 | 149.200.0.0/13 650 | 149.208.0.0/12 651 | 149.224.0.0/12 652 | 149.240.0.0/13 653 | 149.249.0.0/16 654 | 149.250.0.0/15 655 | 149.254.0.0/15 656 | 149.27.0.0/16 657 | 149.3.0.0/16 658 | 149.49.0.0/16 659 | 149.59.0.0/16 660 | 149.62.0.0/16 661 | 150.106.0.0/16 662 | 150.128.0.0/16 663 | 150.132.0.0/16 664 | 150.140.0.0/16 665 | 150.145.0.0/16 666 | 150.146.0.0/16 667 | 150.158.0.0/16 668 | 150.175.0.0/16 669 | 150.178.0.0/16 670 | 150.204.0.0/15 671 | 150.213.0.0/16 672 | 150.214.0.0/16 673 | 150.217.0.0/16 674 | 150.227.0.0/16 675 | 150.236.0.0/15 676 | 150.241.0.0/16 677 | 150.244.0.0/16 678 | 150.251.0.0/16 679 | 150.254.0.0/16 680 | 151.0.0.0/8 681 | 152.105.0.0/16 682 | 152.114.0.0/15 683 | 152.134.0.0/16 684 | 152.143.0.0/16 685 | 152.150.0.0/16 686 | 152.152.0.0/16 687 | 152.66.0.0/16 688 | 152.71.0.0/16 689 | 152.73.0.0/16 690 | 152.77.0.0/16 691 | 152.78.0.0/16 692 | 152.81.0.0/16 693 | 152.88.0.0/16 694 | 152.90.0.0/16 695 | 152.93.0.0/16 696 | 152.94.0.0/15 697 | 152.96.0.0/16 698 | 153.1.0.0/16 699 | 153.100.0.0/16 700 | 153.108.0.0/15 701 | 153.110.0.0/16 702 | 153.112.0.0/16 703 | 153.15.0.0/16 704 | 153.17.0.0/16 705 | 153.19.0.0/16 706 | 153.5.0.0/16 707 | 153.88.0.0/16 708 | 153.92.0.0/14 709 | 153.96.0.0/15 710 | 153.98.0.0/16 711 | 154.14.0.0/15 712 | 154.32.0.0/16 713 | 154.8.0.0/16 714 | 155.105.0.0/16 715 | 155.131.0.0/16 716 | 155.132.0.0/15 717 | 155.136.0.0/15 718 | 155.140.0.0/16 719 | 155.145.0.0/16 720 | 155.158.0.0/16 721 | 155.185.0.0/16 722 | 155.192.0.0/16 723 | 155.198.0.0/16 724 | 155.202.0.0/16 725 | 155.204.0.0/16 726 | 155.207.0.0/16 727 | 155.209.0.0/16 728 | 155.210.0.0/16 729 | 155.223.0.0/16 730 | 155.227.0.0/16 731 | 155.228.0.0/16 732 | 155.231.0.0/16 733 | 155.245.0.0/16 734 | 155.249.0.0/16 735 | 155.250.0.0/16 736 | 155.253.0.0/16 737 | 155.4.0.0/16 738 | 155.45.0.0/16 739 | 155.54.0.0/15 740 | 155.56.0.0/16 741 | 155.66.0.0/16 742 | 155.73.0.0/16 743 | 156.10.0.0/16 744 | 156.106.0.0/16 745 | 156.114.0.0/15 746 | 156.116.0.0/16 747 | 156.118.0.0/16 748 | 156.133.0.0/16 749 | 156.135.0.0/16 750 | 156.14.0.0/16 751 | 156.148.0.0/16 752 | 156.150.0.0/16 753 | 156.17.0.0/16 754 | 156.18.0.0/16 755 | 156.25.0.0/16 756 | 156.28.0.0/16 757 | 156.35.0.0/16 758 | 156.43.0.0/16 759 | 156.48.0.0/15 760 | 156.51.0.0/16 761 | 156.52.0.0/16 762 | 156.54.0.0/16 763 | 156.58.0.0/16 764 | 156.61.0.0/16 765 | 156.67.0.0/16 766 | 156.83.0.0/16 767 | 157.124.0.0/15 768 | 157.129.0.0/16 769 | 157.136.0.0/16 770 | 157.138.0.0/16 771 | 157.140.0.0/16 772 | 157.144.0.0/16 773 | 157.157.0.0/16 774 | 157.158.0.0/15 775 | 157.161.0.0/16 776 | 157.162.0.0/15 777 | 157.164.0.0/16 778 | 157.167.0.0/16 779 | 157.168.0.0/15 780 | 157.171.0.0/16 781 | 157.172.0.0/15 782 | 157.177.0.0/16 783 | 157.180.0.0/15 784 | 157.186.0.0/16 785 | 157.190.0.0/16 786 | 157.193.0.0/16 787 | 157.200.0.0/16 788 | 157.203.0.0/16 789 | 157.228.0.0/16 790 | 157.23.0.0/16 791 | 157.236.0.0/15 792 | 157.24.0.0/14 793 | 157.243.0.0/16 794 | 157.247.0.0/16 795 | 157.249.0.0/16 796 | 157.28.0.0/15 797 | 157.83.0.0/16 798 | 157.84.0.0/16 799 | 157.88.0.0/16 800 | 157.94.0.0/16 801 | 157.96.0.0/16 802 | 157.99.0.0/16 803 | 158.102.0.0/16 804 | 158.105.0.0/16 805 | 158.109.0.0/16 806 | 158.110.0.0/16 807 | 158.112.0.0/16 808 | 158.119.0.0/16 809 | 158.124.0.0/14 810 | 158.129.0.0/16 811 | 158.131.0.0/16 812 | 158.133.0.0/16 813 | 158.143.0.0/16 814 | 158.148.0.0/15 815 | 158.150.0.0/16 816 | 158.152.0.0/16 817 | 158.156.0.0/16 818 | 158.162.0.0/16 819 | 158.166.0.0/15 820 | 158.168.0.0/15 821 | 158.172.0.0/14 822 | 158.176.0.0/14 823 | 158.180.0.0/15 824 | 158.190.0.0/15 825 | 158.192.0.0/14 826 | 158.196.0.0/15 827 | 158.216.0.0/16 828 | 158.218.0.0/16 829 | 158.220.0.0/16 830 | 158.223.0.0/16 831 | 158.225.0.0/16 832 | 158.226.0.0/15 833 | 158.230.0.0/15 834 | 158.232.0.0/15 835 | 158.234.0.0/16 836 | 158.248.0.0/15 837 | 158.250.0.0/16 838 | 158.255.0.0/16 839 | 158.36.0.0/14 840 | 158.41.0.0/16 841 | 158.42.0.0/15 842 | 158.46.0.0/15 843 | 158.49.0.0/16 844 | 158.50.0.0/16 845 | 158.58.0.0/16 846 | 158.64.0.0/16 847 | 158.66.0.0/15 848 | 158.75.0.0/16 849 | 158.90.0.0/16 850 | 158.92.0.0/16 851 | 158.94.0.0/16 852 | 158.99.0.0/16 853 | 159.0.0.0/16 854 | 159.100.0.0/15 855 | 159.103.0.0/16 856 | 159.104.0.0/16 857 | 159.107.0.0/16 858 | 159.109.0.0/16 859 | 159.114.0.0/16 860 | 159.12.0.0/16 861 | 159.122.0.0/16 862 | 159.130.0.0/16 863 | 159.134.0.0/16 864 | 159.144.0.0/16 865 | 159.146.0.0/15 866 | 159.148.0.0/15 867 | 159.15.0.0/16 868 | 159.151.0.0/16 869 | 159.152.0.0/16 870 | 159.154.0.0/16 871 | 159.156.0.0/16 872 | 159.160.0.0/16 873 | 159.162.0.0/16 874 | 159.167.0.0/16 875 | 159.168.0.0/16 876 | 159.170.0.0/15 877 | 159.173.0.0/16 878 | 159.179.0.0/16 879 | 159.180.0.0/16 880 | 159.190.0.0/16 881 | 159.193.0.0/16 882 | 159.194.0.0/15 883 | 159.197.0.0/16 884 | 159.20.0.0/16 885 | 159.200.0.0/16 886 | 159.205.0.0/16 887 | 159.210.0.0/16 888 | 159.213.0.0/16 889 | 159.216.0.0/15 890 | 159.219.0.0/16 891 | 159.22.0.0/15 892 | 159.224.0.0/16 893 | 159.232.0.0/16 894 | 159.236.0.0/15 895 | 159.239.0.0/16 896 | 159.241.0.0/16 897 | 159.244.0.0/15 898 | 159.25.0.0/16 899 | 159.253.0.0/16 900 | 159.254.0.0/15 901 | 159.29.0.0/16 902 | 159.30.0.0/15 903 | 159.34.0.0/16 904 | 159.38.0.0/16 905 | 159.46.0.0/16 906 | 159.50.0.0/15 907 | 159.58.0.0/16 908 | 159.60.0.0/16 909 | 159.7.0.0/16 910 | 159.72.0.0/16 911 | 159.8.0.0/16 912 | 159.81.0.0/16 913 | 159.84.0.0/16 914 | 159.86.0.0/16 915 | 159.92.0.0/15 916 | 159.95.0.0/16 917 | 160.100.0.0/16 918 | 160.103.0.0/16 919 | 160.104.0.0/16 920 | 160.114.0.0/16 921 | 160.180.0.0/16 922 | 160.210.0.0/15 923 | 160.213.0.0/16 924 | 160.214.0.0/16 925 | 160.216.0.0/14 926 | 160.220.0.0/15 927 | 160.228.0.0/16 928 | 160.38.0.0/16 929 | 160.40.0.0/16 930 | 160.44.0.0/14 931 | 160.48.0.0/12 932 | 160.5.0.0/16 933 | 160.6.0.0/16 934 | 160.66.0.0/15 935 | 160.68.0.0/16 936 | 160.70.0.0/15 937 | 160.75.0.0/16 938 | 160.78.0.0/16 939 | 160.8.0.0/15 940 | 160.80.0.0/16 941 | 160.85.0.0/16 942 | 160.92.0.0/16 943 | 160.97.0.0/16 944 | 160.98.0.0/15 945 | 161.104.0.0/15 946 | 161.106.0.0/16 947 | 161.110.0.0/15 948 | 161.112.0.0/16 949 | 161.116.0.0/16 950 | 161.12.0.0/16 951 | 161.134.0.0/16 952 | 161.147.0.0/16 953 | 161.158.0.0/16 954 | 161.17.0.0/16 955 | 161.2.0.0/15 956 | 161.20.0.0/16 957 | 161.202.0.0/16 958 | 161.218.0.0/16 959 | 161.23.0.0/16 960 | 161.252.0.0/16 961 | 161.27.0.0/16 962 | 161.30.0.0/16 963 | 161.37.0.0/16 964 | 161.4.0.0/15 965 | 161.41.0.0/16 966 | 161.42.0.0/16 967 | 161.48.0.0/16 968 | 161.52.0.0/15 969 | 161.54.0.0/16 970 | 161.59.0.0/16 971 | 161.62.0.0/16 972 | 161.67.0.0/16 973 | 161.71.0.0/16 974 | 161.72.0.0/15 975 | 161.74.0.0/16 976 | 161.76.0.0/16 977 | 161.78.0.0/16 978 | 161.8.0.0/15 979 | 161.83.0.0/16 980 | 161.84.0.0/14 981 | 161.88.0.0/14 982 | 161.92.0.0/16 983 | 162.11.0.0/16 984 | 162.13.0.0/16 985 | 162.21.0.0/16 986 | 162.23.0.0/16 987 | 162.25.0.0/16 988 | 162.26.0.0/16 989 | 162.38.0.0/16 990 | 162.86.0.0/16 991 | 163.1.0.0/16 992 | 163.112.0.0/14 993 | 163.116.0.0/15 994 | 163.119.0.0/16 995 | 163.156.0.0/14 996 | 163.160.0.0/12 997 | 163.242.0.0/16 998 | 163.3.0.0/16 999 | 163.34.0.0/16 1000 | 163.5.0.0/16 1001 | 163.62.0.0/15 1002 | 163.64.0.0/11 1003 | 163.9.0.0/16 1004 | 163.96.0.0/12 1005 | 164.0.0.0/11 1006 | 164.126.0.0/15 1007 | 164.128.0.0/12 1008 | 164.177.0.0/16 1009 | 164.215.0.0/16 1010 | 164.32.0.0/13 1011 | 164.40.0.0/16 1012 | 164.48.0.0/16 1013 | 164.59.0.0/16 1014 | 164.60.0.0/15 1015 | 164.81.0.0/16 1016 | 165.114.0.0/16 1017 | 165.218.0.0/16 1018 | 165.222.0.0/16 1019 | 166.49.128.0/17 1020 | 166.8.0.0/13 1021 | 166.87.0.0/16 1022 | 167.111.0.0/16 1023 | 167.168.0.0/16 1024 | 167.172.0.0/16 1025 | 167.203.0.0/16 1026 | 167.81.0.0/16 1027 | 168.1.0.0/16 1028 | 168.139.0.0/16 1029 | 168.187.0.0/16 1030 | 169.32.0.0/11 1031 | 170.236.0.0/15 1032 | 170.255.0.0/16 1033 | 170.60.0.0/16 1034 | 171.16.0.0/12 1035 | 171.32.0.0/15 1036 | 176.0.0.0/8 1037 | 178.0.0.0/8 1038 | 185.0.0.0/8 1039 | 188.0.0.0/8 1040 | 192.100.102.0/23 1041 | 192.100.104.0/21 1042 | 192.100.112.0/20 1043 | 192.100.128.0/22 1044 | 192.100.132.0/23 1045 | 192.100.135.0/24 1046 | 192.100.136.0/22 1047 | 192.100.140.0/24 1048 | 192.100.144.0/24 1049 | 192.100.154.0/24 1050 | 192.100.18.0/24 1051 | 192.100.23.0/24 1052 | 192.100.24.0/23 1053 | 192.100.52.0/24 1054 | 192.100.61.0/24 1055 | 192.100.63.0/24 1056 | 192.100.78.0/24 1057 | 192.100.96.0/22 1058 | 192.101.1.0/24 1059 | 192.101.11.0/24 1060 | 192.101.118.0/24 1061 | 192.101.137.0/24 1062 | 192.101.161.0/24 1063 | 192.101.162.0/23 1064 | 192.101.164.0/22 1065 | 192.101.168.0/24 1066 | 192.101.170.0/24 1067 | 192.101.176.0/24 1068 | 192.101.179.0/24 1069 | 192.101.180.0/24 1070 | 192.101.192.0/24 1071 | 192.101.197.0/24 1072 | 192.101.198.0/24 1073 | 192.101.252.0/24 1074 | 192.101.28.0/24 1075 | 192.101.34.0/24 1076 | 192.101.4.0/24 1077 | 192.101.75.0/24 1078 | 192.101.8.0/24 1079 | 192.101.81.0/24 1080 | 192.101.82.0/23 1081 | 192.101.84.0/22 1082 | 192.101.88.0/23 1083 | 192.101.90.0/24 1084 | 192.102.1.0/24 1085 | 192.102.146.0/23 1086 | 192.102.148.0/22 1087 | 192.102.152.0/21 1088 | 192.102.160.0/20 1089 | 192.102.17.0/24 1090 | 192.102.176.0/23 1091 | 192.102.18.0/23 1092 | 192.102.20.0/22 1093 | 192.102.214.0/24 1094 | 192.102.224.0/23 1095 | 192.102.227.0/24 1096 | 192.102.228.0/23 1097 | 192.102.24.0/21 1098 | 192.102.32.0/19 1099 | 192.102.6.0/23 1100 | 192.102.64.0/20 1101 | 192.102.8.0/24 1102 | 192.102.80.0/23 1103 | 192.102.89.0/24 1104 | 192.102.95.0/24 1105 | 192.103.112.0/22 1106 | 192.103.116.0/24 1107 | 192.103.137.0/24 1108 | 192.103.138.0/23 1109 | 192.103.14.0/24 1110 | 192.103.147.0/24 1111 | 192.103.2.0/24 1112 | 192.103.20.0/24 1113 | 192.103.23.0/24 1114 | 192.103.27.0/24 1115 | 192.103.28.0/22 1116 | 192.103.32.0/21 1117 | 192.103.40.0/24 1118 | 192.103.7.0/24 1119 | 192.103.85.0/24 1120 | 192.103.86.0/23 1121 | 192.103.88.0/21 1122 | 192.103.96.0/20 1123 | 192.104.140.0/24 1124 | 192.104.142.0/24 1125 | 192.104.147.0/24 1126 | 192.104.154.0/23 1127 | 192.104.167.0/24 1128 | 192.104.168.0/24 1129 | 192.104.23.0/24 1130 | 192.104.238.0/24 1131 | 192.104.245.0/24 1132 | 192.104.248.0/24 1133 | 192.104.251.0/24 1134 | 192.104.28.0/23 1135 | 192.104.35.0/24 1136 | 192.104.36.0/23 1137 | 192.104.41.0/24 1138 | 192.104.48.0/24 1139 | 192.104.53.0/24 1140 | 192.104.55.0/24 1141 | 192.104.56.0/23 1142 | 192.104.58.0/24 1143 | 192.104.72.0/24 1144 | 192.104.77.0/24 1145 | 192.104.82.0/24 1146 | 192.105.75.0/24 1147 | 192.106.0.0/16 1148 | 192.107.100.0/24 1149 | 192.107.11.0/24 1150 | 192.107.110.0/24 1151 | 192.107.114.0/24 1152 | 192.107.12.0/23 1153 | 192.107.122.0/23 1154 | 192.107.124.0/22 1155 | 192.107.128.0/23 1156 | 192.107.132.0/24 1157 | 192.107.168.0/24 1158 | 192.107.174.0/24 1159 | 192.107.177.0/24 1160 | 192.107.178.0/24 1161 | 192.107.187.0/24 1162 | 192.107.2.0/24 1163 | 192.107.200.0/21 1164 | 192.107.208.0/20 1165 | 192.107.224.0/21 1166 | 192.107.232.0/23 1167 | 192.107.235.0/24 1168 | 192.107.236.0/24 1169 | 192.107.4.0/23 1170 | 192.107.51.0/24 1171 | 192.107.52.0/22 1172 | 192.107.56.0/21 1173 | 192.107.64.0/19 1174 | 192.107.96.0/22 1175 | 192.108.100.0/23 1176 | 192.108.107.0/24 1177 | 192.108.108.0/24 1178 | 192.108.114.0/23 1179 | 192.108.116.0/22 1180 | 192.108.120.0/23 1181 | 192.108.125.0/24 1182 | 192.108.126.0/24 1183 | 192.108.128.0/19 1184 | 192.108.160.0/21 1185 | 192.108.168.0/22 1186 | 192.108.172.0/23 1187 | 192.108.174.0/24 1188 | 192.108.195.0/24 1189 | 192.108.196.0/22 1190 | 192.108.200.0/21 1191 | 192.108.208.0/22 1192 | 192.108.212.0/23 1193 | 192.108.214.0/24 1194 | 192.108.23.0/24 1195 | 192.108.234.0/24 1196 | 192.108.238.0/24 1197 | 192.108.24.0/21 1198 | 192.108.32.0/20 1199 | 192.108.48.0/23 1200 | 192.108.51.0/24 1201 | 192.108.52.0/22 1202 | 192.108.56.0/21 1203 | 192.108.64.0/20 1204 | 192.108.80.0/21 1205 | 192.108.88.0/22 1206 | 192.108.92.0/24 1207 | 192.109.0.0/19 1208 | 192.109.100.0/23 1209 | 192.109.102.0/24 1210 | 192.109.105.0/24 1211 | 192.109.106.0/23 1212 | 192.109.108.0/22 1213 | 192.109.112.0/21 1214 | 192.109.121.0/24 1215 | 192.109.122.0/23 1216 | 192.109.124.0/22 1217 | 192.109.128.0/18 1218 | 192.109.192.0/19 1219 | 192.109.224.0/20 1220 | 192.109.240.0/23 1221 | 192.109.243.0/24 1222 | 192.109.244.0/22 1223 | 192.109.248.0/21 1224 | 192.109.32.0/21 1225 | 192.109.40.0/22 1226 | 192.109.44.0/24 1227 | 192.109.46.0/23 1228 | 192.109.48.0/20 1229 | 192.109.64.0/21 1230 | 192.109.72.0/23 1231 | 192.109.74.0/24 1232 | 192.109.76.0/22 1233 | 192.109.80.0/21 1234 | 192.109.88.0/22 1235 | 192.109.94.0/23 1236 | 192.109.96.0/23 1237 | 192.109.98.0/24 1238 | 192.111.101.0/24 1239 | 192.111.103.0/24 1240 | 192.111.104.0/24 1241 | 192.111.124.0/23 1242 | 192.111.127.0/24 1243 | 192.111.252.0/24 1244 | 192.111.33.0/24 1245 | 192.111.39.0/24 1246 | 192.111.44.0/24 1247 | 192.111.47.0/24 1248 | 192.111.48.0/24 1249 | 192.111.88.0/24 1250 | 192.112.100.0/24 1251 | 192.112.204.0/24 1252 | 192.112.206.0/24 1253 | 192.112.208.0/24 1254 | 192.112.213.0/24 1255 | 192.112.214.0/24 1256 | 192.112.247.0/24 1257 | 192.112.254.0/24 1258 | 192.112.30.0/23 1259 | 192.112.32.0/24 1260 | 192.112.45.0/24 1261 | 192.112.49.0/24 1262 | 192.112.61.0/24 1263 | 192.112.70.0/23 1264 | 192.112.72.0/21 1265 | 192.112.98.0/23 1266 | 192.113.0.0/16 1267 | 192.114.0.0/15 1268 | 192.116.0.0/15 1269 | 192.118.0.0/16 1270 | 192.12.1.0/24 1271 | 192.12.192.0/23 1272 | 192.12.194.0/24 1273 | 192.12.217.0/24 1274 | 192.12.218.0/24 1275 | 192.12.231.0/24 1276 | 192.12.232.0/24 1277 | 192.12.235.0/24 1278 | 192.12.247.0/24 1279 | 192.12.47.0/24 1280 | 192.12.54.0/24 1281 | 192.12.72.0/23 1282 | 192.12.77.0/24 1283 | 192.12.81.0/24 1284 | 192.12.96.0/24 1285 | 192.12.99.0/24 1286 | 192.121.0.0/16 1287 | 192.122.1.0/24 1288 | 192.122.128.0/23 1289 | 192.122.130.0/24 1290 | 192.122.141.0/24 1291 | 192.122.142.0/23 1292 | 192.122.144.0/23 1293 | 192.122.146.0/24 1294 | 192.122.151.0/24 1295 | 192.122.152.0/21 1296 | 192.122.16.0/20 1297 | 192.122.160.0/21 1298 | 192.122.168.0/23 1299 | 192.122.170.0/24 1300 | 192.122.2.0/23 1301 | 192.122.214.0/24 1302 | 192.122.216.0/21 1303 | 192.122.224.0/21 1304 | 192.122.232.0/23 1305 | 192.122.234.0/24 1306 | 192.122.238.0/23 1307 | 192.122.240.0/23 1308 | 192.122.242.0/24 1309 | 192.122.254.0/24 1310 | 192.122.32.0/19 1311 | 192.122.4.0/22 1312 | 192.122.64.0/18 1313 | 192.122.8.0/21 1314 | 192.124.112.0/24 1315 | 192.124.115.0/24 1316 | 192.124.116.0/24 1317 | 192.124.155.0/24 1318 | 192.124.170.0/23 1319 | 192.124.172.0/22 1320 | 192.124.176.0/20 1321 | 192.124.192.0/20 1322 | 192.124.208.0/21 1323 | 192.124.216.0/22 1324 | 192.124.235.0/24 1325 | 192.124.237.0/24 1326 | 192.124.238.0/23 1327 | 192.124.240.0/22 1328 | 192.124.244.0/23 1329 | 192.124.247.0/24 1330 | 192.124.248.0/24 1331 | 192.124.25.0/24 1332 | 192.124.250.0/23 1333 | 192.124.252.0/23 1334 | 192.124.254.0/24 1335 | 192.124.26.0/23 1336 | 192.124.28.0/24 1337 | 192.124.32.0/24 1338 | 192.124.39.0/24 1339 | 192.124.46.0/24 1340 | 192.125.0.0/16 1341 | 192.126.1.0/24 1342 | 192.126.16.0/20 1343 | 192.126.2.0/23 1344 | 192.126.32.0/19 1345 | 192.126.4.0/22 1346 | 192.126.64.0/24 1347 | 192.126.8.0/21 1348 | 192.129.1.0/24 1349 | 192.129.16.0/20 1350 | 192.129.2.0/23 1351 | 192.129.32.0/20 1352 | 192.129.4.0/22 1353 | 192.129.48.0/21 1354 | 192.129.56.0/22 1355 | 192.129.60.0/23 1356 | 192.129.8.0/21 1357 | 192.129.80.0/24 1358 | 192.129.87.0/24 1359 | 192.129.98.0/24 1360 | 192.130.0.0/16 1361 | 192.131.108.0/24 1362 | 192.131.132.0/24 1363 | 192.131.20.0/24 1364 | 192.131.25.0/24 1365 | 192.131.26.0/24 1366 | 192.131.79.0/24 1367 | 192.131.89.0/24 1368 | 192.131.96.0/24 1369 | 192.132.10.0/23 1370 | 192.132.239.0/24 1371 | 192.132.244.0/23 1372 | 192.132.252.0/24 1373 | 192.132.34.0/24 1374 | 192.132.53.0/24 1375 | 192.132.55.0/24 1376 | 192.132.9.0/24 1377 | 192.132.99.0/24 1378 | 192.133.108.0/22 1379 | 192.133.121.0/24 1380 | 192.133.131.0/24 1381 | 192.133.15.0/24 1382 | 192.133.244.0/24 1383 | 192.133.28.0/24 1384 | 192.133.32.0/24 1385 | 192.133.36.0/24 1386 | 192.133.53.0/24 1387 | 192.133.54.0/23 1388 | 192.133.58.0/24 1389 | 192.133.64.0/24 1390 | 192.134.0.0/16 1391 | 192.135.129.0/24 1392 | 192.135.133.0/24 1393 | 192.135.143.0/24 1394 | 192.135.145.0/24 1395 | 192.135.146.0/23 1396 | 192.135.148.0/22 1397 | 192.135.152.0/21 1398 | 192.135.16.0/20 1399 | 192.135.160.0/21 1400 | 192.135.168.0/24 1401 | 192.135.175.0/24 1402 | 192.135.187.0/24 1403 | 192.135.219.0/24 1404 | 192.135.225.0/24 1405 | 192.135.231.0/24 1406 | 192.135.232.0/23 1407 | 192.135.234.0/24 1408 | 192.135.253.0/24 1409 | 192.135.254.0/24 1410 | 192.135.32.0/22 1411 | 192.135.36.0/23 1412 | 192.135.46.0/24 1413 | 192.135.51.0/24 1414 | 192.135.52.0/23 1415 | 192.135.63.0/24 1416 | 192.135.66.0/24 1417 | 192.135.68.0/24 1418 | 192.135.7.0/24 1419 | 192.135.8.0/21 1420 | 192.135.82.0/24 1421 | 192.136.100.0/23 1422 | 192.136.102.0/24 1423 | 192.136.154.0/23 1424 | 192.136.156.0/24 1425 | 192.136.18.0/23 1426 | 192.136.23.0/24 1427 | 192.136.29.0/24 1428 | 192.136.30.0/23 1429 | 192.136.40.0/23 1430 | 192.136.49.0/24 1431 | 192.136.51.0/24 1432 | 192.136.52.0/24 1433 | 192.136.61.0/24 1434 | 192.136.7.0/24 1435 | 192.136.71.0/24 1436 | 192.136.72.0/21 1437 | 192.136.80.0/20 1438 | 192.136.9.0/24 1439 | 192.136.96.0/22 1440 | 192.138.1.0/24 1441 | 192.138.105.0/24 1442 | 192.138.106.0/23 1443 | 192.138.108.0/22 1444 | 192.138.112.0/22 1445 | 192.138.116.0/23 1446 | 192.138.155.0/24 1447 | 192.138.156.0/23 1448 | 192.138.158.0/24 1449 | 192.138.183.0/24 1450 | 192.138.192.0/24 1451 | 192.138.2.0/23 1452 | 192.138.204.0/24 1453 | 192.138.228.0/22 1454 | 192.138.232.0/24 1455 | 192.138.248.0/24 1456 | 192.138.4.0/22 1457 | 192.138.8.0/24 1458 | 192.138.86.0/24 1459 | 192.139.78.0/24 1460 | 192.144.74.0/24 1461 | 192.144.76.0/23 1462 | 192.146.117.0/24 1463 | 192.146.119.0/24 1464 | 192.146.123.0/24 1465 | 192.146.124.0/23 1466 | 192.146.126.0/24 1467 | 192.146.132.0/24 1468 | 192.146.134.0/23 1469 | 192.146.136.0/22 1470 | 192.146.140.0/23 1471 | 192.146.152.0/24 1472 | 192.146.163.0/24 1473 | 192.146.164.0/22 1474 | 192.146.168.0/23 1475 | 192.146.170.0/24 1476 | 192.146.172.0/22 1477 | 192.146.176.0/22 1478 | 192.146.180.0/23 1479 | 192.146.182.0/24 1480 | 192.146.185.0/24 1481 | 192.146.187.0/24 1482 | 192.146.193.0/24 1483 | 192.146.204.0/24 1484 | 192.146.227.0/24 1485 | 192.146.228.0/24 1486 | 192.146.233.0/24 1487 | 192.146.234.0/24 1488 | 192.146.238.0/23 1489 | 192.146.242.0/24 1490 | 192.147.141.0/24 1491 | 192.147.150.0/24 1492 | 192.147.155.0/24 1493 | 192.147.212.0/24 1494 | 192.147.215.0/24 1495 | 192.147.216.0/23 1496 | 192.147.219.0/24 1497 | 192.147.228.0/24 1498 | 192.147.23.0/24 1499 | 192.147.247.0/24 1500 | 192.147.251.0/24 1501 | 192.147.34.0/24 1502 | 192.147.36.0/24 1503 | 192.147.42.0/24 1504 | 192.147.76.0/22 1505 | 192.148.103.0/24 1506 | 192.148.166.0/23 1507 | 192.148.177.0/24 1508 | 192.148.178.0/23 1509 | 192.148.180.0/22 1510 | 192.148.184.0/23 1511 | 192.148.186.0/24 1512 | 192.148.192.0/23 1513 | 192.148.194.0/24 1514 | 192.148.198.0/23 1515 | 192.148.200.0/21 1516 | 192.148.208.0/21 1517 | 192.148.216.0/24 1518 | 192.148.220.0/24 1519 | 192.148.33.0/24 1520 | 192.148.34.0/23 1521 | 192.148.36.0/22 1522 | 192.148.40.0/21 1523 | 192.148.48.0/20 1524 | 192.148.64.0/20 1525 | 192.148.80.0/21 1526 | 192.148.88.0/22 1527 | 192.148.92.0/24 1528 | 192.149.100.0/24 1529 | 192.149.102.0/24 1530 | 192.149.110.0/23 1531 | 192.149.117.0/24 1532 | 192.149.118.0/23 1533 | 192.149.120.0/23 1534 | 192.149.126.0/24 1535 | 192.149.15.0/24 1536 | 192.149.19.0/24 1537 | 192.149.227.0/24 1538 | 192.149.232.0/24 1539 | 192.149.238.0/24 1540 | 192.149.27.0/24 1541 | 192.149.29.0/24 1542 | 192.149.3.0/24 1543 | 192.149.30.0/23 1544 | 192.149.32.0/23 1545 | 192.149.35.0/24 1546 | 192.149.41.0/24 1547 | 192.149.5.0/24 1548 | 192.149.57.0/24 1549 | 192.149.59.0/24 1550 | 192.149.60.0/24 1551 | 192.149.77.0/24 1552 | 192.149.78.0/23 1553 | 192.150.104.0/24 1554 | 192.150.106.0/24 1555 | 192.150.124.0/24 1556 | 192.150.140.0/24 1557 | 192.150.146.0/24 1558 | 192.150.177.0/24 1559 | 192.150.178.0/23 1560 | 192.150.180.0/22 1561 | 192.150.184.0/24 1562 | 192.150.188.0/23 1563 | 192.150.190.0/24 1564 | 192.150.192.0/22 1565 | 192.150.196.0/23 1566 | 192.150.198.0/24 1567 | 192.150.203.0/24 1568 | 192.150.204.0/23 1569 | 192.150.208.0/23 1570 | 192.150.223.0/24 1571 | 192.150.227.0/24 1572 | 192.150.228.0/22 1573 | 192.150.232.0/23 1574 | 192.150.238.0/24 1575 | 192.150.248.0/24 1576 | 192.150.252.0/24 1577 | 192.150.254.0/24 1578 | 192.150.58.0/23 1579 | 192.150.60.0/22 1580 | 192.150.64.0/21 1581 | 192.150.72.0/24 1582 | 192.150.75.0/24 1583 | 192.150.76.0/24 1584 | 192.150.78.0/23 1585 | 192.150.80.0/22 1586 | 192.150.84.0/24 1587 | 192.150.89.0/24 1588 | 192.150.92.0/24 1589 | 192.150.94.0/24 1590 | 192.152.111.0/24 1591 | 192.152.112.0/24 1592 | 192.152.122.0/24 1593 | 192.152.124.0/24 1594 | 192.152.14.0/24 1595 | 192.152.141.0/24 1596 | 192.152.151.0/24 1597 | 192.152.156.0/24 1598 | 192.152.166.0/23 1599 | 192.152.17.0/24 1600 | 192.152.174.0/24 1601 | 192.152.184.0/22 1602 | 192.152.241.0/24 1603 | 192.152.244.0/24 1604 | 192.152.253.0/24 1605 | 192.152.254.0/24 1606 | 192.152.26.0/23 1607 | 192.152.42.0/24 1608 | 192.152.44.0/24 1609 | 192.152.47.0/24 1610 | 192.152.48.0/22 1611 | 192.152.54.0/24 1612 | 192.152.6.0/24 1613 | 192.152.61.0/24 1614 | 192.152.62.0/23 1615 | 192.152.68.0/24 1616 | 192.152.82.0/24 1617 | 192.152.98.0/24 1618 | 192.153.116.0/24 1619 | 192.153.127.0/24 1620 | 192.153.13.0/24 1621 | 192.153.153.0/24 1622 | 192.153.166.0/24 1623 | 192.153.168.0/24 1624 | 192.153.171.0/24 1625 | 192.153.173.0/24 1626 | 192.153.174.0/23 1627 | 192.153.176.0/22 1628 | 192.153.18.0/23 1629 | 192.153.180.0/23 1630 | 192.153.182.0/24 1631 | 192.153.188.0/23 1632 | 192.153.194.0/24 1633 | 192.153.2.0/23 1634 | 192.153.213.0/24 1635 | 192.153.89.0/24 1636 | 192.155.1.0/24 1637 | 192.155.2.0/23 1638 | 192.155.4.0/23 1639 | 192.155.6.0/24 1640 | 192.156.132.0/24 1641 | 192.156.162.0/24 1642 | 192.156.167.0/24 1643 | 192.156.210.0/24 1644 | 192.156.213.0/24 1645 | 192.156.217.0/24 1646 | 192.156.227.0/24 1647 | 192.156.239.0/24 1648 | 192.156.248.0/24 1649 | 192.157.1.0/24 1650 | 192.157.129.0/24 1651 | 192.157.16.0/23 1652 | 192.157.165.0/24 1653 | 192.157.166.0/23 1654 | 192.157.168.0/22 1655 | 192.157.172.0/24 1656 | 192.157.174.0/24 1657 | 192.157.176.0/24 1658 | 192.157.185.0/24 1659 | 192.157.187.0/24 1660 | 192.157.189.0/24 1661 | 192.157.2.0/23 1662 | 192.157.8.0/21 1663 | 192.159.100.0/22 1664 | 192.159.105.0/24 1665 | 192.159.108.0/23 1666 | 192.159.118.0/24 1667 | 192.159.121.0/24 1668 | 192.159.122.0/24 1669 | 192.159.70.0/24 1670 | 192.159.73.0/24 1671 | 192.159.77.0/24 1672 | 192.159.84.0/23 1673 | 192.159.90.0/24 1674 | 192.159.95.0/24 1675 | 192.159.99.0/24 1676 | 192.16.123.0/24 1677 | 192.16.124.0/22 1678 | 192.16.128.0/19 1679 | 192.16.160.0/22 1680 | 192.16.164.0/23 1681 | 192.16.166.0/24 1682 | 192.16.183.0/24 1683 | 192.16.184.0/21 1684 | 192.16.192.0/21 1685 | 192.16.200.0/23 1686 | 192.16.202.0/24 1687 | 192.160.10.0/24 1688 | 192.160.109.0/24 1689 | 192.160.110.0/24 1690 | 192.160.123.0/24 1691 | 192.160.126.0/24 1692 | 192.160.142.0/23 1693 | 192.160.15.0/24 1694 | 192.160.152.0/24 1695 | 192.160.156.0/24 1696 | 192.160.160.0/24 1697 | 192.160.172.0/24 1698 | 192.160.177.0/24 1699 | 192.160.178.0/23 1700 | 192.160.194.0/23 1701 | 192.160.21.0/24 1702 | 192.160.22.0/23 1703 | 192.160.224.0/23 1704 | 192.160.231.0/24 1705 | 192.160.232.0/23 1706 | 192.160.245.0/24 1707 | 192.160.246.0/23 1708 | 192.160.248.0/23 1709 | 192.160.251.0/24 1710 | 192.160.252.0/24 1711 | 192.160.27.0/24 1712 | 192.160.33.0/24 1713 | 192.160.37.0/24 1714 | 192.160.65.0/24 1715 | 192.160.67.0/24 1716 | 192.160.95.0/24 1717 | 192.160.96.0/24 1718 | 192.161.64.0/23 1719 | 192.162.0.0/16 1720 | 192.163.128.0/19 1721 | 192.163.32.0/19 1722 | 192.163.64.0/18 1723 | 192.164.0.0/14 1724 | 192.171.1.0/24 1725 | 192.171.128.0/18 1726 | 192.171.192.0/21 1727 | 192.171.2.0/23 1728 | 192.171.4.0/23 1729 | 192.172.253.0/24 1730 | 192.173.1.0/24 1731 | 192.173.128.0/21 1732 | 192.173.2.0/23 1733 | 192.173.4.0/24 1734 | 192.174.64.0/22 1735 | 192.174.68.0/24 1736 | 192.175.32.0/20 1737 | 192.176.0.0/16 1738 | 192.18.195.0/24 1739 | 192.187.16.0/21 1740 | 192.187.24.0/23 1741 | 192.188.10.0/24 1742 | 192.188.105.0/24 1743 | 192.188.116.0/23 1744 | 192.188.121.0/24 1745 | 192.188.122.0/24 1746 | 192.188.125.0/24 1747 | 192.188.127.0/24 1748 | 192.188.129.0/24 1749 | 192.188.132.0/24 1750 | 192.188.136.0/24 1751 | 192.188.145.0/24 1752 | 192.188.157.0/24 1753 | 192.188.158.0/24 1754 | 192.188.187.0/24 1755 | 192.188.189.0/24 1756 | 192.188.233.0/24 1757 | 192.188.234.0/23 1758 | 192.188.236.0/23 1759 | 192.188.242.0/23 1760 | 192.188.244.0/22 1761 | 192.188.63.0/24 1762 | 192.188.64.0/23 1763 | 192.188.69.0/24 1764 | 192.188.96.0/24 1765 | 192.189.1.0/24 1766 | 192.189.119.0/24 1767 | 192.189.14.0/24 1768 | 192.189.151.0/24 1769 | 192.189.154.0/24 1770 | 192.189.157.0/24 1771 | 192.189.160.0/24 1772 | 192.189.166.0/23 1773 | 192.189.168.0/23 1774 | 192.189.170.0/24 1775 | 192.189.202.0/23 1776 | 192.189.23.0/24 1777 | 192.189.251.0/24 1778 | 192.189.41.0/24 1779 | 192.189.51.0/24 1780 | 192.189.52.0/24 1781 | 192.189.55.0/24 1782 | 192.189.66.0/24 1783 | 192.189.69.0/24 1784 | 192.189.70.0/24 1785 | 192.189.73.0/24 1786 | 192.189.76.0/24 1787 | 192.189.8.0/22 1788 | 192.190.129.0/24 1789 | 192.190.130.0/23 1790 | 192.190.132.0/24 1791 | 192.190.173.0/24 1792 | 192.190.174.0/24 1793 | 192.190.182.0/23 1794 | 192.190.190.0/23 1795 | 192.190.192.0/23 1796 | 192.190.201.0/24 1797 | 192.190.202.0/24 1798 | 192.190.233.0/24 1799 | 192.190.234.0/23 1800 | 192.190.236.0/24 1801 | 192.190.240.0/24 1802 | 192.190.242.0/24 1803 | 192.190.247.0/24 1804 | 192.190.248.0/23 1805 | 192.190.44.0/24 1806 | 192.190.58.0/23 1807 | 192.190.64.0/24 1808 | 192.190.67.0/24 1809 | 192.190.69.0/24 1810 | 192.190.95.0/24 1811 | 192.194.0.0/16 1812 | 192.195.1.0/24 1813 | 192.195.105.0/24 1814 | 192.195.106.0/24 1815 | 192.195.110.0/24 1816 | 192.195.116.0/23 1817 | 192.195.118.0/24 1818 | 192.195.134.0/23 1819 | 192.195.136.0/21 1820 | 192.195.144.0/22 1821 | 192.195.148.0/24 1822 | 192.195.183.0/24 1823 | 192.195.184.0/24 1824 | 192.195.195.0/24 1825 | 192.195.236.0/24 1826 | 192.195.42.0/23 1827 | 192.195.72.0/24 1828 | 192.195.8.0/24 1829 | 192.195.98.0/24 1830 | 192.196.1.0/24 1831 | 192.196.128.0/20 1832 | 192.196.144.0/21 1833 | 192.196.152.0/22 1834 | 192.196.16.0/20 1835 | 192.196.2.0/23 1836 | 192.196.32.0/19 1837 | 192.196.4.0/22 1838 | 192.196.64.0/18 1839 | 192.196.8.0/21 1840 | 192.199.16.0/20 1841 | 192.203.108.0/23 1842 | 192.203.227.0/24 1843 | 192.203.80.0/24 1844 | 192.206.222.0/23 1845 | 192.206.224.0/23 1846 | 192.206.226.0/24 1847 | 192.206.77.0/24 1848 | 192.206.78.0/23 1849 | 192.206.80.0/23 1850 | 192.206.86.0/24 1851 | 192.207.14.0/24 1852 | 192.207.141.0/24 1853 | 192.207.142.0/24 1854 | 192.207.196.0/24 1855 | 192.207.31.0/24 1856 | 192.231.67.0/24 1857 | 192.231.82.0/24 1858 | 192.238.1.0/24 1859 | 192.238.10.0/24 1860 | 192.238.2.0/23 1861 | 192.238.4.0/22 1862 | 192.238.8.0/23 1863 | 192.245.152.0/24 1864 | 192.245.169.0/24 1865 | 192.245.225.0/24 1866 | 192.247.1.0/24 1867 | 192.247.10.0/24 1868 | 192.247.2.0/23 1869 | 192.247.4.0/22 1870 | 192.247.8.0/23 1871 | 192.251.226.0/24 1872 | 192.251.61.0/24 1873 | 192.251.62.0/23 1874 | 192.251.64.0/23 1875 | 192.26.105.0/24 1876 | 192.26.106.0/23 1877 | 192.26.108.0/23 1878 | 192.26.111.0/24 1879 | 192.26.112.0/20 1880 | 192.26.128.0/24 1881 | 192.26.133.0/24 1882 | 192.26.134.0/23 1883 | 192.26.154.0/23 1884 | 192.26.156.0/22 1885 | 192.26.160.0/19 1886 | 192.26.192.0/23 1887 | 192.26.231.0/24 1888 | 192.26.234.0/24 1889 | 192.26.236.0/22 1890 | 192.26.28.0/22 1891 | 192.26.32.0/20 1892 | 192.31.102.0/24 1893 | 192.31.14.0/24 1894 | 192.31.166.0/23 1895 | 192.31.168.0/22 1896 | 192.31.211.0/24 1897 | 192.31.23.0/24 1898 | 192.31.231.0/24 1899 | 192.31.252.0/24 1900 | 192.31.26.0/23 1901 | 192.31.31.0/24 1902 | 192.31.40.0/24 1903 | 192.31.62.0/24 1904 | 192.33.113.0/24 1905 | 192.33.114.0/24 1906 | 192.33.118.0/23 1907 | 192.33.120.0/21 1908 | 192.33.130.0/23 1909 | 192.33.143.0/24 1910 | 192.33.144.0/23 1911 | 192.33.147.0/24 1912 | 192.33.148.0/22 1913 | 192.33.15.0/24 1914 | 192.33.152.0/21 1915 | 192.33.16.0/24 1916 | 192.33.160.0/22 1917 | 192.33.164.0/23 1918 | 192.33.166.0/24 1919 | 192.33.169.0/24 1920 | 192.33.170.0/23 1921 | 192.33.176.0/22 1922 | 192.33.180.0/23 1923 | 192.33.182.0/24 1924 | 192.33.192.0/19 1925 | 192.33.224.0/21 1926 | 192.33.254.0/24 1927 | 192.33.36.0/24 1928 | 192.33.87.0/24 1929 | 192.33.88.0/21 1930 | 192.33.96.0/20 1931 | 192.34.107.0/24 1932 | 192.34.116.0/24 1933 | 192.34.179.0/24 1934 | 192.34.19.0/24 1935 | 192.34.50.0/24 1936 | 192.35.0.0/20 1937 | 192.35.108.0/24 1938 | 192.35.138.0/24 1939 | 192.35.146.0/24 1940 | 192.35.149.0/24 1941 | 192.35.150.0/23 1942 | 192.35.152.0/23 1943 | 192.35.16.0/22 1944 | 192.35.172.0/24 1945 | 192.35.183.0/24 1946 | 192.35.184.0/21 1947 | 192.35.192.0/24 1948 | 192.35.197.0/24 1949 | 192.35.198.0/24 1950 | 192.35.205.0/24 1951 | 192.35.206.0/23 1952 | 192.35.229.0/24 1953 | 192.35.240.0/22 1954 | 192.35.244.0/24 1955 | 192.35.246.0/23 1956 | 192.35.63.0/24 1957 | 192.35.64.0/21 1958 | 192.35.72.0/24 1959 | 192.35.90.0/24 1960 | 192.35.94.0/24 1961 | 192.36.0.0/15 1962 | 192.38.0.0/16 1963 | 192.40.228.0/24 1964 | 192.40.69.0/24 1965 | 192.40.70.0/23 1966 | 192.40.72.0/21 1967 | 192.40.80.0/24 1968 | 192.41.103.0/24 1969 | 192.41.104.0/21 1970 | 192.41.112.0/20 1971 | 192.41.128.0/21 1972 | 192.41.136.0/24 1973 | 192.41.140.0/22 1974 | 192.41.144.0/23 1975 | 192.41.147.0/24 1976 | 192.41.149.0/24 1977 | 192.41.150.0/23 1978 | 192.41.152.0/21 1979 | 192.41.160.0/24 1980 | 192.41.210.0/24 1981 | 192.41.216.0/24 1982 | 192.41.218.0/24 1983 | 192.41.227.0/24 1984 | 192.42.1.0/24 1985 | 192.42.100.0/24 1986 | 192.42.102.0/24 1987 | 192.42.113.0/24 1988 | 192.42.114.0/23 1989 | 192.42.116.0/22 1990 | 192.42.120.0/21 1991 | 192.42.128.0/22 1992 | 192.42.132.0/24 1993 | 192.42.143.0/24 1994 | 192.42.180.0/22 1995 | 192.42.184.0/21 1996 | 192.42.192.0/21 1997 | 192.42.200.0/23 1998 | 192.42.253.0/24 1999 | 192.42.42.0/23 2000 | 192.42.44.0/22 2001 | 192.42.53.0/24 2002 | 192.42.63.0/24 2003 | 192.42.64.0/24 2004 | 192.42.87.0/24 2005 | 192.43.162.0/23 2006 | 192.43.164.0/22 2007 | 192.43.168.0/22 2008 | 192.43.192.0/22 2009 | 192.43.196.0/24 2010 | 192.43.210.0/24 2011 | 192.43.212.0/24 2012 | 192.43.234.0/24 2013 | 192.44.0.0/18 2014 | 192.44.240.0/21 2015 | 192.44.248.0/22 2016 | 192.44.64.0/22 2017 | 192.44.71.0/24 2018 | 192.44.72.0/21 2019 | 192.44.80.0/21 2020 | 192.44.88.0/23 2021 | 192.44.90.0/24 2022 | 192.47.244.0/22 2023 | 192.47.248.0/23 2024 | 192.48.107.0/24 2025 | 192.48.145.0/24 2026 | 192.48.224.0/24 2027 | 192.48.231.0/24 2028 | 192.48.31.0/24 2029 | 192.49.0.0/16 2030 | 192.5.142.0/24 2031 | 192.5.145.0/24 2032 | 192.5.162.0/24 2033 | 192.5.239.0/24 2034 | 192.5.254.0/24 2035 | 192.5.28.0/23 2036 | 192.5.30.0/24 2037 | 192.5.36.0/24 2038 | 192.5.50.0/24 2039 | 192.5.59.0/24 2040 | 192.5.61.0/24 2041 | 192.5.62.0/24 2042 | 192.5.97.0/24 2043 | 192.51.0.0/20 2044 | 192.52.0.0/19 2045 | 192.52.152.0/24 2046 | 192.52.159.0/24 2047 | 192.52.160.0/23 2048 | 192.52.221.0/24 2049 | 192.52.222.0/23 2050 | 192.52.253.0/24 2051 | 192.52.254.0/24 2052 | 192.52.32.0/20 2053 | 192.52.48.0/23 2054 | 192.52.50.0/24 2055 | 192.53.103.0/24 2056 | 192.53.104.0/24 2057 | 192.54.104.0/24 2058 | 192.54.113.0/24 2059 | 192.54.115.0/24 2060 | 192.54.116.0/22 2061 | 192.54.120.0/24 2062 | 192.54.122.0/24 2063 | 192.54.125.0/24 2064 | 192.54.126.0/23 2065 | 192.54.128.0/24 2066 | 192.54.132.0/24 2067 | 192.54.139.0/24 2068 | 192.54.141.0/24 2069 | 192.54.142.0/23 2070 | 192.54.144.0/20 2071 | 192.54.160.0/19 2072 | 192.54.192.0/20 2073 | 192.54.208.0/21 2074 | 192.54.216.0/22 2075 | 192.54.220.0/23 2076 | 192.54.225.0/24 2077 | 192.54.245.0/24 2078 | 192.54.254.0/24 2079 | 192.54.31.0/24 2080 | 192.54.32.0/20 2081 | 192.54.48.0/22 2082 | 192.54.52.0/24 2083 | 192.54.54.0/23 2084 | 192.54.56.0/21 2085 | 192.54.64.0/20 2086 | 192.54.80.0/24 2087 | 192.55.101.0/24 2088 | 192.55.105.0/24 2089 | 192.55.109.0/24 2090 | 192.55.115.0/24 2091 | 192.55.129.0/24 2092 | 192.55.132.0/24 2093 | 192.55.188.0/24 2094 | 192.55.193.0/24 2095 | 192.55.197.0/24 2096 | 192.55.212.0/24 2097 | 192.55.244.0/24 2098 | 192.55.84.0/24 2099 | 192.55.89.0/24 2100 | 192.58.197.0/24 2101 | 192.58.218.0/24 2102 | 192.58.28.0/22 2103 | 192.58.32.0/22 2104 | 192.58.41.0/24 2105 | 192.58.42.0/23 2106 | 192.58.44.0/22 2107 | 192.58.48.0/20 2108 | 192.58.64.0/20 2109 | 192.58.80.0/21 2110 | 192.58.88.0/23 2111 | 192.64.100.0/22 2112 | 192.64.125.0/24 2113 | 192.64.202.0/24 2114 | 192.64.28.0/24 2115 | 192.64.44.0/23 2116 | 192.65.131.0/24 2117 | 192.65.132.0/24 2118 | 192.65.139.0/24 2119 | 192.65.144.0/23 2120 | 192.65.146.0/24 2121 | 192.65.153.0/24 2122 | 192.65.183.0/24 2123 | 192.65.184.0/21 2124 | 192.65.192.0/22 2125 | 192.65.196.0/23 2126 | 192.65.219.0/24 2127 | 192.65.220.0/22 2128 | 192.65.224.0/22 2129 | 192.65.228.0/24 2130 | 192.65.51.0/24 2131 | 192.65.52.0/22 2132 | 192.65.56.0/21 2133 | 192.65.64.0/22 2134 | 192.65.68.0/23 2135 | 192.65.70.0/24 2136 | 192.65.92.0/23 2137 | 192.65.94.0/24 2138 | 192.65.96.0/24 2139 | 192.66.0.0/16 2140 | 192.67.100.0/22 2141 | 192.67.104.0/24 2142 | 192.67.135.0/24 2143 | 192.67.167.0/24 2144 | 192.67.170.0/24 2145 | 192.67.189.0/24 2146 | 192.67.190.0/23 2147 | 192.67.192.0/20 2148 | 192.67.208.0/24 2149 | 192.67.218.0/24 2150 | 192.67.220.0/23 2151 | 192.67.223.0/24 2152 | 192.67.249.0/24 2153 | 192.67.3.0/24 2154 | 192.67.39.0/24 2155 | 192.67.4.0/24 2156 | 192.67.43.0/24 2157 | 192.67.47.0/24 2158 | 192.67.50.0/24 2159 | 192.67.52.0/24 2160 | 192.67.55.0/24 2161 | 192.67.58.0/24 2162 | 192.67.76.0/24 2163 | 192.67.79.0/24 2164 | 192.67.87.0/24 2165 | 192.67.94.0/24 2166 | 192.68.0.0/20 2167 | 192.68.104.0/22 2168 | 192.68.151.0/24 2169 | 192.68.152.0/23 2170 | 192.68.16.0/22 2171 | 192.68.165.0/24 2172 | 192.68.166.0/23 2173 | 192.68.168.0/23 2174 | 192.68.170.0/24 2175 | 192.68.174.0/24 2176 | 192.68.176.0/24 2177 | 192.68.182.0/24 2178 | 192.68.186.0/24 2179 | 192.68.209.0/24 2180 | 192.68.211.0/24 2181 | 192.68.212.0/22 2182 | 192.68.216.0/24 2183 | 192.68.221.0/24 2184 | 192.68.224.0/24 2185 | 192.68.23.0/24 2186 | 192.68.230.0/24 2187 | 192.68.250.0/23 2188 | 192.68.252.0/24 2189 | 192.68.254.0/24 2190 | 192.68.31.0/24 2191 | 192.68.32.0/20 2192 | 192.68.48.0/22 2193 | 192.68.76.0/22 2194 | 192.68.80.0/20 2195 | 192.68.96.0/21 2196 | 192.70.0.0/18 2197 | 192.70.112.0/21 2198 | 192.70.133.0/24 2199 | 192.70.134.0/24 2200 | 192.70.136.0/24 2201 | 192.70.140.0/22 2202 | 192.70.144.0/20 2203 | 192.70.242.0/24 2204 | 192.70.64.0/19 2205 | 192.70.96.0/20 2206 | 192.71.0.0/16 2207 | 192.73.19.0/24 2208 | 192.73.20.0/24 2209 | 192.73.226.0/24 2210 | 192.73.229.0/24 2211 | 192.73.34.0/23 2212 | 192.73.36.0/22 2213 | 192.73.40.0/22 2214 | 192.73.44.0/24 2215 | 192.76.123.0/24 2216 | 192.76.124.0/22 2217 | 192.76.128.0/22 2218 | 192.76.132.0/24 2219 | 192.76.134.0/23 2220 | 192.76.136.0/21 2221 | 192.76.144.0/20 2222 | 192.76.16.0/20 2223 | 192.76.160.0/21 2224 | 192.76.168.0/22 2225 | 192.76.172.0/24 2226 | 192.76.176.0/24 2227 | 192.76.241.0/24 2228 | 192.76.242.0/23 2229 | 192.76.244.0/22 2230 | 192.76.248.0/24 2231 | 192.76.32.0/22 2232 | 192.76.6.0/23 2233 | 192.76.8.0/21 2234 | 192.77.11.0/24 2235 | 192.77.114.0/23 2236 | 192.77.120.0/22 2237 | 192.77.132.0/22 2238 | 192.77.136.0/23 2239 | 192.77.138.0/24 2240 | 192.77.140.0/23 2241 | 192.80.20.0/23 2242 | 192.80.31.0/24 2243 | 192.80.32.0/21 2244 | 192.80.40.0/23 2245 | 192.80.42.0/24 2246 | 192.80.46.0/24 2247 | 192.80.51.0/24 2248 | 192.81.109.0/24 2249 | 192.81.121.0/24 2250 | 192.81.123.0/24 2251 | 192.81.160.0/24 2252 | 192.81.182.0/23 2253 | 192.81.184.0/24 2254 | 192.81.194.0/24 2255 | 192.81.230.0/24 2256 | 192.81.234.0/24 2257 | 192.81.59.0/24 2258 | 192.81.61.0/24 2259 | 192.81.62.0/24 2260 | 192.82.121.0/24 2261 | 192.82.124.0/24 2262 | 192.82.127.0/24 2263 | 192.82.153.0/24 2264 | 192.82.157.0/24 2265 | 192.82.158.0/24 2266 | 192.82.214.0/24 2267 | 192.82.220.0/23 2268 | 192.82.241.0/24 2269 | 192.83.0.0/18 2270 | 192.83.100.0/24 2271 | 192.83.102.0/24 2272 | 192.83.160.0/24 2273 | 192.83.165.0/24 2274 | 192.83.200.0/24 2275 | 192.83.202.0/24 2276 | 192.83.223.0/24 2277 | 192.83.229.0/24 2278 | 192.83.64.0/19 2279 | 192.83.96.0/22 2280 | 192.84.101.0/24 2281 | 192.84.102.0/23 2282 | 192.84.104.0/22 2283 | 192.84.108.0/23 2284 | 192.84.127.0/24 2285 | 192.84.128.0/20 2286 | 192.84.13.0/24 2287 | 192.84.144.0/21 2288 | 192.84.15.0/24 2289 | 192.84.152.0/22 2290 | 192.84.156.0/24 2291 | 192.84.166.0/24 2292 | 192.84.173.0/24 2293 | 192.84.176.0/20 2294 | 192.84.192.0/20 2295 | 192.84.212.0/24 2296 | 192.84.220.0/23 2297 | 192.84.226.0/23 2298 | 192.84.228.0/23 2299 | 192.84.245.0/24 2300 | 192.84.246.0/23 2301 | 192.84.27.0/24 2302 | 192.84.30.0/24 2303 | 192.84.32.0/23 2304 | 192.84.5.0/24 2305 | 192.84.62.0/24 2306 | 192.84.75.0/24 2307 | 192.84.76.0/22 2308 | 192.84.80.0/22 2309 | 192.84.84.0/24 2310 | 192.84.87.0/24 2311 | 192.84.90.0/23 2312 | 192.84.92.0/22 2313 | 192.84.96.0/22 2314 | 192.86.11.0/24 2315 | 192.86.125.0/24 2316 | 192.86.126.0/23 2317 | 192.86.134.0/24 2318 | 192.86.137.0/24 2319 | 192.86.138.0/24 2320 | 192.86.14.0/24 2321 | 192.86.163.0/24 2322 | 192.86.166.0/23 2323 | 192.86.169.0/24 2324 | 192.86.18.0/24 2325 | 192.86.25.0/24 2326 | 192.86.254.0/24 2327 | 192.86.27.0/24 2328 | 192.86.89.0/24 2329 | 192.87.0.0/16 2330 | 192.88.1.0/24 2331 | 192.88.10.0/24 2332 | 192.88.108.0/24 2333 | 192.88.118.0/24 2334 | 192.88.123.0/24 2335 | 192.88.128.0/24 2336 | 192.88.130.0/24 2337 | 192.88.133.0/24 2338 | 192.88.17.0/24 2339 | 192.88.196.0/24 2340 | 192.88.204.0/24 2341 | 192.88.23.0/24 2342 | 192.88.238.0/23 2343 | 192.88.24.0/24 2344 | 192.88.250.0/23 2345 | 192.88.252.0/23 2346 | 192.88.254.0/24 2347 | 192.88.4.0/24 2348 | 192.88.83.0/24 2349 | 192.88.84.0/24 2350 | 192.88.86.0/24 2351 | 192.88.9.0/24 2352 | 192.88.97.0/24 2353 | 192.88.98.0/24 2354 | 192.89.0.0/16 2355 | 192.91.140.0/23 2356 | 192.91.177.0/24 2357 | 192.91.186.0/24 2358 | 192.91.189.0/24 2359 | 192.91.191.0/24 2360 | 192.91.199.0/24 2361 | 192.91.201.0/24 2362 | 192.91.211.0/24 2363 | 192.91.214.0/23 2364 | 192.91.216.0/21 2365 | 192.91.224.0/21 2366 | 192.91.232.0/23 2367 | 192.91.236.0/22 2368 | 192.91.240.0/21 2369 | 192.92.104.0/23 2370 | 192.92.106.0/24 2371 | 192.92.108.0/23 2372 | 192.92.116.0/24 2373 | 192.92.125.0/24 2374 | 192.92.126.0/23 2375 | 192.92.128.0/21 2376 | 192.92.136.0/22 2377 | 192.92.141.0/24 2378 | 192.92.142.0/23 2379 | 192.92.144.0/21 2380 | 192.92.152.0/23 2381 | 192.92.155.0/24 2382 | 192.92.156.0/24 2383 | 192.92.216.0/24 2384 | 192.92.86.0/24 2385 | 192.92.94.0/24 2386 | 192.93.0.0/16 2387 | 192.94.111.0/24 2388 | 192.94.112.0/22 2389 | 192.94.116.0/23 2390 | 192.94.156.0/22 2391 | 192.94.160.0/22 2392 | 192.94.172.0/24 2393 | 192.94.175.0/24 2394 | 192.94.176.0/20 2395 | 192.94.192.0/21 2396 | 192.94.212.0/24 2397 | 192.94.221.0/24 2398 | 192.94.226.0/24 2399 | 192.94.233.0/24 2400 | 192.94.235.0/24 2401 | 192.94.239.0/24 2402 | 192.94.24.0/24 2403 | 192.94.28.0/24 2404 | 192.94.57.0/24 2405 | 192.94.58.0/24 2406 | 192.94.67.0/24 2407 | 192.94.68.0/24 2408 | 192.94.76.0/24 2409 | 192.98.0.0/16 2410 | 193.0.0.0/8 2411 | 194.0.0.0/7 2412 | 196.1.3.0/24 2413 | 196.1.5.0/24 2414 | 196.1.6.0/24 2415 | 196.1.64.0/22 2416 | 196.1.69.0/24 2417 | 196.1.70.0/24 2418 | 196.15.32.0/19 2419 | 196.2.4.0/22 2420 | 196.3.66.0/23 2421 | 196.3.68.0/22 2422 | 196.3.91.0/24 2423 | 198.11.0.0/22 2424 | 198.133.140.0/24 2425 | 198.133.226.0/24 2426 | 198.133.80.0/22 2427 | 198.133.84.0/23 2428 | 198.135.137.0/24 2429 | 198.135.138.0/24 2430 | 198.135.167.0/24 2431 | 198.147.160.0/24 2432 | 198.148.177.0/24 2433 | 198.148.178.0/24 2434 | 198.17.117.0/24 2435 | 198.17.180.0/23 2436 | 198.17.182.0/24 2437 | 198.17.77.0/24 2438 | 198.206.197.0/24 2439 | 198.206.200.0/23 2440 | 198.206.202.0/24 2441 | 198.22.51.0/24 2442 | 198.22.93.0/24 2443 | 198.22.94.0/23 2444 | 198.22.96.0/23 2445 | 198.240.128.0/17 2446 | 198.36.32.0/21 2447 | 198.36.40.0/22 2448 | 198.36.44.0/23 2449 | 198.36.46.0/24 2450 | 198.51.12.0/24 2451 | 198.51.143.0/24 2452 | 198.51.144.0/23 2453 | 198.51.146.0/24 2454 | 198.99.148.0/24 2455 | 198.99.222.0/24 2456 | 199.43.246.0/23 2457 | 199.53.0.0/16 2458 | 199.91.16.0/20 2459 | 212.0.0.0/7 2460 | 217.0.0.0/8 2461 | 2001:600::/23 2462 | 2001:800::/22 2463 | 2001:1400::/22 2464 | 2001:1a00::/23 2465 | 2001:1c00::/22 2466 | 2001:2000::/20 2467 | 2001:3000::/21 2468 | 2001:3800::/22 2469 | 2001:4000::/23 2470 | 2001:4600::/23 2471 | 2001:4800::/22 2472 | 2001:4c00::/23 2473 | 2001:5000::/20 2474 | 2003::/18 2475 | 2a00::/12 2476 | -------------------------------------------------------------------------------- /data/schema.sql: -------------------------------------------------------------------------------- 1 | -- Database scheme for IRRExplorer 2 | -- Tied to PostgreSQL due to use of cidr type and gist indexing, 3 | -- to effeciently query routes. 4 | -- 5 | -- Requires PostgreSQL 9.4 (gist indexing of cidr/inet) 6 | 7 | 8 | CREATE TABLE sources ( 9 | id serial NOT NULL PRIMARY KEY, 10 | name text UNIQUE NOT NULL, 11 | last_seen_serial integer 12 | ); 13 | 14 | CREATE TABLE managed_routes ( 15 | route cidr NOT NULL, 16 | source_id integer NOT NULL REFERENCES sources(id) 17 | ); 18 | 19 | 20 | CREATE VIEW managed_routes_view AS 21 | SELECT 22 | route, name AS source 23 | FROM 24 | managed_routes LEFT OUTER JOIN sources ON (managed_routes.source_id = sources.id); 25 | 26 | 27 | -- consider expanding this with start/end timestamp later 28 | CREATE TABLE routes ( 29 | route cidr NOT NULL, 30 | asn bigint NOT NULL, 31 | source_id integer NOT NULL REFERENCES sources(id), 32 | 33 | -- The unique constraint may not be the best from an efficiancy point of view, 34 | -- but having duplicates is likely to cause weird results 35 | CONSTRAINT unique_entry UNIQUE (route, asn, source_id), 36 | CONSTRAINT positive_asn CHECK (asn >= 0) 37 | ); 38 | 39 | -- CREATE INDEX route_gist ON routes USING gist (route inet_ops); 40 | 41 | -- Index for routes. This performs a lot better than the inet_ops gist index 42 | 43 | CREATE TYPE inetrange AS range (subtype = inet); 44 | 45 | CREATE FUNCTION cidr_to_range(cidr) returns inetrange language sql AS 'select inetrange(set_masklen($1::inet, 0), set_masklen(broadcast($1), 0))'; 46 | 47 | CREATE INDEX ON routes USING gist ((cidr_to_range(route))); 48 | 49 | 50 | CREATE VIEW routes_view AS 51 | SELECT 52 | route, asn, name AS source 53 | FROM routes LEFT OUTER JOIN sources ON (routes.source_id = sources.id); 54 | 55 | 56 | CREATE TABLE as_sets ( 57 | as_macro text NOT NULL, 58 | members text[] NOT NULL, 59 | source_id integer NOT NULL REFERENCES sources(id), 60 | 61 | CONSTRAINT unique_macro_source UNIQUE (as_macro, source_id) 62 | ); 63 | 64 | 65 | CREATE VIEW as_sets_view AS 66 | SELECT 67 | as_macro, members, name AS source 68 | FROM as_sets LEFT OUTER JOIN sources ON (as_sets.source_id = sources.id); 69 | 70 | 71 | 72 | CREATE OR REPLACE FUNCTION create_managed_route ( 73 | in_route cidr, 74 | in_source varchar 75 | ) 76 | RETURNS integer AS $inserted$ 77 | 78 | DECLARE 79 | source_id integer; 80 | result integer; 81 | BEGIN 82 | -- check if we have source, create if not 83 | SELECT sources.id INTO source_id FROM sources WHERE name = in_source; 84 | IF NOT FOUND THEN 85 | INSERT INTO sources (name) VALUES (in_source) RETURNING id INTO source_id; 86 | END IF; 87 | 88 | INSERT INTO managed_routes (route, source_id) VALUES (in_route, source_id); 89 | 90 | result = 1; 91 | return result; 92 | END; 93 | $inserted$ 94 | LANGUAGE plpgsql; 95 | 96 | 97 | CREATE OR REPLACE FUNCTION create_route ( 98 | in_route cidr, 99 | in_asn bigint, 100 | in_source varchar 101 | ) 102 | RETURNS integer AS $inserted$ 103 | 104 | DECLARE 105 | source_id integer; 106 | result integer; 107 | BEGIN 108 | -- check if we have source, create if not 109 | SELECT sources.id INTO source_id FROM sources WHERE name = in_source; 110 | IF NOT FOUND THEN 111 | INSERT INTO sources (name) VALUES (in_source) RETURNING id INTO source_id; 112 | END IF; 113 | 114 | INSERT INTO routes (route, asn, source_id) VALUES (in_route, in_asn, source_id) 115 | ON CONFLICT DO NOTHING; 116 | 117 | result = 1; 118 | return result; 119 | END; 120 | $inserted$ 121 | LANGUAGE plpgsql; 122 | 123 | 124 | 125 | CREATE OR REPLACE FUNCTION create_as_set ( 126 | in_as_macro text, 127 | in_members text[], 128 | in_source varchar 129 | ) 130 | RETURNS integer AS $inserted$ 131 | 132 | DECLARE 133 | source_id integer; 134 | result integer; 135 | BEGIN 136 | -- check if we have source, create if not 137 | SELECT sources.id INTO source_id FROM sources WHERE name = in_source; 138 | IF NOT FOUND THEN 139 | INSERT INTO sources (name) VALUES (in_source) RETURNING id INTO source_id; 140 | END IF; 141 | 142 | INSERT INTO as_sets (as_macro, members, source_id) VALUES (in_as_macro, in_members, source_id) 143 | ON CONFLICT ON CONSTRAINT unique_macro_source DO UPDATE SET members = in_members; 144 | 145 | result = 1; 146 | return result; 147 | END; 148 | $inserted$ 149 | LANGUAGE plpgsql; 150 | 151 | -------------------------------------------------------------------------------- /db/README: -------------------------------------------------------------------------------- 1 | How to setup to initally setup postgres and load data into it. 2 | 3 | From the db directory, run 4 | 5 | ./boostrap 6 | 7 | And that should be it :-) 8 | 9 | Copy ../irrexplorer_config.yml.dist to ../irrexplorer_config.yml and fill it with the sources you want first though. 10 | 11 | Read bootstrap if you are interested in the details :-) 12 | 13 | -------------------------------------------------------------------------------- /db/bootstrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -ev 4 | 5 | # Bootstrap script for IRRExplorer PostgreSQL database 6 | 7 | # Create database 8 | echo "Please input sudo password to create irrexplorer database (or do it manually)" 9 | #sudo su - postgres -c "createdb irrexplorer" 10 | psql irrexplorer -f ../data/schema.sql 11 | 12 | 13 | # Fetch irr databases 14 | ./fetch ../irrexplorer_config.yml 15 | 16 | # Create sources 17 | for x in *.db*.gz ; do echo $x|cut -f1 -d'.' ;done|sort|uniq| ./create_source > sources.sql 18 | echo "bgp" | ./create_source >> sources.sql 19 | 20 | # Insert sources and create map 21 | psql irrexplorer -f sources.sql 22 | psql irrexplorer -c "select name,id from sources;" -tAF, > sources.map 23 | 24 | # Create routes and as-set data files, filter double repeated routes 25 | # zcatting and processing this twice is sorta silly 26 | zcat *.db*.gz | ./create_irr_routes | uniq -u > irr_routes.data 27 | zcat *.db*.gz | ./create_irr_as_sets > irr_as_sets.data 28 | 29 | # BGP route table dump 30 | curl http://lg01.infra.ring.nlnog.net/table.txt | ./create_bgp > bgp.data 31 | 32 | # Create serial 33 | ./create_serials > serials.sql 34 | 35 | # And the ripe managed space 36 | ./create_managed ripe < ../data/ripe-managed-space.txt > ripe_managed.sql 37 | 38 | # RFC managed / reserved ip space 39 | ./create_managed < ../data/rfc-managed.txt > rfc_managed.sql 40 | 41 | # Load data in postgres 42 | 43 | psql irrexplorer -f ripe_managed.sql 44 | psql irrexplorer -f rfc_managed.sql 45 | psql irrexplorer -f serials.sql 46 | 47 | psql irrexplorer -c "\copy routes from irr_routes.data delimiter '|'" 48 | psql irrexplorer -c "\copy as_sets from irr_as_sets.data delimiter '|'" 49 | psql irrexplorer -c "\copy routes from bgp.data delimiter '|'" 50 | 51 | rm *.gz *.CURRENTSERIAL 52 | -------------------------------------------------------------------------------- /db/create_bgp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import sources 5 | 6 | bgp_id = sources.getSourceMap()['bgp'] 7 | 8 | 9 | def main(): 10 | 11 | for line in sys.stdin: 12 | 13 | route, origin = line.strip().split(' ',1) 14 | print '%s|%s|%s' % (route, origin, bgp_id) 15 | 16 | 17 | if __name__ == '__main__': 18 | main() 19 | 20 | -------------------------------------------------------------------------------- /db/create_irr_as_sets: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import fileinput 4 | import sys 5 | 6 | 7 | def main(): 8 | 9 | import irrparser 10 | 11 | sources = {} 12 | for line in open('sources.map').readlines(): 13 | source, id_ = line.strip().split(',') 14 | sources[source] = id_ 15 | 16 | object_data = [] 17 | for line in fileinput.input(): 18 | if not line == '\n': 19 | object_data.append(line) 20 | else: 21 | obj, values = irrparser.irrParser(object_data) 22 | object_data = [] 23 | 24 | if obj == irrparser.AS_SET: 25 | members = '{' + ','.join(values[1]) + '}' 26 | 27 | source = sources.get(values[2]) 28 | if source is None: 29 | print >> sys.stderr, 'No source for object: ', values[0], members 30 | continue 31 | 32 | fields = (values[0], members, source ) 33 | print '|'.join(fields) 34 | 35 | 36 | if __name__ == '__main__': 37 | sys.path.insert(0, '../irrexplorer') # hack on :-) 38 | main() 39 | -------------------------------------------------------------------------------- /db/create_irr_routes: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import fileinput 4 | import sys 5 | import ipaddr 6 | 7 | 8 | def main(): 9 | 10 | import irrparser 11 | 12 | sources = {} 13 | for line in open('sources.map').readlines(): 14 | source, id_ = line.strip().split(',') 15 | sources[source] = id_ 16 | 17 | object_data = [] 18 | for line in fileinput.input(): 19 | if not line == '\n': 20 | object_data.append(line) 21 | else: 22 | obj, values = irrparser.irrParser(object_data) 23 | object_data = [] 24 | 25 | if obj == irrparser.ROUTE: 26 | try: 27 | ipaddr.IPNetwork(values[0], strict=True) 28 | except ValueError as e: 29 | if 'does not appear to be' in str(e): 30 | pass # usually leading zero in v4 octets, we can handle those 31 | else: 32 | print >> sys.stderr, str(e), 'source: ', values[2] 33 | continue 34 | 35 | source = sources.get(values[2]) 36 | if source is None: 37 | print >> sys.stderr, 'No source for object: ', values[0], values[1] 38 | continue 39 | 40 | fields = ( values[0], str(values[1]), source ) 41 | print '|'.join(fields) 42 | 43 | 44 | if __name__ == '__main__': 45 | sys.path.insert(0, '../irrexplorer') # hack on :-) 46 | main() 47 | -------------------------------------------------------------------------------- /db/create_managed: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | INSERT = "SELECT create_managed_route ('%s', '%s');" 6 | 7 | default_source = sys.argv[1] if len(sys.argv) >= 2 else None 8 | 9 | print 'BEGIN;' 10 | for line in sys.stdin: 11 | 12 | line = line.strip() 13 | if ' ' in line: 14 | prefix, source = line.strip().split(' ',1) 15 | source = source.strip() or default_source 16 | else: 17 | prefix = line 18 | source = default_source 19 | 20 | print INSERT % (prefix, source) 21 | 22 | print 'COMMIT;' 23 | 24 | -------------------------------------------------------------------------------- /db/create_serials: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | 6 | UPDATE_SERIAL = "UPDATE sources SET last_seen_serial = %s WHERE sources.name = '%s';" 7 | 8 | 9 | for file_ in os.listdir(os.getcwd()): 10 | 11 | if file_.endswith('.CURRENTSERIAL'): 12 | 13 | serial = open(file_).read().strip() 14 | source = file_.split('.')[0].lower() 15 | 16 | print UPDATE_SERIAL % (serial, source) 17 | 18 | -------------------------------------------------------------------------------- /db/create_source: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | 6 | CREATE_SOURCE = "INSERT INTO sources (name) VALUES ('%s');" 7 | 8 | 9 | for line in sys.stdin.readlines(): 10 | print CREATE_SOURCE % line.strip() 11 | 12 | -------------------------------------------------------------------------------- /db/fetch: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Tool to fetch databases from irrexplorer yaml config file 4 | 5 | import sys 6 | import subprocess 7 | import yaml 8 | 9 | def fetch(url): 10 | file_name = url.split('/')[-1] 11 | print 'Fetching %s --> %s' % (url, file_name) 12 | args = ['wget', '-4', '-q', '-O', file_name, url] 13 | wget = subprocess.Popen(args) 14 | wget.wait() 15 | 16 | def main(): 17 | 18 | if len(sys.argv) == 1: 19 | print 'No argument(s) given' 20 | print 'Usage: ./fetch < yaml_config_file > [ database ]' 21 | sys.exit(1) 22 | 23 | yml_cfg = sys.argv[1] 24 | cfg = yaml.load(open(yml_cfg)) 25 | 26 | if not 'databases' in cfg: 27 | print 'No database in %s' % yml_cfg 28 | sys.exit(2) 29 | 30 | for db in cfg['databases']: 31 | for db_name, db_info in db.items(): 32 | if len(sys.argv) == 3: 33 | if not db_name == sys.argv[2]: 34 | continue 35 | for dbe in db_info: 36 | for dbk, dbv in dbe.items(): 37 | if dbk in ('serial', 'dump'): 38 | if isinstance(dbv, list): 39 | for i in dbv: 40 | fetch(i) 41 | else: 42 | fetch(dbv) 43 | 44 | 45 | if __name__ == '__main__': 46 | main() 47 | -------------------------------------------------------------------------------- /db/refresh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -evx 4 | 5 | # Fetch irr databases 6 | ./fetch ../irrexplorer_config.yml $1 7 | 8 | # Insert sources and create map 9 | psql irrexplorer -c "select name,id from sources where name = '$1';" -tAF, > sources.map 10 | 11 | # Create routes and as-set data files, filter double repeated routes 12 | # zcatting and processing this twice is sorta silly 13 | zcat *.db*.gz | tee >(./create_irr_routes | sort -u > irr_routes.data) | ./create_irr_as_sets > irr_as_sets.data 14 | 15 | # Create serial 16 | ./create_serials > serials.sql 17 | 18 | # Load data in postgres 19 | psql irrexplorer -f serials.sql 20 | 21 | set +e 22 | psql irrexplorer -c "DELETE FROM routes USING sources WHERE routes.source_id = sources.id AND sources.name = '$1';" 23 | psql irrexplorer -c "DELETE FROM as_sets USING sources WHERE as_sets.source_id = sources.id AND sources.name = '$1';" 24 | 25 | psql irrexplorer -c "\copy routes from irr_routes.data delimiter '|'" 26 | psql irrexplorer -c "\copy as_sets from irr_as_sets.data delimiter '|'" 27 | 28 | set -e 29 | 30 | rm -fv *.gz *.CURRENTSERIAL 31 | -------------------------------------------------------------------------------- /db/refresh_ripe_managed: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -ev 4 | 5 | source_id=$(psql irrexplorer -c "select id from sources where name = 'ripe';" -tAF,) 6 | 7 | ../fetch_ripe_managed.py | sed "s/$/|${source_id}/" > ripe_managed.data 8 | 9 | psql irrexplorer -c "DELETE FROM managed_routes WHERE source_id = '${source_id}';" 10 | psql irrexplorer -c "\copy managed_routes from ripe_managed.data delimiter '|'" 11 | rm ripe_managed.data 12 | -------------------------------------------------------------------------------- /db/sources.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | def getSourceMap(): 4 | 5 | sources = {} 6 | for line in open('sources.map').readlines(): 7 | source, id_ = line.strip().split(',') 8 | sources[source] = id_ 9 | 10 | return sources 11 | 12 | 13 | if __name__ == '__main__': 14 | for k,v in getSourceMap().items(): 15 | print k,v 16 | 17 | -------------------------------------------------------------------------------- /docs/irrexplorer-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/job/irrexplorer/0af6f13b6b81d6dc66e8a1015ec428773d08c17d/docs/irrexplorer-logo.png -------------------------------------------------------------------------------- /exabgp.conf: -------------------------------------------------------------------------------- 1 | neighbor 165.254.255.1 { 2 | description "full feed"; 3 | router-id 192.168.127.1; 4 | local-address 37.77.58.22; 5 | local-as 15562; 6 | peer-as 15562; 7 | graceful-restart; 8 | process testlockdown { 9 | encoder json; 10 | run /usr/local/bin/socat stdin unix-listen:/tmp/exabgp; 11 | receive-routes; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fetch_ripe_managed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Job Snijders 4 | 5 | from aggregate6 import aggregate 6 | 7 | import ipaddress 8 | import requests 9 | import sys 10 | 11 | ripe_url = "http://ftp.ripe.net/ripe/stats/delegated-ripencc-latest" 12 | 13 | r = requests.get(ripe_url) 14 | 15 | pfx_list = [] 16 | 17 | for entry in str(r.text).split('\n'): 18 | if not entry: 19 | continue 20 | try: 21 | afi, start_ip, count = entry.split('|')[2:5] 22 | except ValueError as e: 23 | print(entry) 24 | sys.exit(1) 25 | ip_type = entry.split('|')[-1] 26 | if not ip_type in ["allocated", "assigned"]: 27 | continue 28 | if afi == "ipv4": 29 | first_ip = ipaddress.ip_address(start_ip) 30 | last = int(first_ip) + int(count) - 1 31 | last_ip = ipaddress.ip_address(last) 32 | cidrs = ipaddress.summarize_address_range(first_ip, last_ip) 33 | for prefix in cidrs: 34 | pfx_list.append(str(prefix)) 35 | if afi == "ipv6": 36 | pfx_list.append(("{}/{}".format(start_ip, count))) 37 | 38 | for prefix in aggregate(pfx_list): 39 | print(prefix) 40 | -------------------------------------------------------------------------------- /irrexplorer/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.0.5" 2 | __author__ = "Job Snijders, Peter van Dijk" 3 | __author_email__ = "job@instituut.net" 4 | __copyright__ = "Copyright 2015, Job Snijders & Peter van Dijk" 5 | __license__ = "BSD 2-Clause" 6 | __status__ = "Development" 7 | __url__ = "https://github.com/job/irrexplorer" 8 | 9 | -------------------------------------------------------------------------------- /irrexplorer/bgpupdate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Functionality to update BGP entries in IRRExplorer database. 5 | """ 6 | 7 | import urllib2 8 | import ipaddr 9 | import logging 10 | 11 | INSERT_STM = "SELECT create_route (%s, %s, 'bgp');" 12 | DELETE_STM = "DELETE FROM routes USING sources WHERE routes.route = %s AND routes.asn = %s AND routes.source_id = sources.id AND sources.name = 'bgp';" 13 | 14 | 15 | def updateBGP(source_url, db): 16 | 17 | logging.info('Updating BGP information') 18 | 19 | source_routes = set() 20 | 21 | # get the bgp routes 22 | for line in urllib2.urlopen(source_url): 23 | route, asn = line.strip().split(' ') 24 | source_routes.add( (route, int(asn)) ) 25 | 26 | fltrd_source_routes = set() 27 | for route, asn in source_routes: 28 | try: 29 | route_obj = ipaddr.IPNetwork(route) 30 | except ValueError: 31 | logging.error('Invalid route in BGP feed: %s' % route) 32 | continue 33 | 34 | # block router2router linknets / small blocks 35 | if route_obj.version == 4 and route_obj.prefixlen >= 29: 36 | continue 37 | if route_obj.version == 6 and route_obj.prefixlen >= 124: 38 | continue 39 | 40 | fltrd_source_routes.add((route, int(asn))) 41 | 42 | logging.info('BGP table fetched and table build, %i routes' % (len(source_routes))) 43 | 44 | # then the database routes 45 | db_routes = set() 46 | bgp_rows = db.query_source('bgp') 47 | logging.info('Got database entries, %i routes' % len(bgp_rows)) 48 | 49 | for route, asn in bgp_rows: 50 | db_routes.add((route, int(asn))) 51 | 52 | # calculate the diff, intersection is just for logging 53 | routes_is = fltrd_source_routes & db_routes 54 | deprecated_routes = db_routes - fltrd_source_routes 55 | new_routes = fltrd_source_routes - db_routes 56 | 57 | logging.info('Routes: %i unchanged / %i deprecated / %i new' % (len(routes_is), len(deprecated_routes), len(new_routes))) 58 | 59 | # create + send update statements 60 | cur = db._get_cursor() 61 | 62 | for route, asn in deprecated_routes: 63 | cur.execute(DELETE_STM, (route, asn) ) 64 | 65 | for route, asn in new_routes: 66 | cur.execute(INSERT_STM, (route, asn) ) 67 | 68 | db.conn.commit() 69 | cur.close() # so it doesn't linger while sleeping 70 | 71 | logging.info('BPG update commit done and cursor closed') 72 | 73 | 74 | -------------------------------------------------------------------------------- /irrexplorer/irrparser.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Job Snijders 2 | # Copyright (C) 2015 NORDUnet A/S 3 | # 4 | # This file is part of IRR Explorer 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, 10 | # this list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | # POSSIBILITY OF SUCH DAMAGE. 27 | 28 | 29 | 30 | AS_SET = 'as-set' 31 | ROUTE = 'route' 32 | 33 | 34 | def readAttr(line): 35 | sp = line.split(':',1)[1] 36 | if '#' in sp: 37 | sp = sp.split('#',1)[0] 38 | return sp.strip() 39 | 40 | 41 | def convertASDot(origin): 42 | if '.' in origin: 43 | high, low = map(int, origin.split('.')) 44 | origin = (high << 16) + low 45 | return origin 46 | 47 | 48 | def irrParser(datasource): 49 | 50 | obj_type = None 51 | object_ = None 52 | origin = None 53 | source = None 54 | members = [] 55 | 56 | for line in datasource: 57 | 58 | if line.startswith('route:') or line.startswith('route6:'): 59 | object_ = readAttr(line) 60 | obj_type = ROUTE 61 | ctx = None 62 | 63 | elif line.startswith('as-set:'): 64 | object_ = readAttr(line).upper() 65 | obj_type = AS_SET 66 | ctx = None 67 | 68 | elif line.startswith('origin:'): 69 | origin = readAttr(line)[2:] 70 | origin = convertASDot(origin) 71 | origin = int(origin) 72 | ctx = None 73 | 74 | elif line.startswith('source:'): 75 | source = readAttr(line).lower() 76 | ctx = None 77 | 78 | elif line.startswith('members:'): 79 | members += [ m.strip() for m in readAttr(line).split(',') if m.strip() ] 80 | ctx = members 81 | 82 | elif line.startswith((' ','\t')) and ctx: 83 | ctx += [ m.strip() for m in line.split(',') if m.strip() ] 84 | 85 | else: 86 | ctx = None 87 | 88 | if obj_type == AS_SET: 89 | return AS_SET, (object_, members, source) 90 | elif obj_type == ROUTE: 91 | return ROUTE, (object_, origin, source) 92 | else: # in case no route{,6} or as-set was found 93 | return None, None 94 | -------------------------------------------------------------------------------- /irrexplorer/irrtest.data: -------------------------------------------------------------------------------- 1 | route: 207.72.0.0/14 2 | descr: MERIT Network Inc. 3 | 1000 Oakbrook Drive, Suite 200 4 | Ann Arbor 5 | MI 48104, USA 6 | origin: AS237 7 | mnt-by: MAINT-AS237 8 | changed: rik@merit.edu 20050922 9 | source: RADB 10 | 11 | as-set: AS-test1 12 | descr: Stub ASs for ClubNET 13 | members: AS5726, AS5736, AS20318 14 | admin-c: DG251 15 | tech-c: PC41 16 | notify: route@ns.clubnet.net 17 | mnt-by: MAINT-AS5736-ALTDB 18 | changed: pete@altadena.net 20010713 19 | source: ALTDB 20 | 21 | person: Job Snijders 22 | address: Theodorus Majofskistraat 100 23 | address: 1065 SZ Amsterdam 24 | address: The Netherlands 25 | remarks: PGP key is PGPKEY-7E5BEC10 26 | phone: +31-6-54942365 27 | nic-hdl: JWJS1-RIPE 28 | mnt-by: SNIJDERS-MNT 29 | source: RIPE # Filtered 30 | 31 | as-set: AS-test2 32 | descr: Stub ASs for ClubNET 33 | members: AS5726 34 | members: AS5736, AS20318 35 | admin-c: DG251 36 | tech-c: PC41 37 | notify: route@ns.clubnet.net 38 | mnt-by: MAINT-AS5736-ALTDB 39 | changed: pete@altadena.net 20010713 40 | source: ALTDB 41 | 42 | as-set: AS-test3 43 | descr: Stub ASs for ClubNET 44 | members: AS5726 45 | members: AS5736, AS20318 # herpa 46 | admin-c: DG251 47 | tech-c: PC41 48 | notify: route@ns.clubnet.net 49 | mnt-by: MAINT-AS5736-ALTDB 50 | changed: pete@altadena.net 20010713 51 | source: ALTDB 52 | 53 | as-set: AS-PACIFIC-INTERNET-IX 54 | descr: Pacific Internet Malaysia 55 | c/o 89 Science Park Drive 56 | #02-05/06 Rutherford 57 | Singapore 118261 58 | Republic of Singapore 59 | Tel: +65-6872-1010 60 | Fax: +65-6872-1011 61 | members: AS4628, AS4629 62 | remarks: Peering with AS4628 and AS4629 63 | Email abuse@pacific.net.sg for security issues 64 | Email noc@pacific.net.sg for network issues 65 | admin-c: WH1-AP 66 | tech-c: WH1-AP 67 | notify: noc@pacific.net.sg 68 | mnt-by: MAINT-AS9904 69 | changed: hoou@pacific.net.sg 20020328 70 | source: ALTDB 71 | 72 | as-set: AS-NIXC 73 | descr: ASNs announced by NIXC. 74 | members: AS-NIXC-BACKBONE, AS-NIXC-CUSTOMERS 75 | admin-c: Darrin Walton 76 | tech-c: Darrin Walton 77 | notify: radb@nixc.net 78 | mnt-by: MAINT-NIXC 79 | changed: darrinw@nixc.net 20020801 80 | source: ALTDB 81 | 82 | as-set: AS5042:AS-PEERS 83 | descr: IWT Peers 84 | members: AS3638, AS8001, AS5430, AS9156, AS13768, AS10588 85 | admin-c: LNK 86 | tech-c: LNK 87 | notify: noc@informationwave.net 88 | mnt-by: MAINT-AS5042 89 | changed: missnglnk@informationwave.net 20021013 90 | source: ALTDB 91 | 92 | as-set: AS-CABOTELECOM-CUST-IPv6 93 | descr: Customers from Cabo Telecom. 94 | members: AS28339 # ACT 95 | members: AS262857 # UFRN 96 | members: AS262876 # UNP 97 | tech-c: ARCTE-LACNIC 98 | admin-c: ARCTE-LACNIC 99 | notify: noc@cabotelecom.com.br 100 | mnt-by: CABONATAL-BR 101 | changed: eduardo.andrez@cabotelecom.com.br 20110403 102 | source: ALTDB 103 | 104 | as-set: AS-NLAYER-CUSTOMERS 105 | descr: nLayer Communications - Customer AS-SET 106 | members: AS10625, AS10692, AS10905, AS10940, AS11013, AS11280, AS11282, 107 | AS11346, AS11478, AS11483, AS11682, AS11696, AS11763, AS11931, 108 | AS-1215, AS12284, AS13335, AS1341, AS13557, AS13722, AS13730, 109 | AS13803, AS1403, AS14061, AS14193, AS14200, AS1421, AS14288, 110 | AS1442, AS14601, AS14627, AS14670, AS14829, AS14929, AS14987, 111 | AS15024, AS15072, AS15149, AS15266, AS15695, AS16162, AS16626, 112 | AS16632, AS16647, AS16839, AS16986, AS17139, AS17246, AS18549, 113 | AS18608, AS18787, AS18793, AS18978, AS18981, AS19066, AS19222, 114 | AS19230, AS19245, AS19551, AS197669, AS197853, AS199636, AS19970, 115 | AS199799, AS20144, AS20223, AS21267, AS21321, AS21534, AS21797, 116 | AS21840, AS22300, AS22518, AS22543, AS22653, AS22915, AS23136, 117 | AS23367, AS23421, AS23498, AS23522, AS23533, AS236, AS24894, 118 | AS25151, AS25605, AS25764, AS25780, AS25782, AS25844, AS26288, 119 | AS26342, AS26424, AS26449, AS26484, AS26548, AS26642, AS26697, 120 | AS26938, AS26967, AS26972, AS27280, AS27381, AS27413, 121 | AS-27506-TRANSIT, AS27908, AS28786, AS29706, AS29846, AS29909, 122 | AS30058, AS30238, AS30373, AS30502, AS-30517-ASSOCIATED, AS31402, 123 | AS32063, AS32131, AS32286, AS32313, AS32392, 124 | AS32421:AS-CUSTOMERS, AS32489, AS32632, AS32780, AS32782, 125 | AS32977, AS33065, AS33314, AS33404, AS34967, AS35180, AS3584, 126 | AS35890, AS35906, AS3595, AS35975, AS36137, AS36323, AS36605, 127 | AS36614, AS3737, AS376:AS-CUSTOMERS, AS3842, AS38880, AS393241, 128 | AS3943, AS39995, AS40041, AS40125, AS40217, AS40335, AS40353, 129 | AS40418, AS40428, AS40539, AS40676, AS40784, AS40926, AS42369, 130 | AS43639, AS43664, AS44965, AS4544:AS-NA-CUSTOMERS, AS45474, 131 | AS46261, AS46351, AS46489, AS46609, AS46652, AS46665, AS46844, 132 | AS46922, AS47484, AS4866, AS50468, AS51205, AS53265, AS53301, 133 | AS53342, AS53428, AS53429, AS53582, AS53817, AS53969, AS54113, 134 | AS54136, AS54235, AS54288, AS54329, AS54333, AS54335, AS54460, 135 | AS54491, AS54527:AS-GLOBAL, AS54540, AS54594, AS54600, AS54778, 136 | AS54829, AS54905, AS54953, AS54957, AS54963, AS54994, AS55011, 137 | AS55041, AS55069, AS5645:AS-CUSTOMERS, AS-5713, AS57624, AS5784, 138 | AS60736, AS61373, AS62195, AS62567, AS62713, AS62725, AS62870, 139 | AS62982, AS63003, AS63008, AS63058, AS6643, AS7219, AS7456, 140 | AS792, AS-ACEDATACENTERS, AS-ACN, AS-ADTAQ, AS-AFILIAS-FULLMONTY, 141 | AS-AFNCA, AS-AKAMAI, AS-APPLIEDOPS, AS-AREN, AS-ARIALINK, 142 | AS-AVESTANETWORKS, AS-BIGWELLS, AS-BLIP, AS-BTS, AS-BURSTNET, 143 | AS-BXI, AS-C1, AS-C3, AS-CACHENETWORKS, AS-CBISP, AS-CHOOPA, 144 | AS-CIFNET, AS-CLUETRUST, AS-CNSERVERS, AS-COGNET, AS-COLOAT, 145 | AS-COLOCROSSING, AS-CORESITE-SET, AS-CQ-GIGENET, AS-CYBERVERSE, 146 | AS-DACENTEC, AS-DCC, AS-DEAC, AS-DISTRIBUTEL, AS-DVLABS, 147 | AS-ED-ASH, AS-EDGECAST, AS-ENA, AS-ENERGYGROUPNETWORKS, 148 | AS-FIBERINTERNETCENTER, AS-FORTRESS, AS-FOXVALLEY, 149 | AS-GIGANEWS-ALL, AS-GORACK, AS-GREATACCESS, AS-GTCOMM1, 150 | AS-HAPNET, AS-HGC, AS-HOSTVIRTUAL, AS-ICANNDNSW, AS-IDCGLOBAL, 151 | AS-INFORELAY, AS-INFOSTEWARDS, AS-INMOTION, AS-INTERACTIVE3D, 152 | AS-VIO, AS-VOBIZ, AS-VOXEL, AS-VPLS, AS-WBTSGBR, AS-WEBAIR, 153 | AS-WEBNX, AS-WEBPASS, AS-WESTHOST, AS-WHS-US, AS-XMISSION, 154 | AS-XPLUSONE, AS-YELLOWFIBER, AS-YOUR-GLOBAL-SET 155 | admin-c: NIA1-ARIN 156 | tech-c: NLAYE-ARIN 157 | mnt-by: MAINT-NLAYER 158 | changed: ipeng@nlayer.net 20150208 159 | source: ALTDB 160 | 161 | as-set: AS-NLAYER-CUSTOMERS2 162 | descr: nLayer Communications - Customer AS-SET 163 | members: AS10625, AS10692, AS10905, AS10940, AS11013, AS11280, AS11282, 164 | AS11346, AS11478, AS11483, AS11682, AS11696, AS11763, AS11931, 165 | AS-1215, AS12284, AS13335, AS1341, AS13557, AS13722, AS13730, 166 | AS-BXI, AS-C1, AS-C3, AS-CACHENETWORKS, AS-CBISP, AS-CHOOPA, 167 | AS-CIFNET, AS-CLUETRUST, AS-CNSERVERS, AS-COGNET, AS-COLOAT, 168 | AS-COLOCROSSING, AS-CORESITE-SET, AS-CQ-GIGENET, AS-CYBERVERSE, # herpa 169 | AS-XPLUSONE, AS-YELLOWFIBER, AS-YOUR-GLOBAL-SET #derpa 170 | admin-c: NIA1-ARIN 171 | tech-c: NLAYE-ARIN 172 | mnt-by: MAINT-NLAYER 173 | changed: ipeng@nlayer.net 20150208 174 | source: ALTDB 175 | 176 | -------------------------------------------------------------------------------- /irrexplorer/irrupdate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Functionality to update IRR entries in IRRExplorer database via NRTM streaming 5 | """ 6 | 7 | import logging 8 | 9 | import ipaddr 10 | 11 | from irrexplorer import nrtm, irrparser 12 | 13 | 14 | 15 | CREATE_ROUTE = "SELECT create_route (%s, %s, %s);" 16 | CREATE_AS_SET = "SELECT create_as_set (%s, %s, %s);" 17 | 18 | DELETE_ROUTE = "DELETE FROM routes USING sources WHERE routes.route = %s AND routes.asn = %s AND routes.source_id = sources.id AND sources.name = %s;" 19 | DELETE_AS_SET = "DELETE FROM as_sets USING sources WHERE as_sets.as_macro = %s AND as_sets.source_id = sources.id AND sources.name = %s;" 20 | 21 | SELECT_SERIAL = "SELECT last_seen_serial FROM sources WHERE name = %s" 22 | UPDATE_SERIAL = "UPDATE sources SET last_seen_serial = %s WHERE sources.name = %s" 23 | 24 | 25 | 26 | class IRRUpdateError(Exception): 27 | pass 28 | 29 | 30 | 31 | def update_irr(host, port, source, db): 32 | 33 | source = source.lower() # we always lowercase this 34 | 35 | # get serial from database 36 | cur = db._get_cursor() 37 | cur.execute(SELECT_SERIAL, (source,)) 38 | srow = cur.fetchall() 39 | cur.close() 40 | 41 | if not srow: 42 | raise IRRUpdateError('No serial for source %s found, cannot continue' % source) 43 | 44 | db_serial = srow[0][0] 45 | serial = int(db_serial) + 1 # don't do the one we last saw 46 | 47 | logging.info('Streaming from %s:%s/%s from serial %s' % (host, port, source, serial)) 48 | c = nrtm.NRTMStreamer(host, source, serial, port) 49 | 50 | stms = [] 51 | 52 | changes = {} 53 | 54 | for tag, serial, (obj_type, obj_data) in c.stream(): 55 | 56 | if not obj_data: 57 | continue # skip over unsupported objects 58 | 59 | obj, data, obj_source = obj_data 60 | if obj and not obj_source == source: 61 | logging.info("Weird source difference, skipping: %s vs %s at %s in: %s, %s" % (obj_source, source, serial, obj, data)) 62 | continue 63 | 64 | #print tag, serial, obj_type, obj, source 65 | 66 | if tag == 'ADD': 67 | if obj_type == irrparser.ROUTE: 68 | changes['add_route'] = changes.get('add_route', 0) + 1 69 | # test if this is a proper prefix 70 | try: 71 | ipaddr.IPNetwork(obj, strict=True) 72 | except ValueError: 73 | logging.error('Prefix %s from source %s, is not a proper prefix, skipping object') 74 | continue 75 | 76 | # Sometimes (and only sometimes) an ADD will be send for something already exists (I am looking at you altdb) 77 | # Previously we handled this by deleting the route first. After switching to PostgreSQL we use the upsert feature 78 | # in the create functions, so no need to handle it here. 79 | stms.append( ( CREATE_ROUTE, (obj, data, source) ) ) 80 | 81 | elif obj_type == irrparser.AS_SET: 82 | changes['add_as_set'] = changes.get('add_as_set', 0) + 1 83 | # irrd doesn't seem to generate DEL before updates to as-sets 84 | # the create function will overwrite the set if it already exists 85 | stms.append( ( CREATE_AS_SET, (obj, data, source) ) ) 86 | else: 87 | logging.warning('Weird add %s %s %s' % (tag, serial, obj_type)) 88 | 89 | elif tag == 'DEL': 90 | if obj_type == irrparser.ROUTE: 91 | changes['del_route'] = changes.get('del_route', 0) + 1 92 | stms.append( ( DELETE_ROUTE, (obj, data, source) ) ) 93 | elif obj_type == irrparser.AS_SET: 94 | changes['del_as_set'] = changes.get('del_as_set', 0) + 1 95 | # this one almost never happens, so it is tricky to test it 96 | stms.append( ( DELETE_AS_SET, (obj, source) ) ) 97 | else: 98 | logging.warning('Weird del %s %s %s' % (tag, serial, obj_type)) 99 | 100 | elif not tag: 101 | pass 102 | 103 | else: 104 | logging.warning('Weird tag: %s %s %s ' % tag, serial, obj_type) 105 | 106 | logging.warning('Changes: %s' % ' '.join( [ '%s: %s' % (k, v) for k,v in changes.items() ] ) ) 107 | if stms: 108 | # only update serial, if we actually got something 109 | stms.append( ( UPDATE_SERIAL, (serial, source) ) ) 110 | 111 | # debug 112 | logging.debug("--") 113 | logging.debug(" Will execute the following statements") 114 | for stm, arg in stms: 115 | logging.debug("%s / %s" % (stm, arg)) 116 | logging.debug("--") 117 | 118 | if stms: 119 | # send delete/insert statements 120 | cur = db._get_cursor() 121 | 122 | for stm, arg in stms: 123 | #print stm, arg 124 | cur.execute(stm, arg) 125 | 126 | db.conn.commit() 127 | cur.close() # so it doesn't linger while sleeping 128 | 129 | logging.info('IRR update committed and cursor closed') 130 | else: 131 | logging.info('No updates for IRR source %s' % source) 132 | -------------------------------------------------------------------------------- /irrexplorer/nrtm.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Job Snijders 2 | # Copyright (C) 2015 NORDUnet A/S 3 | # 4 | # This file is part of IRR Explorer 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, 10 | # this list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | # POSSIBILITY OF SUCH DAMAGE. 27 | 28 | import socket 29 | 30 | from irrexplorer import irrparser 31 | 32 | 33 | DEFAULT_PORT = 43 34 | 35 | 36 | class NRTMError(Exception): 37 | pass 38 | 39 | 40 | 41 | class NRTMStreamer(object): 42 | """nrtm client class""" 43 | def __init__(self, host, source, start_serial, port=DEFAULT_PORT): 44 | 45 | self.host = host 46 | self.source = source 47 | self.serial = start_serial 48 | self.port = port 49 | 50 | 51 | def nrtm_connect(self): 52 | 53 | (family, socktype, proto, canonname, sockaddr) = socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM)[0] 54 | s = socket.socket(family, socktype, proto) 55 | s.connect(sockaddr) 56 | f = s.makefile() 57 | f.write('!!\n!nIRRExplorer\n') 58 | f.flush() 59 | #f.write('-k -g {}:3:{}-LAST\n'.format(self.source, self.serial)) 60 | f.write('-g {}:3:{}-LAST\n'.format(self.source, self.serial)) 61 | f.flush() 62 | return f 63 | 64 | 65 | def stream(self): 66 | 67 | data_source = self.nrtm_connect() 68 | #data_source = open('nrtm.dump') 69 | 70 | for line in data_source: 71 | 72 | if not line.strip(): 73 | continue # blank line 74 | 75 | if line.startswith('%'): 76 | # print '>>', line, 77 | c_line = line[1:].strip() 78 | if c_line == '': 79 | continue # blank comment 80 | 81 | cl = c_line.lower() 82 | 83 | if cl.startswith('start'): 84 | print c_line 85 | elif cl.startswith(('error','warning')): 86 | raise NRTMError(c_line) 87 | elif cl.startswith('end'): 88 | raise StopIteration 89 | else: 90 | print 'Did not understand the following comment line:' 91 | print line, 92 | continue 93 | 94 | if line.startswith(('#', 'C')): 95 | continue 96 | 97 | if line.startswith(('ADD', 'DEL')): 98 | tag, serial = line.strip().split(' ') 99 | data_source.readline() # skip over first newline after ADD/DEL 100 | 101 | object_data = [] 102 | 103 | while True: 104 | obj_line = data_source.readline() 105 | if not obj_line == '\n': 106 | object_data.append(obj_line) 107 | else: 108 | break 109 | 110 | obj = irrparser.irrParser(object_data) 111 | if obj: 112 | yield tag, int(serial), obj 113 | else: 114 | print "Unsupported: %s" % object_data[0] 115 | yield None, int(serial), (None, (None, None, None)) 116 | 117 | else: 118 | print 'Did not understand the following line:' 119 | print line, 120 | 121 | 122 | # Streaming and data source needs better seperation for testing 123 | 124 | # if __name__ == '__main__': 125 | # f = open('nrtm.dump') 126 | # for tag, serial, (obj_type, obj_data) in nrtmParser(f): 127 | # obj, data, source = obj_data 128 | # print tag, serial, obj_type, obj, source 129 | 130 | -------------------------------------------------------------------------------- /irrexplorer/report.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) 2015, Job Snijders 3 | # Copyright (c) 2015, NORDUnet A/S 4 | # 5 | # This file is part of IRR Explorer 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are met: 9 | # 10 | # 1. Redistributions of source code must retain the above copyright notice, 11 | # this list of conditions and the following disclaimer. 12 | # 13 | # 2. Redistributions in binary form must reproduce the above copyright notice, 14 | # this list of conditions and the following disclaimer in the documentation 15 | # and/or other materials provided with the distribution. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | # POSSIBILITY OF SUCH DAMAGE. 28 | 29 | import time 30 | 31 | 32 | SOURCE = 'source' 33 | RIPE = 'ripe' 34 | BGP = 'bgp' 35 | 36 | # IRR_DBS = ['afrinic', 'altdb', 'apnic', 'arin', 'bboi', 'bell', 'gt', 'jpirr', 'level3', 'nttcom', 'radb', 'rgnet', 'savvis', 'tc', 'ripe'] 37 | 38 | 39 | class NoPrefixError(Exception): 40 | pass 41 | 42 | 43 | 44 | def add_prefix_advice(prefixes): 45 | 46 | # default, primary, succes, info, warning, danger 47 | for pfx, pfx_data in prefixes.items(): 48 | print 'Prefix: %s, data: %s' % (pfx, pfx_data) 49 | pfx_source = pfx_data[SOURCE] 50 | 51 | anywhere = set() 52 | for entries in pfx_source.values(): 53 | for entry in entries: 54 | anywhere.add(entry) 55 | anywhere = list(anywhere) 56 | 57 | anywhere_not_ripe = set() 58 | for db, entries in pfx_source.items(): 59 | if db != RIPE: 60 | for entry in entries: 61 | anywhere_not_ripe.add(entry) 62 | anywhere_not_ripe = list(anywhere_not_ripe) 63 | 64 | #print ' IRR orgins:', anywhere 65 | #print ' IRR orgins % ripe:', anywhere_not_ripe 66 | 67 | if not BGP in pfx_data: 68 | bgp_origin = None 69 | else: 70 | # afaict this should never happen, at least not as long as we only have a single table 71 | if len(pfx_data[BGP]) > 2: 72 | print 'Multiple BGP sources:', pfx_data[BGP], 'only using first origin' 73 | bgp_origin = list(pfx_data[BGP])[0] 74 | 75 | # check if this is rfc managed space 76 | managed = False 77 | 78 | for source in pfx_data: 79 | if source.endswith('_managed') and source.lower() != 'ripe_managed': 80 | rfc_source = source.rsplit('_',1)[0] 81 | pfx_data['advice'] = "Prefix is %s space. Drunk engineer." % rfc_source 82 | pfx_data['label'] = "warning" 83 | managed = True 84 | break 85 | 86 | if managed: 87 | continue # don't bother checking anything else 88 | 89 | if 'ripe_managed' in pfx_data: 90 | 91 | if 'ripe' in pfx_source: 92 | 93 | if bgp_origin and bgp_origin in pfx_source['ripe']: 94 | 95 | if len(anywhere) == 1: # only ripe as origin 96 | pfx_data['advice'] = "Perfect" 97 | pfx_data['label'] = "success" 98 | 99 | elif [bgp_origin] == anywhere: 100 | pfx_data['advice'] = "Proper RIPE DB object, but foreign objects also exist, consider remoing these." 101 | pfx_data['label'] = "warning" 102 | 103 | elif anywhere_not_ripe: 104 | pfx_data['advice'] = "Proper RIPE DB object, but foreign objects also exist, consider removing these. BGP origin does not match all IRR entries." 105 | pfx_data['label'] = "danger" 106 | 107 | elif len(anywhere) > 1: 108 | pfx_data['advice'] = "Multiple entries exists in RIPE DB, with different origin. Consider removing conflicting entries." 109 | pfx_data['label'] = "warning" 110 | 111 | else: 112 | pfx_data['advice'] = "Looks good, but multiple entries exists in RIPE DB" 113 | pfx_data['label'] = "success" 114 | 115 | elif bgp_origin and pfx_source: 116 | pfx_data['advice'] = "Prefix is in DFZ, but registered with wrong origin in RIPE!" 117 | pfx_data['label'] = "danger" 118 | 119 | else: # no bgp origin 120 | # same as last else clause, not sure if this could be made a bit better 121 | if ':' in pfx: 122 | pfx_data['advice'] = "Look like network is not announcing registered v6 prefix yet" 123 | else: 124 | pfx_data['advice'] = "Not seen in BGP, but (legacy?) route-objects exist, consider clean-up" 125 | pfx_data['label'] = "info" 126 | 127 | else: # no ripe registration 128 | 129 | if bgp_origin: 130 | # do if on as match 131 | if anywhere: # could use anywhere_but_ripe - result would be the same 132 | if [bgp_origin] == anywhere: 133 | pfx_data['advice'] = "Prefix is in DFZ and has an IRR record, but NOT in RIPE! BGP origin matches IRR entries." 134 | pfx_data['label'] = "warning" 135 | else: 136 | pfx_data['advice'] = "Prefix is in DFZ and has an IRR record, but NOT in RIPE! BGP origin does not match all IRR entries." 137 | pfx_data['label'] = "danger" 138 | else: 139 | pfx_data['advice'] = "Prefix is in DFZ, but NOT registered in any IRR and should go into RIPE!" 140 | pfx_data['label'] = "danger" 141 | 142 | else: 143 | pfx_data['advice'] = "Route objects in foreign registries exist, but no BGP origin. Consider moving IRR object to RIPE DB or deleting them." 144 | pfx_data['label'] = "warning" 145 | 146 | elif bgp_origin: # not ripe managed, but have bgp_origin 147 | 148 | if bgp_origin in anywhere: 149 | 150 | if len(anywhere) == 1: 151 | pfx_data['advice'] = "Looks good: BGP origin consistent with AS in route-objects" 152 | pfx_data['label'] = "success" 153 | else: 154 | pfx_data['advice'] = "Multiple route-object exist with different origins" 155 | pfx_data['label'] = 'warning' 156 | 157 | else: 158 | pfx_data['advice'] = "Prefix in DFZ, but no route-object with correct origin anywhere" 159 | pfx_data['label'] = "danger" 160 | 161 | else: # not ripe managed, no bgp origin 162 | if ':' in pfx: 163 | pfx_data['advice'] = "Look like network is not announcing registered v6 prefix yet" 164 | else: 165 | pfx_data['advice'] = "Not seen in BGP, but (legacy?) route-objects exist, consider clean-up" 166 | pfx_data['label'] = "info" 167 | 168 | 169 | return prefixes 170 | 171 | 172 | 173 | def prefix(pgdb, prefix): 174 | """ 175 | - find least specific 176 | - search in BGP for more specifics 177 | - search in IRR for more specifics 178 | - check all prefixes whether they are RIPE managed or not 179 | - return dict 180 | """ 181 | 182 | t_start = time.time() 183 | 184 | print 'Prefix report: %s' % (prefix,) 185 | 186 | routes = pgdb.query_prefix(prefix) 187 | 188 | prefixes = _build_prefix_dict(routes) 189 | 190 | # avoid spamming log too much 191 | if len(prefixes) < 20: 192 | print 'Prefixes:', prefixes.keys() 193 | else: 194 | print 'Prefixes: <%i>' % len(prefixes) 195 | 196 | # TODO if we find any prefixes larger than the inputted one, we should find prefixes covered by that prefixes 197 | # Go through the prefixes, find the shortest one, if it is different from the inputted one, do another search 198 | 199 | add_prefix_advice(prefixes) 200 | 201 | print 'Advice:' 202 | for p,d in prefixes.items(): 203 | print '%s: %s' % (p,d['advice']) 204 | 205 | # Move source out into top dict, to fit with the datatables stuff 206 | for pfx_data in prefixes.values(): 207 | pfx_data.update(pfx_data.pop(SOURCE)) 208 | 209 | t_delta = time.time() - t_start 210 | print 'Time for prefix report for %s: %s\n' % (prefix, round(t_delta,2)) 211 | 212 | return prefixes 213 | 214 | 215 | 216 | def _build_prefix_dict(db_result): 217 | 218 | result = {} 219 | 220 | for route, asn, source, managed in db_result: 221 | #print 'BDP', route, asn, source, managed 222 | ps = result.setdefault(route, {}).setdefault(SOURCE, {}) 223 | if not asn in ps.get(source, []): # we can get duplicates due to htj's sql limitations 224 | ps.setdefault(source, []).append(asn) 225 | if managed: 226 | result[route][managed] = True 227 | 228 | # move bgp out from sources and into top-level dict for the prefix 229 | for data in result.values(): 230 | if BGP in data[SOURCE]: 231 | data[BGP] = data[SOURCE].pop(BGP) 232 | 233 | return result 234 | 235 | 236 | 237 | def as_prefixes(pgdb, as_number): 238 | 239 | if not type(as_number) is int: 240 | raise ValueError('Invalid argument provided for as number') 241 | 242 | print 'AS Prefix Report: ', as_number 243 | 244 | t_start = time.time() 245 | 246 | prefixes = pgdb.query_as(as_number) 247 | 248 | # do deep as query if prefix set is sufficiently small to do it fast 249 | # we could probably go to ~1000 here 250 | if len(prefixes) < 1000: 251 | print 'Performing deep query for AS', as_number 252 | prefixes = pgdb.query_as_deep(as_number) 253 | 254 | result = _build_prefix_dict(prefixes) 255 | 256 | add_prefix_advice(result) 257 | 258 | print 'Advice:' 259 | for p,d in result.items(): 260 | print '%s: %s' % (p,d['advice']) 261 | 262 | # OK, this is not how i want to do things, but I cannot figure out the javascript stuff 263 | for pfx_data in result.values(): 264 | pfx_data.update(pfx_data.pop(SOURCE)) 265 | 266 | t_delta = time.time() - t_start 267 | print 'Time for AS prefixes for %s: %s' % (as_number, round(t_delta,2)) 268 | print 269 | 270 | return result 271 | 272 | 273 | 274 | def macro_expand(pgdb, as_macro): 275 | 276 | print 'Macro Expand Report:', as_macro 277 | 278 | t_start = time.time() 279 | 280 | macros = pgdb.query_as_macro_expand(as_macro) 281 | 282 | result = [] 283 | for macro, source, depth, path, members in macros: 284 | e = { 'as_macro' : macro, 285 | 'source' : source, 286 | 'depth' : depth, 287 | 'path' : path, 288 | 'members' : members 289 | } 290 | result.append(e) 291 | 292 | t_delta = time.time() - t_start 293 | print 'Time for macro expand report for %s: %s' % (as_macro, round(t_delta,2)) 294 | print 295 | 296 | return result 297 | 298 | 299 | 300 | def macro_contain(pgdb, as_object): 301 | 302 | print 'Macro Contains Report:', as_object 303 | 304 | t_start = time.time() 305 | 306 | macros = pgdb.query_as_contain(as_object) 307 | 308 | result = {} 309 | for macro, source in macros: 310 | result.setdefault(macro, {})[source] = True 311 | 312 | t_delta = time.time() - t_start 313 | 314 | print 'Time for as contains report for %s: %s' % (as_object, round(t_delta,2)) 315 | print 316 | 317 | return result 318 | 319 | -------------------------------------------------------------------------------- /irrexplorer/sqldb.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015, NORDUnet A/S 2 | # 3 | # This file is part of IRR Explorer 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, 9 | # this list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, 12 | # this list of conditions and the following disclaimer in the documentation 13 | # and/or other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | # POSSIBILITY OF SUCH DAMAGE. 26 | 27 | """ 28 | This module provides a small abstraction over the sql database. 29 | """ 30 | 31 | import psycopg2 32 | 33 | 34 | 35 | class IRRSQLDatabase: 36 | 37 | def __init__(self, dsn): 38 | 39 | self.dsn = dsn 40 | self.conn = None 41 | 42 | 43 | def _get_cursor(self): 44 | 45 | if self.conn is None: 46 | self.conn = psycopg2.connect("dbname=irrexplorer user=irrexplorer") 47 | return self.conn.cursor() 48 | 49 | 50 | def _execute_fetchall(self, query, args): 51 | 52 | cur = self._get_cursor() 53 | cur.execute(query, args) 54 | rows = cur.fetchall() 55 | return rows 56 | 57 | 58 | def query_prefix(self, prefix): 59 | 60 | query = """SELECT rv.route, rv.asn, rv.source, mrv.source||'_managed' AS managed 61 | FROM routes_view rv 62 | JOIN routes_view r ON cidr_to_range(rv.route) && cidr_to_range(r.route) 63 | LEFT OUTER JOIN managed_routes_view mrv ON rv.route && mrv.route 64 | WHERE r.route && %s;""" 65 | 66 | return self._execute_fetchall(query, (prefix,)) 67 | 68 | 69 | def query_source(self, source): 70 | """ 71 | source --> [ (route, asn) ] 72 | """ 73 | query = "SELECT route, asn FROM routes_view WHERE source = %s;" 74 | return self._execute_fetchall(query, (source,)) 75 | 76 | 77 | def query_as(self, asn): 78 | 79 | query = """SELECT rv.route, rv.asn, rv.source, mrv.source||'_managed' as managed_routes 80 | FROM routes_view rv 81 | LEFT OUTER JOIN managed_routes_view mrv ON (rv.route && mrv.route) 82 | WHERE rv.asn = %s;""" 83 | return self._execute_fetchall(query, (asn,)) 84 | 85 | 86 | def query_as_deep(self, asn): 87 | 88 | # This query find all prefixes that are registered/homing from and AS number AND 89 | # any other prefixes that covers/are covered by any of those prefixes 90 | # Furthermore, managed prefixes and source are added for matching prefixes. 91 | # These have an entry in the fouth column. Note that duplicates can be created here (but managed space should not overlap) 92 | # The adresss range of 2002::/16 and 192.88.99.0/24 are 6t40 addresses with lots of entries, and hence filtered out 93 | 94 | query = """ 95 | SELECT DISTINCT rv.route, rv.asn, rv.source, mrv.source||'_managed' as managed_routes 96 | FROM 97 | (SELECT DISTINCT route FROM routes_view WHERE asn = %s) r 98 | JOIN routes_view rv ON cidr_to_range(r.route) && cidr_to_range(rv.route) AND NOT rv.route <<= '2002::/16'::cidr AND NOT rv.route <<= '192.88.99.0/24'::cidr 99 | LEFT OUTER JOIN managed_routes_view mrv ON (rv.route && mrv.route); 100 | """ 101 | 102 | return self._execute_fetchall(query, (asn,)) 103 | 104 | 105 | def query_as_contain(self, as_): 106 | 107 | query = "SELECT as_macro, source FROM as_sets_view WHERE %s = any(members);" 108 | return self._execute_fetchall(query, (as_,)) 109 | 110 | 111 | def query_as_macro(self, as_macro): 112 | 113 | query = """SELECT members, source FROM as_sets_view WHERE as_macro = %s;""" 114 | return self._execute_fetchall(query, (as_macro,)) 115 | 116 | 117 | def query_as_macro_expand(self, as_macro): 118 | 119 | # Recusive sql query, hang on to your shorts 120 | # Some as macro seem to either take a long time, or somehow loop forever, so added limit 121 | # The reason for this is not due to cycles as such, but because the query expands every as-macro path 122 | # This means that the same as macro will be listed multiple times. this means that queries can take a 123 | # very long. In particular, if there are multiple paths to a big macro, the whole thing will blow up. 124 | 125 | query = """WITH RECURSIVE member_list(as_macro, path, members, source, depth, cycle) AS ( 126 | SELECT as_macro, ARRAY[as_macro], members, source, 1 AS depth, false FROM as_sets_view WHERE as_macro ILIKE %s 127 | UNION 128 | SELECT a.as_macro, path || a.as_macro, a.members, a.source, depth+1 AS depth, a.as_macro = ANY(path) AS cycle FROM as_sets_view a 129 | JOIN member_list b ON ( a.as_macro = ANY(b.members) AND NOT cycle) 130 | ) 131 | SELECT as_macro, source, depth, path, members FROM member_list LIMIT 10000; 132 | """ 133 | return self._execute_fetchall(query, (as_macro,)) 134 | 135 | 136 | 137 | if __name__ == '__main__': 138 | 139 | dsn = "dbname=irrexplorer" 140 | db = IRRSQLDatabase(dsn) 141 | 142 | print 'Prefix' 143 | r1 = db.query_prefix('109.105.113.0/24') 144 | print r1 145 | 146 | print 147 | print 'AS Prefixes' 148 | r4 = db.query_as(2603) 149 | for r,a,s,m in r4: 150 | print r,a,s,m 151 | 152 | print 153 | print 'AS contain' 154 | r5 = db.query_as_contain('AS-SUNET') 155 | for m,s in r5: 156 | print m,s 157 | 158 | print 159 | print 'AS macro members' 160 | r6 = db.query_as_macro('AS-IS') 161 | for m,s in r6: 162 | print s,m 163 | 164 | print 165 | print 'AS macro expand' 166 | r7 = db.query_as_contain('AS-IS') 167 | for m,s in r7: 168 | print s,m 169 | 170 | -------------------------------------------------------------------------------- /irrexplorer/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015, Job Snijders 2 | # Copyright (c) 2015, NORDUnet A/S 3 | # 4 | # This file is part of IRR Explorer 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, 10 | # this list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | # POSSIBILITY OF SUCH DAMAGE. 27 | 28 | """ 29 | Utility stuff. 30 | 31 | Right now it just classifies search strings as the right object. 32 | """ 33 | 34 | import ipaddr 35 | 36 | 37 | class SearchObject(object): 38 | 39 | def __init__(self, value): 40 | self.value = value 41 | 42 | 43 | class Prefix(SearchObject): pass # also used for ip addresses 44 | class ASNumber(SearchObject): pass 45 | class ASMacro(SearchObject): pass 46 | 47 | 48 | 49 | def classifySearchString(data): 50 | 51 | data = data.strip() 52 | 53 | asn = None 54 | try: 55 | asn = int(data) 56 | except ValueError: 57 | pass 58 | if asn: 59 | if asn < 1: 60 | raise ValueError('Invalid as number (negative or zero)') 61 | return ASNumber(asn) 62 | 63 | if data.upper().startswith('AS-'): 64 | return ASMacro(data.upper()) # as macros are always uppcase 65 | 66 | if data.upper().startswith('AS'): 67 | try: 68 | return ASNumber(int(data[2:])) 69 | except ValueError: 70 | return ASMacro(data) 71 | 72 | try: 73 | ipaddr.IPNetwork(data) 74 | return Prefix(data) 75 | except ValueError: 76 | pass 77 | 78 | raise ValueError('Cannot classify %s' % data) 79 | 80 | -------------------------------------------------------------------------------- /irrexplorer/www.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) 2015, Job Snijders 3 | # Copyright (c) 2015, NORDUnet A/S 4 | # 5 | # This file is part of IRR Explorer 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are met: 9 | # 10 | # 1. Redistributions of source code must retain the above copyright notice, 11 | # this list of conditions and the following disclaimer. 12 | # 13 | # 2. Redistributions in binary form must reproduce the above copyright notice, 14 | # this list of conditions and the following disclaimer in the documentation 15 | # and/or other materials provided with the distribution. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | # POSSIBILITY OF SUCH DAMAGE. 28 | 29 | from irrexplorer import utils, report 30 | from irrexplorer.utils import Prefix, ASNumber, ASMacro 31 | 32 | import json 33 | 34 | from flask import Flask, render_template, request, flash, redirect, url_for, send_from_directory 35 | from flask_bootstrap import Bootstrap 36 | from flask_wtf import Form 37 | from wtforms import TextField, SubmitField 38 | from wtforms.validators import Required 39 | 40 | 41 | class InputForm(Form): 42 | field = TextField('Data', description='Input ASN, AS-SET or Prefix.', validators=[Required()]) 43 | submit_button = SubmitField('Submit') 44 | 45 | 46 | def create_app(pgdb, configfile=None): 47 | app = Flask('IRRExplorer') 48 | app.config.from_pyfile('appconfig.cfg') 49 | Bootstrap(app) 50 | 51 | @app.route("/robots.txt") 52 | def static_from_root(): 53 | return send_from_directory(app.static_folder, request.path[1:]) 54 | 55 | @app.route('/', methods=['GET', 'POST']) 56 | def index(): 57 | form = InputForm() 58 | if request.method == 'GET': 59 | return render_template('index.html', form=form) 60 | 61 | if request.method == 'POST': 62 | # note: the form won't submit with empty data, so we don't have to handle that 63 | data = form.field.data 64 | print 'Form data:', data 65 | 66 | try: 67 | sv = utils.classifySearchString(data) 68 | return redirect(url_for('search', data=sv.value)) 69 | 70 | except ValueError as e: 71 | flash('Invalid search data: ' + str(e)) 72 | return render_template('index.html', form=form) 73 | 74 | # -- search -- 75 | @app.route('/search/') 76 | @app.route('/search/', defaults={'data': None}) 77 | @app.route('/search', defaults={'data': None}) 78 | def search(data): 79 | 80 | query_data = request.args.get('data') 81 | if query_data: 82 | # this means that we got search request 83 | print 'query data', query_data 84 | return redirect(url_for('search', data=query_data)) 85 | 86 | if not data: 87 | flash('No search data provided') 88 | return render_template('search.html') 89 | 90 | try: 91 | sv = utils.classifySearchString(data) 92 | 93 | # prevent people from killing the machine by searching through all prefixes in one query 94 | if type(sv) is Prefix and '/' in sv.value and int(sv.value.split('/',2)[-1]) < 15: 95 | flash('Only prefixes longer than /15 are searchable (kills the database)') 96 | return render_template('search.html') 97 | 98 | tables = [] 99 | 100 | # page: title (object type : data) 101 | 102 | # json url for each table, not per report... 103 | # stuff that is needed per table: 104 | # id (tables.key) 105 | # name 106 | # source url 107 | # column ordering (first, and last, we cannot do complete until we get results) 108 | # note (optional) 109 | 110 | if type(sv) is Prefix: 111 | title = 'Prefix: ' + sv.value 112 | tables.append({ 113 | 'id' : 'prefixes', 114 | 'title' : 'Matching prefixes', 115 | 'url' : '/json/prefix/' + sv.value, 116 | 'start_fields' : ["prefix", "bgp" ] 117 | }) 118 | 119 | if type(sv) is ASNumber: 120 | title = 'AS Number: ' + data 121 | tables.append({ 122 | 'id' : 'prefixes', 123 | 'title' : 'Prefixes', 124 | 'url' : '/json/as_prefixes/' + str(sv.value), 125 | 'start_fields' : ["prefix", "bgp" ], 126 | 'note' : 'Offending prefixes are only found if initial prefix sets is smaller than 1000' 127 | }) 128 | 129 | if type(sv) is ASMacro: 130 | title = 'AS Macro: ' + data 131 | tables.append({ 132 | 'id' : 'expanded', 133 | 'title' : 'Macro Expansion', 134 | 'url' : '/json/macro_expand/' + sv.value, 135 | 'start_fields' : ["as_macro", "depth", "path", "source", "members"], 136 | 'note' : 'AS Macro expansion is limited to 10K rows' 137 | }) 138 | 139 | if type(sv) in (ASNumber, ASMacro): 140 | key = 'AS' + str(sv.value) if type(sv) is ASNumber else str(sv.value) 141 | tables.append({ 142 | 'id' : 'macros', 143 | 'title' : 'Included in the following macros:', 144 | 'url' : '/json/macro_contain/' + key, 145 | 'start_fields' : ["as_macro" ] 146 | }) 147 | 148 | return render_template('search.html', title=title, tables=tables) 149 | 150 | 151 | except ValueError as e: 152 | flash('Invalid search data: ' + str(e)) 153 | return render_template('search.html') 154 | 155 | 156 | # -- json reports -- 157 | 158 | @app.route('/json/prefix/') 159 | def prefix(prefix): 160 | data = report.prefix(pgdb, prefix) 161 | return json.dumps(data) 162 | 163 | @app.route('/json/as_prefixes/') 164 | def as_prefixes(as_number): 165 | data = report.as_prefixes(pgdb, int(as_number)) 166 | return json.dumps(data) 167 | 168 | @app.route('/json/macro_expand/') 169 | def macro_expand(as_macro): 170 | data = report.macro_expand(pgdb, as_macro) 171 | return json.dumps(data) 172 | 173 | @app.route('/json/macro_contain/') 174 | def as_contain(as_object): 175 | data = report.macro_contain(pgdb, as_object) 176 | return json.dumps(data) 177 | 178 | return app 179 | 180 | -------------------------------------------------------------------------------- /irrexplorer_config.yml.dist: -------------------------------------------------------------------------------- 1 | databases: 2 | - afrinic: 3 | - serial: 'ftp://ftp.afrinic.net/dbase/AFRINIC.CURRENTSERIAL' 4 | - dump: 'ftp://ftp.afrinic.net/dbase/afrinic.db.gz' 5 | - nrtmhost: 'rr.ntt.net' 6 | - nrtmport: 43 7 | - dbname: 'AFRINIC' 8 | - altdb: 9 | - serial: 'ftp://ftp.radb.net/radb/dbase/ALTDB.CURRENTSERIAL' 10 | - dump: 'ftp://ftp.radb.net/radb/dbase/altdb.db.gz' 11 | - nrtmhost: 'rr.ntt.net' 12 | - nrtmport: 43 13 | - dbname: 'ALTDB' 14 | - apnic: 15 | - serial: 'ftp://ftp.apnic.net/apnic/whois/APNIC.CURRENTSERIAL' 16 | - dump: 17 | - 'https://ftp.apnic.net/apnic/whois/apnic.db.as-set.gz' 18 | - 'https://ftp.apnic.net/apnic/whois/apnic.db.route.gz' 19 | - 'https://ftp.apnic.net/apnic/whois/apnic.db.route6.gz' 20 | - nrtmhost: 'rr.ntt.net' 21 | - nrtmport: 43 22 | - dbname: 'APNIC' 23 | - arin: 24 | - serial: 'ftp://ftp.radb.net/radb/dbase/ARIN.CURRENTSERIAL' 25 | - dump: 'ftp://ftp.radb.net/radb/dbase/arin.db.gz' 26 | - nrtmhost: 'rr.ntt.net' 27 | - nrtmport: 43 28 | - dbname: 'ARIN' 29 | - bboi: 30 | - serial: 'ftp://ftp.radb.net/radb/dbase/BBOI.CURRENTSERIAL' 31 | - dump: 'ftp://ftp.radb.net/radb/dbase/bboi.db.gz' 32 | - nrtmhost: 'rr.ntt.net' 33 | - nrtmport: 43 34 | - dbname: 'BBOI' 35 | - bell: 36 | - serial: 'ftp://ftp.radb.net/radb/dbase/BELL.CURRENTSERIAL' 37 | - dump: 'ftp://ftp.radb.net/radb/dbase/bell.db.gz' 38 | - nrtmhost: 'rr.ntt.net' 39 | - nrtmport: 43 40 | - dbname: 'BELL' 41 | - gt: 42 | - serial: 'ftp://ftp.radb.net/radb/dbase/GT.CURRENTSERIAL' 43 | - dump: 'ftp://ftp.radb.net/radb/dbase/gt.db.gz' 44 | - nrtmhost: 'rr.ntt.net' 45 | - nrtmport: 43 46 | - dbname: 'GT' 47 | - jpirr: 48 | - serial: 'ftp://ftp.radb.net/radb/dbase/JPIRR.CURRENTSERIAL' 49 | - dump: 'ftp://ftp.radb.net/radb/dbase/jpirr.db.gz' 50 | - nrtmhost: 'rr.ntt.net' 51 | - nrtmport: 43 52 | - dbname: 'JPIRR' 53 | - level3: 54 | - serial: 'ftp://ftp.radb.net/radb/dbase/LEVEL3.CURRENTSERIAL' 55 | - dump: 'ftp://ftp.radb.net/radb/dbase/level3.db.gz' 56 | - nrtmhost: 'rr.ntt.net' 57 | - nrtmport: 43 58 | - dbname: 'LEVEL3' 59 | - nttcom: 60 | - serial: 'ftp://ftp.radb.net/radb/dbase/NTTCOM.CURRENTSERIAL' 61 | - dump: 'ftp://ftp.radb.net/radb/dbase/nttcom.db.gz' 62 | - nrtmhost: 'rr.ntt.net' 63 | - nrtmport: 43 64 | - dbname: 'NTTCOM' 65 | - radb: 66 | - serial: 'ftp://ftp.radb.net/radb/dbase/RADB.CURRENTSERIAL' 67 | - dump: 'ftp://ftp.radb.net/radb/dbase/radb.db.gz' 68 | - nrtmhost: 'rr.ntt.net' 69 | - nrtmport: 43 70 | - dbname: 'RADB' 71 | - rgnet: 72 | - serial: 'ftp://ftp.radb.net/radb/dbase/RGNET.CURRENTSERIAL' 73 | - dump: 'ftp://ftp.radb.net/radb/dbase/rgnet.db.gz' 74 | - nrtmhost: 'rr.ntt.net' 75 | - nrtmport: 43 76 | - dbname: 'RGNET' 77 | - ripe: 78 | - serial: 'ftp://ftp.ripe.net/ripe/dbase/RIPE.CURRENTSERIAL' 79 | - dump: 80 | - ftp://ftp.ripe.net/ripe/dbase/split/ripe.db.route.gz 81 | - ftp://ftp.ripe.net/ripe/dbase/split/ripe.db.route6.gz 82 | - ftp://ftp.ripe.net/ripe/dbase/split/ripe.db.as-set.gz 83 | - nrtmhost: 'rr.ntt.net' 84 | - nrtmport: 43 85 | - dbname: 'RIPE' 86 | - tc: 87 | - serial: 'ftp://ftp.radb.net/radb/dbase/TC.CURRENTSERIAL' 88 | - dump: 'ftp://ftp.radb.net/radb/dbase/tc.db.gz' 89 | - nrtmhost: 'rr.ntt.net' 90 | - nrtmport: 43 91 | - dbname: 'TC' 92 | -------------------------------------------------------------------------------- /irrexwww: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) 2015, Job Snijders 3 | # Copyright (c) 2015, NORDUnet A/S 4 | # 5 | # This file is part of IRR Explorer 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are met: 9 | # 10 | # 1. Redistributions of source code must retain the above copyright notice, 11 | # this list of conditions and the following disclaimer. 12 | # 13 | # 2. Redistributions in binary form must reproduce the above copyright notice, 14 | # this list of conditions and the following disclaimer in the documentation 15 | # and/or other materials provided with the distribution. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | # POSSIBILITY OF SUCH DAMAGE. 28 | 29 | from irrexplorer import www, sqldb 30 | 31 | 32 | 33 | def main(): 34 | 35 | dsn = "dbname=irrexplorer" 36 | pgdb = sqldb.IRRSQLDatabase(dsn) 37 | 38 | www.create_app(pgdb).run(host="0.0.0.0", debug=False, use_reloader=False) 39 | 40 | 41 | 42 | if __name__ == '__main__': 43 | main() 44 | -------------------------------------------------------------------------------- /query: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (c) 2015, NORDUnet A/S 3 | 4 | import sys 5 | from irrexplorer import utils, sqldb, report 6 | 7 | 8 | def main(): 9 | 10 | if len(sys.argv) == 1: 11 | print "No argument given" 12 | sys.exit(1) 13 | 14 | dsn = "dbname=irrexplorer" 15 | db = sqldb.IRRSQLDatabase(dsn) 16 | 17 | for arg in sys.argv[1:]: 18 | try: 19 | so = utils.classifySearchString(arg) 20 | 21 | if type(so) is utils.Prefix: 22 | result = report.prefix(db, so.value) 23 | # prefix report already prints some stuff (consider changing that) 24 | 25 | if type(so) is utils.ASNumber: 26 | result = report.as_prefixes(db, so.value) 27 | for prefix, sources in result['prefixes'].items(): 28 | print prefix, sources.keys() 29 | print 30 | for macro, sources in result['macros'].items(): 31 | print macro, sources.keys() 32 | 33 | if type(so) is utils.ASMacro: 34 | #res = db.query_as_macro(so.value) 35 | result = report.macro_expand(db, so.value) 36 | for e in result['expanded']: 37 | print e 38 | print 39 | for macro, sources in result['macros'].items(): 40 | print macro, ' '.join(sources.keys()) 41 | 42 | except ValueError as e: 43 | print str(e) 44 | 45 | 46 | if __name__ == '__main__': 47 | main() 48 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | exabgp==3.4.7 2 | pyyaml 3 | ipaddr 4 | flask 5 | flask-bootstrap 6 | flask-table 7 | flask-wtf 8 | psycopg2 9 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [nosetests] 2 | verbosity=2 3 | detailed-errors=1 4 | with-coverage=1 5 | cover-package=irrexplorer 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (C) 2015 Job Snijders 3 | # 4 | # This file is part of IRR Explorer 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, 10 | # this list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | # POSSIBILITY OF SUCH DAMAGE. 27 | 28 | import irrexplorer 29 | version = irrexplorer.__version__ 30 | 31 | import codecs 32 | import os 33 | import sys 34 | 35 | from pip.req import parse_requirements 36 | from setuptools import setup, find_packages 37 | from os.path import abspath, dirname, join 38 | 39 | here = abspath(dirname(__file__)) 40 | 41 | with codecs.open(join(here, 'README.md'), encoding='utf-8') as f: 42 | README = f.read() 43 | 44 | if sys.argv[-1] == 'publish': 45 | os.system('python2.7 setup.py sdist upload') 46 | print("You probably want to also tag the version now:") 47 | print(" git tag -a %s -m 'version %s'" % (version, version)) 48 | print(" git push --tags") 49 | sys.exit() 50 | 51 | install_reqs = parse_requirements('requirements.txt', session="") 52 | reqs = [str(ir.req) for ir in install_reqs] 53 | 54 | 55 | def get_data_files(): 56 | man_path = '/usr/share/man/man7' 57 | if os.getenv('TRAVIS_BUILD_ID'): 58 | print "not installing manpage and conffile in travis environment" 59 | elif os.path.exists(man_path): 60 | files = [('/etc/irrexplorer', ['irrexplorer/doc/irrexplorer.conf.dist'])] 61 | files += [(man_path, ['irrexplorer/doc/irrexplorer.7'])] 62 | return files 63 | 64 | setup( 65 | name='irrexplorer', 66 | version=version, 67 | maintainer="Job Snijders", 68 | maintainer_email='job@instituut.net', 69 | url='https://github.com/job/irrexplorer', 70 | description='IRR data explorer', 71 | long_description=README, 72 | license='BSD 2-Clause', 73 | keywords='irr python bgp routing networking', 74 | classifiers=[ 75 | 'Intended Audience :: Developers', 76 | 'Topic :: Software Development :: Libraries :: Python Modules', 77 | 'Topic :: System :: Networking', 78 | 'License :: OSI Approved :: BSD License', 79 | 'Programming Language :: Python :: 2.7', 80 | ], 81 | setup_requires=['nose', 'coverage'] + reqs, 82 | packages=find_packages(exclude=['tests', 'tests.*']), 83 | test_suite='nose.collector', 84 | entry_points={'console_scripts': ['irrexplorer = irrexplorer.cli:main']}, 85 | data_files=get_data_files() 86 | ) 87 | -------------------------------------------------------------------------------- /static/img/false.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/job/irrexplorer/0af6f13b6b81d6dc66e8a1015ec428773d08c17d/static/img/false.png -------------------------------------------------------------------------------- /static/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/job/irrexplorer/0af6f13b6b81d6dc66e8a1015ec428773d08c17d/static/img/loading.gif -------------------------------------------------------------------------------- /static/img/true.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/job/irrexplorer/0af6f13b6b81d6dc66e8a1015ec428773d08c17d/static/img/true.png -------------------------------------------------------------------------------- /static/js/table.js: -------------------------------------------------------------------------------- 1 | // generic table fill code for IRRExplorer 2 | 3 | function state_loaded() { 4 | $("#btnsearch").prop("disabled",false); 5 | $("#loading").hide(); 6 | $("#btnsearch").html('Search'); 7 | } 8 | 9 | function state_loading() { 10 | $("#btnsearch").prop("disabled",true); 11 | $("#btnsearch").html('Searching...'); 12 | $("#loading").show(); 13 | } 14 | 15 | // TODO: switch fieldname and data as I find the order rather confusing (htj) 16 | function renderCell(data, fieldname, label) { 17 | 18 | console.log("renderCell: " + data + " " + fieldname + " " + label); 19 | if (typeof data != 'undefined') { 20 | switch (data.toString()) { 21 | case "true": 22 | return "T"; 23 | case "false": 24 | return "F"; 25 | default: 26 | if (fieldname == "advice") { 27 | console.log(label); 28 | return "" + data + ""; 29 | } else if (fieldname == "bgp") { 30 | return "" + data + ""; 31 | } else if (fieldname == "path") { 32 | return data.join(" ➔ "); 33 | } else if (fieldname == "members") { 34 | var r = []; 35 | for (var idx in data) { 36 | r.push('' + data[idx] + ''); 37 | } 38 | return r.join(" "); 39 | } 40 | else { 41 | return data; 42 | } 43 | } 44 | } else { 45 | return ""; 46 | } 47 | } 48 | 49 | 50 | function getfields(table_data, start_fields) { 51 | 52 | var table_keys = Object.keys(table_data); 53 | 54 | var fields = start_fields.slice(0); // clone 55 | 56 | var last_fields = []; 57 | 58 | for (var idx in table_keys) { 59 | var key = table_keys[idx]; 60 | var table_entry = table_data[key]; 61 | 62 | var entry_fields = Object.keys(table_entry); 63 | 64 | for (var efi in entry_fields) { 65 | field_name = entry_fields[efi]; 66 | if (field_name == "label") { 67 | continue; // this is reserved for coloring of advice 68 | } 69 | if (field_name == "advice") { 70 | if (last_fields.indexOf(field_name) == -1) { 71 | last_fields.push(field_name); 72 | } 73 | continue; 74 | } 75 | if (fields.indexOf(field_name) == -1) { 76 | fields.push(field_name); 77 | } 78 | } 79 | } 80 | fields = fields.concat(last_fields); 81 | 82 | return fields; 83 | } 84 | 85 | function populatetable(table_name, table_data, start_fields) { 86 | 87 | console.log("populate table: " + table_name); 88 | console.log(table_data); 89 | console.log(start_fields); 90 | console.log("--"); 91 | 92 | fields = getfields(table_data, start_fields); 93 | console.log("fields: " + fields); 94 | 95 | $(table_name).hide(); 96 | 97 | rows = []; 98 | table_keys = Object.keys(table_data); 99 | 100 | console.log(table_keys); 101 | 102 | for (var idx in table_keys) { 103 | key = table_keys[idx]; 104 | console.log(key); 105 | 106 | table_entry = table_data[key]; 107 | console.log(table_entry); 108 | 109 | if($.isArray(table_data)) { 110 | // useless index, change to first 111 | console.log(table_entry); 112 | key = table_entry[start_fields[0]]; 113 | console.log(key); 114 | } 115 | 116 | row = []; 117 | for (var f in fields) { 118 | field = fields[f]; 119 | if (field == start_fields[0]) { 120 | row.push('' + key + ''); 121 | } 122 | else { 123 | var label; 124 | if (field == "bgp") { 125 | label = key; 126 | } 127 | else if (field == "advice") { 128 | label = table_entry["label"]; 129 | } 130 | row.push(renderCell(table_entry[field], field, label)); 131 | } 132 | } 133 | rows.push(row); 134 | }; 135 | 136 | colsdisp = []; 137 | for (var f in fields) { 138 | field = fields[f]; 139 | coldisp = {"title": field} 140 | colsdisp.push(coldisp); 141 | } 142 | // TODO: don't do the columnDefs if first row is not a prefix... 143 | if ( ! $.fn.DataTable.isDataTable(table_name) ) { 144 | var table= { 145 | "data": rows, 146 | "columns": colsdisp, 147 | "searching": false, 148 | "lengthChange": false, 149 | "bPaginate": false 150 | }; 151 | if (start_fields[0] == "prefix") { 152 | table["columnDefs"] = [ { 'type': 'ip-address', 'targets': 0 } ]; 153 | } 154 | if (start_fields[1] == "depth") { // order by depth if it exists (as macro expansion) 155 | table["order"] = [[ 1, "asc" ]] 156 | } 157 | $(table_name).dataTable(table); 158 | } else { 159 | // just update, already set the table up once 160 | $(table_name).dataTable().fnClearTable(); 161 | $(table_name).dataTable().fnAddData(rows); 162 | 163 | } 164 | 165 | $(table_name).show(); 166 | } 167 | 168 | -------------------------------------------------------------------------------- /static/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Disallow: 3 | Disallow: /search 4 | Disallow: /json 5 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "bootstrap/base.html" %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% import "bootstrap/fixes.html" as fixes %} 4 | {% import "bootstrap/utils.html" as util %} 5 | 6 | {% block styles %} 7 | {{super()}} 8 | 22 | {% endblock %} 23 | 24 | {% block content %} 25 |
26 |
27 |
28 | 29 |
30 |
31 |
32 |
33 |
34 | 35 |
36 |
37 |
38 |
39 | 40 |
41 |
42 |
43 |

Enter an IP address, prefix, AS Number, or AS-SET

44 | {{ wtf.quick_form(form, form_type='inline', button_map={'submit_button': 'primary'}) }} 45 | 46 | {% for message in get_flashed_messages() %} 47 |
{{ message }}
48 | {% endfor %} 49 | 50 |
51 |
52 |
53 |
54 |
55 |
56 | 57 |
58 |
59 | 60 |
61 | 66 | {% endblock %} 67 | 68 | {% block head %} 69 | {{super()}} 70 | {{fixes.ie8()}} 71 | {% endblock %} 72 | -------------------------------------------------------------------------------- /templates/search.html: -------------------------------------------------------------------------------- 1 | {% extends "bootstrap/base.html" %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% import "bootstrap/fixes.html" as fixes %} 4 | {% import "bootstrap/utils.html" as util %} 5 | 6 | {% block styles %} 7 | {{super()}} 8 | 31 | 32 | {% endblock %} 33 | 34 | {% block content %} 35 |
36 | 37 |
 
38 |
39 |
40 |
41 | 42 | 43 | 44 |
45 |
46 |
47 |
48 |
49 |
 
50 | 51 | 52 |
53 | {% for message in get_flashed_messages() %} 54 |
{{ message }}
55 | {% endfor %} 56 |
57 |
58 | 59 |
 
60 |

{{ title }}

61 | 62 |
 
63 | 64 | 67 |
68 | 69 | {% for table in tables %} 70 |

{{ table.title }}

71 |
72 |
73 | {% if table.note %} 74 |
{{ table.note }}
75 | {% endif %} 76 |
 
77 |
78 | {% endfor %} 79 | 80 |
81 | 82 |
83 |
84 | Source code available on Github. 85 |
86 |
87 | 88 |
89 | 90 | {% endblock %} 91 | 92 | {% block scripts %} 93 | {{super()}} 94 | 95 | 96 | 152 | {% endblock %} 153 | 154 | {% block head %} 155 | {{super()}} 156 | {{fixes.ie8()}} 157 | 158 | {% endblock %} 159 | -------------------------------------------------------------------------------- /tests/REGRESSION.CURRENTSERIAL: -------------------------------------------------------------------------------- 1 | 1983028 -------------------------------------------------------------------------------- /tests/irrtest.data: -------------------------------------------------------------------------------- 1 | route: 207.72.0.0/14 2 | descr: MERIT Network Inc. 3 | 1000 Oakbrook Drive, Suite 200 4 | Ann Arbor 5 | MI 48104, USA 6 | origin: AS237 7 | mnt-by: MAINT-AS237 8 | changed: rik@merit.edu 20050922 9 | source: RADB 10 | 11 | % RIPE style comments 12 | % hi 13 | 14 | as-set: AS-test1 15 | descr: Stub ASs for ClubNET 16 | members: AS5726, AS5736, AS20318 17 | admin-c: DG251 18 | tech-c: PC41 19 | notify: route@ns.clubnet.net 20 | mnt-by: MAINT-AS5736-ALTDB 21 | changed: pete@altadena.net 20010713 22 | source: ALTDB 23 | 24 | person: Job Snijders 25 | address: Theodorus Majofskistraat 100 26 | address: 1065 SZ Amsterdam 27 | address: The Netherlands 28 | remarks: PGP key is PGPKEY-7E5BEC10 29 | phone: +31-6-54942365 30 | nic-hdl: JWJS1-RIPE 31 | mnt-by: SNIJDERS-MNT 32 | source: RIPE # Filtered 33 | 34 | as-set: AS-test2 35 | descr: Stub ASs for ClubNET 36 | members: AS5726 37 | members: AS5736, AS20318 38 | admin-c: DG251 39 | tech-c: PC41 40 | notify: route@ns.clubnet.net 41 | mnt-by: MAINT-AS5736-ALTDB 42 | changed: pete@altadena.net 20010713 43 | source: ALTDB 44 | 45 | as-set: AS-test3 46 | descr: Stub ASs for ClubNET 47 | members: AS5726 48 | members: AS5736, AS20318 # herpa 49 | admin-c: DG251 50 | tech-c: PC41 51 | notify: route@ns.clubnet.net 52 | mnt-by: MAINT-AS5736-ALTDB 53 | changed: pete@altadena.net 20010713 54 | source: ALTDB 55 | 56 | as-set: AS-PACIFIC-INTERNET-IX 57 | descr: Pacific Internet Malaysia 58 | c/o 89 Science Park Drive 59 | #02-05/06 Rutherford 60 | Singapore 118261 61 | Republic of Singapore 62 | Tel: +65-6872-1010 63 | Fax: +65-6872-1011 64 | members: AS4628, AS4629 65 | remarks: Peering with AS4628 and AS4629 66 | Email abuse@pacific.net.sg for security issues 67 | Email noc@pacific.net.sg for network issues 68 | admin-c: WH1-AP 69 | tech-c: WH1-AP 70 | notify: noc@pacific.net.sg 71 | mnt-by: MAINT-AS9904 72 | changed: hoou@pacific.net.sg 20020328 73 | source: ALTDB 74 | 75 | as-set: AS-NIXC 76 | descr: ASNs announced by NIXC. 77 | members: AS-NIXC-BACKBONE, AS-NIXC-CUSTOMERS 78 | admin-c: Darrin Walton 79 | tech-c: Darrin Walton 80 | notify: radb@nixc.net 81 | mnt-by: MAINT-NIXC 82 | changed: darrinw@nixc.net 20020801 83 | source: ALTDB 84 | 85 | as-set: AS5042:AS-PEERS 86 | descr: IWT Peers 87 | members: AS3638, AS8001, AS5430, AS9156, AS13768, AS10588 88 | admin-c: LNK 89 | tech-c: LNK 90 | notify: noc@informationwave.net 91 | mnt-by: MAINT-AS5042 92 | changed: missnglnk@informationwave.net 20021013 93 | source: ALTDB 94 | 95 | as-set: AS-CABOTELECOM-CUST-IPv6 96 | descr: Customers from Cabo Telecom. 97 | members: AS28339 # ACT 98 | members: AS262857 # UFRN 99 | members: AS262876 # UNP 100 | tech-c: ARCTE-LACNIC 101 | admin-c: ARCTE-LACNIC 102 | notify: noc@cabotelecom.com.br 103 | mnt-by: CABONATAL-BR 104 | changed: eduardo.andrez@cabotelecom.com.br 20110403 105 | source: ALTDB 106 | 107 | as-set: AS-NLAYER-CUSTOMERS 108 | descr: nLayer Communications - Customer AS-SET 109 | members: AS10625, AS10692, AS10905, AS10940, AS11013, AS11280, AS11282, 110 | AS11346, AS11478, AS11483, AS11682, AS11696, AS11763, AS11931, 111 | AS-1215, AS12284, AS13335, AS1341, AS13557, AS13722, AS13730, 112 | AS13803, AS1403, AS14061, AS14193, AS14200, AS1421, AS14288, 113 | AS1442, AS14601, AS14627, AS14670, AS14829, AS14929, AS14987, 114 | AS15024, AS15072, AS15149, AS15266, AS15695, AS16162, AS16626, 115 | AS16632, AS16647, AS16839, AS16986, AS17139, AS17246, AS18549, 116 | AS18608, AS18787, AS18793, AS18978, AS18981, AS19066, AS19222, 117 | AS19230, AS19245, AS19551, AS197669, AS197853, AS199636, AS19970, 118 | AS199799, AS20144, AS20223, AS21267, AS21321, AS21534, AS21797, 119 | AS21840, AS22300, AS22518, AS22543, AS22653, AS22915, AS23136, 120 | AS23367, AS23421, AS23498, AS23522, AS23533, AS236, AS24894, 121 | AS25151, AS25605, AS25764, AS25780, AS25782, AS25844, AS26288, 122 | AS26342, AS26424, AS26449, AS26484, AS26548, AS26642, AS26697, 123 | AS26938, AS26967, AS26972, AS27280, AS27381, AS27413, 124 | AS-27506-TRANSIT, AS27908, AS28786, AS29706, AS29846, AS29909, 125 | AS30058, AS30238, AS30373, AS30502, AS-30517-ASSOCIATED, AS31402, 126 | AS32063, AS32131, AS32286, AS32313, AS32392, 127 | AS32421:AS-CUSTOMERS, AS32489, AS32632, AS32780, AS32782, 128 | AS32977, AS33065, AS33314, AS33404, AS34967, AS35180, AS3584, 129 | AS35890, AS35906, AS3595, AS35975, AS36137, AS36323, AS36605, 130 | AS36614, AS3737, AS376:AS-CUSTOMERS, AS3842, AS38880, AS393241, 131 | AS3943, AS39995, AS40041, AS40125, AS40217, AS40335, AS40353, 132 | AS40418, AS40428, AS40539, AS40676, AS40784, AS40926, AS42369, 133 | AS43639, AS43664, AS44965, AS4544:AS-NA-CUSTOMERS, AS45474, 134 | AS46261, AS46351, AS46489, AS46609, AS46652, AS46665, AS46844, 135 | AS46922, AS47484, AS4866, AS50468, AS51205, AS53265, AS53301, 136 | AS53342, AS53428, AS53429, AS53582, AS53817, AS53969, AS54113, 137 | AS54136, AS54235, AS54288, AS54329, AS54333, AS54335, AS54460, 138 | AS54491, AS54527:AS-GLOBAL, AS54540, AS54594, AS54600, AS54778, 139 | AS54829, AS54905, AS54953, AS54957, AS54963, AS54994, AS55011, 140 | AS55041, AS55069, AS5645:AS-CUSTOMERS, AS-5713, AS57624, AS5784, 141 | AS60736, AS61373, AS62195, AS62567, AS62713, AS62725, AS62870, 142 | AS62982, AS63003, AS63008, AS63058, AS6643, AS7219, AS7456, 143 | AS792, AS-ACEDATACENTERS, AS-ACN, AS-ADTAQ, AS-AFILIAS-FULLMONTY, 144 | AS-AFNCA, AS-AKAMAI, AS-APPLIEDOPS, AS-AREN, AS-ARIALINK, 145 | AS-AVESTANETWORKS, AS-BIGWELLS, AS-BLIP, AS-BTS, AS-BURSTNET, 146 | AS-BXI, AS-C1, AS-C3, AS-CACHENETWORKS, AS-CBISP, AS-CHOOPA, 147 | AS-CIFNET, AS-CLUETRUST, AS-CNSERVERS, AS-COGNET, AS-COLOAT, 148 | AS-COLOCROSSING, AS-CORESITE-SET, AS-CQ-GIGENET, AS-CYBERVERSE, 149 | AS-DACENTEC, AS-DCC, AS-DEAC, AS-DISTRIBUTEL, AS-DVLABS, 150 | AS-ED-ASH, AS-EDGECAST, AS-ENA, AS-ENERGYGROUPNETWORKS, 151 | AS-FIBERINTERNETCENTER, AS-FORTRESS, AS-FOXVALLEY, 152 | AS-GIGANEWS-ALL, AS-GORACK, AS-GREATACCESS, AS-GTCOMM1, 153 | AS-HAPNET, AS-HGC, AS-HOSTVIRTUAL, AS-ICANNDNSW, AS-IDCGLOBAL, 154 | AS-INFORELAY, AS-INFOSTEWARDS, AS-INMOTION, AS-INTERACTIVE3D, 155 | AS-VIO, AS-VOBIZ, AS-VOXEL, AS-VPLS, AS-WBTSGBR, AS-WEBAIR, 156 | AS-WEBNX, AS-WEBPASS, AS-WESTHOST, AS-WHS-US, AS-XMISSION, 157 | AS-XPLUSONE, AS-YELLOWFIBER, AS-YOUR-GLOBAL-SET 158 | admin-c: NIA1-ARIN 159 | tech-c: NLAYE-ARIN 160 | mnt-by: MAINT-NLAYER 161 | changed: ipeng@nlayer.net 20150208 162 | source: ALTDB 163 | 164 | as-set: AS-NLAYER-CUSTOMERS2 165 | descr: nLayer Communications - Customer AS-SET 166 | members: AS10625, AS10692, AS10905, AS10940, AS11013, AS11280, AS11282, 167 | AS11346, AS11478, AS11483, AS11682, AS11696, AS11763, AS11931, 168 | AS-1215, AS12284, AS13335, AS1341, AS13557, AS13722, AS13730, 169 | AS-BXI, AS-C1, AS-C3, AS-CACHENETWORKS, AS-CBISP, AS-CHOOPA, 170 | AS-CIFNET, AS-CLUETRUST, AS-CNSERVERS, AS-COGNET, AS-COLOAT, 171 | AS-COLOCROSSING, AS-CORESITE-SET, AS-CQ-GIGENET, AS-CYBERVERSE, # herpa 172 | AS-XPLUSONE, AS-YELLOWFIBER, AS-YOUR-GLOBAL-SET #derpa 173 | admin-c: NIA1-ARIN 174 | tech-c: NLAYE-ARIN 175 | mnt-by: MAINT-NLAYER 176 | changed: ipeng@nlayer.net 20150208 177 | source: ALTDB 178 | 179 | # EOF 180 | -------------------------------------------------------------------------------- /tests/nrtm_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (C) 2015 Job Snijders 3 | # 4 | # This file is part of IRR Explorer 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, 10 | # this list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | # POSSIBILITY OF SUCH DAMAGE. 27 | 28 | """ 29 | Small script to emulate a NRTM server 30 | Copyright (C) 2015 Job Snijders 31 | 32 | Registry name: REGRESSION :-) 33 | 34 | Get a sample or NRTM: 35 | echo -k -g RADB:3:$(echo $(curl -s \ 36 | ftp://ftp.radb.net/radb/dbase/RADB.CURRENTSERIAL) - 5 | bc)-LAST \ 37 | | nc whois.radb.net 43 38 | 39 | """ 40 | 41 | import time 42 | import socket 43 | from thread import start_new_thread 44 | 45 | host = '::' 46 | port = 4444 47 | flowinfo = 0 48 | scopeid = 0 49 | sockaddr = (host, port, flowinfo, scopeid) 50 | 51 | nrtm_data_1 = """%START Version: 3 regression 1983029-1983034 52 | 53 | ADD 1983029 54 | 55 | route: 180.211.93.0/24 56 | descr: route-object of PT. KINGS NETWORK INDONESIA 57 | Internet Services Provider 58 | Bekasi, ID 59 | origin: AS45725 60 | notify: windhu@i.net.id 61 | mnt-by: MAINT-AS45725 62 | changed: windhu@i.net.id 20150209 #11:51:47Z 63 | source: REGRESSION 64 | 65 | ADD 1983030 66 | 67 | route: 180.211.92.0/24 68 | descr: route-object of PT. KINGS NETWORK INDONESIA 69 | Internet Services Provider 70 | Bekasi, ID 71 | origin: AS45725 72 | notify: windhu@i.net.id 73 | mnt-by: MAINT-AS45725 74 | changed: windhu@i.net.id 20150209 #11:52:15Z 75 | source: REGRESSION 76 | 77 | ADD 1983031 78 | 79 | mntner: MAINT-AS198492 80 | descr: rPeer Ltd 81 | admin-c: Denis Nuja 82 | tech-c: Denis Nuja 83 | upd-to: denis@falizmaj.org 84 | mnt-nfy: denis@falizmaj.org 85 | auth: CRYPT-PW HIDDENCRYPTPW 86 | mnt-by: MAINT-AS198492 87 | changed: e@e.net 20150203 88 | source: REGRESSION 89 | 90 | ADD 1983032 91 | 92 | aut-num: AS198492 93 | as-name: RPEER-1 94 | descr: rPeer Ltd 95 | admin-c: Denis Nuja 96 | tech-c: Denis Nuja 97 | mnt-by: MAINT-AS198492 98 | changed: d@d.net 99 | source: REGRESSION 100 | 101 | ADD 1983033 102 | 103 | route: 91.235.170.0/23 104 | descr: rPeer Ltd 105 | origin: AS198492 106 | mnt-by: MAINT-AS198492 107 | changed: d@d.com 108 | source: REGRESSION 109 | 110 | ADD 1983034 111 | 112 | aut-num: AS198492 113 | as-name: RPEER-1 114 | descr: rPeer Ltd 115 | import: from AS174 accept any 116 | import: from AS9119 accept any 117 | import: from AS198785 accept any 118 | export: to AS174 announce AS198492 119 | export: to AS9119 announce AS198492 120 | export: to AS198785 announce AS198492 121 | admin-c: Denis Nuja 122 | tech-c: Denis Nuja 123 | mnt-by: MAINT-AS198492 124 | changed: d@d.com 125 | source: REGRESSION 126 | 127 | %END REGRESSION 128 | """ 129 | 130 | nrtm_data_2 = """ 131 | ADD 1983035 132 | 133 | route: 5.8.47.0/24 134 | descr: Depo Data Center 135 | origin: AS50896 136 | mnt-by: MNT-DEPO40 137 | changed: unread@ripe.net 20000101 138 | source: REGRESSION 139 | remarks: **************************** 140 | remarks: * THIS OBJECT IS MODIFIED 141 | remarks: * Please note that all data that is generally regarded as personal 142 | remarks: * data has been removed from this object. 143 | remarks: * To view the original object, please query the RIPE Database at: 144 | remarks: * http://www.ripe.net/whois 145 | remarks: **************************** 146 | 147 | """ 148 | 149 | 150 | def clientthread(conn): 151 | conn.send('% Welcome to the NRTM test server.\n\n') 152 | while True: 153 | data = conn.recv(1024).strip() 154 | if not data: 155 | break 156 | print data 157 | if data == "-k -g REGRESSION:3:1983029-LAST": 158 | # send feed (copied from RADB) 159 | print "sending:" 160 | print nrtm_data_1 161 | conn.sendall(nrtm_data_1) 162 | # keep socket open, act like persistent 163 | time.sleep(10) 164 | # client requested refresh, but instead gets latest object 165 | print "sending:" 166 | print nrtm_data_2 167 | conn.sendall(nrtm_data_2) 168 | time.sleep(1) 169 | conn.close() 170 | if data == "!q": 171 | conn.close() 172 | conn.close() 173 | 174 | if __name__ == "__main__": 175 | sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0) 176 | sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) 177 | sock.bind(sockaddr) 178 | sock.listen(10) 179 | while True: 180 | conn, addr = sock.accept() 181 | print 'Connected with ' + addr[0] + ':' + str(addr[1]) 182 | start_new_thread(clientthread, (conn,)) 183 | sock.close() 184 | -------------------------------------------------------------------------------- /tests/nrtm_test.yml: -------------------------------------------------------------------------------- 1 | databases: 2 | regression: 3 | serial: 'tests/REGRESSION.CURRENTSERIAL' 4 | dump: 'tests/irrtest.data' 5 | nrtmhost: 'localhost' 6 | nrtmport: 4444 7 | -------------------------------------------------------------------------------- /tests/test_nrtmclient.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (C) 2015 Job Snijders 3 | # 4 | # This file is part of IRR Explorer 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, 10 | # this list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | # POSSIBILITY OF SUCH DAMAGE. 27 | 28 | import unittest 29 | 30 | from irrexplorer import nrtm, config 31 | 32 | 33 | class TestNRTM(unittest.TestCase): 34 | def test_00__test_nrtm(self): 35 | feedconfig = config('tests/nrtm_test.yml').databases['regression'] 36 | feed = nrtm.client(**feedconfig) 37 | for cmd, serial, obj in feed.get(): 38 | if not obj: 39 | continue 40 | print cmd, serial, len(obj) 41 | if cmd == "ADD" and serial == 1983035 and len(obj) == 4: 42 | self.assertTrue(True) 43 | 44 | def main(): 45 | unittest.main() 46 | 47 | if __name__ == '__main__': 48 | main() 49 | -------------------------------------------------------------------------------- /tests/test_regression.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (C) 2015 Job Snijders 3 | # 4 | # This file is part of IRR Explorer 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, 10 | # this list of conditions and the following disclaimer. 11 | # 12 | # 2. Redistributions in binary form must reproduce the above copyright notice, 13 | # this list of conditions and the following disclaimer in the documentation 14 | # and/or other materials provided with the distribution. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | # POSSIBILITY OF SUCH DAMAGE. 27 | 28 | from __future__ import print_function, division, absolute_import, unicode_literals 29 | 30 | import unittest 31 | 32 | from irrexplorer import parser 33 | 34 | 35 | class TestIRRExplorer(unittest.TestCase): 36 | def test_00__parse_rpsl_dump(self): 37 | dump = open('tests/irrtest.data') 38 | self.assertTrue(list(parser.parse_dump(dump))) 39 | 40 | 41 | def main(): 42 | unittest.main() 43 | 44 | if __name__ == '__main__': 45 | main() 46 | -------------------------------------------------------------------------------- /tests/test_utils.py: -------------------------------------------------------------------------------- 1 | # test classification 2 | 3 | import unittest 4 | 5 | from irrexplorer import utils 6 | 7 | 8 | class TestClassification(unittest.TestCase): 9 | 10 | def test_classification(self): 11 | 12 | a = utils.classifySearchString('10.0.0.1') 13 | self.assertEquals(type(a), utils.Prefix) 14 | 15 | a = utils.classifySearchString('1.3.4.0/24') 16 | self.assertEquals(type(a), utils.Prefix) 17 | 18 | a = utils.classifySearchString('AS2603') 19 | self.assertEquals(type(a), utils.ASNumber) 20 | 21 | a = utils.classifySearchString('AS-NTT') 22 | self.assertEquals(type(a), utils.ASMacro) 23 | 24 | a = utils.classifySearchString('AS-57344') 25 | self.assertEquals(type(a), utils.ASMacro) 26 | 27 | a = utils.classifySearchString('AS9498:AS-BHARTI-IN') 28 | self.assertEquals(type(a), utils.ASMacro) 29 | 30 | 31 | 32 | 33 | def main(): 34 | unittest.main() 35 | 36 | 37 | if __name__ == '__main__': 38 | main() 39 | 40 | -------------------------------------------------------------------------------- /worker: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Script to update BGP and IRR entries in the IRRExplorer database. 5 | """ 6 | 7 | import os 8 | import time 9 | import argparse 10 | import logging 11 | 12 | import yaml 13 | 14 | from irrexplorer import sqldb, bgpupdate, irrupdate 15 | 16 | 17 | DEFAULT_DATABASE = 'irrexplorer' 18 | DEFAULT_BGP_SOURCE = 'http://lg01.infra.ring.nlnog.net/table.txt' 19 | DEFAULT_IRR_SPEC = 'irrexplorer_config.yml' 20 | DEFAULT_LOG_FILE = 'irrworker.log' 21 | 22 | DEFAULT_UPDATE_INTERVAL = 300 # 5 minutes, the nlnog table is updated at that frequency 23 | 24 | 25 | INSERT_STM = "SELECT create_route (%s, %s, 'bgp');" 26 | DELETE_STM = "DELETE FROM routes USING sources WHERE routes.route = %s AND routes.asn = %s AND routes.source_id = sources.id AND sources.name = 'bgp';" 27 | 28 | 29 | 30 | def create_parser(): 31 | 32 | parser = argparse.ArgumentParser(description='Continously update BGP table in IRRExplorer database') 33 | parser.add_argument('-b', '--bgp-source', dest='bgp_source', default=DEFAULT_BGP_SOURCE, help='Source URL for BGP routing table (default: nlnog ring table)') 34 | parser.add_argument('-r', '--irr-spec', dest='irr_spec', default=DEFAULT_IRR_SPEC, help='IRR specifications file (default: %s)' % DEFAULT_IRR_SPEC) 35 | parser.add_argument('-d', '--database', dest='database', default=DEFAULT_DATABASE, help='IRRExplorer database name (default: %s)' % DEFAULT_DATABASE) 36 | parser.add_argument('-i', '--interval', dest='interval', default=DEFAULT_UPDATE_INTERVAL, help='Interval between updates (default: %i seconds)' % DEFAULT_UPDATE_INTERVAL) 37 | parser.add_argument('-l', '--logfile', dest='logfile', default=DEFAULT_LOG_FILE, help='Log file (default: %s)' % DEFAULT_LOG_FILE) 38 | return parser 39 | 40 | 41 | 42 | def parse_irr_spec(irr_spec): 43 | 44 | specs = [] 45 | 46 | if not os.path.exists(irr_spec): 47 | print 'Error: IRR spec file does not exist' 48 | return specs # don't fail on this (bgp update should be allowed to run) 49 | 50 | irr_cfg = open(irr_spec) 51 | cfg = yaml.load(irr_cfg) 52 | 53 | for db in cfg['databases']: 54 | for db_name, db_info in db.items(): 55 | host = port = source = None 56 | for dbe in db_info: 57 | host = dbe.get('nrtmhost', host) 58 | port = dbe.get('nrtmport', port) 59 | source = dbe.get('dbname', source) 60 | 61 | if host and source: 62 | specs.append( (host, port, source) ) 63 | else: 64 | print 'Could not parse %s for NRTM info' % db_name 65 | 66 | return specs 67 | 68 | 69 | 70 | def main(): 71 | 72 | parser = create_parser() 73 | args = parser.parse_args() 74 | 75 | update_interval = int(args.interval) 76 | 77 | irr_sources = parse_irr_spec(args.irr_spec) 78 | 79 | logging.basicConfig(filename=args.logfile, format='%(asctime)s %(levelname)s: %(message)s', level=logging.DEBUG) 80 | 81 | dsn = 'dbname=%s' % args.database 82 | db = sqldb.IRRSQLDatabase(dsn) 83 | 84 | logging.info('Worker started') 85 | 86 | while True: 87 | 88 | t_start = time.time() 89 | 90 | # bgp 91 | try: 92 | bgpupdate.updateBGP(args.bgp_source, db) 93 | except Exception as e: 94 | logging.error('Error duing bgp update: %s' % str(e)) 95 | 96 | # irr update 97 | for host, port, source in irr_sources: 98 | try: 99 | irrupdate.update_irr(host, port, source, db) 100 | except Exception as e: 101 | logging.error('Error during IRR update: %s' % str(e)) 102 | if "don't exist!" in str(e): 103 | logging.error( 104 | "ERROR: the above error probably means that the gap between your seed" + 105 | "snapshot and the current SERIAL on the stream source is too large.") 106 | 107 | # sleep 108 | 109 | t_sleep = update_interval - (time.time() - t_start) 110 | 111 | if t_sleep < 0: 112 | logging.info('Update took longer time than sleep interval, skipping sleep') 113 | else: 114 | logging.info('Sleeping for %i seconds' % t_sleep) 115 | time.sleep(t_sleep) 116 | logging.info('--') 117 | 118 | 119 | if __name__ == '__main__': 120 | main() 121 | 122 | --------------------------------------------------------------------------------