1# -*- coding: utf-8 -*- 2 3from __future__ import absolute_import 4from __future__ import print_function 5from __future__ import unicode_literals 6from __future__ import with_statement 7 8from zope.interface import implementer 9from zope.interface import Interface, Attribute 10 11 12class ITor(Interface): 13 """ 14 Represents a tor instance. This high-level API should provide all 15 objects you need to interact with tor. 16 """ 17 18 process = Attribute("TorProcessProtocol instance if we launched this Tor") 19 protocol = Attribute("A TorControlProtocol connected to our Tor") 20 version = Attribute("The version of the Tor we're connected to") 21 22 def quit(self): 23 """ 24 Closes the control connection, and if we launched this Tor 25 instance we'll send it a TERM and wait until it exits. 26 27 :return: a Deferred that fires when we've quit 28 """ 29 30 def get_config(self): 31 """ 32 :return: a Deferred that fires with a TorConfig instance. This 33 instance represents up-to-date configuration of the tor 34 instance (even if another controller is connected). If you 35 call this more than once you'll get the same TorConfig back. 36 """ 37 38 def create_state(self): 39 """ 40 returns a Deferred that fires with a ready-to-go 41 :class:`txtorcon.TorState` instance. 42 """ 43 44 def web_agent(self, pool=None, _socks_endpoint=None): 45 """ 46 :param _socks_endpoint: If ``None`` (the default), a suitable 47 SOCKS port is chosen from our config (or added). If supplied, 48 should be a Deferred which fires an IStreamClientEndpoint 49 (e.g. the return-value from 50 :meth:`txtorcon.TorConfig.socks_endpoint`) or an immediate 51 IStreamClientEndpoint You probably don't need to mess with 52 this. 53 54 :param pool: passed on to the Agent (as ``pool=``) 55 """ 56 57 def dns_resolve(self, hostname): 58 """ 59 :param hostname: a string 60 61 :returns: a Deferred that calbacks with the hostname as looked-up 62 via Tor (or errback). This uses Tor's custom extension to the 63 SOCKS5 protocol. 64 """ 65 66 def dns_resolve_ptr(self, ip): 67 """ 68 :param ip: a string, like "127.0.0.1" 69 70 :returns: a Deferred that calbacks with the IP address as 71 looked-up via Tor (or errback). This uses Tor's custom 72 extension to the SOCKS5 protocol. 73 """ 74 75 def stream_via(self, host, port, tls=False, _socks_endpoint=None): 76 """ 77 This returns an IStreamClientEndpoint instance that will use this 78 Tor (via SOCKS) to visit the ``(host, port)`` indicated. 79 80 :param host: The host to connect to. You MUST pass host-names 81 to this. If you absolutely know that you've not leaked DNS 82 (e.g. you save IPs in your app's configuration or similar) 83 then you can pass an IP. 84 85 :param port: Port to connect to. 86 87 :param tls: If True, it will wrap the return endpoint in one 88 that does TLS (default: False). 89 90 :param _socks_endpoint: Normally not needed (default: None) 91 but you can pass an IStreamClientEndpoint_ directed at one 92 of the local Tor's SOCKS5 ports (e.g. created with 93 :meth:`txtorcon.TorConfig.create_socks_endpoint`). Can be 94 a Deferred. 95 """ 96 97 98class IStreamListener(Interface): 99 """ 100 Notifications about changes to a :class:`txtorcon.Stream`. 101 102 If you wish for your listener to be added to *all* new streams, 103 see :meth:`txtorcon.TorState.add_stream_listener`. 104 """ 105 106 def stream_new(stream): 107 "a new stream has been created" 108 109 def stream_succeeded(stream): 110 "stream has succeeded" 111 112 def stream_attach(stream, circuit): 113 "the stream has been attached to a circuit" 114 115 def stream_detach(stream, **kw): 116 """ 117 the stream has been detached from its circuit 118 119 :param kw: 120 provides any flags for this event, which will include at 121 least REASON (but may include anything). See control-spec. 122 """ 123 124 def stream_closed(stream, **kw): 125 """ 126 stream has been closed (won't be in controller's list anymore). 127 128 :param kw: 129 provides any flags for this event, which will include at 130 least REASON (but may include anything). See control-spec. 131 """ 132 133 def stream_failed(stream, **kw): 134 """ 135 stream failed for some reason (won't be in controller's list anymore). 136 137 :param kw: 138 a dict of all the flags for the stream failure; see 139 control-spec but these will include REASON and sometimes 140 REMOTE_REASON (if the remote Tor closed the 141 connection). Both an all-uppercase and all-lowercase 142 version of each keyword is supplied (by the library; Tor 143 provides all-uppercase only). Others may include 144 BUILD_FLAGS, PURPOSE, HS_STATE, REND_QUERY, TIME_CREATED 145 (or anything else). 146 """ 147 148 149@implementer(IStreamListener) 150class StreamListenerMixin(object): 151 """ 152 Implements all of :class:`txtorcon.IStreamListener` with no-op 153 methods. You may subclass from this if you don't care about most 154 of the notifications. 155 """ 156 157 def stream_new(self, stream): 158 pass 159 160 def stream_succeeded(self, stream): 161 pass 162 163 def stream_attach(self, stream, circuit): 164 pass 165 166 def stream_detach(self, stream, **kw): 167 pass 168 169 def stream_closed(self, stream, **kw): 170 pass 171 172 def stream_failed(self, stream, **kw): 173 pass 174 175 176class IStreamAttacher(Interface): 177 """ 178 Used by :class:`txtorcon.TorState` to map streams to circuits (see 179 :meth:`txtorcon.TorState.set_attacher`). 180 181 Each time a new :class:`txtorcon.Stream` is created, this 182 interface will be queried to find out which 183 :class:`txtorcon.Circuit` it should be attached to. 184 185 Only advanced use-cases should need to use this directly; for most 186 users, using the :func:`txtorcon.Circuit.stream_via` interface 187 should be preferred. 188 """ 189 190 def attach_stream_failure(stream, fail): 191 """ 192 :param stream: 193 The stream we were trying to attach. 194 195 :param fail: 196 A Failure instance. 197 198 A failure has occurred while trying to attach the stream. 199 """ 200 201 def attach_stream(stream, circuits): 202 """ 203 :param stream: 204 The stream to attach, which will be in NEW or NEWRESOLVE 205 state. 206 207 :param circuits: 208 all currently available :class:`txtorcon.Circuit` objects 209 in the :class:`txtorcon.TorState` in a dict indexed by id. 210 Note they are *not* limited to BUILT circuits. 211 212 You should return a :class:`txtorcon.Circuit` instance which 213 should be at state BUILT in the currently running Tor. You may 214 also return a Deferred which will callback with the desired 215 circuit. In this case, you will probably need to be aware that 216 the callback from :meth:`txtorcon.TorState.build_circuit` does 217 not wait for the circuit to be in BUILT state. 218 219 Alternatively, you may return None in which case the Tor 220 controller will be told to choose a circuit itself. 221 222 Note that Tor will refuse to attach to any circuit not in 223 BUILT state; see ATTACHSTREAM in control-spec.txt 224 225 Note also that although you get a request to attach a stream 226 that ends in .onion Tor doesn't currently let you specify how 227 to attach .onion addresses and will always give a 551 error. 228 """ 229 230 231class ICircuitContainer(Interface): 232 """ 233 An interface that contains a bunch of Circuit objects and can look 234 them up by id. 235 """ 236 237 def find_circuit(circ_id): 238 ":return: a circuit for the cird_id, or exception." 239 240 def close_circuit(circuit, **kwargs): 241 """ 242 Close a circuit. 243 :return: a Deferred which callbacks when the closing process 244 is started (not necessarily finished inside Tor). 245 """ 246 247 # FIXME do we need an IStreamContainer that Stream instances get? 248 # (Currently, they get an ICircuitContainer...) 249 def close_stream(stream, **kwargs): 250 """ 251 Close a stream. 252 :return: a Deferred which callbacks when the closing process 253 is started (not necessarily finished inside Tor). 254 """ 255 256 257class ICircuitListener(Interface): 258 """ 259 An interface to listen for updates to Circuits. 260 """ 261 262 def circuit_new(circuit): 263 """A new circuit has been created. You'll always get one of 264 these for every Circuit even if it doesn't go through the "launched" 265 state.""" 266 267 def circuit_launched(circuit): 268 "A new circuit has been started." 269 270 def circuit_extend(circuit, router): 271 "A circuit has been extended to include a new router hop." 272 273 def circuit_built(circuit): 274 """ 275 A circuit has been extended to all hops (usually 3 for user 276 circuits). 277 """ 278 279 def circuit_closed(circuit, **kw): 280 """ 281 A circuit has been closed cleanly (won't be in controller's list 282 any more). 283 284 :param kw: 285 A dict of additional args. REASON is alsways included, and 286 often REMOTE_REASON also. See the control-spec 287 documentation. As of this writing, REASON is one of the 288 following strings: MISC, RESOLVEFAILED, CONNECTREFUSED, 289 EXITPOLICY, DESTROY, DONE, TIMEOUT, NOROUTE, HIBERNATING, 290 INTERNAL,RESOURCELIMIT, CONNRESET, TORPROTOCOL, 291 NOTDIRECTORY, END, PRIVATE_ADDR. However, don't depend on 292 that: it could be anything. 293 294 To facilitate declaring args you want in the method 295 (e.g. ``circuit_failed(self, circuit, reason=None, 296 remote_reason=None, **kw)``) lower-case versions of all the 297 keys are also provided (pointing to the same -- usually 298 UPPERCASE -- strings as the upper-case keys). 299 300 """ 301 302 def circuit_failed(circuit, **kw): 303 """ 304 A circuit has been closed because something went wrong. 305 306 The circuit won't be in the TorState's list anymore. 307 308 :param kw: 309 A dict of additional args. REASON is alsways included, and 310 often REMOTE_REASON also. See the control-spec 311 documentation. As of this writing, REASON is one of the 312 following strings: MISC, RESOLVEFAILED, CONNECTREFUSED, 313 EXITPOLICY, DESTROY, DONE, TIMEOUT, NOROUTE, HIBERNATING, 314 INTERNAL,RESOURCELIMIT, CONNRESET, TORPROTOCOL, 315 NOTDIRECTORY, END, PRIVATE_ADDR. However, don't depend on 316 that: it could be anything. 317 318 To facilitate declaring args you want in the method 319 (e.g. ``circuit_failed(self, circuit, reason=None, 320 remote_reason=None, **kw)``) lower-case versions of all the 321 keys are also provided (pointing to the same -- usually 322 UPPERCASE -- strings as the upper-case keys). 323 """ 324 325 326@implementer(ICircuitListener) 327class CircuitListenerMixin(object): 328 """ 329 Implements all of ICircuitListener with no-op methods. Subclass 330 from this if you don't care about most of the notifications. 331 """ 332 333 def circuit_new(self, circuit): 334 pass 335 336 def circuit_launched(self, circuit): 337 pass 338 339 def circuit_extend(self, circuit, router): 340 pass 341 342 def circuit_built(self, circuit): 343 pass 344 345 def circuit_closed(self, circuit, **kw): 346 pass 347 348 def circuit_failed(self, circuit, **kw): 349 pass 350 351 352class ITorControlProtocol(Interface): 353 """ 354 This defines the API to the TorController object. 355 356 This is the usual entry-point to this library, and you shouldn't 357 need to call methods outside this interface. 358 """ 359 360 def get_info(info): 361 """ 362 :return: a Deferred which will callback with the info keys you 363 asked for. For values ones, see control-spec. 364 """ 365 366 def get_conf(*args): 367 """ 368 Returns one or many configuration values via Deferred. See 369 control-spec for valid keys. The value will be a dictionary. 370 """ 371 372 def signal(signal_name): 373 """ 374 Issues a signal to Tor. See control-spec or .valid_signals for 375 which ones are available and their return values. 376 """ 377 378 def build_circuit(routers): 379 """ 380 Builds a circuit consisting of exactly the routers specified, 381 in order. This issues a series of EXTENDCIRCUIT calls to Tor; 382 the deferred returned from this is for the final 383 EXTEND. FIXME: should return the Circuit instance, but 384 currently returns final extend message 'EXTEND 1234' for 385 example. 386 """ 387 388 def close_circuit(circuit): 389 """ 390 Asks Tor to close the circuit. Note that the Circuit instance 391 is only removed as a result of the next CIRC CLOSED event. The 392 Deferred returned from this method callbacks when the 393 CLOSECIRCUIT command has successfully executed, not when the 394 circuit is actually gone. 395 396 If you wish to know when this circuit is actually gone, add an 397 ICircuitListener and wait for circuit_closed() 398 """ 399 400 def add_event_listener(evt, callback): 401 """ 402 Add a listener to an Event object. This may be called multiple 403 times for the same event. Every time the event happens, the 404 callback method will be called. The callback has one argument 405 (a string, the contents of the event, minus the '650' and the 406 name of the event) 407 408 FIXME: should have an interface for the callback. 409 """ 410 411 412class IRouterContainer(Interface): 413 414 unique_routers = Attribute("contains a list of all the Router instances") 415 416 def router_from_id(routerid): 417 """ 418 Note that this method MUST always return a Router instance -- 419 if you ask for a router ID that didn't yet exist, it is 420 created (although without IP addresses and such because it 421 wasn't in the consensus). You may find out if a Router came 422 from the 'GETINFO ns/all' list by checking the from_consensus 423 attribute. This is to simplify code like in Circuit.update() 424 that needs to handle the case where an EXTENDED circuit event 425 is the only time we've seen a Router -- it's possible for Tor 426 to do things with routers not in the consensus (like extend 427 circuits to them). 428 429 :return: a router by its ID. 430 """ 431 432 433class IAddrListener(Interface): 434 def addrmap_added(addr): 435 """ 436 A new address was added to the address map. 437 """ 438 439 def addrmap_expired(name): 440 """ 441 An address has expired from the address map. 442 """ 443