root / plugins / tor / tor_ @ a7139bca
Historique | Voir | Annoter | Télécharger (17,5 ko)
| 1 | a7139bca | Lars Kruse | #!/usr/bin/env python3 |
|---|---|---|---|
| 2 | 87325764 | daftaupe | ''' |
| 3 | =head1 NAME |
||
| 4 | f9d8ce70 | Lars Kruse | |
| 5 | 17f78427 | Lars Kruse | tor_ |
| 6 | 87325764 | daftaupe | |
| 7 | =head1 DESCRIPTION |
||
| 8 | f9d8ce70 | Lars Kruse | |
| 9 | 8713eb37 | Lars Kruse | Wildcard plugin that gathers some metrics from the Tor daemon |
| 10 | f9d8ce70 | Lars Kruse | (https://github.com/daftaupe/munin-tor). |
| 11 | 87325764 | daftaupe | |
| 12 | Derived from https://github.com/mweinelt/munin-tor |
||
| 13 | |||
| 14 | f9d8ce70 | Lars Kruse | This plugin requires the stem library (https://stem.torproject.org/). |
| 15 | |||
| 16 | This plugin requires the GeoIP library (https://www.maxmind.com) for the countries plugin. |
||
| 17 | |||
| 18 | Available plugins: |
||
| 19 | |||
| 20 | =over 4 |
||
| 21 | |||
| 22 | =item tor_bandwidth - graph the glabal bandwidth |
||
| 23 | |||
| 24 | =item tor_connections - graph the number of connexions |
||
| 25 | |||
| 26 | =item tor_countries - graph the countries represented our connexions |
||
| 27 | |||
| 28 | =item tor_dormant - graph if tor is dormant or not |
||
| 29 | |||
| 30 | =item tor_flags - graph the different flags of the relay |
||
| 31 | |||
| 32 | =item tor_routers - graph the number of routers seen by the relay |
||
| 33 | 87325764 | daftaupe | |
| 34 | f9d8ce70 | Lars Kruse | =item tor_traffic - graph the read/written traffic |
| 35 | |||
| 36 | =back |
||
| 37 | 87325764 | daftaupe | |
| 38 | =head2 CONFIGURATION |
||
| 39 | f9d8ce70 | Lars Kruse | |
| 40 | The default configuration is: |
||
| 41 | |||
| 42 | [tor_*] |
||
| 43 | user toranon # or any other user/group that is running tor |
||
| 44 | group toranon |
||
| 45 | env.torcachefile munin_tor_country_stats.json |
||
| 46 | env.torconnectmethod port |
||
| 47 | env.torgeoippath /usr/share/GeoIP/GeoIP.dat |
||
| 48 | env.tormaxcountries 15 |
||
| 49 | env.torport 9051 |
||
| 50 | env.torsocket /var/run/tor/control |
||
| 51 | |||
| 52 | To make it connect through a socket, you simply need to change C<torconnectmethod>: |
||
| 53 | |||
| 54 | env.torconnectmethod socket |
||
| 55 | 87325764 | daftaupe | |
| 56 | =head1 COPYRIGHT |
||
| 57 | f9d8ce70 | Lars Kruse | |
| 58 | 87325764 | daftaupe | MIT License |
| 59 | |||
| 60 | f9d8ce70 | Lars Kruse | SPDX-License-Identifier: MIT |
| 61 | |||
| 62 | 87325764 | daftaupe | =head1 AUTHOR |
| 63 | f9d8ce70 | Lars Kruse | |
| 64 | 452003a3 | Pierre-Alain TORET | Pierre-Alain TORET <pierre-alain.toret@protonmail.com> |
| 65 | 24ab44ca | Lars Kruse | |
| 66 | =head1 MAGIC MARKERS |
||
| 67 | f9d8ce70 | Lars Kruse | |
| 68 | #%# family=auto |
||
| 69 | #%# capabilities=autoconf suggest |
||
| 70 | |||
| 71 | =cut |
||
| 72 | 87325764 | daftaupe | ''' |
| 73 | 0d549a44 | daftaupe | |
| 74 | import collections |
||
| 75 | import json |
||
| 76 | import os |
||
| 77 | 87325764 | daftaupe | import sys |
| 78 | |||
| 79 | ec2d1fea | daftaupe | try: |
| 80 | import GeoIP |
||
| 81 | import stem |
||
| 82 | import stem.control |
||
| 83 | import stem.connection |
||
| 84 | except ImportError: |
||
| 85 | # missing dependencies are reported via "autoconf" |
||
| 86 | # thus failure is acceptable here |
||
| 87 | pass |
||
| 88 | 0d549a44 | daftaupe | |
| 89 | default_torcachefile = 'munin_tor_country_stats.json' |
||
| 90 | 87325764 | daftaupe | default_torconnectmethod = 'port' |
| 91 | 832ecbad | wodry | default_torgeoippath = '/usr/share/GeoIP/GeoIP.dat' |
| 92 | 87325764 | daftaupe | default_tormaxcountries = 15 |
| 93 | 0d549a44 | daftaupe | default_torport = 9051 |
| 94 | default_torsocket = '/var/run/tor/control' |
||
| 95 | |||
| 96 | |||
| 97 | class ConnectionError(Exception): |
||
| 98 | """Error connecting to the controller""" |
||
| 99 | |||
| 100 | |||
| 101 | class AuthError(Exception): |
||
| 102 | """Error authenticating to the controller""" |
||
| 103 | |||
| 104 | |||
| 105 | def authenticate(controller): |
||
| 106 | try: |
||
| 107 | controller.authenticate() |
||
| 108 | return |
||
| 109 | except stem.connection.MissingPassword: |
||
| 110 | pass |
||
| 111 | |||
| 112 | try: |
||
| 113 | password = os.environ['torpassword'] |
||
| 114 | except KeyError: |
||
| 115 | raise AuthError("Please configure the 'torpassword' "
|
||
| 116 | "environment variable") |
||
| 117 | |||
| 118 | try: |
||
| 119 | controller.authenticate(password=password) |
||
| 120 | except stem.connection.PasswordAuthFailed: |
||
| 121 | 87325764 | daftaupe | print("Authentication failed (incorrect password)", file=sys.stderr)
|
| 122 | 0d549a44 | daftaupe | |
| 123 | |||
| 124 | def gen_controller(): |
||
| 125 | 87325764 | daftaupe | connect_method = os.environ.get('torconnectmethod', default_torconnectmethod)
|
| 126 | 0d549a44 | daftaupe | if connect_method == 'port': |
| 127 | 24ab44ca | Lars Kruse | return stem.control.Controller.from_port(port=int(os.environ.get('torport',
|
| 128 | default_torport))) |
||
| 129 | 0d549a44 | daftaupe | elif connect_method == 'socket': |
| 130 | 24ab44ca | Lars Kruse | return stem.control.Controller.from_socket_file(path=os.environ.get('torsocket',
|
| 131 | default_torsocket)) |
||
| 132 | 0d549a44 | daftaupe | else: |
| 133 | 24ab44ca | Lars Kruse | print("env.torconnectmethod contains an invalid value. "
|
| 134 | "Please specify either 'port' or 'socket'.", file=sys.stderr) |
||
| 135 | 87325764 | daftaupe | sys.exit(1) |
| 136 | 0d549a44 | daftaupe | |
| 137 | |||
| 138 | ######################### |
||
| 139 | # Base Class |
||
| 140 | ######################### |
||
| 141 | |||
| 142 | |||
| 143 | class TorPlugin(object): |
||
| 144 | def __init__(self): |
||
| 145 | raise NotImplementedError |
||
| 146 | |||
| 147 | def conf(self): |
||
| 148 | raise NotImplementedError |
||
| 149 | |||
| 150 | @staticmethod |
||
| 151 | def conf_from_dict(graph, labels): |
||
| 152 | # header |
||
| 153 | 71f92805 | Pierre-Alain TORET | for key, val in graph.items(): |
| 154 | 0d549a44 | daftaupe | print('graph_{} {}'.format(key, val))
|
| 155 | # values |
||
| 156 | 71f92805 | Pierre-Alain TORET | for label, attributes in labels.items(): |
| 157 | for key, val in attributes.items(): |
||
| 158 | 0d549a44 | daftaupe | print('{}.{} {}'.format(label, key, val))
|
| 159 | |||
| 160 | @staticmethod |
||
| 161 | def autoconf(): |
||
| 162 | try: |
||
| 163 | 87325764 | daftaupe | import stem |
| 164 | |||
| 165 | except ImportError as e: |
||
| 166 | ec2d1fea | daftaupe | print('no (failed to import the required python module "stem": {})'.format(e))
|
| 167 | 87325764 | daftaupe | |
| 168 | try: |
||
| 169 | 24ab44ca | Lars Kruse | import GeoIP # noqa: F401 |
| 170 | 87325764 | daftaupe | |
| 171 | except ImportError as e: |
||
| 172 | ef913139 | daftaupe | print('no (failed to import the required python module "GeoIP": {})'.format(e))
|
| 173 | 87325764 | daftaupe | |
| 174 | try: |
||
| 175 | 0d549a44 | daftaupe | with gen_controller() as controller: |
| 176 | try: |
||
| 177 | authenticate(controller) |
||
| 178 | print('yes')
|
||
| 179 | except stem.connection.AuthenticationFailure as e: |
||
| 180 | print('no (Authentication failed: {})'.format(e))
|
||
| 181 | |||
| 182 | except stem.connection: |
||
| 183 | print('no (Connection failed)')
|
||
| 184 | |||
| 185 | @staticmethod |
||
| 186 | def suggest(): |
||
| 187 | 24ab44ca | Lars Kruse | options = ['bandwidth', 'connections', 'countries', 'dormant', 'flags', 'routers', |
| 188 | 'traffic'] |
||
| 189 | 0d549a44 | daftaupe | |
| 190 | for option in options: |
||
| 191 | print(option) |
||
| 192 | |||
| 193 | def fetch(self): |
||
| 194 | raise NotImplementedError |
||
| 195 | |||
| 196 | |||
| 197 | ########################## |
||
| 198 | # Child Classes |
||
| 199 | ########################## |
||
| 200 | |||
| 201 | |||
| 202 | class TorBandwidth(TorPlugin): |
||
| 203 | def __init__(self): |
||
| 204 | pass |
||
| 205 | |||
| 206 | def conf(self): |
||
| 207 | f14887f5 | daftaupe | graph = {'title': 'Tor observed bandwidth',
|
| 208 | 0d549a44 | daftaupe | 'args': '-l 0 --base 1000', |
| 209 | 'vlabel': 'bytes/s', |
||
| 210 | 87325764 | daftaupe | 'category': 'network', |
| 211 | 0d549a44 | daftaupe | 'info': 'estimated capacity based on usage in bytes/s'} |
| 212 | labels = {'bandwidth': {'label': 'bandwidth', 'min': 0, 'type': 'GAUGE'}}
|
||
| 213 | |||
| 214 | TorPlugin.conf_from_dict(graph, labels) |
||
| 215 | |||
| 216 | def fetch(self): |
||
| 217 | with gen_controller() as controller: |
||
| 218 | try: |
||
| 219 | authenticate(controller) |
||
| 220 | except stem.connection.AuthenticationFailure as e: |
||
| 221 | print('Authentication failed ({})'.format(e))
|
||
| 222 | return |
||
| 223 | |||
| 224 | # Get fingerprint of our own relay to look up the descriptor for. |
||
| 225 | # In Stem 1.3.0 and later, get_server_descriptor() will fetch the |
||
| 226 | # relay's own descriptor if no argument is provided, so this will |
||
| 227 | # no longer be needed. |
||
| 228 | fingerprint = controller.get_info('fingerprint', None)
|
||
| 229 | if fingerprint is None: |
||
| 230 | print("Error while reading fingerprint from Tor daemon", file=sys.stderr)
|
||
| 231 | 87325764 | daftaupe | sys.exit(1) |
| 232 | 0d549a44 | daftaupe | |
| 233 | response = controller.get_server_descriptor(fingerprint, None) |
||
| 234 | if response is None: |
||
| 235 | print("Error while getting server descriptor from Tor daemon", file=sys.stderr)
|
||
| 236 | 87325764 | daftaupe | sys.exit(1) |
| 237 | 0d549a44 | daftaupe | print('bandwidth.value {}'.format(response.observed_bandwidth))
|
| 238 | |||
| 239 | |||
| 240 | class TorConnections(TorPlugin): |
||
| 241 | def __init__(self): |
||
| 242 | pass |
||
| 243 | |||
| 244 | def conf(self): |
||
| 245 | f14887f5 | daftaupe | graph = {'title': 'Tor connections',
|
| 246 | 0d549a44 | daftaupe | 'args': '-l 0 --base 1000', |
| 247 | 'vlabel': 'connections', |
||
| 248 | 87325764 | daftaupe | 'category': 'network', |
| 249 | 0d549a44 | daftaupe | 'info': 'OR connections by state'} |
| 250 | labels = {'new': {'label': 'new', 'min': 0, 'max': 25000, 'type': 'GAUGE'},
|
||
| 251 | 'launched': {'label': 'launched', 'min': 0, 'max': 25000, 'type': 'GAUGE'},
|
||
| 252 | 'connected': {'label': 'connected', 'min': 0, 'max': 25000, 'type': 'GAUGE'},
|
||
| 253 | 'failed': {'label': 'failed', 'min': 0, 'max': 25000, 'type': 'GAUGE'},
|
||
| 254 | 'closed': {'label': 'closed', 'min': 0, 'max': 25000, 'type': 'GAUGE'}}
|
||
| 255 | |||
| 256 | TorPlugin.conf_from_dict(graph, labels) |
||
| 257 | |||
| 258 | def fetch(self): |
||
| 259 | with gen_controller() as controller: |
||
| 260 | try: |
||
| 261 | authenticate(controller) |
||
| 262 | |||
| 263 | response = controller.get_info('orconn-status', None)
|
||
| 264 | if response is None: |
||
| 265 | print("No response from Tor daemon in TorConnection.fetch()", file=sys.stderr)
|
||
| 266 | 87325764 | daftaupe | sys.exit(1) |
| 267 | 0d549a44 | daftaupe | else: |
| 268 | connections = response.split('\n')
|
||
| 269 | states = dict((state, 0) for state in stem.ORStatus) |
||
| 270 | for connection in connections: |
||
| 271 | states[connection.rsplit(None, 1)[-1]] += 1 |
||
| 272 | 71f92805 | Pierre-Alain TORET | for state, count in states.items(): |
| 273 | 0d549a44 | daftaupe | print('{}.value {}'.format(state.lower(), count))
|
| 274 | except stem.connection.AuthenticationFailure as e: |
||
| 275 | print('Authentication failed ({})'.format(e))
|
||
| 276 | |||
| 277 | |||
| 278 | class TorCountries(TorPlugin): |
||
| 279 | def __init__(self): |
||
| 280 | # Configure plugin |
||
| 281 | self.cache_dir_name = os.environ.get('torcachedir', None)
|
||
| 282 | if self.cache_dir_name is not None: |
||
| 283 | 24ab44ca | Lars Kruse | self.cache_dir_name = os.path.join( |
| 284 | self.cache_dir_name, os.environ.get('torcachefile', default_torcachefile))
|
||
| 285 | 0d549a44 | daftaupe | |
| 286 | 87325764 | daftaupe | max_countries = os.environ.get('tormaxcountries', default_tormaxcountries)
|
| 287 | 0d549a44 | daftaupe | self.max_countries = int(max_countries) |
| 288 | |||
| 289 | geoip_path = os.environ.get('torgeoippath', default_torgeoippath)
|
||
| 290 | 87325764 | daftaupe | self.geodb = GeoIP.open(geoip_path, GeoIP.GEOIP_MEMORY_CACHE) |
| 291 | 0d549a44 | daftaupe | |
| 292 | def conf(self): |
||
| 293 | """Configure plugin""" |
||
| 294 | |||
| 295 | f14887f5 | daftaupe | graph = {'title': 'Tor countries',
|
| 296 | 0d549a44 | daftaupe | 'args': '-l 0 --base 1000', |
| 297 | 'vlabel': 'countries', |
||
| 298 | 87325764 | daftaupe | 'category': 'network', |
| 299 | 0d549a44 | daftaupe | 'info': 'OR connections by state'} |
| 300 | labels = {}
|
||
| 301 | |||
| 302 | countries_num = self.top_countries() |
||
| 303 | |||
| 304 | for c, v in countries_num: |
||
| 305 | labels[c] = {'label': c, 'min': 0, 'max': 25000, 'type': 'GAUGE'}
|
||
| 306 | |||
| 307 | TorPlugin.conf_from_dict(graph, labels) |
||
| 308 | |||
| 309 | # If needed, create cache file at config time |
||
| 310 | if self.cache_dir_name: |
||
| 311 | with open(self.cache_dir_name, 'w') as f: |
||
| 312 | json.dump(countries_num, f) |
||
| 313 | |||
| 314 | def fetch(self): |
||
| 315 | """Generate metrics""" |
||
| 316 | |||
| 317 | # If possible, read cached data instead of doing the processing twice |
||
| 318 | try: |
||
| 319 | with open(self.cache_dir_name) as f: |
||
| 320 | countries_num = json.load(f) |
||
| 321 | 24ab44ca | Lars Kruse | except (IOError, ValueError): |
| 322 | 0d549a44 | daftaupe | # Fallback if cache_dir_name is not set, unreadable or any other |
| 323 | # error |
||
| 324 | countries_num = self.top_countries() |
||
| 325 | |||
| 326 | for c, v in countries_num: |
||
| 327 | print("%s.value %d" % (c, v))
|
||
| 328 | |||
| 329 | @staticmethod |
||
| 330 | def _gen_ipaddrs_from_statuses(controller): |
||
| 331 | """Generate a sequence of ipaddrs for every network status""" |
||
| 332 | for desc in controller.get_network_statuses(): |
||
| 333 | ipaddr = desc.address |
||
| 334 | yield ipaddr |
||
| 335 | |||
| 336 | 87325764 | daftaupe | @staticmethod |
| 337 | def simplify(cn): |
||
| 338 | """Simplify country name""" |
||
| 339 | cn = cn.replace(' ', '_')
|
||
| 340 | cn = cn.replace("'", '_')
|
||
| 341 | cn = cn.split(',', 1)[0]
|
||
| 342 | return cn |
||
| 343 | |||
| 344 | 0d549a44 | daftaupe | def _gen_countries(self, controller): |
| 345 | """Generate a sequence of countries for every built circuit""" |
||
| 346 | for ipaddr in self._gen_ipaddrs_from_statuses(controller): |
||
| 347 | country = self.geodb.country_name_by_addr(ipaddr) |
||
| 348 | if country is None: |
||
| 349 | yield 'Unknown' |
||
| 350 | continue |
||
| 351 | |||
| 352 | 87325764 | daftaupe | yield self.simplify(country) |
| 353 | 0d549a44 | daftaupe | |
| 354 | def top_countries(self): |
||
| 355 | """Build a list of top countries by number of circuits""" |
||
| 356 | with gen_controller() as controller: |
||
| 357 | try: |
||
| 358 | authenticate(controller) |
||
| 359 | c = collections.Counter(self._gen_countries(controller)) |
||
| 360 | return sorted(c.most_common(self.max_countries)) |
||
| 361 | except stem.connection.AuthenticationFailure as e: |
||
| 362 | print('Authentication failed ({})'.format(e))
|
||
| 363 | return [] |
||
| 364 | |||
| 365 | |||
| 366 | class TorDormant(TorPlugin): |
||
| 367 | def __init__(self): |
||
| 368 | pass |
||
| 369 | |||
| 370 | def conf(self): |
||
| 371 | f14887f5 | daftaupe | graph = {'title': 'Tor dormant',
|
| 372 | 0d549a44 | daftaupe | 'args': '-l 0 --base 1000', |
| 373 | 'vlabel': 'dormant', |
||
| 374 | 87325764 | daftaupe | 'category': 'network', |
| 375 | 0d549a44 | daftaupe | 'info': 'Is Tor not building circuits because it is idle?'} |
| 376 | labels = {'dormant': {'label': 'dormant', 'min': 0, 'max': 1, 'type': 'GAUGE'}}
|
||
| 377 | |||
| 378 | TorPlugin.conf_from_dict(graph, labels) |
||
| 379 | |||
| 380 | def fetch(self): |
||
| 381 | with gen_controller() as controller: |
||
| 382 | try: |
||
| 383 | authenticate(controller) |
||
| 384 | |||
| 385 | response = controller.get_info('dormant', None)
|
||
| 386 | if response is None: |
||
| 387 | print("Error while reading dormant state from Tor daemon", file=sys.stderr)
|
||
| 388 | 87325764 | daftaupe | sys.exit(1) |
| 389 | 0d549a44 | daftaupe | print('dormant.value {}'.format(response))
|
| 390 | except stem.connection.AuthenticationFailure as e: |
||
| 391 | print('Authentication failed ({})'.format(e))
|
||
| 392 | |||
| 393 | |||
| 394 | class TorFlags(TorPlugin): |
||
| 395 | def __init__(self): |
||
| 396 | pass |
||
| 397 | |||
| 398 | def conf(self): |
||
| 399 | f14887f5 | daftaupe | graph = {'title': 'Tor relay flags',
|
| 400 | 0d549a44 | daftaupe | 'args': '-l 0 --base 1000', |
| 401 | 'vlabel': 'flags', |
||
| 402 | 87325764 | daftaupe | 'category': 'network', |
| 403 | 0d549a44 | daftaupe | 'info': 'Flags active for relay'} |
| 404 | labels = {flag: {'label': flag, 'min': 0, 'max': 1, 'type': 'GAUGE'} for flag in stem.Flag}
|
||
| 405 | |||
| 406 | TorPlugin.conf_from_dict(graph, labels) |
||
| 407 | |||
| 408 | def fetch(self): |
||
| 409 | with gen_controller() as controller: |
||
| 410 | try: |
||
| 411 | authenticate(controller) |
||
| 412 | except stem.connection.AuthenticationFailure as e: |
||
| 413 | print('Authentication failed ({})'.format(e))
|
||
| 414 | return |
||
| 415 | |||
| 416 | # Get fingerprint of our own relay to look up the status entry for. |
||
| 417 | # In Stem 1.3.0 and later, get_network_status() will fetch the |
||
| 418 | # relay's own status entry if no argument is provided, so this will |
||
| 419 | # no longer be needed. |
||
| 420 | fingerprint = controller.get_info('fingerprint', None)
|
||
| 421 | if fingerprint is None: |
||
| 422 | print("Error while reading fingerprint from Tor daemon", file=sys.stderr)
|
||
| 423 | 87325764 | daftaupe | sys.exit(1) |
| 424 | 0d549a44 | daftaupe | |
| 425 | response = controller.get_network_status(fingerprint, None) |
||
| 426 | if response is None: |
||
| 427 | print("Error while getting server descriptor from Tor daemon", file=sys.stderr)
|
||
| 428 | 87325764 | daftaupe | sys.exit(1) |
| 429 | 0d549a44 | daftaupe | for flag in stem.Flag: |
| 430 | if flag in response.flags: |
||
| 431 | print('{}.value 1'.format(flag))
|
||
| 432 | else: |
||
| 433 | print('{}.value 0'.format(flag))
|
||
| 434 | |||
| 435 | |||
| 436 | class TorRouters(TorPlugin): |
||
| 437 | def __init__(self): |
||
| 438 | pass |
||
| 439 | |||
| 440 | def conf(self): |
||
| 441 | f14887f5 | daftaupe | graph = {'title': 'Tor routers',
|
| 442 | 0d549a44 | daftaupe | 'args': '-l 0', |
| 443 | 'vlabel': 'routers', |
||
| 444 | 87325764 | daftaupe | 'category': 'network', |
| 445 | 0d549a44 | daftaupe | 'info': 'known Tor onion routers'} |
| 446 | 24ab44ca | Lars Kruse | labels = {'routers': {'label': 'routers', 'min': 0, 'type': 'GAUGE'}}
|
| 447 | 0d549a44 | daftaupe | TorPlugin.conf_from_dict(graph, labels) |
| 448 | |||
| 449 | def fetch(self): |
||
| 450 | with gen_controller() as controller: |
||
| 451 | try: |
||
| 452 | authenticate(controller) |
||
| 453 | except stem.connection.AuthenticationFailure as e: |
||
| 454 | print('Authentication failed ({})'.format(e))
|
||
| 455 | return |
||
| 456 | response = controller.get_info('ns/all', None)
|
||
| 457 | if response is None: |
||
| 458 | print("Error while reading ns/all from Tor daemon", file=sys.stderr)
|
||
| 459 | 87325764 | daftaupe | sys.exit(1) |
| 460 | 0d549a44 | daftaupe | else: |
| 461 | routers = response.split('\n')
|
||
| 462 | 832ecbad | wodry | onr = 0 |
| 463 | for router in routers: |
||
| 464 | if router[0] == "r": |
||
| 465 | onr += 1 |
||
| 466 | 17f78427 | Lars Kruse | |
| 467 | 0d549a44 | daftaupe | print('routers.value {}'.format(onr))
|
| 468 | |||
| 469 | |||
| 470 | class TorTraffic(TorPlugin): |
||
| 471 | def __init__(self): |
||
| 472 | pass |
||
| 473 | |||
| 474 | def conf(self): |
||
| 475 | f14887f5 | daftaupe | graph = {'title': 'Tor traffic',
|
| 476 | 0d549a44 | daftaupe | 'args': '-l 0 --base 1024', |
| 477 | 168f6f92 | Pierre-Alain TORET | 'vlabel': 'bytes/s', |
| 478 | 87325764 | daftaupe | 'category': 'network', |
| 479 | 0d549a44 | daftaupe | 'info': 'bytes read/written'} |
| 480 | labels = {'read': {'label': 'read', 'min': 0, 'type': 'DERIVE'},
|
||
| 481 | 'written': {'label': 'written', 'min': 0, 'type': 'DERIVE'}}
|
||
| 482 | |||
| 483 | TorPlugin.conf_from_dict(graph, labels) |
||
| 484 | |||
| 485 | def fetch(self): |
||
| 486 | with gen_controller() as controller: |
||
| 487 | try: |
||
| 488 | authenticate(controller) |
||
| 489 | except stem.connection.AuthenticationFailure as e: |
||
| 490 | print('Authentication failed ({})'.format(e))
|
||
| 491 | return |
||
| 492 | |||
| 493 | response = controller.get_info('traffic/read', None)
|
||
| 494 | if response is None: |
||
| 495 | print("Error while reading traffic/read from Tor daemon", file=sys.stderr)
|
||
| 496 | 87325764 | daftaupe | sys.exit(1) |
| 497 | 0d549a44 | daftaupe | |
| 498 | print('read.value {}'.format(response))
|
||
| 499 | |||
| 500 | response = controller.get_info('traffic/written', None)
|
||
| 501 | if response is None: |
||
| 502 | print("Error while reading traffic/write from Tor daemon", file=sys.stderr)
|
||
| 503 | 87325764 | daftaupe | sys.exit(1) |
| 504 | 0d549a44 | daftaupe | print('written.value {}'.format(response))
|
| 505 | |||
| 506 | |||
| 507 | ########################## |
||
| 508 | 17f78427 | Lars Kruse | # Main |
| 509 | 0d549a44 | daftaupe | ########################## |
| 510 | |||
| 511 | |||
| 512 | def main(): |
||
| 513 | if len(sys.argv) > 1: |
||
| 514 | param = sys.argv[1].lower() |
||
| 515 | else: |
||
| 516 | param = 'fetch' |
||
| 517 | |||
| 518 | if param == 'autoconf': |
||
| 519 | TorPlugin.autoconf() |
||
| 520 | sys.exit() |
||
| 521 | elif param == 'suggest': |
||
| 522 | TorPlugin.suggest() |
||
| 523 | sys.exit() |
||
| 524 | else: |
||
| 525 | # detect data provider |
||
| 526 | if __file__.endswith('_bandwidth'):
|
||
| 527 | provider = TorBandwidth() |
||
| 528 | elif __file__.endswith('_connections'):
|
||
| 529 | provider = TorConnections() |
||
| 530 | elif __file__.endswith('_countries'):
|
||
| 531 | provider = TorCountries() |
||
| 532 | elif __file__.endswith('_dormant'):
|
||
| 533 | provider = TorDormant() |
||
| 534 | elif __file__.endswith('_flags'):
|
||
| 535 | provider = TorFlags() |
||
| 536 | elif __file__.endswith('_routers'):
|
||
| 537 | provider = TorRouters() |
||
| 538 | elif __file__.endswith('_traffic'):
|
||
| 539 | provider = TorTraffic() |
||
| 540 | else: |
||
| 541 | 24ab44ca | Lars Kruse | print('Unknown plugin name, try "suggest" for a list of possible ones.',
|
| 542 | file=sys.stderr) |
||
| 543 | 87325764 | daftaupe | sys.exit(1) |
| 544 | 0d549a44 | daftaupe | |
| 545 | if param == 'config': |
||
| 546 | provider.conf() |
||
| 547 | elif param == 'fetch': |
||
| 548 | provider.fetch() |
||
| 549 | else: |
||
| 550 | 87325764 | daftaupe | print('Unknown parameter "{}"'.format(param), file=sys.stderr)
|
| 551 | ec2d1fea | daftaupe | sys.exit(1) |
| 552 | 0d549a44 | daftaupe | |
| 553 | 24ab44ca | Lars Kruse | |
| 554 | 0d549a44 | daftaupe | if __name__ == '__main__': |
| 555 | main() |
