diff options
Diffstat (limited to 'contrib/TorControl.py')
-rwxr-xr-x | contrib/TorControl.py | 464 |
1 files changed, 0 insertions, 464 deletions
diff --git a/contrib/TorControl.py b/contrib/TorControl.py deleted file mode 100755 index 2cc7cca13..000000000 --- a/contrib/TorControl.py +++ /dev/null @@ -1,464 +0,0 @@ -#!/usr/bin/python -# TorControl.py -- Python module to interface with Tor Control interface. -# Copyright 2005 Nick Mathewson -- See LICENSE for licensing information. -#$Id$ - -# THIS MODULE IS OBSOLETE! -# -# There is a "TorCtl.py" module in the "control" directory in Tor CVS; -# this new module supports the new ('version 1') Tor controller protocol -# and has a far nicer and more object-oriented design than this module does. -# -# No further support will be done on this module. - -import socket -import struct -import sys - -#__all__ = [ "MSG_TYPE", "" ] - -class _Enum: - # Helper: define an ordered dense name-to-number 1-1 mapping. - def __init__(self, start, names): - self.nameOf = {} - idx = start - for name in names: - setattr(self,name,idx) - self.nameOf[idx] = name - idx += 1 -class _Enum2: - # Helper: define an ordered sparse name-to-number 1-1 mapping. - def __init__(self, **args): - self.__dict__.update(args) - self.nameOf = {} - for k,v in args.items(): - self.nameOf[v] = k - -# Message types that client or server can send. -MSG_TYPE = _Enum(0x0000, - ["ERROR", - "DONE", - "SETCONF", - "GETCONF", - "CONFVALUE", - "SETEVENTS", - "EVENT", - "AUTH", - "SAVECONF", - "SIGNAL", - "MAPADDRESS", - "GETINFO", - "INFOVALUE", - "EXTENDCIRCUIT", - "ATTACHSTREAM", - "POSTDESCRIPTOR", - "FRAGMENTHEADER", - "FRAGMENT", - "REDIRECTSTREAM", - "CLOSESTREAM", - "CLOSECIRCUIT", - ]) - -# Make sure that the enumeration code is working. -assert MSG_TYPE.SAVECONF == 0x0008 -assert MSG_TYPE.CLOSECIRCUIT == 0x0014 - -# Types of "EVENT" message. -EVENT_TYPE = _Enum(0x0001, - ["CIRCSTATUS", - "STREAMSTATUS", - "ORCONNSTATUS", - "BANDWIDTH", - "OBSOLETE_LOG", - "NEWDESC", - "DEBUG_MSG", - "INFO_MSG", - "NOTICE_MSG", - "WARN_MSG", - "ERR_MSG", - ]) - -assert EVENT_TYPE.ERR_MSG == 0x000B -assert EVENT_TYPE.OBSOLETE_LOG == 0x0005 - -# Status codes for "CIRCSTATUS" events. -CIRC_STATUS = _Enum(0x00, - ["LAUNCHED", - "BUILT", - "EXTENDED", - "FAILED", - "CLOSED"]) - -# Status codes for "STREAMSTATUS" events -STREAM_STATUS = _Enum(0x00, - ["SENT_CONNECT", - "SENT_RESOLVE", - "SUCCEEDED", - "FAILED", - "CLOSED", - "NEW_CONNECT", - "NEW_RESOLVE", - "DETACHED"]) - -# Status codes for "ORCONNSTATUS" events -OR_CONN_STATUS = _Enum(0x00, - ["LAUNCHED","CONNECTED","FAILED","CLOSED"]) - -# Signal codes for "SIGNAL" events. -SIGNAL = _Enum2(HUP=0x01,INT=0x02,USR1=0x0A,USR2=0x0C,TERM=0x0F) - -# Error codes for "ERROR" events. -ERR_CODES = { - 0x0000 : "Unspecified error", - 0x0001 : "Internal error", - 0x0002 : "Unrecognized message type", - 0x0003 : "Syntax error", - 0x0004 : "Unrecognized configuration key", - 0x0005 : "Invalid configuration value", - 0x0006 : "Unrecognized byte code", - 0x0007 : "Unauthorized", - 0x0008 : "Failed authentication attempt", - 0x0009 : "Resource exhausted", - 0x000A : "No such stream", - 0x000B : "No such circuit", - 0x000C : "No such OR" -} - -class TorCtlError(Exception): - "Generic error raised by TorControl code." - pass - -class ProtocolError(TorCtlError): - "Raised on violations in Tor controller protocol" - pass - -class ErrorReply(TorCtlError): - "" - pass - -def parseHostAndPort(h): - host, port = "localhost", 9051 - if ":" in h: - i = h.index(":") - host = h[:i] - try: - port = int(h[i+1:]) - except ValueError: - print "Bad hostname %r"%h - sys.exit(1) - elif h: - try: - port = int(h) - except ValueError: - host = h - - return host, port - -def _unpack_msg(msg): - "return None, minLength, body or type,body,rest" - if len(msg) < 4: - return None, 4, msg - length,type = struct.unpack("!HH",msg) - if len(msg) >= 4+length: - return type,msg[4:4+length],msg[4+length:] - else: - return None,4+length,msg - -def _minLengthToPack(bytes): - whole,left = divmod(bytes,65535) - if left: - return whole*(65535+4)+4+left - else: - return whole*(65535+4) - -def unpack_msg(msg): - "returns as for _unpack_msg" - tp,body,rest = _unpack_msg(msg) - if tp != MSG_TYPE.FRAGMENTHEADER: - return tp, body, rest - - if len(body) < 6: - raise ProtocolError("FRAGMENTHEADER message too short") - - realType,realLength = struct.unpack("!HL", body[:6]) - - # Okay; could the message _possibly_ be here? - minLength = _minLengthToPack(realLength+6) - if len(msg) < minLength: - return None, minLength, msg - - # Okay; optimistically try to build up the msg. - soFar = [ body[6:] ] - lenSoFarLen = len(body)-6 - while len(rest)>=4 and lenSoFar < realLength: - ln, tp = struct.unpack("!HH", rest[:4]) - if tp != MSG_TYPE.FRAGMENT: - raise ProtocolError("Missing FRAGMENT message") - soFar.append(rest[4:4+ln]) - lenSoFar += ln - if 4+ln > len(rest): - rest = "" - leftInPacket = 4+ln-len(rest) - else: - rest = rest[4+ln:] - leftInPacket=0 - - if lenSoFar == realLength: - return realType, "".join(soFar), rest - elif lenSoFar > realLength: - raise ProtocolError("Bad fragmentation: message longer than declared") - else: - inOtherPackets = realLength-lenSoFar-leftInPacket - minLength = _minLengthToPack(inOtherPackets) - return None, len(msg)+leftInPacket+inOtherPackets, msg - -def _receive_msg(s): - body = "" - header = s.recv(4) - length,type = struct.unpack("!HH",header) - if length: - while length > len(body): - body += s.recv(length-len(body)) - return length,type,body - -def receive_message(s): - length, tp, body = _receive_msg(s) - if tp != MSG_TYPE.FRAGMENTHEADER: - return length, tp, body - if length < 6: - raise ProtocolError("FRAGMENTHEADER message too short") - realType,realLength = struct.unpack("!HL", body[:6]) - data = [ body[6:] ] - soFar = len(data[0]) - while 1: - length, tp, body = _receive_msg(s) - if tp != MSG_TYPE.FRAGMENT: - raise ProtocolError("Missing FRAGMENT message") - soFar += length - data.append(body) - if soFar == realLength: - return realLength, realType, "".join(data) - elif soFar > realLengtH: - raise ProtocolError("FRAGMENT message too long!") - -_event_handler = None -def receive_reply(s, expected=None): - while 1: - _, tp, body = receive_message(s) - if tp == MSG_TYPE.EVENT: - if _event_handler is not None: - _event_handler(body) - elif tp == MSG_TYPE.ERROR: - if len(body)<2: - raise ProtocolError("(Truncated error message)") - errCode, = struct.unpack("!H", body[:2]) - raise ErrorReply((errCode, - ERR_CODES.get(errCode,"[unrecognized]"), - body[2:])) - elif (expected is not None) and (tp not in expected): - raise ProtocolError("Unexpected message type 0x%04x"%tp) - else: - return tp, body - -def pack_message(type, body=""): - length = len(body) - if length < 65536: - reqheader = struct.pack("!HH", length, type) - return "%s%s"%(reqheader,body) - - fragheader = struct.pack("!HHHL", - 65535, MSG_TYPE.FRAGMENTHEADER, type, length) - msgs = [ fragheader, body[:65535-6] ] - body = body[65535-6:] - while body: - if len(body) > 65535: - fl = 65535 - else: - fl = len(body) - fragheader = struct.pack("!HH", MSG_TYPE.FRAGMENT, fl) - msgs.append(fragheader) - msgs.append(body[:fl]) - body = body[fl:] - - return "".join(msgs) - -def send_message(s, type, body=""): - s.sendall(pack_message(type, body)) - -def authenticate(s): - send_message(s,MSG_TYPE.AUTH) - type,body = receive_reply(s) - return - -def _parseKV(body,sep=" ",term="\n"): - res = [] - for line in body.split(term): - if not line: continue - print repr(line) - k, v = line.split(sep,1) - res.append((k,v)) - return res - -def get_option(s,name): - send_message(s,MSG_TYPE.GETCONF,name) - tp,body = receive_reply(s,[MSG_TYPE.CONFVALUE]) - return _parseKV(body) - -def set_option(s,msg): - send_message(s,MSG_TYPE.SETCONF,msg) - tp,body = receive_reply(s,[MSG_TYPE.DONE]) - -def get_info(s,name): - send_message(s,MSG_TYPE.GETINFO,name) - tp,body = receive_reply(s,[MSG_TYPE.INFOVALUE]) - kvs = body.split("\0") - d = {} - for i in xrange(0,len(kvs)-1,2): - d[kvs[i]] = kvs[i+1] - return d - -def set_events(s,events): - send_message(s,MSG_TYPE.SETEVENTS, - "".join([struct.pack("!H", event) for event in events])) - type,body = receive_reply(s,[MSG_TYPE.DONE]) - return - -def save_conf(s): - send_message(s,MSG_TYPE.SAVECONF) - receive_reply(s,[MSG_TYPE.DONE]) - -def send_signal(s, sig): - send_message(s,MSG_TYPE.SIGNAL,struct.pack("B",sig)) - receive_reply(s,[MSG_TYPE.DONE]) - -def map_address(s, kv): - msg = [ "%s %s\n"%(k,v) for k,v in kv ] - send_message(s,MSG_TYPE.MAPADDRESS,"".join(msg)) - tp, body = receive_reply(s,[MSG_TYPE.DONE]) - return _parseKV(body) - -def extend_circuit(s, circid, hops): - msg = struct.pack("!L",circid) + ",".join(hops) + "\0" - send_message(s,MSG_TYPE.EXTENDCIRCUIT,msg) - tp, body = receive_reply(s,[MSG_TYPE.DONE]) - if len(body) != 4: - raise ProtocolError("Extendcircuit reply too short or long") - return struct.unpack("!L",body)[0] - -def redirect_stream(s, streamid, newtarget): - msg = struct.pack("!L",streamid) + newtarget + "\0" - send_message(s,MSG_TYPE.REDIRECTSTREAM,msg) - tp,body = receive_reply(s,[MSG_TYPE.DONE]) - -def attach_stream(s, streamid, circid): - msg = struct.pack("!LL",streamid, circid) - send_message(s,MSG_TYPE.ATTACHSTREAM,msg) - tp,body = receive_reply(s,[MSG_TYPE.DONE]) - -def close_stream(s, streamid, reason=0, flags=0): - msg = struct.pack("!LBB",streamid,reason,flags) - send_message(s,MSG_TYPE.CLOSESTREAM,msg) - tp,body = receive_reply(s,[MSG_TYPE.DONE]) - -def close_circuit(s, circid, flags=0): - msg = struct.pack("!LB",circid,flags) - send_message(s,MSG_TYPE.CLOSECIRCUIT,msg) - tp,body = receive_reply(s,[MSG_TYPE.DONE]) - -def post_descriptor(s, descriptor): - send_message(s,MSG_TYPE.POSTDESCRIPTOR,descriptor) - tp,body = receive_reply(s,[MSG_TYPE.DONE]) - -def _unterminate(s): - if s[-1] == '\0': - return s[:-1] - else: - return s - -def unpack_event(body): - if len(body)<2: - raise ProtocolError("EVENT body too short.") - evtype, = struct.unpack("!H", body[:2]) - body = body[2:] - if evtype == EVENT_TYPE.CIRCSTATUS: - if len(body)<5: - raise ProtocolError("CIRCUITSTATUS event too short.") - status,ident = struct.unpack("!BL", body[:5]) - path = _unterminate(body[5:]).split(",") - args = status, ident, path - elif evtype == EVENT_TYPE.STREAMSTATUS: - if len(body)<5: - raise ProtocolError("CIRCUITSTATUS event too short.") - status,ident = struct.unpack("!BL", body[:5]) - target = _unterminate(body[5:]) - args = status, ident, target - elif evtype == EVENT_TYPE.ORCONNSTATUS: - if len(body)<2: - raise ProtocolError("CIRCUITSTATUS event too short.") - status = ord(body[0]) - target = _unterminate(body[1:]) - args = status, target - elif evtype == EVENT_TYPE.BANDWIDTH: - if len(body)<8: - raise ProtocolError("BANDWIDTH event too short.") - read, written = struct.unpack("!LL",body[:8]) - args = read, written - elif evtype == EVENT_TYPE.OBSOLETE_LOG: - args = (_unterminate(body),) - elif evtype == EVENT_TYPE.NEWDESC: - args = (_unterminate(body).split(","),) - elif EVENT_TYPE.DEBUG_MSG <= evtype <= EVENT_TYPE.ERR_MSG: - args = (EVENT_TYPE.nameOf(evtype), _unterminate(body)) - else: - args = (body,) - - return evtype, args - -def listen_for_events(s): - while(1): - _,type,body = receive_message(s) - print unpack_event(body) - return - -def do_main_loop(host,port): - print "host is %s:%d"%(host,port) - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((host,port)) - authenticate(s) - print "nick",`get_option(s,"nickname")` - print get_option(s,"DirFetchPeriod\n") - print `get_info(s,"version")` - #print `get_info(s,"desc/name/moria1")` - print `get_info(s,"network-status")` - print `get_info(s,"addr-mappings/all")` - print `get_info(s,"addr-mappings/config")` - print `get_info(s,"addr-mappings/cache")` - print `get_info(s,"addr-mappings/control")` - print `map_address(s, [("0.0.0.0", "Foobar.com"), - ("1.2.3.4", "foobaz.com"), - ("frebnitz.com", "5.6.7.8"), - (".", "abacinator.onion")])` - print `extend_circuit(s,0,["moria1"])` - print '========' - #print `extend_circuit(s,0,[""])` - print '========' - #send_signal(s,1) - #save_conf(s) - - #set_option(s,"1") - #set_option(s,"bandwidthburstbytes 100000") - #set_option(s,"runasdaemon 1") - #set_events(s,[EVENT_TYPE.WARN]) - set_events(s,[EVENT_TYPE.OBSOLETE_LOG]) - - listen_for_events(s) - - return - -if __name__ == '__main__': - if len(sys.argv) != 2: - print "Syntax: TorControl.py torhost:torport" - sys.exit(0) - sh,sp = parseHostAndPort(sys.argv[1]) - do_main_loop(sh,sp) - |