1# Copyright 2011-2019, Damian Johnson and The Tor Project 2# See LICENSE for licensing information 3 4""" 5Module for interacting with the Tor control socket. The 6:class:`~stem.control.Controller` is a wrapper around a 7:class:`~stem.socket.ControlSocket`, retaining many of its methods (connect, 8close, is_alive, etc) in addition to providing its own for working with the 9socket at a higher level. 10 11Stem has `several ways <../faq.html#how-do-i-connect-to-tor>`_ of getting a 12:class:`~stem.control.Controller`, but the most flexible are 13:func:`~stem.control.Controller.from_port` and 14:func:`~stem.control.Controller.from_socket_file`. These static 15:class:`~stem.control.Controller` methods give you an **unauthenticated** 16Controller you can then authenticate yourself using its 17:func:`~stem.control.Controller.authenticate` method. For example... 18 19:: 20 21 import getpass 22 import sys 23 24 import stem 25 import stem.connection 26 27 from stem.control import Controller 28 29 if __name__ == '__main__': 30 try: 31 controller = Controller.from_port() 32 except stem.SocketError as exc: 33 print("Unable to connect to tor on port 9051: %s" % exc) 34 sys.exit(1) 35 36 try: 37 controller.authenticate() 38 except stem.connection.MissingPassword: 39 pw = getpass.getpass("Controller password: ") 40 41 try: 42 controller.authenticate(password = pw) 43 except stem.connection.PasswordAuthFailed: 44 print("Unable to authenticate, password is incorrect") 45 sys.exit(1) 46 except stem.connection.AuthenticationFailure as exc: 47 print("Unable to authenticate: %s" % exc) 48 sys.exit(1) 49 50 print("Tor is running version %s" % controller.get_version()) 51 controller.close() 52 53If you're fine with allowing your script to raise exceptions then this can be more nicely done as... 54 55:: 56 57 from stem.control import Controller 58 59 if __name__ == '__main__': 60 with Controller.from_port() as controller: 61 controller.authenticate() 62 63 print("Tor is running version %s" % controller.get_version()) 64 65**Module Overview:** 66 67:: 68 69 event_description - brief description of a tor event type 70 71 Controller - General controller class intended for direct use 72 | |- from_port - Provides a Controller based on a port connection. 73 | +- from_socket_file - Provides a Controller based on a socket file connection. 74 | 75 |- authenticate - authenticates this controller with tor 76 |- reconnect - reconnects and authenticates to socket 77 | 78 |- get_info - issues a GETINFO query for a parameter 79 |- get_version - provides our tor version 80 |- get_exit_policy - provides our exit policy 81 |- get_ports - provides the local ports where tor is listening for connections 82 |- get_listeners - provides the addresses and ports where tor is listening for connections 83 |- get_accounting_stats - provides stats related to relaying limits 84 |- get_protocolinfo - information about the controller interface 85 |- get_user - provides the user tor is running as 86 |- get_pid - provides the pid of our tor process 87 |- get_start_time - timestamp when the tor process began 88 |- get_uptime - duration tor has been running 89 |- is_user_traffic_allowed - checks if we send or receive direct user traffic 90 | 91 |- get_microdescriptor - querying the microdescriptor for a relay 92 |- get_microdescriptors - provides all currently available microdescriptors 93 |- get_server_descriptor - querying the server descriptor for a relay 94 |- get_server_descriptors - provides all currently available server descriptors 95 |- get_network_status - querying the router status entry for a relay 96 |- get_network_statuses - provides all presently available router status entries 97 |- get_hidden_service_descriptor - queries the given hidden service descriptor 98 | 99 |- get_conf - gets the value of a configuration option 100 |- get_conf_map - gets the values of multiple configuration options 101 |- is_set - determines if an option differs from its default 102 |- set_conf - sets the value of a configuration option 103 |- reset_conf - reverts configuration options to their default values 104 |- set_options - sets or resets the values of multiple configuration options 105 | 106 |- get_hidden_service_conf - provides our hidden service configuration 107 |- set_hidden_service_conf - sets our hidden service configuration 108 |- create_hidden_service - creates a new hidden service or adds a new port 109 |- remove_hidden_service - removes a hidden service or drops a port 110 | 111 |- list_ephemeral_hidden_services - list ephemeral hidden serivces 112 |- create_ephemeral_hidden_service - create a new ephemeral hidden service 113 |- remove_ephemeral_hidden_service - removes an ephemeral hidden service 114 | 115 |- add_event_listener - attaches an event listener to be notified of tor events 116 |- remove_event_listener - removes a listener so it isn't notified of further events 117 | 118 |- is_caching_enabled - true if the controller has enabled caching 119 |- set_caching - enables or disables caching 120 |- clear_cache - clears any cached results 121 | 122 |- load_conf - loads configuration information as if it was in the torrc 123 |- save_conf - saves configuration information to the torrc 124 | 125 |- is_feature_enabled - checks if a given controller feature is enabled 126 |- enable_feature - enables a controller feature that has been disabled by default 127 | 128 |- get_circuit - provides an active circuit 129 |- get_circuits - provides a list of active circuits 130 |- new_circuit - create new circuits 131 |- extend_circuit - create new circuits and extend existing ones 132 |- repurpose_circuit - change a circuit's purpose 133 |- close_circuit - close a circuit 134 | 135 |- get_streams - provides a list of active streams 136 |- attach_stream - attach a stream to a circuit 137 |- close_stream - close a stream 138 | 139 |- signal - sends a signal to the tor client 140 |- is_newnym_available - true if tor would currently accept a NEWNYM signal 141 |- get_newnym_wait - seconds until tor would accept a NEWNYM signal 142 |- get_effective_rate - provides our effective relaying rate limit 143 |- is_geoip_unavailable - true if we've discovered our geoip db to be unavailable 144 |- map_address - maps one address to another such that connections to the original are replaced with the other 145 +- drop_guards - drops our set of guard relays and picks a new set 146 147 BaseController - Base controller class asynchronous message handling 148 |- msg - communicates with the tor process 149 |- is_alive - reports if our connection to tor is open or closed 150 |- is_localhost - returns if the connection is for the local system or not 151 |- connection_time - time when we last connected or disconnected 152 |- is_authenticated - checks if we're authenticated to tor 153 |- connect - connects or reconnects to tor 154 |- close - shuts down our connection to the tor process 155 |- get_socket - provides the socket used for control communication 156 |- get_latest_heartbeat - timestamp for when we last heard from tor 157 |- add_status_listener - notifies a callback of changes in our status 158 +- remove_status_listener - prevents further notification of status changes 159 160.. data:: State (enum) 161 162 Enumeration for states that a controller can have. 163 164 ========== =========== 165 State Description 166 ========== =========== 167 **INIT** new control connection 168 **RESET** received a reset/sighup signal 169 **CLOSED** control connection closed 170 ========== =========== 171 172.. data:: EventType (enum) 173 174 Known types of events that the 175 :func:`~stem.control.Controller.add_event_listener` method of the 176 :class:`~stem.control.Controller` can listen for. 177 178 The most frequently listened for event types tend to be the logging events 179 (**DEBUG**, **INFO**, **NOTICE**, **WARN**, and **ERR**), bandwidth usage 180 (**BW**), and circuit or stream changes (**CIRC** and **STREAM**). 181 182 Enums are mapped to :class:`~stem.response.events.Event` subclasses as 183 follows... 184 185 .. deprecated:: 1.6.0 186 187 Tor dropped EventType.AUTHDIR_NEWDESCS as of version 0.3.2.1. 188 (:spec:`6e887ba`) 189 190 ======================= =========== 191 EventType Event Class 192 ======================= =========== 193 **ADDRMAP** :class:`stem.response.events.AddrMapEvent` 194 **AUTHDIR_NEWDESCS** :class:`stem.response.events.AuthDirNewDescEvent` 195 **BUILDTIMEOUT_SET** :class:`stem.response.events.BuildTimeoutSetEvent` 196 **BW** :class:`stem.response.events.BandwidthEvent` 197 **CELL_STATS** :class:`stem.response.events.CellStatsEvent` 198 **CIRC** :class:`stem.response.events.CircuitEvent` 199 **CIRC_BW** :class:`stem.response.events.CircuitBandwidthEvent` 200 **CIRC_MINOR** :class:`stem.response.events.CircMinorEvent` 201 **CLIENTS_SEEN** :class:`stem.response.events.ClientsSeenEvent` 202 **CONF_CHANGED** :class:`stem.response.events.ConfChangedEvent` 203 **CONN_BW** :class:`stem.response.events.ConnectionBandwidthEvent` 204 **DEBUG** :class:`stem.response.events.LogEvent` 205 **DESCCHANGED** :class:`stem.response.events.DescChangedEvent` 206 **ERR** :class:`stem.response.events.LogEvent` 207 **GUARD** :class:`stem.response.events.GuardEvent` 208 **HS_DESC** :class:`stem.response.events.HSDescEvent` 209 **HS_DESC_CONTENT** :class:`stem.response.events.HSDescContentEvent` 210 **INFO** :class:`stem.response.events.LogEvent` 211 **NETWORK_LIVENESS** :class:`stem.response.events.NetworkLivenessEvent` 212 **NEWCONSENSUS** :class:`stem.response.events.NewConsensusEvent` 213 **NEWDESC** :class:`stem.response.events.NewDescEvent` 214 **NOTICE** :class:`stem.response.events.LogEvent` 215 **NS** :class:`stem.response.events.NetworkStatusEvent` 216 **ORCONN** :class:`stem.response.events.ORConnEvent` 217 **SIGNAL** :class:`stem.response.events.SignalEvent` 218 **STATUS_CLIENT** :class:`stem.response.events.StatusEvent` 219 **STATUS_GENERAL** :class:`stem.response.events.StatusEvent` 220 **STATUS_SERVER** :class:`stem.response.events.StatusEvent` 221 **STREAM** :class:`stem.response.events.StreamEvent` 222 **STREAM_BW** :class:`stem.response.events.StreamBwEvent` 223 **TB_EMPTY** :class:`stem.response.events.TokenBucketEmptyEvent` 224 **TRANSPORT_LAUNCHED** :class:`stem.response.events.TransportLaunchedEvent` 225 **WARN** :class:`stem.response.events.LogEvent` 226 ======================= =========== 227 228.. data:: Listener (enum) 229 230 Purposes for inbound connections that Tor handles. 231 232 .. versionchanged:: 1.8.0 233 Added the EXTOR and HTTPTUNNEL listeners. 234 235 =============== =========== 236 Listener Description 237 =============== =========== 238 **OR** traffic we're relaying as a member of the network (torrc's **ORPort** and **ORListenAddress**) 239 **DIR** mirroring for tor descriptor content (torrc's **DirPort** and **DirListenAddress**) 240 **SOCKS** client traffic we're sending over Tor (torrc's **SocksPort** and **SocksListenAddress**) 241 **TRANS** transparent proxy handling (torrc's **TransPort** and **TransListenAddress**) 242 **NATD** forwarding for ipfw NATD connections (torrc's **NatdPort** and **NatdListenAddress**) 243 **DNS** DNS lookups for our traffic (torrc's **DNSPort** and **DNSListenAddress**) 244 **CONTROL** controller applications (torrc's **ControlPort** and **ControlListenAddress**) 245 **EXTOR** pluggable transport for Extended ORPorts (torrc's **ExtORPort**) 246 **HTTPTUNNEL** http tunneling proxy (torrc's **HTTPTunnelPort**) 247 =============== =========== 248""" 249 250import calendar 251import collections 252import functools 253import inspect 254import io 255import os 256import threading 257import time 258 259try: 260 # Added in 2.7 261 from collections import OrderedDict 262except ImportError: 263 from stem.util.ordereddict import OrderedDict 264 265try: 266 # Added in 3.x 267 import queue 268except ImportError: 269 import Queue as queue 270 271import stem.descriptor.microdescriptor 272import stem.descriptor.reader 273import stem.descriptor.router_status_entry 274import stem.descriptor.server_descriptor 275import stem.exit_policy 276import stem.response 277import stem.response.events 278import stem.socket 279import stem.util 280import stem.util.conf 281import stem.util.connection 282import stem.util.enum 283import stem.util.str_tools 284import stem.util.system 285import stem.util.tor_tools 286import stem.version 287 288from stem import UNDEFINED, CircStatus, Signal 289from stem.util import log 290 291# When closing the controller we attempt to finish processing enqueued events, 292# but if it takes longer than this we terminate. 293 294EVENTS_LISTENING_TIMEOUT = 0.1 295 296MALFORMED_EVENTS = 'MALFORMED_EVENTS' 297 298# state changes a control socket can have 299 300State = stem.util.enum.Enum('INIT', 'RESET', 'CLOSED') 301 302# TODO: consider merging this with stem.response.event in stem 2.x? (#32689) 303 304EventType = stem.util.enum.UppercaseEnum( 305 'ADDRMAP', 306 'AUTHDIR_NEWDESCS', 307 'BUILDTIMEOUT_SET', 308 'BW', 309 'CELL_STATS', 310 'CIRC', 311 'CIRC_BW', 312 'CIRC_MINOR', 313 'CONF_CHANGED', 314 'CONN_BW', 315 'CLIENTS_SEEN', 316 'DEBUG', 317 'DESCCHANGED', 318 'ERR', 319 'GUARD', 320 'HS_DESC', 321 'HS_DESC_CONTENT', 322 'INFO', 323 'NETWORK_LIVENESS', 324 'NEWCONSENSUS', 325 'NEWDESC', 326 'NOTICE', 327 'NS', 328 'ORCONN', 329 'SIGNAL', 330 'STATUS_CLIENT', 331 'STATUS_GENERAL', 332 'STATUS_SERVER', 333 'STREAM', 334 'STREAM_BW', 335 'TB_EMPTY', 336 'TRANSPORT_LAUNCHED', 337 'WARN', 338) 339 340Listener = stem.util.enum.UppercaseEnum( 341 'OR', 342 'DIR', 343 'SOCKS', 344 'TRANS', 345 'NATD', 346 'DNS', 347 'CONTROL', 348 'EXTOR', 349 'HTTPTUNNEL', 350) 351 352# torrc options that cannot be changed once tor's running 353 354IMMUTABLE_CONFIG_OPTIONS = set(map(stem.util.str_tools._to_unicode, map(str.lower, ( 355 'AccelDir', 356 'AccelName', 357 'DataDirectory', 358 'DisableAllSwap', 359 'DisableDebuggerAttachment', 360 'HardwareAccel', 361 'HiddenServiceNonAnonymousMode', 362 'HiddenServiceSingleHopMode', 363 'KeepBindCapabilities', 364 'PidFile', 365 'RunAsDaemon', 366 'Sandbox', 367 'SyslogIdentityTag', 368 'TokenBucketRefillInterval', 369 'User', 370)))) 371 372LOG_CACHE_FETCHES = True # provide trace level logging for cache hits 373 374# Configuration options that are fetched by a special key. The keys are 375# lowercase to make case insensitive lookups easier. 376 377MAPPED_CONFIG_KEYS = { 378 'hiddenservicedir': 'HiddenServiceOptions', 379 'hiddenserviceport': 'HiddenServiceOptions', 380 'hiddenserviceversion': 'HiddenServiceOptions', 381 'hiddenserviceauthorizeclient': 'HiddenServiceOptions', 382 'hiddenserviceoptions': 'HiddenServiceOptions', 383} 384 385# unchangeable GETINFO parameters 386 387CACHEABLE_GETINFO_PARAMS = ( 388 'address', 389 'version', 390 'config-file', 391 'exit-policy/default', 392 'fingerprint', 393 'config/names', 394 'config/defaults', 395 'info/names', 396 'events/names', 397 'features/names', 398 'process/descriptor-limit', 399 'status/version/current', 400) 401 402CACHEABLE_GETINFO_PARAMS_UNTIL_SETCONF = ( 403 'accounting/enabled', 404) 405 406# GETCONF parameters we shouldn't cache. This includes hidden service 407# perameters due to the funky way they're set and retrieved (for instance, 408# 'SETCONF HiddenServiceDir' effects 'GETCONF HiddenServiceOptions'). 409 410UNCACHEABLE_GETCONF_PARAMS = ( 411 'hiddenserviceoptions', 412 'hiddenservicedir', 413 'hiddenserviceport', 414 'hiddenserviceversion', 415 'hiddenserviceauthorizeclient', 416) 417 418SERVER_DESCRIPTORS_UNSUPPORTED = "Tor is currently not configured to retrieve \ 419server descriptors. As of Tor version 0.2.3.25 it downloads microdescriptors \ 420instead unless you set 'UseMicrodescriptors 0' in your torrc." 421 422EVENT_DESCRIPTIONS = None 423 424 425class AccountingStats(collections.namedtuple('AccountingStats', ['retrieved', 'status', 'interval_end', 'time_until_reset', 'read_bytes', 'read_bytes_left', 'read_limit', 'written_bytes', 'write_bytes_left', 'write_limit'])): 426 """ 427 Accounting information, determining the limits where our relay suspends 428 itself. 429 430 :var float retrieved: unix timestamp for when this was fetched 431 :var str status: hibernation status of 'awake', 'soft', or 'hard' 432 :var datetime interval_end: time when our limits reset 433 :var int time_until_reset: seconds until our limits reset 434 :var int read_bytes: number of bytes we've read relaying 435 :var int read_bytes_left: number of bytes we can read until we suspend 436 :var int read_limit: reading threshold where we suspend 437 :var int written_bytes: number of bytes we've written relaying 438 :var int write_bytes_left: number of bytes we can write until we suspend 439 :var int write_limit: writing threshold where we suspend 440 """ 441 442 443class UserTrafficAllowed(collections.namedtuple('UserTrafficAllowed', ['inbound', 'outbound'])): 444 """ 445 Indicates if we're likely to be servicing direct user traffic or not. 446 447 :var bool inbound: if **True** we're likely providing guard or bridge connnections 448 :var bool outbound: if **True** we're likely providng exit connections 449 """ 450 451 452class CreateHiddenServiceOutput(collections.namedtuple('CreateHiddenServiceOutput', ['path', 'hostname', 'hostname_for_client', 'config'])): 453 """ 454 Attributes of a hidden service we've created. 455 456 Both the **hostnames** and **hostname_for_client** attributes can only be 457 provided if we're able to read the hidden service directory. If the method 458 was called with **client_names** then we may provide the 459 **hostname_for_client**, and otherwise can provide the **hostnames**. 460 461 :var str path: hidden service directory 462 :var str hostname: content of the hostname file if available 463 :var dict hostname_for_client: mapping of client names to their onion address 464 if available 465 :var dict config: tor's new hidden service configuration 466 """ 467 468 469def with_default(yields = False): 470 """ 471 Provides a decorator to support having a default value. This should be 472 treated as private. 473 """ 474 475 def decorator(func): 476 def get_default(func, args, kwargs): 477 arg_names = inspect.getargspec(func).args[1:] # drop 'self' 478 default_position = arg_names.index('default') if 'default' in arg_names else None 479 480 if default_position is not None and default_position < len(args): 481 return args[default_position] 482 else: 483 return kwargs.get('default', UNDEFINED) 484 485 if not yields: 486 @functools.wraps(func) 487 def wrapped(self, *args, **kwargs): 488 try: 489 return func(self, *args, **kwargs) 490 except: 491 default = get_default(func, args, kwargs) 492 493 if default == UNDEFINED: 494 raise 495 else: 496 return default 497 else: 498 @functools.wraps(func) 499 def wrapped(self, *args, **kwargs): 500 try: 501 for val in func(self, *args, **kwargs): 502 yield val 503 except: 504 default = get_default(func, args, kwargs) 505 506 if default == UNDEFINED: 507 raise 508 else: 509 if default is not None: 510 for val in default: 511 yield val 512 513 return wrapped 514 515 return decorator 516 517 518def event_description(event): 519 """ 520 Provides a description for Tor events. 521 522 :param str event: the event for which a description is needed 523 524 :returns: **str** The event description or **None** if this is an event name 525 we don't have a description for 526 """ 527 528 global EVENT_DESCRIPTIONS 529 530 if EVENT_DESCRIPTIONS is None: 531 config = stem.util.conf.Config() 532 config_path = os.path.join(os.path.dirname(__file__), 'settings.cfg') 533 534 try: 535 config.load(config_path) 536 EVENT_DESCRIPTIONS = dict([(key.lower()[18:], config.get_value(key)) for key in config.keys() if key.startswith('event.description.')]) 537 except Exception as exc: 538 log.warn("BUG: stem failed to load its internal manual information from '%s': %s" % (config_path, exc)) 539 return None 540 541 return EVENT_DESCRIPTIONS.get(event.lower()) 542 543 544class BaseController(object): 545 """ 546 Controller for the tor process. This is a minimal base class for other 547 controllers, providing basic process communication and event listing. Don't 548 use this directly - subclasses like the :class:`~stem.control.Controller` 549 provide higher level functionality. 550 551 It's highly suggested that you don't interact directly with the 552 :class:`~stem.socket.ControlSocket` that we're constructed from - use our 553 wrapper methods instead. 554 555 If the **control_socket** is already authenticated to Tor then the caller 556 should provide the **is_authenticated** flag. Otherwise, we will treat the 557 socket as though it hasn't yet been authenticated. 558 """ 559 560 def __init__(self, control_socket, is_authenticated = False): 561 self._socket = control_socket 562 self._msg_lock = threading.RLock() 563 564 self._status_listeners = [] # tuples of the form (callback, spawn_thread) 565 self._status_listeners_lock = threading.RLock() 566 567 # queues where incoming messages are directed 568 self._reply_queue = queue.Queue() 569 self._event_queue = queue.Queue() 570 571 # thread to continually pull from the control socket 572 self._reader_thread = None 573 574 # thread to pull from the _event_queue and call handle_event 575 self._event_notice = threading.Event() 576 self._event_thread = None 577 578 # saves our socket's prior _connect() and _close() methods so they can be 579 # called along with ours 580 581 self._socket_connect = self._socket._connect 582 self._socket_close = self._socket._close 583 584 self._socket._connect = self._connect 585 self._socket._close = self._close 586 587 self._last_heartbeat = 0.0 # timestamp for when we last heard from tor 588 self._is_authenticated = False 589 590 self._state_change_threads = [] # threads we've spawned to notify of state changes 591 592 if self._socket.is_alive(): 593 self._launch_threads() 594 595 if is_authenticated: 596 self._post_authentication() 597 598 def msg(self, message): 599 """ 600 Sends a message to our control socket and provides back its reply. 601 602 :param str message: message to be formatted and sent to tor 603 604 :returns: :class:`~stem.response.ControlMessage` with the response 605 606 :raises: 607 * :class:`stem.ProtocolError` the content from the socket is 608 malformed 609 * :class:`stem.SocketError` if a problem arises in using the 610 socket 611 * :class:`stem.SocketClosed` if the socket is shut down 612 """ 613 614 with self._msg_lock: 615 # If our _reply_queue isn't empty then one of a few things happened... 616 # 617 # - Our connection was closed and probably re-restablished. This was 618 # in reply to pulling for an asynchronous event and getting this is 619 # expected - ignore it. 620 # 621 # - Pulling for asynchronous events produced an error. If this was a 622 # ProtocolError then it's a tor bug, and if a non-closure SocketError 623 # then it was probably a socket glitch. Deserves an INFO level log 624 # message. 625 # 626 # - This is a leftover response for a msg() call. We can't tell who an 627 # exception was earmarked for, so we only know that this was the case 628 # if it's a ControlMessage. 629 # 630 # This is the most concerning situation since it indicates that one of 631 # our callers didn't get their reply. However, this is still a 632 # perfectly viable use case. For instance... 633 # 634 # 1. We send a request. 635 # 2. The reader thread encounters an exception, for instance a socket 636 # error. We enqueue the exception. 637 # 3. The reader thread receives the reply. 638 # 4. We raise the socket error, and have an undelivered message. 639 # 640 # Thankfully this only seems to arise in edge cases around rapidly 641 # closing/reconnecting the socket. 642 643 while not self._reply_queue.empty(): 644 try: 645 response = self._reply_queue.get_nowait() 646 647 if isinstance(response, stem.SocketClosed): 648 pass # this is fine 649 elif isinstance(response, stem.ProtocolError): 650 log.info('Tor provided a malformed message (%s)' % response) 651 elif isinstance(response, stem.ControllerError): 652 log.info('Socket experienced a problem (%s)' % response) 653 elif isinstance(response, stem.response.ControlMessage): 654 log.info('Failed to deliver a response: %s' % response) 655 except queue.Empty: 656 # the empty() method is documented to not be fully reliable so this 657 # isn't entirely surprising 658 659 break 660 661 try: 662 self._socket.send(message) 663 response = self._reply_queue.get() 664 665 # If the message we received back had an exception then re-raise it to the 666 # caller. Otherwise return the response. 667 668 if isinstance(response, stem.ControllerError): 669 raise response 670 else: 671 return response 672 except stem.SocketClosed: 673 # If the recv() thread caused the SocketClosed then we could still be 674 # in the process of closing. Calling close() here so that we can 675 # provide an assurance to the caller that when we raise a SocketClosed 676 # exception we are shut down afterward for realz. 677 678 self.close() 679 raise 680 681 def is_alive(self): 682 """ 683 Checks if our socket is currently connected. This is a pass-through for our 684 socket's :func:`~stem.socket.BaseSocket.is_alive` method. 685 686 :returns: **bool** that's **True** if our socket is connected and **False** otherwise 687 """ 688 689 return self._socket.is_alive() 690 691 def is_localhost(self): 692 """ 693 Returns if the connection is for the local system or not. 694 695 .. versionadded:: 1.3.0 696 697 :returns: **bool** that's **True** if the connection is for the local host and **False** otherwise 698 """ 699 700 return self._socket.is_localhost() 701 702 def connection_time(self): 703 """ 704 Provides the unix timestamp for when our socket was either connected or 705 disconnected. That is to say, the time we connected if we're currently 706 connected and the time we disconnected if we're not connected. 707 708 .. versionadded:: 1.3.0 709 710 :returns: **float** for when we last connected or disconnected, zero if 711 we've never connected 712 """ 713 714 return self._socket.connection_time() 715 716 def is_authenticated(self): 717 """ 718 Checks if our socket is both connected and authenticated. 719 720 :returns: **bool** that's **True** if our socket is authenticated to tor 721 and **False** otherwise 722 """ 723 724 return self._is_authenticated if self.is_alive() else False 725 726 def connect(self): 727 """ 728 Reconnects our control socket. This is a pass-through for our socket's 729 :func:`~stem.socket.ControlSocket.connect` method. 730 731 :raises: :class:`stem.SocketError` if unable to make a socket 732 """ 733 734 self._socket.connect() 735 736 def close(self): 737 """ 738 Closes our socket connection. This is a pass-through for our socket's 739 :func:`~stem.socket.BaseSocket.close` method. 740 """ 741 742 self._socket.close() 743 744 # Join on any outstanding state change listeners. Closing is a state change 745 # of its own, so if we have any listeners it's quite likely there's some 746 # work in progress. 747 # 748 # It's important that we do this outside of our locks so those daemons have 749 # access to us. This is why we're doing this here rather than _close(). 750 751 for t in self._state_change_threads: 752 if t.is_alive() and threading.current_thread() != t: 753 t.join() 754 755 def get_socket(self): 756 """ 757 Provides the socket used to speak with the tor process. Communicating with 758 the socket directly isn't advised since it may confuse this controller. 759 760 :returns: :class:`~stem.socket.ControlSocket` we're communicating with 761 """ 762 763 return self._socket 764 765 def get_latest_heartbeat(self): 766 """ 767 Provides the unix timestamp for when we last heard from tor. This is zero 768 if we've never received a message. 769 770 :returns: float for the unix timestamp of when we last heard from tor 771 """ 772 773 return self._last_heartbeat 774 775 def add_status_listener(self, callback, spawn = True): 776 """ 777 Notifies a given function when the state of our socket changes. Functions 778 are expected to be of the form... 779 780 :: 781 782 my_function(controller, state, timestamp) 783 784 The state is a value from the :data:`stem.control.State` enum. Functions 785 **must** allow for new values. The timestamp is a float for the unix time 786 when the change occurred. 787 788 This class only provides **State.INIT** and **State.CLOSED** notifications. 789 Subclasses may provide others. 790 791 If spawn is **True** then the callback is notified via a new daemon thread. 792 If **False** then the notice is under our locks, within the thread where 793 the change occurred. In general this isn't advised, especially if your 794 callback could block for a while. If still outstanding these threads are 795 joined on as part of closing this controller. 796 797 :param function callback: function to be notified when our state changes 798 :param bool spawn: calls function via a new thread if **True**, otherwise 799 it's part of the connect/close method call 800 """ 801 802 with self._status_listeners_lock: 803 self._status_listeners.append((callback, spawn)) 804 805 def remove_status_listener(self, callback): 806 """ 807 Stops listener from being notified of further events. 808 809 :param function callback: function to be removed from our listeners 810 811 :returns: **bool** that's **True** if we removed one or more occurrences of 812 the callback, **False** otherwise 813 """ 814 815 with self._status_listeners_lock: 816 new_listeners, is_changed = [], False 817 818 for listener, spawn in self._status_listeners: 819 if listener != callback: 820 new_listeners.append((listener, spawn)) 821 else: 822 is_changed = True 823 824 self._status_listeners = new_listeners 825 return is_changed 826 827 def __enter__(self): 828 return self 829 830 def __exit__(self, exit_type, value, traceback): 831 self.close() 832 833 def _handle_event(self, event_message): 834 """ 835 Callback to be overwritten by subclasses for event listening. This is 836 notified whenever we receive an event from the control socket. 837 838 :param stem.response.ControlMessage event_message: message received from 839 the control socket 840 """ 841 842 pass 843 844 def _connect(self): 845 self._launch_threads() 846 self._notify_status_listeners(State.INIT) 847 self._socket_connect() 848 self._is_authenticated = False 849 850 def _close(self): 851 # Our is_alive() state is now false. Our reader thread should already be 852 # awake from recv() raising a closure exception. Wake up the event thread 853 # too so it can end. 854 855 self._event_notice.set() 856 self._is_authenticated = False 857 858 # joins on our threads if it's safe to do so 859 860 for t in (self._reader_thread, self._event_thread): 861 if t and t.is_alive() and threading.current_thread() != t: 862 t.join() 863 864 self._notify_status_listeners(State.CLOSED) 865 866 self._socket_close() 867 868 def _post_authentication(self): 869 # actions to be taken after we have a newly authenticated connection 870 871 self._is_authenticated = True 872 873 def _notify_status_listeners(self, state): 874 """ 875 Informs our status listeners that a state change occurred. 876 877 :param stem.control.State state: state change that has occurred 878 """ 879 880 # Any changes to our is_alive() state happen under the send lock, so we 881 # need to have it to ensure it doesn't change beneath us. 882 883 with self._socket._get_send_lock(): 884 with self._status_listeners_lock: 885 # States imply that our socket is either alive or not, which may not 886 # hold true when multiple events occur in quick succession. For 887 # instance, a sighup could cause two events (State.RESET for the sighup 888 # and State.CLOSE if it causes tor to crash). However, there's no 889 # guarantee of the order in which they occur, and it would be bad if 890 # listeners got the State.RESET last, implying that we were alive. 891 892 expect_alive = None 893 894 if state in (State.INIT, State.RESET): 895 expect_alive = True 896 elif state == State.CLOSED: 897 expect_alive = False 898 899 change_timestamp = time.time() 900 901 if expect_alive is not None and expect_alive != self.is_alive(): 902 return 903 904 self._state_change_threads = list(filter(lambda t: t.is_alive(), self._state_change_threads)) 905 906 for listener, spawn in self._status_listeners: 907 if spawn: 908 args = (self, state, change_timestamp) 909 910 notice_thread = threading.Thread(target = listener, args = args, name = '%s notification' % state) 911 notice_thread.setDaemon(True) 912 notice_thread.start() 913 self._state_change_threads.append(notice_thread) 914 else: 915 listener(self, state, change_timestamp) 916 917 def _launch_threads(self): 918 """ 919 Initializes daemon threads. Threads can't be reused so we need to recreate 920 them if we're restarted. 921 """ 922 923 # In theory concurrent calls could result in multiple start() calls on a 924 # single thread, which would cause an unexpected exception. Best be safe. 925 926 with self._socket._get_send_lock(): 927 if not self._reader_thread or not self._reader_thread.is_alive(): 928 self._reader_thread = threading.Thread(target = self._reader_loop, name = 'Tor listener') 929 self._reader_thread.setDaemon(True) 930 self._reader_thread.start() 931 932 if not self._event_thread or not self._event_thread.is_alive(): 933 self._event_thread = threading.Thread(target = self._event_loop, name = 'Event notifier') 934 self._event_thread.setDaemon(True) 935 self._event_thread.start() 936 937 def _reader_loop(self): 938 """ 939 Continually pulls from the control socket, directing the messages into 940 queues based on their type. Controller messages come in two varieties... 941 942 * Responses to messages we've sent (GETINFO, SETCONF, etc). 943 * Asynchronous events, identified by a status code of 650. 944 """ 945 946 while self.is_alive(): 947 try: 948 control_message = self._socket.recv() 949 self._last_heartbeat = time.time() 950 951 if control_message.content()[-1][0] == '650': 952 # asynchronous message, adds to the event queue and wakes up its handler 953 self._event_queue.put(control_message) 954 self._event_notice.set() 955 else: 956 # response to a msg() call 957 self._reply_queue.put(control_message) 958 except stem.ControllerError as exc: 959 # Assume that all exceptions belong to the reader. This isn't always 960 # true, but the msg() call can do a better job of sorting it out. 961 # 962 # Be aware that the msg() method relies on this to unblock callers. 963 964 self._reply_queue.put(exc) 965 966 def _event_loop(self): 967 """ 968 Continually pulls messages from the _event_queue and sends them to our 969 handle_event callback. This is done via its own thread so subclasses with a 970 lengthy handle_event implementation don't block further reading from the 971 socket. 972 """ 973 974 socket_closed_at = None 975 976 while True: 977 try: 978 event_message = self._event_queue.get_nowait() 979 self._handle_event(event_message) 980 self._event_queue.task_done() 981 982 # Attempt to finish processing enqueued events when our controller closes 983 984 if not self.is_alive(): 985 if not socket_closed_at: 986 socket_closed_at = time.time() 987 elif time.time() - socket_closed_at > EVENTS_LISTENING_TIMEOUT: 988 break 989 except queue.Empty: 990 if not self.is_alive(): 991 break 992 993 self._event_notice.wait(0.05) 994 self._event_notice.clear() 995 996 997class Controller(BaseController): 998 """ 999 Connection with Tor's control socket. This is built on top of the 1000 BaseController and provides a more user friendly API for library users. 1001 """ 1002 1003 @staticmethod 1004 def from_port(address = '127.0.0.1', port = 'default'): 1005 """ 1006 Constructs a :class:`~stem.socket.ControlPort` based Controller. 1007 1008 If the **port** is **'default'** then this checks on both 9051 (default 1009 for relays) and 9151 (default for the Tor Browser). This default may change 1010 in the future. 1011 1012 .. versionchanged:: 1.5.0 1013 Use both port 9051 and 9151 by default. 1014 1015 :param str address: ip address of the controller 1016 :param int port: port number of the controller 1017 1018 :returns: :class:`~stem.control.Controller` attached to the given port 1019 1020 :raises: :class:`stem.SocketError` if we're unable to establish a connection 1021 """ 1022 1023 import stem.connection 1024 1025 if not stem.util.connection.is_valid_ipv4_address(address): 1026 raise ValueError('Invalid IP address: %s' % address) 1027 elif port != 'default' and not stem.util.connection.is_valid_port(port): 1028 raise ValueError('Invalid port: %s' % port) 1029 1030 if port == 'default': 1031 control_port = stem.connection._connection_for_default_port(address) 1032 else: 1033 control_port = stem.socket.ControlPort(address, port) 1034 1035 return Controller(control_port) 1036 1037 @staticmethod 1038 def from_socket_file(path = '/var/run/tor/control'): 1039 """ 1040 Constructs a :class:`~stem.socket.ControlSocketFile` based Controller. 1041 1042 :param str path: path where the control socket is located 1043 1044 :returns: :class:`~stem.control.Controller` attached to the given socket file 1045 1046 :raises: :class:`stem.SocketError` if we're unable to establish a connection 1047 """ 1048 1049 control_socket = stem.socket.ControlSocketFile(path) 1050 return Controller(control_socket) 1051 1052 def __init__(self, control_socket, is_authenticated = False): 1053 self._is_caching_enabled = True 1054 self._request_cache = {} 1055 self._last_newnym = 0.0 1056 1057 self._cache_lock = threading.RLock() 1058 1059 # mapping of event types to their listeners 1060 1061 self._event_listeners = {} 1062 self._event_listeners_lock = threading.RLock() 1063 self._enabled_features = [] 1064 self._is_geoip_unavailable = None 1065 1066 self._last_address_exc = None 1067 self._last_fingerprint_exc = None 1068 1069 super(Controller, self).__init__(control_socket, is_authenticated) 1070 1071 def _sighup_listener(event): 1072 if event.signal == Signal.RELOAD: 1073 self.clear_cache() 1074 self._notify_status_listeners(State.RESET) 1075 1076 self.add_event_listener(_sighup_listener, EventType.SIGNAL) 1077 1078 def _confchanged_listener(event): 1079 if self.is_caching_enabled(): 1080 to_cache_changed = dict((k.lower(), v) for k, v in event.changed.items()) 1081 to_cache_unset = dict((k.lower(), []) for k in event.unset) # [] represents None value in cache 1082 1083 to_cache = {} 1084 to_cache.update(to_cache_changed) 1085 to_cache.update(to_cache_unset) 1086 1087 self._set_cache(to_cache, 'getconf') 1088 1089 self._confchanged_cache_invalidation(to_cache) 1090 1091 self.add_event_listener(_confchanged_listener, EventType.CONF_CHANGED) 1092 1093 def _address_changed_listener(event): 1094 if event.action in ('EXTERNAL_ADDRESS', 'DNS_USELESS'): 1095 self._set_cache({'exit_policy': None}) 1096 self._set_cache({'address': None}, 'getinfo') 1097 self._last_address_exc = None 1098 1099 self.add_event_listener(_address_changed_listener, EventType.STATUS_SERVER) 1100 1101 def close(self): 1102 self.clear_cache() 1103 super(Controller, self).close() 1104 1105 def authenticate(self, *args, **kwargs): 1106 """ 1107 A convenience method to authenticate the controller. This is just a 1108 pass-through to :func:`stem.connection.authenticate`. 1109 """ 1110 1111 import stem.connection 1112 stem.connection.authenticate(self, *args, **kwargs) 1113 1114 def reconnect(self, *args, **kwargs): 1115 """ 1116 Reconnects and authenticates to our control socket. 1117 1118 .. versionadded:: 1.5.0 1119 1120 :raises: 1121 * :class:`stem.SocketError` if unable to re-establish socket 1122 * :class:`stem.connection.AuthenticationFailure` if unable to authenticate 1123 """ 1124 1125 with self._msg_lock: 1126 self.connect() 1127 self.clear_cache() 1128 self.authenticate(*args, **kwargs) 1129 1130 @with_default() 1131 def get_info(self, params, default = UNDEFINED, get_bytes = False): 1132 """ 1133 get_info(params, default = UNDEFINED, get_bytes = False) 1134 1135 Queries the control socket for the given GETINFO option. If provided a 1136 default then that's returned if the GETINFO option is undefined or the 1137 call fails for any reason (error response, control port closed, initiated, 1138 etc). 1139 1140 .. versionchanged:: 1.1.0 1141 Added the get_bytes argument. 1142 1143 .. versionchanged:: 1.7.0 1144 Errors commonly provided a :class:`stem.ProtocolError` when we should 1145 raise a :class:`stem.OperationFailed`. 1146 1147 :param str,list params: GETINFO option or options to be queried 1148 :param object default: response if the query fails 1149 :param bool get_bytes: provides **bytes** values rather than a **str** under python 3.x 1150 1151 :returns: 1152 Response depends upon how we were called as follows... 1153 1154 * **str** with the response if our param was a **str** 1155 * **dict** with the 'param => response' mapping if our param was a **list** 1156 * default if one was provided and our call failed 1157 1158 :raises: 1159 * :class:`stem.ControllerError` if the call fails and we weren't 1160 provided a default response 1161 * :class:`stem.InvalidArguments` if the 'params' requested was 1162 invalid 1163 * :class:`stem.ProtocolError` if the geoip database is unavailable 1164 """ 1165 1166 start_time = time.time() 1167 reply = {} 1168 1169 if stem.util._is_str(params): 1170 is_multiple = False 1171 params = set([params]) 1172 else: 1173 if not params: 1174 return {} 1175 1176 is_multiple = True 1177 params = set(params) 1178 1179 for param in params: 1180 if param.startswith('ip-to-country/') and param != 'ip-to-country/0.0.0.0' and self.is_geoip_unavailable(): 1181 raise stem.ProtocolError('Tor geoip database is unavailable') 1182 elif param == 'address' and self._last_address_exc: 1183 raise self._last_address_exc # we already know we can't resolve an address 1184 elif param == 'fingerprint' and self._last_fingerprint_exc and self.get_conf('ORPort', None) is None: 1185 raise self._last_fingerprint_exc # we already know we're not a relay 1186 1187 # check for cached results 1188 1189 from_cache = [param.lower() for param in params] 1190 cached_results = self._get_cache_map(from_cache, 'getinfo') 1191 1192 for key in cached_results: 1193 user_expected_key = _case_insensitive_lookup(params, key) 1194 reply[user_expected_key] = cached_results[key] 1195 params.remove(user_expected_key) 1196 1197 # if everything was cached then short circuit making the query 1198 if not params: 1199 if LOG_CACHE_FETCHES: 1200 log.trace('GETINFO %s (cache fetch)' % ' '.join(reply.keys())) 1201 1202 if is_multiple: 1203 return reply 1204 else: 1205 return list(reply.values())[0] 1206 1207 try: 1208 response = self.msg('GETINFO %s' % ' '.join(params)) 1209 stem.response.convert('GETINFO', response) 1210 response._assert_matches(params) 1211 1212 # usually we want unicode values under python 3.x 1213 1214 if stem.prereq.is_python_3() and not get_bytes: 1215 response.entries = dict((k, stem.util.str_tools._to_unicode(v)) for (k, v) in response.entries.items()) 1216 1217 reply.update(response.entries) 1218 1219 if self.is_caching_enabled(): 1220 to_cache = {} 1221 1222 for key, value in response.entries.items(): 1223 key = key.lower() # make case insensitive 1224 1225 if key in CACHEABLE_GETINFO_PARAMS or key in CACHEABLE_GETINFO_PARAMS_UNTIL_SETCONF: 1226 to_cache[key] = value 1227 elif key.startswith('ip-to-country/'): 1228 to_cache[key] = value 1229 1230 self._set_cache(to_cache, 'getinfo') 1231 1232 if 'address' in params: 1233 self._last_address_exc = None 1234 1235 if 'fingerprint' in params: 1236 self._last_fingerprint_exc = None 1237 1238 log.debug('GETINFO %s (runtime: %0.4f)' % (' '.join(params), time.time() - start_time)) 1239 1240 if is_multiple: 1241 return reply 1242 else: 1243 return list(reply.values())[0] 1244 except stem.ControllerError as exc: 1245 if 'address' in params: 1246 self._last_address_exc = exc 1247 1248 if 'fingerprint' in params: 1249 self._last_fingerprint_exc = exc 1250 1251 log.debug('GETINFO %s (failed: %s)' % (' '.join(params), exc)) 1252 raise 1253 1254 @with_default() 1255 def get_version(self, default = UNDEFINED): 1256 """ 1257 get_version(default = UNDEFINED) 1258 1259 A convenience method to get tor version that current controller is 1260 connected to. 1261 1262 :param object default: response if the query fails 1263 1264 :returns: :class:`~stem.version.Version` of the tor instance that we're 1265 connected to 1266 1267 :raises: 1268 * :class:`stem.ControllerError` if unable to query the version 1269 * **ValueError** if unable to parse the version 1270 1271 An exception is only raised if we weren't provided a default response. 1272 """ 1273 1274 version = self._get_cache('version') 1275 1276 if not version: 1277 version_str = self.get_info('version') 1278 version = stem.version.Version(version_str[4:] if version_str.startswith('Tor ') else version_str) 1279 self._set_cache({'version': version}) 1280 1281 return version 1282 1283 @with_default() 1284 def get_exit_policy(self, default = UNDEFINED): 1285 """ 1286 get_exit_policy(default = UNDEFINED) 1287 1288 Effective ExitPolicy for our relay. 1289 1290 .. versionchanged:: 1.7.0 1291 Policies retrieved through 'GETINFO exit-policy/full' rather than 1292 parsing the user's torrc entries. This should be more reliable for 1293 some edge cases. (:trac:`25739`) 1294 1295 :param object default: response if the query fails 1296 1297 :returns: :class:`~stem.exit_policy.ExitPolicy` of the tor instance that 1298 we're connected to 1299 1300 :raises: 1301 * :class:`stem.ControllerError` if unable to query the policy 1302 * **ValueError** if unable to parse the policy 1303 1304 An exception is only raised if we weren't provided a default response. 1305 """ 1306 1307 policy = self._get_cache('exit_policy') 1308 1309 if not policy: 1310 try: 1311 policy = stem.exit_policy.ExitPolicy(*self.get_info('exit-policy/full').splitlines()) 1312 self._set_cache({'exit_policy': policy}) 1313 except stem.OperationFailed: 1314 # There's a few situations where 'GETINFO exit-policy/full' will fail, 1315 # most commonly... 1316 # 1317 # * Error 551: Descriptor still rebuilding - not ready yet 1318 # 1319 # Tor hasn't yet finished making our server descriptor. This often 1320 # arises when tor has first started. 1321 # 1322 # * Error 552: Not running in server mode 1323 # 1324 # We're not configured to be a relay (no ORPort), or haven't yet 1325 # been able to determine our externally facing IP address. 1326 # 1327 # When these arise best we can do is infer our policy from the torrc. 1328 # Skipping caching so we'll retry GETINFO policy resolution next time 1329 # we're called. 1330 1331 rules = [] 1332 1333 if self.get_conf('ExitRelay') == '0': 1334 rules.append('reject *:*') 1335 1336 if self.get_conf('ExitPolicyRejectPrivate') == '1': 1337 rules.append('reject private:*') 1338 1339 for policy_line in self.get_conf('ExitPolicy', multiple = True): 1340 rules += policy_line.split(',') 1341 1342 rules += self.get_info('exit-policy/default').split(',') 1343 1344 policy = stem.exit_policy.get_config_policy(rules, self.get_info('address', None)) 1345 1346 return policy 1347 1348 @with_default() 1349 def get_ports(self, listener_type, default = UNDEFINED): 1350 """ 1351 get_ports(listener_type, default = UNDEFINED) 1352 1353 Provides the local ports where tor is listening for the given type of 1354 connections. This is similar to 1355 :func:`~stem.control.Controller.get_listeners`, but doesn't provide 1356 addresses nor include non-local endpoints. 1357 1358 .. versionadded:: 1.2.0 1359 1360 :param stem.control.Listener listener_type: connection type being handled 1361 by the ports we return 1362 :param object default: response if the query fails 1363 1364 :returns: **list** of **ints** for the local ports where tor handles 1365 connections of the given type 1366 1367 :raises: :class:`stem.ControllerError` if unable to determine the ports 1368 and no default was provided 1369 """ 1370 1371 def is_localhost(address): 1372 if stem.util.connection.is_valid_ipv4_address(address): 1373 return address == '0.0.0.0' or address.startswith('127.') 1374 elif stem.util.connection.is_valid_ipv6_address(address): 1375 return stem.util.connection.expand_ipv6_address(address) in ( 1376 '0000:0000:0000:0000:0000:0000:0000:0000', 1377 '0000:0000:0000:0000:0000:0000:0000:0001', 1378 ) 1379 else: 1380 log.info("Request for %s ports got an address that's neither IPv4 or IPv6: %s" % (listener_type, address)) 1381 return False 1382 1383 return [port for (addr, port) in self.get_listeners(listener_type) if is_localhost(addr)] 1384 1385 @with_default() 1386 def get_listeners(self, listener_type, default = UNDEFINED): 1387 """ 1388 get_listeners(listener_type, default = UNDEFINED) 1389 1390 Provides the addresses and ports where tor is listening for connections of 1391 the given type. This is similar to 1392 :func:`~stem.control.Controller.get_ports` but includes listener addresses 1393 and non-local endpoints. 1394 1395 .. versionadded:: 1.2.0 1396 1397 .. versionchanged:: 1.5.0 1398 Recognize listeners with IPv6 addresses. 1399 1400 :param stem.control.Listener listener_type: connection type being handled 1401 by the listeners we return 1402 :param object default: response if the query fails 1403 1404 :returns: **list** of **(address, port)** tuples for the available 1405 listeners 1406 1407 :raises: :class:`stem.ControllerError` if unable to determine the listeners 1408 and no default was provided 1409 """ 1410 1411 listeners = self._get_cache(listener_type, 'listeners') 1412 1413 if listeners is None: 1414 proxy_addrs = [] 1415 query = 'net/listeners/%s' % listener_type.lower() 1416 1417 try: 1418 for listener in self.get_info(query).split(): 1419 if not (listener.startswith('"') and listener.endswith('"')): 1420 raise stem.ProtocolError("'GETINFO %s' responses are expected to be quoted: %s" % (query, listener)) 1421 elif ':' not in listener: 1422 raise stem.ProtocolError("'GETINFO %s' had a listener without a colon: %s" % (query, listener)) 1423 1424 listener = listener[1:-1] # strip quotes 1425 addr, port = listener.rsplit(':', 1) 1426 1427 # Skip unix sockets, for instance... 1428 # 1429 # GETINFO net/listeners/control 1430 # 250-net/listeners/control="unix:/tmp/tor/socket" 1431 # 250 OK 1432 1433 if addr == 'unix': 1434 continue 1435 1436 if addr.startswith('[') and addr.endswith(']'): 1437 addr = addr[1:-1] # unbracket ipv6 address 1438 1439 proxy_addrs.append((addr, port)) 1440 except stem.InvalidArguments: 1441 # Tor version is old (pre-tor-0.2.2.26-beta), use get_conf() instead. 1442 # Some options (like the ORPort) can have optional attributes after the 1443 # actual port number. 1444 1445 port_option = { 1446 Listener.OR: 'ORPort', 1447 Listener.DIR: 'DirPort', 1448 Listener.SOCKS: 'SocksPort', 1449 Listener.TRANS: 'TransPort', 1450 Listener.NATD: 'NatdPort', 1451 Listener.DNS: 'DNSPort', 1452 Listener.CONTROL: 'ControlPort', 1453 }[listener_type] 1454 1455 listener_option = { 1456 Listener.OR: 'ORListenAddress', 1457 Listener.DIR: 'DirListenAddress', 1458 Listener.SOCKS: 'SocksListenAddress', 1459 Listener.TRANS: 'TransListenAddress', 1460 Listener.NATD: 'NatdListenAddress', 1461 Listener.DNS: 'DNSListenAddress', 1462 Listener.CONTROL: 'ControlListenAddress', 1463 }[listener_type] 1464 1465 port_value = self.get_conf(port_option).split()[0] 1466 1467 for listener in self.get_conf(listener_option, multiple = True): 1468 if ':' in listener: 1469 addr, port = listener.rsplit(':', 1) 1470 1471 if addr.startswith('[') and addr.endswith(']'): 1472 addr = addr[1:-1] # unbracket ipv6 address 1473 1474 proxy_addrs.append((addr, port)) 1475 else: 1476 proxy_addrs.append((listener, port_value)) 1477 1478 # validate that address/ports are valid, and convert ports to ints 1479 1480 for addr, port in proxy_addrs: 1481 if not stem.util.connection.is_valid_ipv4_address(addr) and not stem.util.connection.is_valid_ipv6_address(addr): 1482 raise stem.ProtocolError('Invalid address for a %s listener: %s' % (listener_type, addr)) 1483 elif not stem.util.connection.is_valid_port(port): 1484 raise stem.ProtocolError('Invalid port for a %s listener: %s' % (listener_type, port)) 1485 1486 listeners = [(addr, int(port)) for (addr, port) in proxy_addrs] 1487 self._set_cache({listener_type: listeners}, 'listeners') 1488 1489 return listeners 1490 1491 @with_default() 1492 def get_accounting_stats(self, default = UNDEFINED): 1493 """ 1494 get_accounting_stats(default = UNDEFINED) 1495 1496 Provides stats related to our relaying limitations if AccountingMax was set 1497 in our torrc. 1498 1499 .. versionadded:: 1.3.0 1500 1501 :param object default: response if the query fails 1502 1503 :returns: :class:`~stem.control.AccountingStats` with our accounting stats 1504 1505 :raises: :class:`stem.ControllerError` if unable to determine the listeners 1506 and no default was provided 1507 """ 1508 1509 if self.get_info('accounting/enabled') != '1': 1510 raise stem.ControllerError("Accounting isn't enabled") 1511 1512 retrieved = time.time() 1513 status = self.get_info('accounting/hibernating') 1514 interval_end = self.get_info('accounting/interval-end') 1515 used = self.get_info('accounting/bytes') 1516 left = self.get_info('accounting/bytes-left') 1517 1518 interval_end = stem.util.str_tools._parse_timestamp(interval_end) 1519 used_read, used_written = [int(val) for val in used.split(' ', 1)] 1520 left_read, left_written = [int(val) for val in left.split(' ', 1)] 1521 1522 return AccountingStats( 1523 retrieved = retrieved, 1524 status = status, 1525 interval_end = interval_end, 1526 time_until_reset = max(0, calendar.timegm(interval_end.timetuple()) - int(retrieved)), 1527 read_bytes = used_read, 1528 read_bytes_left = left_read, 1529 read_limit = used_read + left_read, 1530 written_bytes = used_written, 1531 write_bytes_left = left_written, 1532 write_limit = used_written + left_written, 1533 ) 1534 1535 def get_socks_listeners(self, default = UNDEFINED): 1536 """ 1537 Provides the SOCKS **(address, port)** tuples that tor has open. 1538 1539 .. deprecated:: 1.2.0 1540 Use :func:`~stem.control.Controller.get_listeners` with 1541 **Listener.SOCKS** instead. 1542 1543 :param object default: response if the query fails 1544 1545 :returns: list of **(address, port)** tuples for the available SOCKS 1546 listeners 1547 1548 :raises: :class:`stem.ControllerError` if unable to determine the listeners 1549 and no default was provided 1550 """ 1551 1552 return self.get_listeners(Listener.SOCKS, default) 1553 1554 @with_default() 1555 def get_protocolinfo(self, default = UNDEFINED): 1556 """ 1557 get_protocolinfo(default = UNDEFINED) 1558 1559 A convenience method to get the protocol info of the controller. 1560 1561 :param object default: response if the query fails 1562 1563 :returns: :class:`~stem.response.protocolinfo.ProtocolInfoResponse` provided by tor 1564 1565 :raises: 1566 * :class:`stem.ProtocolError` if the PROTOCOLINFO response is 1567 malformed 1568 * :class:`stem.SocketError` if problems arise in establishing or 1569 using the socket 1570 1571 An exception is only raised if we weren't provided a default response. 1572 """ 1573 1574 import stem.connection 1575 return stem.connection.get_protocolinfo(self) 1576 1577 @with_default() 1578 def get_user(self, default = UNDEFINED): 1579 """ 1580 get_user(default = UNDEFINED) 1581 1582 Provides the user tor is running as. This often only works if tor is 1583 running locally. Also, most of its checks are platform dependent, and hence 1584 are not entirely reliable. 1585 1586 .. versionadded:: 1.1.0 1587 1588 :param object default: response if the query fails 1589 1590 :returns: str with the username tor is running as 1591 """ 1592 1593 user = self._get_cache('user') 1594 1595 if user: 1596 return user 1597 1598 user = self.get_info('process/user', None) 1599 1600 if not user and self.is_localhost(): 1601 pid = self.get_pid(None) 1602 1603 if pid: 1604 user = stem.util.system.user(pid) 1605 1606 if user: 1607 self._set_cache({'user': user}) 1608 return user 1609 else: 1610 raise ValueError("Unable to resolve tor's user" if self.is_localhost() else "Tor isn't running locally") 1611 1612 @with_default() 1613 def get_pid(self, default = UNDEFINED): 1614 """ 1615 get_pid(default = UNDEFINED) 1616 1617 Provides the process id of tor. This often only works if tor is running 1618 locally. Also, most of its checks are platform dependent, and hence are not 1619 entirely reliable. 1620 1621 .. versionadded:: 1.1.0 1622 1623 :param object default: response if the query fails 1624 1625 :returns: **int** for tor's pid 1626 1627 :raises: **ValueError** if unable to determine the pid and no default was 1628 provided 1629 """ 1630 1631 pid = self._get_cache('pid') 1632 1633 if pid: 1634 return pid 1635 1636 getinfo_pid = self.get_info('process/pid', None) 1637 1638 if getinfo_pid and getinfo_pid.isdigit(): 1639 pid = int(getinfo_pid) 1640 1641 if not pid and self.is_localhost(): 1642 pid_file_path = self.get_conf('PidFile', None) 1643 1644 if pid_file_path is not None: 1645 with open(pid_file_path) as pid_file: 1646 pid_file_contents = pid_file.read().strip() 1647 1648 if pid_file_contents.isdigit(): 1649 pid = int(pid_file_contents) 1650 1651 if not pid: 1652 pid = stem.util.system.pid_by_name('tor') 1653 1654 if not pid: 1655 control_socket = self.get_socket() 1656 1657 if isinstance(control_socket, stem.socket.ControlPort): 1658 pid = stem.util.system.pid_by_port(control_socket.port) 1659 elif isinstance(control_socket, stem.socket.ControlSocketFile): 1660 pid = stem.util.system.pid_by_open_file(control_socket.path) 1661 1662 if pid: 1663 self._set_cache({'pid': pid}) 1664 return pid 1665 else: 1666 raise ValueError("Unable to resolve tor's pid" if self.is_localhost() else "Tor isn't running locally") 1667 1668 @with_default() 1669 def get_start_time(self, default = UNDEFINED): 1670 """ 1671 get_start_time(default = UNDEFINED) 1672 1673 Provides when the tor process began. 1674 1675 .. versionadded:: 1.8.0 1676 1677 :param object default: response if the query fails 1678 1679 :returns: **float** for the unix timestamp of when the tor process began 1680 1681 :raises: **ValueError** if unable to determine when the process began and 1682 no default was provided 1683 """ 1684 1685 start_time = self._get_cache('start_time') 1686 1687 if start_time: 1688 return start_time 1689 1690 if self.get_version() >= stem.version.Requirement.GETINFO_UPTIME: 1691 uptime = self.get_info('uptime', None) 1692 1693 if uptime: 1694 if not uptime.isdigit(): 1695 raise ValueError("'GETINFO uptime' did not provide a valid numeric response: %s" % uptime) 1696 1697 start_time = time.time() - float(uptime) 1698 1699 if not start_time and self.is_localhost(): 1700 # Tor doesn't yet support this GETINFO option, attempt to determine the 1701 # uptime of the process ourselves. 1702 1703 if not self.is_localhost(): 1704 raise ValueError('Unable to determine the uptime when tor is not running locally') 1705 1706 pid = self.get_pid(None) 1707 1708 if not pid: 1709 raise ValueError('Unable to determine the pid of the tor process') 1710 1711 start_time = stem.util.system.start_time(pid) 1712 1713 if start_time: 1714 self._set_cache({'start_time': start_time}) 1715 return start_time 1716 else: 1717 raise ValueError("Unable to resolve when tor began" if self.is_localhost() else "Tor isn't running locally") 1718 1719 @with_default() 1720 def get_uptime(self, default = UNDEFINED): 1721 """ 1722 get_uptime(default = UNDEFINED) 1723 1724 Provides the duration in seconds that tor has been running. 1725 1726 .. versionadded:: 1.8.0 1727 1728 :param object default: response if the query fails 1729 1730 :returns: **float** for the number of seconds tor has been running 1731 1732 :raises: **ValueError** if unable to determine the uptime and no default 1733 was provided 1734 """ 1735 1736 return time.time() - self.get_start_time() 1737 1738 def is_user_traffic_allowed(self): 1739 """ 1740 Checks if we're likely to service direct user traffic. This essentially 1741 boils down to... 1742 1743 * If we're a bridge or guard relay, inbound connections are possibly from 1744 users. 1745 1746 * If our exit policy allows traffic then output connections are possibly 1747 from users. 1748 1749 Note the word 'likely'. These is a decent guess in practice, but not always 1750 correct. For instance, information about which flags we have are only 1751 fetched periodically. 1752 1753 This method is intended to help you avoid eavesdropping on user traffic. 1754 Monitoring user connections is not only unethical, but likely a violation 1755 of wiretapping laws. 1756 1757 .. versionadded:: 1.5.0 1758 1759 :returns: :class:`~stem.cotroller.UserTrafficAllowed` with **inbound** and 1760 **outbound** boolean attributes to indicate if we're likely servicing 1761 direct user traffic 1762 """ 1763 1764 inbound_allowed, outbound_allowed = False, False 1765 1766 if self.get_conf('BridgeRelay', None) == '1': 1767 inbound_allowed = True 1768 1769 if self.get_conf('ORPort', None): 1770 if not inbound_allowed: 1771 consensus_entry = self.get_network_status(default = None) 1772 inbound_allowed = consensus_entry and 'Guard' in consensus_entry.flags 1773 1774 exit_policy = self.get_exit_policy(None) 1775 outbound_allowed = exit_policy and exit_policy.is_exiting_allowed() 1776 1777 return UserTrafficAllowed(inbound_allowed, outbound_allowed) 1778 1779 @with_default() 1780 def get_microdescriptor(self, relay = None, default = UNDEFINED): 1781 """ 1782 get_microdescriptor(relay = None, default = UNDEFINED) 1783 1784 Provides the microdescriptor for the relay with the given fingerprint or 1785 nickname. If the relay identifier could be either a fingerprint *or* 1786 nickname then it's queried as a fingerprint. 1787 1788 If no **relay** is provided then this defaults to ourselves. Remember that 1789 this requires that we've retrieved our own descriptor from remote 1790 authorities so this both won't be available for newly started relays and 1791 may be up to around an hour out of date. 1792 1793 .. versionchanged:: 1.3.0 1794 Changed so we'd fetch our own descriptor if no 'relay' is provided. 1795 1796 :param str relay: fingerprint or nickname of the relay to be queried 1797 :param object default: response if the query fails 1798 1799 :returns: :class:`~stem.descriptor.microdescriptor.Microdescriptor` for the given relay 1800 1801 :raises: 1802 * :class:`stem.DescriptorUnavailable` if unable to provide a descriptor 1803 for the given relay 1804 * :class:`stem.ControllerError` if unable to query the descriptor 1805 * **ValueError** if **relay** doesn't conform with the pattern for being 1806 a fingerprint or nickname 1807 1808 An exception is only raised if we weren't provided a default response. 1809 """ 1810 1811 if relay is None: 1812 try: 1813 relay = self.get_info('fingerprint') 1814 except stem.ControllerError as exc: 1815 raise stem.ControllerError('Unable to determine our own fingerprint: %s' % exc) 1816 1817 if stem.util.tor_tools.is_valid_fingerprint(relay): 1818 query = 'md/id/%s' % relay 1819 elif stem.util.tor_tools.is_valid_nickname(relay): 1820 query = 'md/name/%s' % relay 1821 else: 1822 raise ValueError("'%s' isn't a valid fingerprint or nickname" % relay) 1823 1824 try: 1825 desc_content = self.get_info(query, get_bytes = True) 1826 except stem.InvalidArguments as exc: 1827 if str(exc).startswith('GETINFO request contained unrecognized keywords:'): 1828 raise stem.DescriptorUnavailable("Tor was unable to provide the descriptor for '%s'" % relay) 1829 else: 1830 raise 1831 1832 if not desc_content: 1833 raise stem.DescriptorUnavailable('Descriptor information is unavailable, tor might still be downloading it') 1834 1835 return stem.descriptor.microdescriptor.Microdescriptor(desc_content) 1836 1837 @with_default(yields = True) 1838 def get_microdescriptors(self, default = UNDEFINED): 1839 """ 1840 get_microdescriptors(default = UNDEFINED) 1841 1842 Provides an iterator for all of the microdescriptors that tor currently 1843 knows about. 1844 1845 Prior to Tor 0.3.5.1 this information was not available via the control 1846 protocol. When connected to prior versions we read the microdescriptors 1847 directly from disk instead, which will not work remotely or if our process 1848 lacks read permissions. 1849 1850 :param list default: items to provide if the query fails 1851 1852 :returns: iterates over 1853 :class:`~stem.descriptor.microdescriptor.Microdescriptor` for relays in 1854 the tor network 1855 1856 :raises: :class:`stem.ControllerError` if unable to query tor and no 1857 default was provided 1858 """ 1859 1860 if self.get_version() >= stem.version.Requirement.GETINFO_MICRODESCRIPTORS: 1861 desc_content = self.get_info('md/all', get_bytes = True) 1862 1863 if not desc_content: 1864 raise stem.DescriptorUnavailable('Descriptor information is unavailable, tor might still be downloading it') 1865 1866 for desc in stem.descriptor.microdescriptor._parse_file(io.BytesIO(desc_content)): 1867 yield desc 1868 else: 1869 # TODO: remove when tor versions that require this are obsolete 1870 1871 data_directory = self.get_conf('DataDirectory', None) 1872 1873 if data_directory is None: 1874 raise stem.OperationFailed(message = "Unable to determine tor's data directory") 1875 1876 if not os.path.exists(data_directory): 1877 raise stem.OperationFailed(message = "Data directory reported by tor doesn't exist (%s)" % data_directory) 1878 1879 microdescriptor_file = None 1880 1881 for filename in ('cached-microdescs', 'cached-microdescs.new'): 1882 cached_descriptors = os.path.join(data_directory, filename) 1883 1884 if os.path.exists(cached_descriptors): 1885 microdescriptor_file = cached_descriptors 1886 break 1887 1888 if microdescriptor_file is None: 1889 raise stem.OperationFailed(message = "Data directory doesn't contain cached microdescriptors (%s)" % data_directory) 1890 1891 for desc in stem.descriptor.parse_file(microdescriptor_file): 1892 # It shouldn't be possible for these to be something other than 1893 # microdescriptors but as the saying goes: trust but verify. 1894 1895 if not isinstance(desc, stem.descriptor.microdescriptor.Microdescriptor): 1896 raise stem.OperationFailed(message = 'BUG: Descriptor reader provided non-microdescriptor content (%s)' % type(desc)) 1897 1898 yield desc 1899 1900 @with_default() 1901 def get_server_descriptor(self, relay = None, default = UNDEFINED): 1902 """ 1903 get_server_descriptor(relay = None, default = UNDEFINED) 1904 1905 Provides the server descriptor for the relay with the given fingerprint or 1906 nickname. If the relay identifier could be either a fingerprint *or* 1907 nickname then it's queried as a fingerprint. 1908 1909 If no **relay** is provided then this defaults to ourselves. Remember that 1910 this requires that we've retrieved our own descriptor from remote 1911 authorities so this both won't be available for newly started relays and 1912 may be up to around an hour out of date. 1913 1914 **As of Tor version 0.2.3.25 relays no longer get server descriptors by 1915 default.** It's advised that you use microdescriptors instead, but if you 1916 really need server descriptors then you can get them by setting 1917 'UseMicrodescriptors 0'. 1918 1919 .. versionchanged:: 1.3.0 1920 Changed so we'd fetch our own descriptor if no 'relay' is provided. 1921 1922 :param str relay: fingerprint or nickname of the relay to be queried 1923 :param object default: response if the query fails 1924 1925 :returns: :class:`~stem.descriptor.server_descriptor.RelayDescriptor` for the given relay 1926 1927 :raises: 1928 * :class:`stem.DescriptorUnavailable` if unable to provide a descriptor 1929 for the given relay 1930 * :class:`stem.ControllerError` if unable to query the descriptor 1931 * **ValueError** if **relay** doesn't conform with the pattern for being 1932 a fingerprint or nickname 1933 1934 An exception is only raised if we weren't provided a default response. 1935 """ 1936 1937 try: 1938 if relay is None: 1939 try: 1940 relay = self.get_info('fingerprint') 1941 except stem.ControllerError as exc: 1942 raise stem.ControllerError('Unable to determine our own fingerprint: %s' % exc) 1943 1944 if stem.util.tor_tools.is_valid_fingerprint(relay): 1945 query = 'desc/id/%s' % relay 1946 elif stem.util.tor_tools.is_valid_nickname(relay): 1947 query = 'desc/name/%s' % relay 1948 else: 1949 raise ValueError("'%s' isn't a valid fingerprint or nickname" % relay) 1950 1951 try: 1952 desc_content = self.get_info(query, get_bytes = True) 1953 except stem.InvalidArguments as exc: 1954 if str(exc).startswith('GETINFO request contained unrecognized keywords:'): 1955 raise stem.DescriptorUnavailable("Tor was unable to provide the descriptor for '%s'" % relay) 1956 else: 1957 raise 1958 1959 if not desc_content: 1960 raise stem.DescriptorUnavailable('Descriptor information is unavailable, tor might still be downloading it') 1961 1962 return stem.descriptor.server_descriptor.RelayDescriptor(desc_content) 1963 except: 1964 if not self._is_server_descriptors_available(): 1965 raise ValueError(SERVER_DESCRIPTORS_UNSUPPORTED) 1966 1967 raise 1968 1969 @with_default(yields = True) 1970 def get_server_descriptors(self, default = UNDEFINED): 1971 """ 1972 get_server_descriptors(default = UNDEFINED) 1973 1974 Provides an iterator for all of the server descriptors that tor currently 1975 knows about. 1976 1977 **As of Tor version 0.2.3.25 relays no longer get server descriptors by 1978 default.** It's advised that you use microdescriptors instead, but if you 1979 really need server descriptors then you can get them by setting 1980 'UseMicrodescriptors 0'. 1981 1982 :param list default: items to provide if the query fails 1983 1984 :returns: iterates over 1985 :class:`~stem.descriptor.server_descriptor.RelayDescriptor` for relays in 1986 the tor network 1987 1988 :raises: :class:`stem.ControllerError` if unable to query tor and no 1989 default was provided 1990 """ 1991 1992 # TODO: We should iterate over the descriptors as they're read from the 1993 # socket rather than reading the whole thing into memory. 1994 # 1995 # https://trac.torproject.org/8248 1996 1997 desc_content = self.get_info('desc/all-recent', get_bytes = True) 1998 1999 if not desc_content: 2000 if not self._is_server_descriptors_available(): 2001 raise stem.ControllerError(SERVER_DESCRIPTORS_UNSUPPORTED) 2002 else: 2003 raise stem.DescriptorUnavailable('Descriptor information is unavailable, tor might still be downloading it') 2004 2005 for desc in stem.descriptor.server_descriptor._parse_file(io.BytesIO(desc_content)): 2006 yield desc 2007 2008 def _is_server_descriptors_available(self): 2009 """ 2010 Checks to see if tor server descriptors should be available or not. 2011 """ 2012 2013 # TODO: Replace with a 'GETINFO desc/download-enabled' request when they're 2014 # widely available... 2015 # 2016 # https://gitweb.torproject.org/torspec.git/commit/?id=378699c 2017 2018 return self.get_version() < stem.version.Requirement.MICRODESCRIPTOR_IS_DEFAULT or \ 2019 self.get_conf('UseMicrodescriptors', None) == '0' 2020 2021 @with_default() 2022 def get_network_status(self, relay = None, default = UNDEFINED): 2023 """ 2024 get_network_status(relay = None, default = UNDEFINED) 2025 2026 Provides the router status entry for the relay with the given fingerprint 2027 or nickname. If the relay identifier could be either a fingerprint *or* 2028 nickname then it's queried as a fingerprint. 2029 2030 If no **relay** is provided then this defaults to ourselves. Remember that 2031 this requires that we've retrieved our own descriptor from remote 2032 authorities so this both won't be available for newly started relays and 2033 may be up to around an hour out of date. 2034 2035 .. versionchanged:: 1.3.0 2036 Changed so we'd fetch our own descriptor if no 'relay' is provided. 2037 2038 :param str relay: fingerprint or nickname of the relay to be queried 2039 :param object default: response if the query fails 2040 2041 :returns: :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3` 2042 for the given relay 2043 2044 :raises: 2045 * :class:`stem.DescriptorUnavailable` if unable to provide a descriptor 2046 for the given relay 2047 * :class:`stem.ControllerError` if unable to query the descriptor 2048 * **ValueError** if **relay** doesn't conform with the pattern for being 2049 a fingerprint or nickname 2050 2051 An exception is only raised if we weren't provided a default response. 2052 """ 2053 2054 if relay is None: 2055 try: 2056 relay = self.get_info('fingerprint') 2057 except stem.ControllerError as exc: 2058 raise stem.ControllerError('Unable to determine our own fingerprint: %s' % exc) 2059 2060 if stem.util.tor_tools.is_valid_fingerprint(relay): 2061 query = 'ns/id/%s' % relay 2062 elif stem.util.tor_tools.is_valid_nickname(relay): 2063 query = 'ns/name/%s' % relay 2064 else: 2065 raise ValueError("'%s' isn't a valid fingerprint or nickname" % relay) 2066 2067 try: 2068 desc_content = self.get_info(query, get_bytes = True) 2069 except stem.InvalidArguments as exc: 2070 if str(exc).startswith('GETINFO request contained unrecognized keywords:'): 2071 raise stem.DescriptorUnavailable("Tor was unable to provide the descriptor for '%s'" % relay) 2072 else: 2073 raise 2074 2075 if not desc_content: 2076 raise stem.DescriptorUnavailable('Descriptor information is unavailable, tor might still be downloading it') 2077 2078 return stem.descriptor.router_status_entry.RouterStatusEntryV3(desc_content) 2079 2080 @with_default(yields = True) 2081 def get_network_statuses(self, default = UNDEFINED): 2082 """ 2083 get_network_statuses(default = UNDEFINED) 2084 2085 Provides an iterator for all of the router status entries that tor 2086 currently knows about. 2087 2088 :param list default: items to provide if the query fails 2089 2090 :returns: iterates over 2091 :class:`~stem.descriptor.router_status_entry.RouterStatusEntryV3` for 2092 relays in the tor network 2093 2094 :raises: :class:`stem.ControllerError` if unable to query tor and no 2095 default was provided 2096 """ 2097 2098 # TODO: We should iterate over the descriptors as they're read from the 2099 # socket rather than reading the whole thing into memory. 2100 # 2101 # https://trac.torproject.org/8248 2102 2103 desc_content = self.get_info('ns/all', get_bytes = True) 2104 2105 if not desc_content: 2106 raise stem.DescriptorUnavailable('Descriptor information is unavailable, tor might still be downloading it') 2107 2108 desc_iterator = stem.descriptor.router_status_entry._parse_file( 2109 io.BytesIO(desc_content), 2110 False, 2111 entry_class = stem.descriptor.router_status_entry.RouterStatusEntryV3, 2112 ) 2113 2114 for desc in desc_iterator: 2115 yield desc 2116 2117 @with_default() 2118 def get_hidden_service_descriptor(self, address, default = UNDEFINED, servers = None, await_result = True, timeout = None): 2119 """ 2120 get_hidden_service_descriptor(address, default = UNDEFINED, servers = None, await_result = True) 2121 2122 Provides the descriptor for a hidden service. The **address** is the 2123 '.onion' address of the hidden service (for instance 3g2upl4pq6kufc4m.onion 2124 for DuckDuckGo). 2125 2126 If **await_result** is **True** then this blocks until we either receive 2127 the descriptor or the request fails. If **False** this returns right away. 2128 2129 **This method only supports v2 hidden services, not v3.** (:trac:`25417`) 2130 2131 .. versionadded:: 1.4.0 2132 2133 .. versionchanged:: 1.7.0 2134 Added the timeout argument. 2135 2136 :param str address: address of the hidden service descriptor, the '.onion' suffix is optional 2137 :param object default: response if the query fails 2138 :param list servers: requrest the descriptor from these specific servers 2139 :param float timeout: seconds to wait when **await_result** is **True** 2140 2141 :returns: :class:`~stem.descriptor.hidden_service.HiddenServiceDescriptorV2` 2142 for the given service if **await_result** is **True**, or **None** otherwise 2143 2144 :raises: 2145 * :class:`stem.DescriptorUnavailable` if **await_result** is **True** and 2146 unable to provide a descriptor for the given service 2147 * :class:`stem.Timeout` if **timeout** was reached 2148 * :class:`stem.ControllerError` if unable to query the descriptor 2149 * **ValueError** if **address** doesn't conform with the pattern of a 2150 hidden service address 2151 2152 An exception is only raised if we weren't provided a default response. 2153 """ 2154 2155 if address.endswith('.onion'): 2156 address = address[:-6] 2157 2158 if not stem.util.tor_tools.is_valid_hidden_service_address(address): 2159 raise ValueError("'%s.onion' isn't a valid hidden service address" % address) 2160 2161 if self.get_version() < stem.version.Requirement.HSFETCH: 2162 raise stem.UnsatisfiableRequest(message = 'HSFETCH was added in tor version %s' % stem.version.Requirement.HSFETCH) 2163 2164 hs_desc_queue, hs_desc_listener = queue.Queue(), None 2165 hs_desc_content_queue, hs_desc_content_listener = queue.Queue(), None 2166 start_time = time.time() 2167 2168 if await_result: 2169 def hs_desc_listener(event): 2170 hs_desc_queue.put(event) 2171 2172 def hs_desc_content_listener(event): 2173 hs_desc_content_queue.put(event) 2174 2175 self.add_event_listener(hs_desc_listener, EventType.HS_DESC) 2176 self.add_event_listener(hs_desc_content_listener, EventType.HS_DESC_CONTENT) 2177 2178 try: 2179 request = 'HSFETCH %s' % address 2180 2181 if servers: 2182 request += ' ' + ' '.join(['SERVER=%s' % s for s in servers]) 2183 2184 response = self.msg(request) 2185 stem.response.convert('SINGLELINE', response) 2186 2187 if not response.is_ok(): 2188 raise stem.ProtocolError('HSFETCH returned unexpected response code: %s' % response.code) 2189 2190 if not await_result: 2191 return None # not waiting, so nothing to provide back 2192 else: 2193 while True: 2194 event = _get_with_timeout(hs_desc_content_queue, timeout, start_time) 2195 2196 if event.address == address: 2197 if event.descriptor: 2198 return event.descriptor 2199 else: 2200 # no descriptor, looking through HS_DESC to figure out why 2201 2202 while True: 2203 event = _get_with_timeout(hs_desc_queue, timeout, start_time) 2204 2205 if event.address == address and event.action == stem.HSDescAction.FAILED: 2206 if event.reason == stem.HSDescReason.NOT_FOUND: 2207 raise stem.DescriptorUnavailable('No running hidden service at %s.onion' % address) 2208 else: 2209 raise stem.DescriptorUnavailable('Unable to retrieve the descriptor for %s.onion (retrieved from %s): %s' % (address, event.directory_fingerprint, event.reason)) 2210 finally: 2211 if hs_desc_listener: 2212 self.remove_event_listener(hs_desc_listener) 2213 2214 if hs_desc_content_listener: 2215 self.remove_event_listener(hs_desc_content_listener) 2216 2217 def get_conf(self, param, default = UNDEFINED, multiple = False): 2218 """ 2219 get_conf(param, default = UNDEFINED, multiple = False) 2220 2221 Queries the current value for a configuration option. Some configuration 2222 options (like the ExitPolicy) can have multiple values. This provides a 2223 **list** with all of the values if **multiple** is **True**. Otherwise this 2224 will be a **str** with the first value. 2225 2226 If provided with a **default** then that is provided if the configuration 2227 option was unset or the query fails (invalid configuration option, error 2228 response, control port closed, initiated, etc). 2229 2230 If the configuration value is unset and no **default** was given then this 2231 provides **None** if **multiple** was **False** and an empty list if it was 2232 **True**. 2233 2234 :param str param: configuration option to be queried 2235 :param object default: response if the option is unset or the query fails 2236 :param bool multiple: if **True** then provides a list with all of the 2237 present values (this is an empty list if the config option is unset) 2238 2239 :returns: 2240 Response depends upon how we were called as follows... 2241 2242 * **str** with the configuration value if **multiple** was **False**, 2243 **None** if it was unset 2244 * **list** with the response strings if multiple was **True** 2245 * default if one was provided and the configuration option was either 2246 unset or our call failed 2247 2248 :raises: 2249 * :class:`stem.ControllerError` if the call fails and we weren't 2250 provided a default response 2251 * :class:`stem.InvalidArguments` if the configuration option 2252 requested was invalid 2253 """ 2254 2255 # Config options are case insensitive and don't contain whitespace. Using 2256 # strip so the following check will catch whitespace-only params. 2257 2258 param = param.lower().strip() 2259 2260 if not param: 2261 return default if default != UNDEFINED else None 2262 2263 entries = self.get_conf_map(param, default, multiple) 2264 return _case_insensitive_lookup(entries, param, default) 2265 2266 def get_conf_map(self, params, default = UNDEFINED, multiple = True): 2267 """ 2268 get_conf_map(params, default = UNDEFINED, multiple = True) 2269 2270 Similar to :func:`~stem.control.Controller.get_conf` but queries multiple 2271 configuration options, providing back a mapping of those options to their 2272 values. 2273 2274 There are three use cases for GETCONF: 2275 2276 1. a single value is provided (e.g. **ControlPort**) 2277 2. multiple values are provided for the option (e.g. **ExitPolicy**) 2278 3. a set of options that weren't necessarily requested are returned (for 2279 instance querying **HiddenServiceOptions** gives **HiddenServiceDir**, 2280 **HiddenServicePort**, etc) 2281 2282 The vast majority of the options fall into the first two categories, in 2283 which case calling :func:`~stem.control.Controller.get_conf` is sufficient. 2284 However, for batch queries or the special options that give a set of values 2285 this provides back the full response. As of tor version 0.2.1.25 2286 **HiddenServiceOptions** was the only option that falls into the third 2287 category. 2288 2289 **Note:** HiddenServiceOptions are best retrieved via the 2290 :func:`~stem.control.Controller.get_hidden_service_conf` method instead. 2291 2292 :param str,list params: configuration option(s) to be queried 2293 :param object default: value for the mappings if the configuration option 2294 is either undefined or the query fails 2295 :param bool multiple: if **True** then the values provided are lists with 2296 all of the present values 2297 2298 :returns: 2299 **dict** of the 'config key => value' mappings. The value is a... 2300 2301 * **str** if **multiple** is **False**, **None** if the configuration 2302 option is unset 2303 * **list** if **multiple** is **True** 2304 * the **default** if it was set and the value was either undefined or our 2305 lookup failed 2306 2307 :raises: 2308 * :class:`stem.ControllerError` if the call fails and we weren't provided 2309 a default response 2310 * :class:`stem.InvalidArguments` if the configuration option requested 2311 was invalid 2312 """ 2313 2314 start_time = time.time() 2315 reply = {} 2316 2317 if stem.util._is_str(params): 2318 params = [params] 2319 2320 # remove strings which contain only whitespace 2321 params = [entry for entry in params if entry.strip()] 2322 2323 if params == []: 2324 return {} 2325 2326 # translate context sensitive options 2327 lookup_params = set([MAPPED_CONFIG_KEYS.get(entry, entry) for entry in params]) 2328 2329 # check for cached results 2330 2331 from_cache = [param.lower() for param in lookup_params] 2332 cached_results = self._get_cache_map(from_cache, 'getconf') 2333 2334 for key in cached_results: 2335 user_expected_key = _case_insensitive_lookup(lookup_params, key) 2336 reply[user_expected_key] = cached_results[key] 2337 lookup_params.remove(user_expected_key) 2338 2339 # if everything was cached then short circuit making the query 2340 if not lookup_params: 2341 if LOG_CACHE_FETCHES: 2342 log.trace('GETCONF %s (cache fetch)' % ' '.join(reply.keys())) 2343 2344 return self._get_conf_dict_to_response(reply, default, multiple) 2345 2346 try: 2347 response = self.msg('GETCONF %s' % ' '.join(lookup_params)) 2348 stem.response.convert('GETCONF', response) 2349 reply.update(response.entries) 2350 2351 if self.is_caching_enabled(): 2352 to_cache = dict((k.lower(), v) for k, v in response.entries.items()) 2353 2354 self._set_cache(to_cache, 'getconf') 2355 2356 # Maps the entries back to the parameters that the user requested so the 2357 # capitalization matches (ie, if they request "exitpolicy" then that 2358 # should be the key rather than "ExitPolicy"). When the same 2359 # configuration key is provided multiple times this determines the case 2360 # based on the first and ignores the rest. 2361 # 2362 # This retains the tor provided camel casing of MAPPED_CONFIG_KEYS 2363 # entries since the user didn't request those by their key, so we can't 2364 # be sure what they wanted. 2365 2366 for key in list(reply): 2367 if not key.lower() in MAPPED_CONFIG_KEYS.values(): 2368 user_expected_key = _case_insensitive_lookup(params, key, key) 2369 2370 if key != user_expected_key: 2371 reply[user_expected_key] = reply[key] 2372 del reply[key] 2373 2374 log.debug('GETCONF %s (runtime: %0.4f)' % (' '.join(lookup_params), time.time() - start_time)) 2375 return self._get_conf_dict_to_response(reply, default, multiple) 2376 except stem.ControllerError as exc: 2377 log.debug('GETCONF %s (failed: %s)' % (' '.join(lookup_params), exc)) 2378 2379 if default != UNDEFINED: 2380 return dict((param, default) for param in params) 2381 else: 2382 raise 2383 2384 def _get_conf_dict_to_response(self, config_dict, default, multiple): 2385 """ 2386 Translates a dictionary of 'config key => [value1, value2...]' into the 2387 return value of :func:`~stem.control.Controller.get_conf_map`, taking into 2388 account what the caller requested. 2389 """ 2390 2391 return_dict = {} 2392 2393 for key, values in list(config_dict.items()): 2394 if values == []: 2395 # config option was unset 2396 if default != UNDEFINED: 2397 return_dict[key] = default 2398 else: 2399 return_dict[key] = [] if multiple else None 2400 else: 2401 return_dict[key] = values if multiple else values[0] 2402 2403 return return_dict 2404 2405 @with_default() 2406 def is_set(self, param, default = UNDEFINED): 2407 """ 2408 is_set(param, default = UNDEFINED) 2409 2410 Checks if a configuration option differs from its default or not. 2411 2412 .. versionadded:: 1.5.0 2413 2414 :param str param: configuration option to check 2415 :param object default: response if the query fails 2416 2417 :returns: **True** if option differs from its default and **False** 2418 otherwise 2419 2420 :raises: :class:`stem.ControllerError` if the call fails and we weren't 2421 provided a default response 2422 """ 2423 2424 return param in self._get_custom_options() 2425 2426 def _get_custom_options(self): 2427 result = self._get_cache('get_custom_options') 2428 2429 if not result: 2430 config_lines = self.get_info('config-text').splitlines() 2431 2432 # Tor provides some config options even if they haven't been set... 2433 # 2434 # https://trac.torproject.org/projects/tor/ticket/2362 2435 # https://trac.torproject.org/projects/tor/ticket/17909 2436 2437 default_lines = ( 2438 'Log notice stdout', 2439 'Log notice file /var/log/tor/log', 2440 'DataDirectory /home/%s/.tor' % self.get_user('undefined'), 2441 'HiddenServiceStatistics 0', 2442 ) 2443 2444 for line in default_lines: 2445 if line in config_lines: 2446 config_lines.remove(line) 2447 2448 result = dict([line.split(' ', 1) for line in config_lines]) 2449 self._set_cache({'get_custom_options': result}) 2450 2451 return result 2452 2453 def set_conf(self, param, value): 2454 """ 2455 Changes the value of a tor configuration option. Our value can be any of 2456 the following... 2457 2458 * a string to set a single value 2459 * a list of strings to set a series of values (for instance the ExitPolicy) 2460 * None to either set the value to 0/NULL 2461 2462 :param str param: configuration option to be set 2463 :param str,list value: value to set the parameter to 2464 2465 :raises: 2466 * :class:`stem.ControllerError` if the call fails 2467 * :class:`stem.InvalidArguments` if configuration options 2468 requested was invalid 2469 * :class:`stem.InvalidRequest` if the configuration setting is 2470 impossible or if there's a syntax error in the configuration values 2471 """ 2472 2473 self.set_options({param: value}, False) 2474 2475 def reset_conf(self, *params): 2476 """ 2477 Reverts one or more parameters to their default values. 2478 2479 :param str params: configuration option to be reset 2480 2481 :raises: 2482 * :class:`stem.ControllerError` if the call fails 2483 * :class:`stem.InvalidArguments` if configuration options requested was invalid 2484 * :class:`stem.InvalidRequest` if the configuration setting is 2485 impossible or if there's a syntax error in the configuration values 2486 """ 2487 2488 self.set_options(dict([(entry, None) for entry in params]), True) 2489 2490 def set_options(self, params, reset = False): 2491 """ 2492 Changes multiple tor configuration options via either a SETCONF or 2493 RESETCONF query. Both behave identically unless our value is None, in which 2494 case SETCONF sets the value to 0 or NULL, and RESETCONF returns it to its 2495 default value. This accepts str, list, or None values in a similar fashion 2496 to :func:`~stem.control.Controller.set_conf`. For example... 2497 2498 :: 2499 2500 my_controller.set_options({ 2501 'Nickname': 'caerSidi', 2502 'ExitPolicy': ['accept *:80', 'accept *:443', 'reject *:*'], 2503 'ContactInfo': 'caerSidi-exit@someplace.com', 2504 'Log': None, 2505 }) 2506 2507 The params can optionally be a list of key/value tuples, though the only 2508 reason this type of argument would be useful is for hidden service 2509 configuration (those options are order dependent). 2510 2511 :param dict,list params: mapping of configuration options to the values 2512 we're setting it to 2513 :param bool reset: issues a RESETCONF, returning **None** values to their 2514 defaults if **True** 2515 2516 :raises: 2517 * :class:`stem.ControllerError` if the call fails 2518 * :class:`stem.InvalidArguments` if configuration options 2519 requested was invalid 2520 * :class:`stem.InvalidRequest` if the configuration setting is 2521 impossible or if there's a syntax error in the configuration values 2522 """ 2523 2524 start_time = time.time() 2525 2526 # constructs the SETCONF or RESETCONF query 2527 query_comp = ['RESETCONF' if reset else 'SETCONF'] 2528 2529 if isinstance(params, dict): 2530 params = list(params.items()) 2531 2532 for param, value in params: 2533 if isinstance(value, str): 2534 query_comp.append('%s="%s"' % (param, value.strip())) 2535 elif isinstance(value, collections.Iterable): 2536 query_comp.extend(['%s="%s"' % (param, val.strip()) for val in value]) 2537 elif not value: 2538 query_comp.append(param) 2539 else: 2540 raise ValueError('Cannot set %s to %s since the value was a %s but we only accept strings' % (param, value, type(value).__name__)) 2541 2542 query = ' '.join(query_comp) 2543 response = self.msg(query) 2544 stem.response.convert('SINGLELINE', response) 2545 2546 if response.is_ok(): 2547 log.debug('%s (runtime: %0.4f)' % (query, time.time() - start_time)) 2548 2549 if self.is_caching_enabled(): 2550 # clear cache for params; the CONF_CHANGED event will set cache for changes 2551 to_cache = dict((k.lower(), None) for k, v in params) 2552 self._set_cache(to_cache, 'getconf') 2553 self._confchanged_cache_invalidation(dict(params)) 2554 else: 2555 log.debug('%s (failed, code: %s, message: %s)' % (query, response.code, response.message)) 2556 immutable_params = [k for k, v in params if stem.util.str_tools._to_unicode(k).lower() in IMMUTABLE_CONFIG_OPTIONS] 2557 2558 if immutable_params: 2559 raise stem.InvalidArguments(message = "%s cannot be changed while tor's running" % ', '.join(sorted(immutable_params)), arguments = immutable_params) 2560 2561 if response.code == '552': 2562 if response.message.startswith("Unrecognized option: Unknown option '"): 2563 key = response.message[37:response.message.find("'", 37)] 2564 raise stem.InvalidArguments(response.code, response.message, [key]) 2565 raise stem.InvalidRequest(response.code, response.message) 2566 elif response.code in ('513', '553'): 2567 raise stem.InvalidRequest(response.code, response.message) 2568 else: 2569 raise stem.ProtocolError('Returned unexpected status code: %s' % response.code) 2570 2571 @with_default() 2572 def get_hidden_service_conf(self, default = UNDEFINED): 2573 """ 2574 get_hidden_service_conf(default = UNDEFINED) 2575 2576 This provides a mapping of hidden service directories to their 2577 attribute's key/value pairs. All hidden services are assured to have a 2578 'HiddenServicePort', but other entries may or may not exist. 2579 2580 :: 2581 2582 { 2583 "/var/lib/tor/hidden_service_empty/": { 2584 "HiddenServicePort": [ 2585 ] 2586 }, 2587 "/var/lib/tor/hidden_service_with_two_ports/": { 2588 "HiddenServiceAuthorizeClient": "stealth a, b", 2589 "HiddenServicePort": [ 2590 (8020, "127.0.0.1", 8020), # the ports order is kept 2591 (8021, "127.0.0.1", 8021) 2592 ], 2593 "HiddenServiceVersion": "2" 2594 }, 2595 } 2596 2597 .. versionadded:: 1.3.0 2598 2599 :param object default: response if the query fails 2600 2601 :returns: **dict** with the hidden service configuration 2602 2603 :raises: :class:`stem.ControllerError` if the call fails and we weren't 2604 provided a default response 2605 """ 2606 2607 service_dir_map = self._get_cache('hidden_service_conf') 2608 2609 if service_dir_map is not None: 2610 if LOG_CACHE_FETCHES: 2611 log.trace('GETCONF HiddenServiceOptions (cache fetch)') 2612 2613 return service_dir_map 2614 2615 start_time = time.time() 2616 2617 try: 2618 response = self.msg('GETCONF HiddenServiceOptions') 2619 stem.response.convert('GETCONF', response) 2620 log.debug('GETCONF HiddenServiceOptions (runtime: %0.4f)' % 2621 (time.time() - start_time)) 2622 except stem.ControllerError as exc: 2623 log.debug('GETCONF HiddenServiceOptions (failed: %s)' % exc) 2624 raise 2625 2626 service_dir_map = OrderedDict() 2627 directory = None 2628 2629 for status_code, divider, content in response.content(): 2630 if content == 'HiddenServiceOptions': 2631 continue 2632 2633 if '=' not in content: 2634 continue 2635 2636 k, v = content.split('=', 1) 2637 2638 if k == 'HiddenServiceDir': 2639 directory = v 2640 service_dir_map[directory] = {'HiddenServicePort': []} 2641 elif k == 'HiddenServicePort': 2642 port = target_port = v 2643 target_address = '127.0.0.1' 2644 2645 if not v.isdigit(): 2646 port, target = v.split() 2647 2648 if target.isdigit(): 2649 target_port = target 2650 else: 2651 target_address, target_port = target.rsplit(':', 1) 2652 2653 if not stem.util.connection.is_valid_port(port): 2654 raise stem.ProtocolError('GETCONF provided an invalid HiddenServicePort port (%s): %s' % (port, content)) 2655 elif not stem.util.connection.is_valid_ipv4_address(target_address): 2656 raise stem.ProtocolError('GETCONF provided an invalid HiddenServicePort target address (%s): %s' % (target_address, content)) 2657 elif not stem.util.connection.is_valid_port(target_port): 2658 raise stem.ProtocolError('GETCONF provided an invalid HiddenServicePort target port (%s): %s' % (target_port, content)) 2659 2660 service_dir_map[directory]['HiddenServicePort'].append((int(port), target_address, int(target_port))) 2661 else: 2662 service_dir_map[directory][k] = v 2663 2664 self._set_cache({'hidden_service_conf': service_dir_map}) 2665 return service_dir_map 2666 2667 def set_hidden_service_conf(self, conf): 2668 """ 2669 Update all the configured hidden services from a dictionary having 2670 the same format as 2671 :func:`~stem.control.Controller.get_hidden_service_conf`. 2672 2673 For convenience the HiddenServicePort entries can be an integer, string, or 2674 tuple. If an **int** then we treat it as just a port. If a **str** we pass 2675 that directly as the HiddenServicePort. And finally, if a **tuple** then 2676 it's expected to be the **(port, target_address, target_port)** as provided 2677 by :func:`~stem.control.Controller.get_hidden_service_conf`. 2678 2679 This is to say the following three are equivalent... 2680 2681 :: 2682 2683 "HiddenServicePort": [ 2684 80, 2685 '80 127.0.0.1:80', 2686 (80, '127.0.0.1', 80), 2687 ] 2688 2689 .. versionadded:: 1.3.0 2690 2691 :param dict conf: configuration dictionary 2692 2693 :raises: 2694 * :class:`stem.ControllerError` if the call fails 2695 * :class:`stem.InvalidArguments` if configuration options 2696 requested was invalid 2697 * :class:`stem.InvalidRequest` if the configuration setting is 2698 impossible or if there's a syntax error in the configuration values 2699 """ 2700 2701 # If we're not adding or updating any hidden services then call RESETCONF 2702 # so we drop existing values. Otherwise calling SETCONF is a no-op. 2703 2704 if not conf: 2705 self.reset_conf('HiddenServiceDir') 2706 return 2707 2708 # Convert conf dictionary into a list of ordered config tuples 2709 2710 hidden_service_options = [] 2711 2712 for directory in conf: 2713 hidden_service_options.append(('HiddenServiceDir', directory)) 2714 2715 for k, v in list(conf[directory].items()): 2716 if k == 'HiddenServicePort': 2717 for entry in v: 2718 if isinstance(entry, int): 2719 entry = '%s 127.0.0.1:%s' % (entry, entry) 2720 elif isinstance(entry, str): 2721 pass # just pass along what the user gave us 2722 elif isinstance(entry, tuple): 2723 port, target_address, target_port = entry 2724 entry = '%s %s:%s' % (port, target_address, target_port) 2725 2726 hidden_service_options.append(('HiddenServicePort', entry)) 2727 else: 2728 hidden_service_options.append((k, str(v))) 2729 2730 self.set_options(hidden_service_options) 2731 2732 def create_hidden_service(self, path, port, target_address = None, target_port = None, auth_type = None, client_names = None): 2733 """ 2734 Create a new hidden service. If the directory is already present, a 2735 new port is added. 2736 2737 Our *.onion address is fetched by reading the hidden service directory. 2738 However, this directory is only readable by the tor user, so if unavailable 2739 the **hostname** will be **None**. 2740 2741 **As of Tor 0.2.7.1 there's two ways for creating hidden services, and this 2742 method is no longer recommended.** Rather, try using 2743 :func:`~stem.control.Controller.create_ephemeral_hidden_service` instead. 2744 2745 .. versionadded:: 1.3.0 2746 2747 .. versionchanged:: 1.4.0 2748 Added the auth_type and client_names arguments. 2749 2750 :param str path: path for the hidden service's data directory 2751 :param int port: hidden service port 2752 :param str target_address: address of the service, by default 127.0.0.1 2753 :param int target_port: port of the service, by default this is the same as 2754 **port** 2755 :param str auth_type: authentication type: basic, stealth or None to disable auth 2756 :param list client_names: client names (1-16 characters "A-Za-z0-9+-_") 2757 2758 :returns: :class:`~stem.cotroller.CreateHiddenServiceOutput` if we create 2759 or update a hidden service, **None** otherwise 2760 2761 :raises: :class:`stem.ControllerError` if the call fails 2762 """ 2763 2764 if not stem.util.connection.is_valid_port(port): 2765 raise ValueError("%s isn't a valid port number" % port) 2766 elif target_address and not stem.util.connection.is_valid_ipv4_address(target_address): 2767 raise ValueError("%s isn't a valid IPv4 address" % target_address) 2768 elif target_port is not None and not stem.util.connection.is_valid_port(target_port): 2769 raise ValueError("%s isn't a valid port number" % target_port) 2770 elif auth_type not in (None, 'basic', 'stealth'): 2771 raise ValueError("%s isn't a recognized type of authentication" % auth_type) 2772 2773 port = int(port) 2774 target_address = target_address if target_address else '127.0.0.1' 2775 target_port = port if target_port is None else int(target_port) 2776 2777 conf = self.get_hidden_service_conf() 2778 2779 if path in conf and (port, target_address, target_port) in conf[path]['HiddenServicePort']: 2780 return None 2781 2782 conf.setdefault(path, OrderedDict()).setdefault('HiddenServicePort', []).append((port, target_address, target_port)) 2783 2784 if auth_type and client_names: 2785 hsac = "%s %s" % (auth_type, ','.join(client_names)) 2786 conf[path]['HiddenServiceAuthorizeClient'] = hsac 2787 2788 # Tor 0.3.5 changes its default for HS creation from v2 to v3. This is 2789 # fine, but there's a couple options that are incompatible with v3. If 2790 # creating a service with one of those we should explicitly create a v2 2791 # service instead. 2792 # 2793 # https://trac.torproject.org/projects/tor/ticket/27446 2794 2795 for path in conf: 2796 if 'HiddenServiceAuthorizeClient' in conf[path] or 'RendPostPeriod' in conf[path]: 2797 conf[path]['HiddenServiceVersion'] = '2' 2798 2799 self.set_hidden_service_conf(conf) 2800 2801 hostname, hostname_for_client = None, {} 2802 2803 if self.is_localhost(): 2804 hostname_path = os.path.join(path, 'hostname') 2805 2806 if not os.path.isabs(hostname_path): 2807 cwd = stem.util.system.cwd(self.get_pid(None)) 2808 2809 if cwd: 2810 hostname_path = stem.util.system.expand_path(hostname_path, cwd) 2811 2812 if os.path.isabs(hostname_path): 2813 start_time = time.time() 2814 2815 while not os.path.exists(hostname_path): 2816 wait_time = time.time() - start_time 2817 2818 if wait_time >= 3: 2819 break 2820 else: 2821 time.sleep(0.05) 2822 2823 try: 2824 with open(hostname_path) as hostname_file: 2825 hostname = hostname_file.read().strip() 2826 2827 if client_names and '\n' in hostname: 2828 # When there's multiple clients this looks like... 2829 # 2830 # ndisjxzkgcdhrwqf.onion sjUwjTSPznqWLdOPuwRUzg # client: c1 2831 # ndisjxzkgcdhrwqf.onion sUu92axuL5bKnA76s2KRfw # client: c2 2832 2833 for line in hostname.splitlines(): 2834 if ' # client: ' in line: 2835 address = line.split()[0] 2836 client = line.split(' # client: ', 1)[1] 2837 2838 if len(address) == 22 and address.endswith('.onion'): 2839 hostname_for_client[client] = address 2840 except: 2841 pass 2842 2843 return CreateHiddenServiceOutput( 2844 path = path, 2845 hostname = hostname, 2846 hostname_for_client = hostname_for_client, 2847 config = conf, 2848 ) 2849 2850 def remove_hidden_service(self, path, port = None): 2851 """ 2852 Discontinues a given hidden service. 2853 2854 .. versionadded:: 1.3.0 2855 2856 :param str path: path for the hidden service's data directory 2857 :param int port: hidden service port 2858 2859 :returns: **True** if the hidden service is discontinued, **False** if it 2860 wasn't running in the first place 2861 2862 :raises: :class:`stem.ControllerError` if the call fails 2863 """ 2864 2865 if port and not stem.util.connection.is_valid_port(port): 2866 raise ValueError("%s isn't a valid port number" % port) 2867 2868 port = int(port) if port else None 2869 conf = self.get_hidden_service_conf() 2870 2871 if path not in conf: 2872 return False 2873 2874 if not port: 2875 del conf[path] 2876 else: 2877 to_remove = [entry for entry in conf[path]['HiddenServicePort'] if entry[0] == port] 2878 2879 if not to_remove: 2880 return False 2881 2882 for entry in to_remove: 2883 conf[path]['HiddenServicePort'].remove(entry) 2884 2885 if not conf[path]['HiddenServicePort']: 2886 del conf[path] # no ports left 2887 2888 self.set_hidden_service_conf(conf) 2889 return True 2890 2891 @with_default() 2892 def list_ephemeral_hidden_services(self, default = UNDEFINED, our_services = True, detached = False): 2893 """ 2894 list_ephemeral_hidden_services(default = UNDEFINED, our_services = True, detached = False) 2895 2896 Lists hidden service addresses created by 2897 :func:`~stem.control.Controller.create_ephemeral_hidden_service`. 2898 2899 .. versionadded:: 1.4.0 2900 2901 .. versionchanged:: 1.6.0 2902 Tor change caused this to start providing empty strings if unset 2903 (:trac:`21329`). 2904 2905 :param object default: response if the query fails 2906 :param bool our_services: include services created with this controller 2907 that weren't flagged as 'detached' 2908 :param bool detached: include services whos contiuation isn't tied to a 2909 controller 2910 2911 :returns: **list** of hidden service addresses without their '.onion' 2912 suffix 2913 2914 :raises: :class:`stem.ControllerError` if the call fails and we weren't 2915 provided a default response 2916 """ 2917 2918 if self.get_version() < stem.version.Requirement.ADD_ONION: 2919 raise stem.UnsatisfiableRequest(message = 'Ephemeral hidden services were added in tor version %s' % stem.version.Requirement.ADD_ONION) 2920 2921 result = [] 2922 2923 if our_services: 2924 try: 2925 result += self.get_info('onions/current').split('\n') 2926 except (stem.ProtocolError, stem.OperationFailed) as exc: 2927 # TODO: Tor's behavior around this was changed in Feb 2017, we should 2928 # drop it when all versions that did this are deprecated... 2929 # 2930 # https://trac.torproject.org/projects/tor/ticket/21329 2931 2932 if 'No onion services of the specified type.' not in str(exc): 2933 raise 2934 2935 if detached: 2936 try: 2937 result += self.get_info('onions/detached').split('\n') 2938 except (stem.ProtocolError, stem.OperationFailed) as exc: 2939 if 'No onion services of the specified type.' not in str(exc): 2940 raise 2941 2942 return [r for r in result if r] # drop any empty responses (GETINFO is blank if unset) 2943 2944 def create_ephemeral_hidden_service(self, ports, key_type = 'NEW', key_content = 'BEST', discard_key = False, detached = False, await_publication = False, timeout = None, basic_auth = None, max_streams = None): 2945 """ 2946 Creates a new hidden service. Unlike 2947 :func:`~stem.control.Controller.create_hidden_service` this style of 2948 hidden service doesn't touch disk, carrying with it a lot of advantages. 2949 This is the suggested method for making hidden services. 2950 2951 Our **ports** argument can be a single port... 2952 2953 :: 2954 2955 create_ephemeral_hidden_service(80) 2956 2957 ... list of ports the service is available on... 2958 2959 :: 2960 2961 create_ephemeral_hidden_service([80, 443]) 2962 2963 ... or a mapping of hidden service ports to their targets... 2964 2965 :: 2966 2967 create_ephemeral_hidden_service({80: 80, 443: '173.194.33.133:443'}) 2968 2969 If **basic_auth** is provided this service will require basic 2970 authentication to access. This means users must set HidServAuth in their 2971 torrc with credentials to access it. 2972 2973 **basic_auth** is a mapping of usernames to their credentials. If the 2974 credential is **None** one is generated and returned as part of the 2975 response. For instance, only bob can access using the given newly generated 2976 credentials... 2977 2978 :: 2979 2980 >>> response = controller.create_ephemeral_hidden_service(80, basic_auth = {'bob': None}) 2981 >>> print(response.client_auth) 2982 {'bob': 'nKwfvVPmTNr2k2pG0pzV4g'} 2983 2984 ... while both alice and bob can access with existing credentials in the 2985 following... 2986 2987 :: 2988 2989 controller.create_ephemeral_hidden_service(80, basic_auth = { 2990 'alice': 'l4BT016McqV2Oail+Bwe6w', 2991 'bob': 'vGnNRpWYiMBFTWD2gbBlcA', 2992 }) 2993 2994 To create a **version 3** service simply specify **ED25519-V3** as the 2995 our key type, and to create a **version 2** service use **RSA1024**. The 2996 default version of newly created hidden services is based on the 2997 **HiddenServiceVersion** value in your torrc... 2998 2999 :: 3000 3001 response = controller.create_ephemeral_hidden_service( 3002 80, 3003 key_content = 'ED25519-V3', 3004 await_publication = True, 3005 ) 3006 3007 print('service established at %s.onion' % response.service_id) 3008 3009 .. versionadded:: 1.4.0 3010 3011 .. versionchanged:: 1.5.0 3012 Added the basic_auth argument. 3013 3014 .. versionchanged:: 1.5.0 3015 Added support for non-anonymous services. To do so set 3016 'HiddenServiceSingleHopMode 1' and 'HiddenServiceNonAnonymousMode 1' in 3017 your torrc. 3018 3019 .. versionchanged:: 1.7.0 3020 Added the timeout and max_streams arguments. 3021 3022 :param int,list,dict ports: hidden service port(s) or mapping of hidden 3023 service ports to their targets 3024 :param str key_type: type of key being provided, generates a new key if 3025 'NEW' (options are: **NEW**, **RSA1024**, and **ED25519-V3**) 3026 :param str key_content: key for the service to use or type of key to be 3027 generated (options when **key_type** is **NEW** are **BEST**, 3028 **RSA1024**, and **ED25519-V3**) 3029 :param bool discard_key: avoid providing the key back in our response 3030 :param bool detached: continue this hidden service even after this control 3031 connection is closed if **True** 3032 :param bool await_publication: blocks until our descriptor is successfully 3033 published if **True** 3034 :param float timeout: seconds to wait when **await_result** is **True** 3035 :param dict basic_auth: required user credentials to access this service 3036 :param int max_streams: maximum number of streams the hidden service will 3037 accept, unlimited if zero or not set 3038 3039 :returns: :class:`~stem.response.add_onion.AddOnionResponse` with the response 3040 3041 :raises: 3042 * :class:`stem.ControllerError` if the call fails 3043 * :class:`stem.Timeout` if **timeout** was reached 3044 """ 3045 3046 if self.get_version() < stem.version.Requirement.ADD_ONION: 3047 raise stem.UnsatisfiableRequest(message = 'Ephemeral hidden services were added in tor version %s' % stem.version.Requirement.ADD_ONION) 3048 3049 hs_desc_queue, hs_desc_listener = queue.Queue(), None 3050 start_time = time.time() 3051 3052 if await_publication: 3053 def hs_desc_listener(event): 3054 hs_desc_queue.put(event) 3055 3056 self.add_event_listener(hs_desc_listener, EventType.HS_DESC) 3057 3058 request = 'ADD_ONION %s:%s' % (key_type, key_content) 3059 3060 flags = [] 3061 3062 if discard_key: 3063 flags.append('DiscardPK') 3064 3065 if detached: 3066 flags.append('Detach') 3067 3068 if basic_auth is not None: 3069 if self.get_version() < stem.version.Requirement.ADD_ONION_BASIC_AUTH: 3070 raise stem.UnsatisfiableRequest(message = 'Basic authentication support was added to ADD_ONION in tor version %s' % stem.version.Requirement.ADD_ONION_BASIC_AUTH) 3071 3072 flags.append('BasicAuth') 3073 3074 if max_streams is not None: 3075 if self.get_version() < stem.version.Requirement.ADD_ONION_MAX_STREAMS: 3076 raise stem.UnsatisfiableRequest(message = 'Limitation of the maximum number of streams to accept was added to ADD_ONION in tor version %s' % stem.version.Requirement.ADD_ONION_MAX_STREAMS) 3077 3078 flags.append('MaxStreamsCloseCircuit') 3079 3080 if self.get_version() >= stem.version.Requirement.ADD_ONION_NON_ANONYMOUS: 3081 if self.get_conf('HiddenServiceSingleHopMode', None) == '1' and self.get_conf('HiddenServiceNonAnonymousMode', None) == '1': 3082 flags.append('NonAnonymous') 3083 3084 if flags: 3085 request += ' Flags=%s' % ','.join(flags) 3086 3087 if max_streams is not None: 3088 request += ' MaxStreams=%s' % max_streams 3089 3090 if isinstance(ports, int): 3091 request += ' Port=%s' % ports 3092 elif isinstance(ports, list): 3093 for port in ports: 3094 request += ' Port=%s' % port 3095 elif isinstance(ports, dict): 3096 for port, target in ports.items(): 3097 request += ' Port=%s,%s' % (port, target) 3098 else: 3099 raise ValueError("The 'ports' argument of create_ephemeral_hidden_service() needs to be an int, list, or dict") 3100 3101 if basic_auth is not None: 3102 for client_name, client_blob in basic_auth.items(): 3103 if client_blob: 3104 request += ' ClientAuth=%s:%s' % (client_name, client_blob) 3105 else: 3106 request += ' ClientAuth=%s' % client_name 3107 3108 response = self.msg(request) 3109 stem.response.convert('ADD_ONION', response) 3110 3111 if await_publication: 3112 # We should receive five UPLOAD events, followed by up to another five 3113 # UPLOADED to indicate they've finished. Presently tor seems to have an 3114 # issue where the address is provided for UPLOAD but not UPLOADED so need 3115 # to just guess that if it's for the same hidden service authority then 3116 # it's what we're looking for. 3117 3118 directories_uploaded_to, failures = [], [] 3119 3120 try: 3121 while True: 3122 event = _get_with_timeout(hs_desc_queue, timeout, start_time) 3123 3124 if event.action == stem.HSDescAction.UPLOAD and event.address == response.service_id: 3125 directories_uploaded_to.append(event.directory_fingerprint) 3126 elif event.action == stem.HSDescAction.UPLOADED and event.directory_fingerprint in directories_uploaded_to: 3127 break # successfully uploaded to a HS authority... maybe 3128 elif event.action == stem.HSDescAction.FAILED and event.directory_fingerprint in directories_uploaded_to: 3129 failures.append('%s (%s)' % (event.directory_fingerprint, event.reason)) 3130 3131 if len(directories_uploaded_to) == len(failures): 3132 raise stem.OperationFailed(message = 'Failed to upload our hidden service descriptor to %s' % ', '.join(failures)) 3133 finally: 3134 self.remove_event_listener(hs_desc_listener) 3135 3136 return response 3137 3138 def remove_ephemeral_hidden_service(self, service_id): 3139 """ 3140 Discontinues a given hidden service that was created with 3141 :func:`~stem.control.Controller.create_ephemeral_hidden_service`. 3142 3143 .. versionadded:: 1.4.0 3144 3145 :param str service_id: hidden service address without the '.onion' suffix 3146 3147 :returns: **True** if the hidden service is discontinued, **False** if it 3148 wasn't running in the first place 3149 3150 :raises: :class:`stem.ControllerError` if the call fails 3151 """ 3152 3153 if self.get_version() < stem.version.Requirement.ADD_ONION: 3154 raise stem.UnsatisfiableRequest(message = 'Ephemeral hidden services were added in tor version %s' % stem.version.Requirement.ADD_ONION) 3155 3156 response = self.msg('DEL_ONION %s' % service_id) 3157 stem.response.convert('SINGLELINE', response) 3158 3159 if response.is_ok(): 3160 return True 3161 elif response.code == '552': 3162 return False # no hidden service to discontinue 3163 else: 3164 raise stem.ProtocolError('DEL_ONION returned unexpected response code: %s' % response.code) 3165 3166 def add_event_listener(self, listener, *events): 3167 """ 3168 Directs further tor controller events to a given function. The function is 3169 expected to take a single argument, which is a 3170 :class:`~stem.response.events.Event` subclass. For instance the following 3171 would print the bytes sent and received by tor over five seconds... 3172 3173 :: 3174 3175 import time 3176 from stem.control import Controller, EventType 3177 3178 def print_bw(event): 3179 print('sent: %i, received: %i' % (event.written, event.read)) 3180 3181 with Controller.from_port(port = 9051) as controller: 3182 controller.authenticate() 3183 controller.add_event_listener(print_bw, EventType.BW) 3184 time.sleep(5) 3185 3186 If a new control connection is initialized then this listener will be 3187 reattached. 3188 3189 If tor emits a malformed event it can be received by listening for the 3190 stem.control.MALFORMED_EVENTS constant. 3191 3192 .. versionchanged:: 1.7.0 3193 Listener exceptions and malformed events no longer break further event 3194 processing. Added the **MALFORMED_EVENTS** constant. 3195 3196 :param functor listener: function to be called when an event is received 3197 :param stem.control.EventType events: event types to be listened for 3198 3199 :raises: :class:`stem.ProtocolError` if unable to set the events 3200 """ 3201 3202 # first checking that tor supports these event types 3203 3204 with self._event_listeners_lock: 3205 if self.is_authenticated(): 3206 for event_type in events: 3207 event_type = stem.response.events.EVENT_TYPE_TO_CLASS.get(event_type) 3208 3209 if event_type and (self.get_version() < event_type._VERSION_ADDED): 3210 raise stem.InvalidRequest(552, '%s event requires Tor version %s or later' % (event_type, event_type._VERSION_ADDED)) 3211 3212 for event_type in events: 3213 self._event_listeners.setdefault(event_type, []).append(listener) 3214 3215 failed_events = self._attach_listeners()[1] 3216 3217 # restricted the failures to just things we requested 3218 3219 failed_events = set(failed_events).intersection(set(events)) 3220 3221 if failed_events: 3222 raise stem.ProtocolError('SETEVENTS rejected %s' % ', '.join(failed_events)) 3223 3224 def remove_event_listener(self, listener): 3225 """ 3226 Stops a listener from being notified of further tor events. 3227 3228 :param stem.control.EventListener listener: listener to be removed 3229 3230 :raises: :class:`stem.ProtocolError` if unable to set the events 3231 """ 3232 3233 with self._event_listeners_lock: 3234 event_types_changed = False 3235 3236 for event_type, event_listeners in list(self._event_listeners.items()): 3237 if listener in event_listeners: 3238 event_listeners.remove(listener) 3239 3240 if len(event_listeners) == 0: 3241 event_types_changed = True 3242 del self._event_listeners[event_type] 3243 3244 if event_types_changed: 3245 response = self.msg('SETEVENTS %s' % ' '.join(self._event_listeners.keys())) 3246 3247 if not response.is_ok(): 3248 raise stem.ProtocolError('SETEVENTS received unexpected response\n%s' % response) 3249 3250 def _get_cache(self, param, namespace = None): 3251 """ 3252 Queries our request cache for the given key. 3253 3254 :param str param: key to be queried 3255 :param str namespace: namespace in which to check for the key 3256 3257 :returns: cached value corresponding to key or **None** if the key wasn't found 3258 """ 3259 3260 with self._cache_lock: 3261 if not self.is_caching_enabled(): 3262 return None 3263 3264 cache_key = '%s.%s' % (namespace, param) if namespace else param 3265 return self._request_cache.get(cache_key, None) 3266 3267 def _get_cache_map(self, params, namespace = None): 3268 """ 3269 Queries our request cache for multiple entries. 3270 3271 :param list params: keys to be queried 3272 :param str namespace: namespace in which to check for the keys 3273 3274 :returns: **dict** of 'param => cached value' pairs of keys present in cache 3275 """ 3276 3277 with self._cache_lock: 3278 cached_values = {} 3279 3280 if self.is_caching_enabled(): 3281 for param in params: 3282 cache_key = '%s.%s' % (namespace, param) if namespace else param 3283 3284 if cache_key in self._request_cache: 3285 cached_values[param] = self._request_cache[cache_key] 3286 3287 return cached_values 3288 3289 def _set_cache(self, params, namespace = None): 3290 """ 3291 Sets the given request cache entries. If the new cache value is **None** 3292 then it is removed from our cache. 3293 3294 :param dict params: **dict** of 'cache_key => value' pairs to be cached 3295 :param str namespace: namespace for the keys 3296 """ 3297 3298 with self._cache_lock: 3299 if not self.is_caching_enabled(): 3300 return 3301 3302 # if params is None then clear the namespace 3303 3304 if params is None and namespace: 3305 for cache_key in list(self._request_cache.keys()): 3306 if cache_key.startswith('%s.' % namespace): 3307 del self._request_cache[cache_key] 3308 3309 return 3310 3311 # remove uncacheable items 3312 if namespace == 'getconf': 3313 # shallow copy before edit so as not to change it for the caller 3314 params = params.copy() 3315 for key in UNCACHEABLE_GETCONF_PARAMS: 3316 if key in params: 3317 del params[key] 3318 3319 for key, value in list(params.items()): 3320 if namespace: 3321 cache_key = '%s.%s' % (namespace, key) 3322 else: 3323 cache_key = key 3324 3325 if value is None: 3326 if cache_key in list(self._request_cache.keys()): 3327 del self._request_cache[cache_key] 3328 else: 3329 self._request_cache[cache_key] = value 3330 3331 def _confchanged_cache_invalidation(self, params): 3332 """ 3333 Drops dependent portions of the cache when configuration changes. 3334 3335 :param dict params: **dict** of 'config_key => value' pairs for configs 3336 that changed. The entries' values are currently unused. 3337 """ 3338 3339 with self._cache_lock: 3340 if not self.is_caching_enabled(): 3341 return 3342 3343 if any('hidden' in param.lower() for param in params.keys()): 3344 self._set_cache({'hidden_service_conf': None}) 3345 3346 # reset any getinfo parameters that can be changed by a SETCONF 3347 3348 self._set_cache(dict([(k.lower(), None) for k in CACHEABLE_GETINFO_PARAMS_UNTIL_SETCONF]), 'getinfo') 3349 self._set_cache(None, 'listeners') 3350 3351 self._set_cache({'get_custom_options': None}) 3352 3353 self._set_cache({'exit_policy': None}) # numerous options can change our policy 3354 3355 def is_caching_enabled(self): 3356 """ 3357 **True** if caching has been enabled, **False** otherwise. 3358 3359 :returns: bool to indicate if caching is enabled 3360 """ 3361 3362 return self._is_caching_enabled 3363 3364 def set_caching(self, enabled): 3365 """ 3366 Enables or disables caching of information retrieved from tor. 3367 3368 :param bool enabled: **True** to enable caching, **False** to disable it 3369 """ 3370 3371 self._is_caching_enabled = enabled 3372 3373 if not self._is_caching_enabled: 3374 self.clear_cache() 3375 3376 def clear_cache(self): 3377 """ 3378 Drops any cached results. 3379 """ 3380 3381 with self._cache_lock: 3382 self._request_cache = {} 3383 self._last_newnym = 0.0 3384 self._is_geoip_unavailable = None 3385 3386 def load_conf(self, configtext): 3387 """ 3388 Sends the configuration text to Tor and loads it as if it has been read from 3389 the torrc. 3390 3391 :param str configtext: the configuration text 3392 3393 :raises: :class:`stem.ControllerError` if the call fails 3394 """ 3395 3396 response = self.msg('LOADCONF\n%s' % configtext) 3397 stem.response.convert('SINGLELINE', response) 3398 3399 if response.code in ('552', '553'): 3400 if response.code == '552' and response.message.startswith('Invalid config file: Failed to parse/validate config: Unknown option'): 3401 raise stem.InvalidArguments(response.code, response.message, [response.message[70:response.message.find('.', 70) - 1]]) 3402 raise stem.InvalidRequest(response.code, response.message) 3403 elif not response.is_ok(): 3404 raise stem.ProtocolError('+LOADCONF Received unexpected response\n%s' % str(response)) 3405 3406 def save_conf(self, force = False): 3407 """ 3408 Saves the current configuration options into the active torrc file. 3409 3410 .. versionchanged:: 1.6.0 3411 Added the force argument. 3412 3413 :param bool force: overwrite the configuration even if it includes a 3414 '%include' clause, this is ignored if tor doesn't support it 3415 3416 :raises: 3417 * :class:`stem.ControllerError` if the call fails 3418 * :class:`stem.OperationFailed` if the client is unable to save 3419 the configuration file 3420 """ 3421 3422 if self.get_version() < stem.version.Requirement.SAVECONF_FORCE: 3423 force = False 3424 3425 response = self.msg('SAVECONF FORCE' if force else 'SAVECONF') 3426 stem.response.convert('SINGLELINE', response) 3427 3428 if response.is_ok(): 3429 return True 3430 elif response.code == '551': 3431 raise stem.OperationFailed(response.code, response.message) 3432 else: 3433 raise stem.ProtocolError('SAVECONF returned unexpected response code') 3434 3435 def is_feature_enabled(self, feature): 3436 """ 3437 Checks if a control connection feature is enabled. These features can be 3438 enabled using :func:`~stem.control.Controller.enable_feature`. 3439 3440 :param str feature: feature to be checked 3441 3442 :returns: **True** if feature is enabled, **False** otherwise 3443 """ 3444 3445 feature = feature.upper() 3446 3447 if feature in self._enabled_features: 3448 return True 3449 else: 3450 # check if this feature is on by default 3451 defaulted_version = None 3452 3453 if feature == 'EXTENDED_EVENTS': 3454 defaulted_version = stem.version.Requirement.FEATURE_EXTENDED_EVENTS 3455 elif feature == 'VERBOSE_NAMES': 3456 defaulted_version = stem.version.Requirement.FEATURE_VERBOSE_NAMES 3457 3458 if defaulted_version: 3459 our_version = self.get_version(None) 3460 3461 if our_version and our_version >= defaulted_version: 3462 self._enabled_features.append(feature) 3463 3464 return feature in self._enabled_features 3465 3466 def enable_feature(self, features): 3467 """ 3468 Enables features that are disabled by default to maintain backward 3469 compatibility. Once enabled, a feature cannot be disabled and a new 3470 control connection must be opened to get a connection with the feature 3471 disabled. Feature names are case-insensitive. 3472 3473 The following features are currently accepted: 3474 3475 * EXTENDED_EVENTS - Requests the extended event syntax 3476 * VERBOSE_NAMES - Replaces ServerID with LongName in events and GETINFO results 3477 3478 :param str,list features: a single feature or a list of features to be enabled 3479 3480 :raises: 3481 * :class:`stem.ControllerError` if the call fails 3482 * :class:`stem.InvalidArguments` if features passed were invalid 3483 """ 3484 3485 if stem.util._is_str(features): 3486 features = [features] 3487 3488 response = self.msg('USEFEATURE %s' % ' '.join(features)) 3489 stem.response.convert('SINGLELINE', response) 3490 3491 if not response.is_ok(): 3492 if response.code == '552': 3493 invalid_feature = [] 3494 3495 if response.message.startswith('Unrecognized feature "'): 3496 invalid_feature = [response.message[22:response.message.find('"', 22)]] 3497 3498 raise stem.InvalidArguments(response.code, response.message, invalid_feature) 3499 3500 raise stem.ProtocolError('USEFEATURE provided an invalid response code: %s' % response.code) 3501 3502 self._enabled_features += [entry.upper() for entry in features] 3503 3504 @with_default() 3505 def get_circuit(self, circuit_id, default = UNDEFINED): 3506 """ 3507 get_circuit(circuit_id, default = UNDEFINED) 3508 3509 Provides a circuit currently available from tor. 3510 3511 :param int circuit_id: circuit to be fetched 3512 :param object default: response if the query fails 3513 3514 :returns: :class:`stem.response.events.CircuitEvent` for the given circuit 3515 3516 :raises: 3517 * :class:`stem.ControllerError` if the call fails 3518 * **ValueError** if the circuit doesn't exist 3519 3520 An exception is only raised if we weren't provided a default response. 3521 """ 3522 3523 for circ in self.get_circuits(): 3524 if circ.id == circuit_id: 3525 return circ 3526 3527 raise ValueError("Tor currently does not have a circuit with the id of '%s'" % circuit_id) 3528 3529 @with_default() 3530 def get_circuits(self, default = UNDEFINED): 3531 """ 3532 get_circuits(default = UNDEFINED) 3533 3534 Provides tor's currently available circuits. 3535 3536 :param object default: response if the query fails 3537 3538 :returns: **list** of :class:`stem.response.events.CircuitEvent` for our circuits 3539 3540 :raises: :class:`stem.ControllerError` if the call fails and no default was provided 3541 """ 3542 3543 circuits = [] 3544 response = self.get_info('circuit-status') 3545 3546 for circ in response.splitlines(): 3547 circ_message = stem.socket.recv_message(io.BytesIO(stem.util.str_tools._to_bytes('650 CIRC %s\r\n' % circ))) 3548 stem.response.convert('EVENT', circ_message) 3549 circuits.append(circ_message) 3550 3551 return circuits 3552 3553 def new_circuit(self, path = None, purpose = 'general', await_build = False, timeout = None): 3554 """ 3555 Requests a new circuit. If the path isn't provided, one is automatically 3556 selected. 3557 3558 .. versionchanged:: 1.7.0 3559 Added the timeout argument. 3560 3561 :param list,str path: one or more relays to make a circuit through 3562 :param str purpose: 'general' or 'controller' 3563 :param bool await_build: blocks until the circuit is built if **True** 3564 :param float timeout: seconds to wait when **await_build** is **True** 3565 3566 :returns: str of the circuit id of the newly created circuit 3567 3568 :raises: 3569 * :class:`stem.ControllerError` if the call fails 3570 * :class:`stem.Timeout` if **timeout** was reached 3571 """ 3572 3573 return self.extend_circuit('0', path, purpose, await_build, timeout) 3574 3575 def extend_circuit(self, circuit_id = '0', path = None, purpose = 'general', await_build = False, timeout = None): 3576 """ 3577 Either requests the creation of a new circuit or extends an existing one. 3578 3579 When called with a circuit value of zero (the default) a new circuit is 3580 created, and when non-zero the circuit with that id is extended. If the 3581 path isn't provided, one is automatically selected. 3582 3583 A python interpreter session used to create circuits could look like this... 3584 3585 :: 3586 3587 >>> controller.extend_circuit('0', ['718BCEA286B531757ACAFF93AE04910EA73DE617', '30BAB8EE7606CBD12F3CC269AE976E0153E7A58D', '2765D8A8C4BBA3F89585A9FFE0E8575615880BEB']) 3588 19 3589 >>> controller.extend_circuit('0') 3590 20 3591 >>> print(controller.get_info('circuit-status')) 3592 20 EXTENDED $718BCEA286B531757ACAFF93AE04910EA73DE617=KsmoinOK,$649F2D0ACF418F7CFC6539AB2257EB2D5297BAFA=Eskimo BUILD_FLAGS=NEED_CAPACITY PURPOSE=GENERAL TIME_CREATED=2012-12-06T13:51:11.433755 3593 19 BUILT $718BCEA286B531757ACAFF93AE04910EA73DE617=KsmoinOK,$30BAB8EE7606CBD12F3CC269AE976E0153E7A58D=Pascal1,$2765D8A8C4BBA3F89585A9FFE0E8575615880BEB=Anthracite PURPOSE=GENERAL TIME_CREATED=2012-12-06T13:50:56.969938 3594 3595 .. versionchanged:: 1.7.0 3596 Added the timeout argument. 3597 3598 :param str circuit_id: id of a circuit to be extended 3599 :param list,str path: one or more relays to make a circuit through, this is 3600 required if the circuit id is non-zero 3601 :param str purpose: 'general' or 'controller' 3602 :param bool await_build: blocks until the circuit is built if **True** 3603 :param float timeout: seconds to wait when **await_build** is **True** 3604 3605 :returns: str of the circuit id of the created or extended circuit 3606 3607 :raises: 3608 * :class:`stem.InvalidRequest` if one of the parameters were invalid 3609 * :class:`stem.CircuitExtensionFailed` if we were waiting for the circuit 3610 to build but it failed 3611 * :class:`stem.Timeout` if **timeout** was reached 3612 * :class:`stem.ControllerError` if the call fails 3613 """ 3614 3615 # Attaches a temporary listener for CIRC events if we'll be waiting for it 3616 # to build. This is icky, but we can't reliably do this via polling since 3617 # we then can't get the failure if it can't be created. 3618 3619 circ_queue, circ_listener = queue.Queue(), None 3620 start_time = time.time() 3621 3622 if await_build: 3623 def circ_listener(event): 3624 circ_queue.put(event) 3625 3626 self.add_event_listener(circ_listener, EventType.CIRC) 3627 3628 try: 3629 # we might accidently get integer circuit ids 3630 circuit_id = str(circuit_id) 3631 3632 if path is None and circuit_id == '0': 3633 path_opt_version = stem.version.Requirement.EXTENDCIRCUIT_PATH_OPTIONAL 3634 3635 if not self.get_version() >= path_opt_version: 3636 raise stem.InvalidRequest(512, 'EXTENDCIRCUIT requires the path prior to version %s' % path_opt_version) 3637 3638 args = [circuit_id] 3639 3640 if stem.util._is_str(path): 3641 path = [path] 3642 3643 if path: 3644 args.append(','.join(path)) 3645 3646 if purpose: 3647 args.append('purpose=%s' % purpose) 3648 3649 response = self.msg('EXTENDCIRCUIT %s' % ' '.join(args)) 3650 stem.response.convert('SINGLELINE', response) 3651 3652 if response.code in ('512', '552'): 3653 raise stem.InvalidRequest(response.code, response.message) 3654 elif not response.is_ok(): 3655 raise stem.ProtocolError('EXTENDCIRCUIT returned unexpected response code: %s' % response.code) 3656 3657 if not response.message.startswith('EXTENDED '): 3658 raise stem.ProtocolError('EXTENDCIRCUIT response invalid:\n%s', response) 3659 3660 new_circuit = response.message.split(' ', 1)[1] 3661 3662 if await_build: 3663 while True: 3664 circ = _get_with_timeout(circ_queue, timeout, start_time) 3665 3666 if circ.id == new_circuit: 3667 if circ.status == CircStatus.BUILT: 3668 break 3669 elif circ.status == CircStatus.FAILED: 3670 raise stem.CircuitExtensionFailed('Circuit failed to be created: %s' % circ.reason, circ) 3671 elif circ.status == CircStatus.CLOSED: 3672 raise stem.CircuitExtensionFailed('Circuit was closed prior to build', circ) 3673 3674 return new_circuit 3675 finally: 3676 if circ_listener: 3677 self.remove_event_listener(circ_listener) 3678 3679 def repurpose_circuit(self, circuit_id, purpose): 3680 """ 3681 Changes a circuit's purpose. Currently, two purposes are recognized... 3682 * general 3683 * controller 3684 3685 :param str circuit_id: id of the circuit whose purpose is to be changed 3686 :param str purpose: purpose (either 'general' or 'controller') 3687 3688 :raises: :class:`stem.InvalidArguments` if the circuit doesn't exist or if the purpose was invalid 3689 """ 3690 3691 response = self.msg('SETCIRCUITPURPOSE %s purpose=%s' % (circuit_id, purpose)) 3692 stem.response.convert('SINGLELINE', response) 3693 3694 if not response.is_ok(): 3695 if response.code == '552': 3696 raise stem.InvalidRequest(response.code, response.message) 3697 else: 3698 raise stem.ProtocolError('SETCIRCUITPURPOSE returned unexpected response code: %s' % response.code) 3699 3700 def close_circuit(self, circuit_id, flag = ''): 3701 """ 3702 Closes the specified circuit. 3703 3704 :param str circuit_id: id of the circuit to be closed 3705 :param str flag: optional value to modify closing, the only flag available 3706 is 'IfUnused' which will not close the circuit unless it is unused 3707 3708 :raises: :class:`stem.InvalidArguments` if the circuit is unknown 3709 :raises: :class:`stem.InvalidRequest` if not enough information is provided 3710 """ 3711 3712 response = self.msg('CLOSECIRCUIT %s %s' % (circuit_id, flag)) 3713 stem.response.convert('SINGLELINE', response) 3714 3715 if not response.is_ok(): 3716 if response.code in ('512', '552'): 3717 if response.message.startswith('Unknown circuit '): 3718 raise stem.InvalidArguments(response.code, response.message, [circuit_id]) 3719 raise stem.InvalidRequest(response.code, response.message) 3720 else: 3721 raise stem.ProtocolError('CLOSECIRCUIT returned unexpected response code: %s' % response.code) 3722 3723 @with_default() 3724 def get_streams(self, default = UNDEFINED): 3725 """ 3726 get_streams(default = UNDEFINED) 3727 3728 Provides the list of streams tor is currently handling. 3729 3730 :param object default: response if the query fails 3731 3732 :returns: list of :class:`stem.response.events.StreamEvent` objects 3733 3734 :raises: :class:`stem.ControllerError` if the call fails and no default was 3735 provided 3736 """ 3737 3738 streams = [] 3739 response = self.get_info('stream-status') 3740 3741 for stream in response.splitlines(): 3742 message = stem.socket.recv_message(io.BytesIO(stem.util.str_tools._to_bytes('650 STREAM %s\r\n' % stream))) 3743 stem.response.convert('EVENT', message) 3744 streams.append(message) 3745 3746 return streams 3747 3748 def attach_stream(self, stream_id, circuit_id, exiting_hop = None): 3749 """ 3750 Attaches a stream to a circuit. 3751 3752 Note: Tor attaches streams to circuits automatically unless the 3753 __LeaveStreamsUnattached configuration variable is set to '1' 3754 3755 :param str stream_id: id of the stream that must be attached 3756 :param str circuit_id: id of the circuit to which it must be attached 3757 :param int exiting_hop: hop in the circuit where traffic should exit 3758 3759 :raises: 3760 * :class:`stem.InvalidRequest` if the stream or circuit id were unrecognized 3761 * :class:`stem.UnsatisfiableRequest` if the stream isn't in a state where it can be attached 3762 * :class:`stem.OperationFailed` if the stream couldn't be attached for any other reason 3763 """ 3764 3765 query = 'ATTACHSTREAM %s %s' % (stream_id, circuit_id) 3766 3767 if exiting_hop: 3768 query += ' HOP=%s' % exiting_hop 3769 3770 response = self.msg(query) 3771 stem.response.convert('SINGLELINE', response) 3772 3773 if not response.is_ok(): 3774 if response.code == '552': 3775 raise stem.InvalidRequest(response.code, response.message) 3776 elif response.code == '551': 3777 raise stem.OperationFailed(response.code, response.message) 3778 elif response.code == '555': 3779 raise stem.UnsatisfiableRequest(response.code, response.message) 3780 else: 3781 raise stem.ProtocolError('ATTACHSTREAM returned unexpected response code: %s' % response.code) 3782 3783 def close_stream(self, stream_id, reason = stem.RelayEndReason.MISC, flag = ''): 3784 """ 3785 Closes the specified stream. 3786 3787 :param str stream_id: id of the stream to be closed 3788 :param stem.RelayEndReason reason: reason the stream is closing 3789 :param str flag: not currently used 3790 3791 :raises: 3792 * :class:`stem.InvalidArguments` if the stream or reason are not recognized 3793 * :class:`stem.InvalidRequest` if the stream and/or reason are missing 3794 """ 3795 3796 # there's a single value offset between RelayEndReason.index_of() and the 3797 # value that tor expects since tor's value starts with the index of one 3798 3799 response = self.msg('CLOSESTREAM %s %s %s' % (stream_id, stem.RelayEndReason.index_of(reason) + 1, flag)) 3800 stem.response.convert('SINGLELINE', response) 3801 3802 if not response.is_ok(): 3803 if response.code in ('512', '552'): 3804 if response.message.startswith('Unknown stream '): 3805 raise stem.InvalidArguments(response.code, response.message, [stream_id]) 3806 elif response.message.startswith('Unrecognized reason '): 3807 raise stem.InvalidArguments(response.code, response.message, [reason]) 3808 raise stem.InvalidRequest(response.code, response.message) 3809 else: 3810 raise stem.ProtocolError('CLOSESTREAM returned unexpected response code: %s' % response.code) 3811 3812 def signal(self, signal): 3813 """ 3814 Sends a signal to the Tor client. 3815 3816 :param stem.Signal signal: type of signal to be sent 3817 3818 :raises: 3819 * :class:`stem.ControllerError` if sending the signal failed 3820 * :class:`stem.InvalidArguments` if signal provided wasn't recognized 3821 """ 3822 3823 response = self.msg('SIGNAL %s' % signal) 3824 stem.response.convert('SINGLELINE', response) 3825 3826 if response.is_ok(): 3827 if signal == stem.Signal.NEWNYM: 3828 self._last_newnym = time.time() 3829 else: 3830 if response.code == '552': 3831 raise stem.InvalidArguments(response.code, response.message, [signal]) 3832 3833 raise stem.ProtocolError('SIGNAL response contained unrecognized status code: %s' % response.code) 3834 3835 def is_newnym_available(self): 3836 """ 3837 Indicates if tor would currently accept a NEWNYM signal. This can only 3838 account for signals sent via this controller. 3839 3840 .. versionadded:: 1.2.0 3841 3842 :returns: **True** if tor would currently accept a NEWNYM signal, **False** 3843 otherwise 3844 """ 3845 3846 if self.is_alive(): 3847 return self.get_newnym_wait() == 0.0 3848 else: 3849 return False 3850 3851 def get_newnym_wait(self): 3852 """ 3853 Provides the number of seconds until a NEWNYM signal would be respected. 3854 This can only account for signals sent via this controller. 3855 3856 .. versionadded:: 1.2.0 3857 3858 :returns: **float** for the number of seconds until tor would respect 3859 another NEWNYM signal 3860 """ 3861 3862 return max(0.0, self._last_newnym + 10 - time.time()) 3863 3864 @with_default() 3865 def get_effective_rate(self, default = UNDEFINED, burst = False): 3866 """ 3867 get_effective_rate(default = UNDEFINED, burst = False) 3868 3869 Provides the maximum rate this relay is configured to relay in bytes per 3870 second. This is based on multiple torrc parameters if they're set... 3871 3872 * Effective Rate = min(BandwidthRate, RelayBandwidthRate, MaxAdvertisedBandwidth) 3873 * Effective Burst = min(BandwidthBurst, RelayBandwidthBurst) 3874 3875 .. versionadded:: 1.3.0 3876 3877 :param object default: response if the query fails 3878 :param bool burst: provides the burst bandwidth, otherwise this provides 3879 the standard rate 3880 3881 :returns: **int** with the effective bandwidth rate in bytes per second 3882 3883 :raises: :class:`stem.ControllerError` if the call fails and no default was 3884 provided 3885 """ 3886 3887 if not burst: 3888 attributes = ('BandwidthRate', 'RelayBandwidthRate', 'MaxAdvertisedBandwidth') 3889 else: 3890 attributes = ('BandwidthBurst', 'RelayBandwidthBurst') 3891 3892 value = None 3893 3894 for attr in attributes: 3895 attr_value = int(self.get_conf(attr)) 3896 3897 if attr_value == 0 and attr.startswith('Relay'): 3898 continue # RelayBandwidthRate and RelayBandwidthBurst default to zero 3899 3900 value = min(value, attr_value) if value else attr_value 3901 3902 return value 3903 3904 def is_geoip_unavailable(self): 3905 """ 3906 Provides **True** if tor's geoip database is unavailable, **False** 3907 otherwise. 3908 3909 .. versionchanged:: 1.6.0 3910 No longer requires previously failed GETINFO requests to determine this. 3911 3912 .. deprecated:: 1.6.0 3913 This is available as of Tor 0.3.2.1 through the following instead... 3914 3915 :: 3916 3917 controller.get_info('ip-to-country/ipv4-available', 0) == '1' 3918 3919 :returns: **bool** indicating if we've determined tor's geoip database to 3920 be unavailable or not 3921 """ 3922 3923 if self._is_geoip_unavailable is None: 3924 try: 3925 self.get_info('ip-to-country/0.0.0.0') 3926 self._is_geoip_unavailable = False 3927 except stem.ControllerError as exc: 3928 if 'GeoIP data not loaded' in str(exc): 3929 self._is_geoip_unavailable = True 3930 else: 3931 return False # unexpected issue, fail open and don't cache 3932 3933 return self._is_geoip_unavailable 3934 3935 def map_address(self, mapping): 3936 """ 3937 Map addresses to replacement addresses. Tor replaces subseqent connections 3938 to the original addresses with the replacement addresses. 3939 3940 If the original address is a null address, i.e., one of '0.0.0.0', '::0', or 3941 '.' Tor picks an original address itself and returns it in the reply. If the 3942 original address is already mapped to a different address the mapping is 3943 removed. 3944 3945 :param dict mapping: mapping of original addresses to replacement addresses 3946 3947 :raises: 3948 * :class:`stem.InvalidRequest` if the addresses are malformed 3949 * :class:`stem.OperationFailed` if Tor couldn't fulfill the request 3950 3951 :returns: **dict** with 'original -> replacement' address mappings 3952 """ 3953 3954 mapaddress_arg = ' '.join(['%s=%s' % (k, v) for (k, v) in list(mapping.items())]) 3955 response = self.msg('MAPADDRESS %s' % mapaddress_arg) 3956 stem.response.convert('MAPADDRESS', response) 3957 3958 return response.entries 3959 3960 def drop_guards(self): 3961 """ 3962 Drops our present guard nodes and picks a new set. 3963 3964 .. versionadded:: 1.2.0 3965 3966 :raises: :class:`stem.ControllerError` if Tor couldn't fulfill the request 3967 """ 3968 3969 if self.get_version() < stem.version.Requirement.DROPGUARDS: 3970 raise stem.UnsatisfiableRequest(message = 'DROPGUARDS was added in tor version %s' % stem.version.Requirement.DROPGUARDS) 3971 3972 self.msg('DROPGUARDS') 3973 3974 def _post_authentication(self): 3975 super(Controller, self)._post_authentication() 3976 3977 # try to re-attach event listeners to the new instance 3978 3979 with self._event_listeners_lock: 3980 try: 3981 failed_events = self._attach_listeners()[1] 3982 3983 if failed_events: 3984 # remove our listeners for these so we don't keep failing 3985 for event_type in failed_events: 3986 del self._event_listeners[event_type] 3987 3988 logging_id = 'stem.controller.event_reattach-%s' % '-'.join(failed_events) 3989 log.log_once(logging_id, log.WARN, 'We were unable to re-attach our event listeners to the new tor instance for: %s' % ', '.join(failed_events)) 3990 except stem.ProtocolError as exc: 3991 log.warn('Unable to issue the SETEVENTS request to re-attach our listeners (%s)' % exc) 3992 3993 # issue TAKEOWNERSHIP if we're the owning process for this tor instance 3994 3995 owning_pid = self.get_conf('__OwningControllerProcess', None) 3996 3997 if owning_pid == str(os.getpid()) and self.is_localhost(): 3998 response = self.msg('TAKEOWNERSHIP') 3999 stem.response.convert('SINGLELINE', response) 4000 4001 if response.is_ok(): 4002 # Now that tor is tracking our ownership of the process via the control 4003 # connection, we can stop having it check for us via our pid. 4004 4005 try: 4006 self.reset_conf('__OwningControllerProcess') 4007 except stem.ControllerError as exc: 4008 log.warn("We were unable to reset tor's __OwningControllerProcess configuration. It will continue to periodically check if our pid exists. (%s)" % exc) 4009 else: 4010 log.warn('We were unable assert ownership of tor through TAKEOWNERSHIP, despite being configured to be the owning process through __OwningControllerProcess. (%s)' % response) 4011 4012 def _handle_event(self, event_message): 4013 try: 4014 stem.response.convert('EVENT', event_message) 4015 event_type = event_message.type 4016 except stem.ProtocolError as exc: 4017 log.error('Tor sent a malformed event (%s): %s' % (exc, event_message)) 4018 event_type = MALFORMED_EVENTS 4019 4020 with self._event_listeners_lock: 4021 for listener_type, event_listeners in list(self._event_listeners.items()): 4022 if listener_type == event_type: 4023 for listener in event_listeners: 4024 try: 4025 listener(event_message) 4026 except Exception as exc: 4027 log.warn('Event listener raised an uncaught exception (%s): %s' % (exc, event_message)) 4028 4029 def _attach_listeners(self): 4030 """ 4031 Attempts to subscribe to the self._event_listeners events from tor. This is 4032 a no-op if we're not currently authenticated. 4033 4034 :returns: tuple of the form (set_events, failed_events) 4035 4036 :raises: :class:`stem.ControllerError` if unable to make our request to tor 4037 """ 4038 4039 set_events, failed_events = [], [] 4040 4041 with self._event_listeners_lock: 4042 if self.is_authenticated(): 4043 # try to set them all 4044 response = self.msg('SETEVENTS %s' % ' '.join(self._event_listeners.keys())) 4045 4046 if response.is_ok(): 4047 set_events = list(self._event_listeners.keys()) 4048 else: 4049 # One of the following likely happened... 4050 # 4051 # * Our user attached listeners before having an authenticated 4052 # connection, so we couldn't check if we met the version 4053 # requirement. 4054 # 4055 # * User attached listeners to one tor instance, then connected us to 4056 # an older tor instancce. 4057 # 4058 # * Some other controller hiccup (far less likely). 4059 # 4060 # See if we can set some subset of our events. 4061 4062 for event in list(self._event_listeners.keys()): 4063 response = self.msg('SETEVENTS %s' % ' '.join(set_events + [event])) 4064 4065 if response.is_ok(): 4066 set_events.append(event) 4067 else: 4068 failed_events.append(event) 4069 4070 return (set_events, failed_events) 4071 4072 4073def _parse_circ_path(path): 4074 """ 4075 Parses a circuit path as a list of **(fingerprint, nickname)** tuples. Tor 4076 circuit paths are defined as being of the form... 4077 4078 :: 4079 4080 Path = LongName *("," LongName) 4081 LongName = Fingerprint [ ( "=" / "~" ) Nickname ] 4082 4083 example: 4084 $999A226EBED397F331B612FE1E4CFAE5C1F201BA=piyaz 4085 4086 ... *unless* this is prior to tor version 0.2.2.1 with the VERBOSE_NAMES 4087 feature turned off (or before version 0.1.2.2 where the feature was 4088 introduced). In that case either the fingerprint or nickname in the tuple 4089 will be **None**, depending on which is missing. 4090 4091 :: 4092 4093 Path = ServerID *("," ServerID) 4094 ServerID = Nickname / Fingerprint 4095 4096 example: 4097 $E57A476CD4DFBD99B4EE52A100A58610AD6E80B9,hamburgerphone,PrivacyRepublic14 4098 4099 :param str path: circuit path to be parsed 4100 4101 :returns: list of **(fingerprint, nickname)** tuples, fingerprints do not have a proceeding '$' 4102 4103 :raises: :class:`stem.ProtocolError` if the path is malformed 4104 """ 4105 4106 if path: 4107 try: 4108 return [_parse_circ_entry(entry) for entry in path.split(',')] 4109 except stem.ProtocolError as exc: 4110 # include the path with the exception 4111 raise stem.ProtocolError('%s: %s' % (exc, path)) 4112 else: 4113 return [] 4114 4115 4116def _parse_circ_entry(entry): 4117 """ 4118 Parses a single relay's 'LongName' or 'ServerID'. See the 4119 :func:`~stem.control._parse_circ_path` function for more information. 4120 4121 :param str entry: relay information to be parsed 4122 4123 :returns: **(fingerprint, nickname)** tuple 4124 4125 :raises: :class:`stem.ProtocolError` if the entry is malformed 4126 """ 4127 4128 if '=' in entry: 4129 # common case 4130 fingerprint, nickname = entry.split('=') 4131 elif '~' in entry: 4132 # this is allowed for by the spec, but I've never seen it used 4133 fingerprint, nickname = entry.split('~') 4134 elif entry[0] == '$': 4135 # old style, fingerprint only 4136 fingerprint, nickname = entry, None 4137 else: 4138 # old style, nickname only 4139 fingerprint, nickname = None, entry 4140 4141 if fingerprint is not None: 4142 if not stem.util.tor_tools.is_valid_fingerprint(fingerprint, True): 4143 raise stem.ProtocolError('Fingerprint in the circuit path is malformed (%s)' % fingerprint) 4144 4145 fingerprint = fingerprint[1:] # strip off the leading '$' 4146 4147 if nickname is not None and not stem.util.tor_tools.is_valid_nickname(nickname): 4148 raise stem.ProtocolError('Nickname in the circuit path is malformed (%s)' % nickname) 4149 4150 return (fingerprint, nickname) 4151 4152 4153@with_default() 4154def _case_insensitive_lookup(entries, key, default = UNDEFINED): 4155 """ 4156 Makes a case insensitive lookup within a list or dictionary, providing the 4157 first matching entry that we come across. 4158 4159 :param list,dict entries: list or dictionary to be searched 4160 :param str key: entry or key value to look up 4161 :param object default: value to be returned if the key doesn't exist 4162 4163 :returns: case insensitive match or default if one was provided and key wasn't found 4164 4165 :raises: **ValueError** if no such value exists 4166 """ 4167 4168 if entries is not None: 4169 if isinstance(entries, dict): 4170 for k, v in list(entries.items()): 4171 if k.lower() == key.lower(): 4172 return v 4173 else: 4174 for entry in entries: 4175 if entry.lower() == key.lower(): 4176 return entry 4177 4178 raise ValueError("key '%s' doesn't exist in dict: %s" % (key, entries)) 4179 4180 4181def _get_with_timeout(event_queue, timeout, start_time): 4182 """ 4183 Pulls an item from a queue with a given timeout. 4184 """ 4185 4186 if timeout: 4187 time_left = timeout - (time.time() - start_time) 4188 4189 if time_left <= 0: 4190 raise stem.Timeout('Reached our %0.1f second timeout' % timeout) 4191 4192 try: 4193 return event_queue.get(True, time_left) 4194 except queue.Empty: 4195 raise stem.Timeout('Reached our %0.1f second timeout' % timeout) 4196 else: 4197 return event_queue.get() 4198