|
| 1 | +#!/usr/bin/env python3 |
| 2 | +""" Subscribe to the RIPE RIS-Live stream and process it """ |
| 3 | + |
| 4 | +## (c) 2019 Jared Mauch |
| 5 | + |
| 6 | +import json |
| 7 | +import time |
| 8 | +import websocket |
| 9 | +import sys |
| 10 | + |
| 11 | +## Uncomment and update this with a unique identifier for the RIPE team |
| 12 | +#url = "wss://ris-live.ripe.net/v1/ws/?client=username_at_example_com" |
| 13 | + |
| 14 | +asn = '20940' |
| 15 | + |
| 16 | +# store start time |
| 17 | +last_periodic = time.time() |
| 18 | +periodic_interval = 90 # 90 seconds |
| 19 | + |
| 20 | +noisy_prefix = {} |
| 21 | +noisy_aspath = {} |
| 22 | +while True: |
| 23 | + ws = websocket.WebSocket() |
| 24 | + try: |
| 25 | + ws.connect(url) |
| 26 | + except websocket.WebSocketBadStatusException as e: |
| 27 | + print(e, "while calling connect()") |
| 28 | + time.sleep(30) |
| 29 | + continue |
| 30 | + |
| 31 | + # subscribe to all BGP Updates |
| 32 | + ws.send(json.dumps({"type": "ris_subscribe", "data": {"type": "UPDATE", "path": asn}})) |
| 33 | + try: |
| 34 | + for data in ws: |
| 35 | + # get current time |
| 36 | + now = time.time() |
| 37 | + if now - last_periodic > periodic_interval: |
| 38 | + print("============ periodic ============") |
| 39 | + # |
| 40 | + count = 0 |
| 41 | + for k ,v in sorted(noisy_prefix.items(), key=lambda kv:(kv[1], kv[0]), reverse=True): |
| 42 | + if count > 10: |
| 43 | + break |
| 44 | + if noisy_prefix[k] > 100: |
| 45 | + print(k, noisy_prefix[k]) |
| 46 | + count = count + 1 |
| 47 | + count = 0 |
| 48 | + for k, v in sorted(noisy_aspath.items(), key=lambda kv:(kv[1], kv[0]), reverse=True): |
| 49 | + if count > 10: |
| 50 | + break |
| 51 | + if noisy_aspath[k] > 100: |
| 52 | + print(k, noisy_aspath[k]) |
| 53 | + count = count + 1 |
| 54 | + |
| 55 | + noisy_prefix = {} |
| 56 | + noisy_aspath = {} |
| 57 | + last_periodic = now |
| 58 | + print("============ periodic ============") |
| 59 | + # |
| 60 | + |
| 61 | + parsed = json.loads(data) |
| 62 | + if parsed.get('type', None) == 'ris_error': |
| 63 | + print(data) |
| 64 | + if parsed.get('type', None) == 'ris_message': |
| 65 | + # print(parsed["type"], parsed["data"]) |
| 66 | + parsed_data = parsed.get("data", None) |
| 67 | + announcements = parsed_data.get('announcements', None) |
| 68 | + withdrawls = parsed_data.get('withdrawls', None) |
| 69 | + try: |
| 70 | + as_path = ' '.join(str(x) for x in parsed_data.get('path', None)) |
| 71 | + except: |
| 72 | + as_path = '' |
| 73 | + if announcements is not None: |
| 74 | + for announcement in announcements: |
| 75 | + for prefix in announcement['prefixes']: |
| 76 | +# print("add|%s|%s" % (prefix, as_path)) |
| 77 | + noisy_prefix[prefix] = noisy_prefix.get(prefix, 0) + 1 |
| 78 | + noisy_aspath[as_path] = noisy_aspath.get(as_path, 0) + 1 |
| 79 | + |
| 80 | + if withdrawls is not None: |
| 81 | + for announcement in withdrawls: |
| 82 | + for prefix in announcement['prefixes']: |
| 83 | +# print("del|%s|%s" % (prefix, as_path)) |
| 84 | + noisy_prefix[prefix] = noisy_prefix.get(prefix, 0) + 1 |
| 85 | + noisy_aspath[as_path] = noisy_aspath.get(as_path, 0) + 1 |
| 86 | + |
| 87 | + except websocket.WebSocketConnectionClosedException as e: |
| 88 | + print("Disconnected, sleeping for a few then reconnect", e) |
| 89 | + time.sleep(30) |
| 90 | + except ConnectionResetError as e: |
| 91 | + print("Disconnected, sleeping for a few then reconnect", e) |
| 92 | + time.sleep(30) |
| 93 | + except BrokenPipeError as e: |
| 94 | + print("Disconnected, sleeping for a few then reconnect", e) |
| 95 | + time.sleep(30) |
| 96 | + except websocket.WebSocketBadStatusException as e: |
| 97 | + print("Disconnected, sleeping for a few then reconnect", e) |
| 98 | + time.sleep(30) |
| 99 | + except websocket.WebSocketTimeoutException as e: |
| 100 | + print("Disconnected, sleeping for a few then reconnect", e) |
| 101 | + time.sleep(30) |
| 102 | + except KeyboardInterrupt: |
| 103 | + print("User stop requested") |
| 104 | + sys.exit() |
| 105 | + except Exception as e: |
| 106 | + print("some other error?", e) |
| 107 | + time.sleep(30) |
| 108 | + |
| 109 | +## |
| 110 | +## ris_message |
| 111 | +### {'timestamp': 1550258410.78, |
| 112 | +### 'peer': '217.29.66.88', |
| 113 | +### 'peer_asn': '20811', |
| 114 | +### 'id': '217.29.66.88-1550258410.78-59479614', |
| 115 | +### 'host': 'rrc10', |
| 116 | +### 'type': 'UPDATE', |
| 117 | +### 'path': [20811, 8529, 9155, 51914, 51914, 51914, 51914], |
| 118 | +### 'origin': 'igp', |
| 119 | +### 'announcements': |
| 120 | +### [{'next_hop': '217.29.67.63', 'prefixes': ['91.221.128.0/24']} ] |
| 121 | +### } |
| 122 | +## ris_message |
| 123 | +### {'timestamp': 1550258410.78, |
| 124 | +### 'peer': '217.29.66.88', |
| 125 | +### 'peer_asn': '20811', |
| 126 | +### 'id': '217.29.66.88-1550258410.78-59479616', |
| 127 | +### 'host': 'rrc10', |
| 128 | +### 'type': 'UPDATE', |
| 129 | +### 'path': [20811, 8529, 49666, 42440, 205647, 44400, 47843], |
| 130 | +### 'origin': 'igp', |
| 131 | +### 'announcements': [ |
| 132 | +#### {'next_hop': '217.29.67.63', |
| 133 | +#### 'prefixes': |
| 134 | +##### ['87.248.144.0/24', |
| 135 | +##### '87.248.150.0/24', |
| 136 | +##### '87.248.139.0/24', |
| 137 | +##### '87.248.153.0/24', |
| 138 | +##### '87.248.149.0/24', |
| 139 | +##### '87.248.145.0/24', |
| 140 | +##### '87.248.152.0/24', |
| 141 | +##### '87.248.151.0/24', |
| 142 | +##### '87.248.138.0/24', |
| 143 | +##### '87.248.133.0/24', |
| 144 | +##### '87.248.147.0/24', |
| 145 | +##### '87.248.155.0/24', |
| 146 | +##### '87.248.131.0/24', |
| 147 | +##### '87.248.132.0/24', |
| 148 | +##### '87.248.136.0/24', |
| 149 | +##### '87.248.154.0/24', |
| 150 | +##### '87.248.156.0/24', |
| 151 | +##### '87.248.158.0/24', |
| 152 | +##### '87.248.134.0/24', |
| 153 | +##### '87.248.135.0/24', |
| 154 | +##### '87.248.129.0/24', |
| 155 | +##### '87.248.130.0/24', |
| 156 | +##### '87.248.146.0/24', |
| 157 | +##### '87.248.128.0/24', |
| 158 | +##### '87.248.137.0/24'] |
| 159 | +#### } |
| 160 | +### ] |
| 161 | +### } |
0 commit comments