TorControl.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. #!/usr/bin/python
  2. # TorControl.py -- Python module to interface with Tor Control interface.
  3. # Copyright 2005 Nick Mathewson -- See LICENSE for licensing information.
  4. #$Id$
  5. # THIS MODULE IS OBSOLETE!
  6. #
  7. # There is a "TorCtl.py" module in the "control" directory in Tor CVS;
  8. # this new module supports the new ('version 1') Tor controller protocol
  9. # and has a far nicer and more object-oriented design than this module does.
  10. #
  11. # No further support will be done on this module.
  12. import socket
  13. import struct
  14. import sys
  15. #__all__ = [ "MSG_TYPE", "" ]
  16. class _Enum:
  17. # Helper: define an ordered dense name-to-number 1-1 mapping.
  18. def __init__(self, start, names):
  19. self.nameOf = {}
  20. idx = start
  21. for name in names:
  22. setattr(self,name,idx)
  23. self.nameOf[idx] = name
  24. idx += 1
  25. class _Enum2:
  26. # Helper: define an ordered sparse name-to-number 1-1 mapping.
  27. def __init__(self, **args):
  28. self.__dict__.update(args)
  29. self.nameOf = {}
  30. for k,v in args.items():
  31. self.nameOf[v] = k
  32. # Message types that client or server can send.
  33. MSG_TYPE = _Enum(0x0000,
  34. ["ERROR",
  35. "DONE",
  36. "SETCONF",
  37. "GETCONF",
  38. "CONFVALUE",
  39. "SETEVENTS",
  40. "EVENT",
  41. "AUTH",
  42. "SAVECONF",
  43. "SIGNAL",
  44. "MAPADDRESS",
  45. "GETINFO",
  46. "INFOVALUE",
  47. "EXTENDCIRCUIT",
  48. "ATTACHSTREAM",
  49. "POSTDESCRIPTOR",
  50. "FRAGMENTHEADER",
  51. "FRAGMENT",
  52. "REDIRECTSTREAM",
  53. "CLOSESTREAM",
  54. "CLOSECIRCUIT",
  55. ])
  56. # Make sure that the enumeration code is working.
  57. assert MSG_TYPE.SAVECONF == 0x0008
  58. assert MSG_TYPE.CLOSECIRCUIT == 0x0014
  59. # Types of "EVENT" message.
  60. EVENT_TYPE = _Enum(0x0001,
  61. ["CIRCSTATUS",
  62. "STREAMSTATUS",
  63. "ORCONNSTATUS",
  64. "BANDWIDTH",
  65. "OBSOLETE_LOG",
  66. "NEWDESC",
  67. "DEBUG_MSG",
  68. "INFO_MSG",
  69. "NOTICE_MSG",
  70. "WARN_MSG",
  71. "ERR_MSG",
  72. ])
  73. assert EVENT_TYPE.ERR_MSG == 0x000B
  74. assert EVENT_TYPE.OBSOLETE_LOG == 0x0005
  75. # Status codes for "CIRCSTATUS" events.
  76. CIRC_STATUS = _Enum(0x00,
  77. ["LAUNCHED",
  78. "BUILT",
  79. "EXTENDED",
  80. "FAILED",
  81. "CLOSED"])
  82. # Status codes for "STREAMSTATUS" events
  83. STREAM_STATUS = _Enum(0x00,
  84. ["SENT_CONNECT",
  85. "SENT_RESOLVE",
  86. "SUCCEEDED",
  87. "FAILED",
  88. "CLOSED",
  89. "NEW_CONNECT",
  90. "NEW_RESOLVE",
  91. "DETACHED"])
  92. # Status codes for "ORCONNSTATUS" events
  93. OR_CONN_STATUS = _Enum(0x00,
  94. ["LAUNCHED","CONNECTED","FAILED","CLOSED"])
  95. # Signal codes for "SIGNAL" events.
  96. SIGNAL = _Enum2(HUP=0x01,INT=0x02,USR1=0x0A,USR2=0x0C,TERM=0x0F)
  97. # Error codes for "ERROR" events.
  98. ERR_CODES = {
  99. 0x0000 : "Unspecified error",
  100. 0x0001 : "Internal error",
  101. 0x0002 : "Unrecognized message type",
  102. 0x0003 : "Syntax error",
  103. 0x0004 : "Unrecognized configuration key",
  104. 0x0005 : "Invalid configuration value",
  105. 0x0006 : "Unrecognized byte code",
  106. 0x0007 : "Unauthorized",
  107. 0x0008 : "Failed authentication attempt",
  108. 0x0009 : "Resource exhausted",
  109. 0x000A : "No such stream",
  110. 0x000B : "No such circuit",
  111. 0x000C : "No such OR"
  112. }
  113. class TorCtlError(Exception):
  114. "Generic error raised by TorControl code."
  115. pass
  116. class ProtocolError(TorCtlError):
  117. "Raised on violations in Tor controller protocol"
  118. pass
  119. class ErrorReply(TorCtlError):
  120. ""
  121. pass
  122. def parseHostAndPort(h):
  123. host, port = "localhost", 9051
  124. if ":" in h:
  125. i = h.index(":")
  126. host = h[:i]
  127. try:
  128. port = int(h[i+1:])
  129. except ValueError:
  130. print "Bad hostname %r"%h
  131. sys.exit(1)
  132. elif h:
  133. try:
  134. port = int(h)
  135. except ValueError:
  136. host = h
  137. return host, port
  138. def _unpack_msg(msg):
  139. "return None, minLength, body or type,body,rest"
  140. if len(msg) < 4:
  141. return None, 4, msg
  142. length,type = struct.unpack("!HH",msg)
  143. if len(msg) >= 4+length:
  144. return type,msg[4:4+length],msg[4+length:]
  145. else:
  146. return None,4+length,msg
  147. def _minLengthToPack(bytes):
  148. whole,left = divmod(bytes,65535)
  149. if left:
  150. return whole*(65535+4)+4+left
  151. else:
  152. return whole*(65535+4)
  153. def unpack_msg(msg):
  154. "returns as for _unpack_msg"
  155. tp,body,rest = _unpack_msg(msg)
  156. if tp != MSG_TYPE.FRAGMENTHEADER:
  157. return tp, body, rest
  158. if len(body) < 6:
  159. raise ProtocolError("FRAGMENTHEADER message too short")
  160. realType,realLength = struct.unpack("!HL", body[:6])
  161. # Okay; could the message _possibly_ be here?
  162. minLength = _minLengthToPack(realLength+6)
  163. if len(msg) < minLength:
  164. return None, minLength, msg
  165. # Okay; optimistically try to build up the msg.
  166. soFar = [ body[6:] ]
  167. lenSoFarLen = len(body)-6
  168. while len(rest)>=4 and lenSoFar < realLength:
  169. ln, tp = struct.unpack("!HH", rest[:4])
  170. if tp != MSG_TYPE.FRAGMENT:
  171. raise ProtocolError("Missing FRAGMENT message")
  172. soFar.append(rest[4:4+ln])
  173. lenSoFar += ln
  174. if 4+ln > len(rest):
  175. rest = ""
  176. leftInPacket = 4+ln-len(rest)
  177. else:
  178. rest = rest[4+ln:]
  179. leftInPacket=0
  180. if lenSoFar == realLength:
  181. return realType, "".join(soFar), rest
  182. elif lenSoFar > realLength:
  183. raise ProtocolError("Bad fragmentation: message longer than declared")
  184. else:
  185. inOtherPackets = realLength-lenSoFar-leftInPacket
  186. minLength = _minLengthToPack(inOtherPackets)
  187. return None, len(msg)+leftInPacket+inOtherPackets, msg
  188. def _receive_msg(s):
  189. body = ""
  190. header = s.recv(4)
  191. length,type = struct.unpack("!HH",header)
  192. if length:
  193. while length > len(body):
  194. body += s.recv(length-len(body))
  195. return length,type,body
  196. def receive_message(s):
  197. length, tp, body = _receive_msg(s)
  198. if tp != MSG_TYPE.FRAGMENTHEADER:
  199. return length, tp, body
  200. if length < 6:
  201. raise ProtocolError("FRAGMENTHEADER message too short")
  202. realType,realLength = struct.unpack("!HL", body[:6])
  203. data = [ body[6:] ]
  204. soFar = len(data[0])
  205. while 1:
  206. length, tp, body = _receive_msg(s)
  207. if tp != MSG_TYPE.FRAGMENT:
  208. raise ProtocolError("Missing FRAGMENT message")
  209. soFar += length
  210. data.append(body)
  211. if soFar == realLength:
  212. return realLength, realType, "".join(data)
  213. elif soFar > realLengtH:
  214. raise ProtocolError("FRAGMENT message too long!")
  215. _event_handler = None
  216. def receive_reply(s, expected=None):
  217. while 1:
  218. _, tp, body = receive_message(s)
  219. if tp == MSG_TYPE.EVENT:
  220. if _event_handler is not None:
  221. _event_handler(body)
  222. elif tp == MSG_TYPE.ERROR:
  223. if len(body)<2:
  224. raise ProtocolError("(Truncated error message)")
  225. errCode, = struct.unpack("!H", body[:2])
  226. raise ErrorReply((errCode,
  227. ERR_CODES.get(errCode,"[unrecognized]"),
  228. body[2:]))
  229. elif (expected is not None) and (tp not in expected):
  230. raise ProtocolError("Unexpected message type 0x%04x"%tp)
  231. else:
  232. return tp, body
  233. def pack_message(type, body=""):
  234. length = len(body)
  235. if length < 65536:
  236. reqheader = struct.pack("!HH", length, type)
  237. return "%s%s"%(reqheader,body)
  238. fragheader = struct.pack("!HHHL",
  239. 65535, MSG_TYPE.FRAGMENTHEADER, type, length)
  240. msgs = [ fragheader, body[:65535-6] ]
  241. body = body[65535-6:]
  242. while body:
  243. if len(body) > 65535:
  244. fl = 65535
  245. else:
  246. fl = len(body)
  247. fragheader = struct.pack("!HH", MSG_TYPE.FRAGMENT, fl)
  248. msgs.append(fragheader)
  249. msgs.append(body[:fl])
  250. body = body[fl:]
  251. return "".join(msgs)
  252. def send_message(s, type, body=""):
  253. s.sendall(pack_message(type, body))
  254. def authenticate(s):
  255. send_message(s,MSG_TYPE.AUTH)
  256. type,body = receive_reply(s)
  257. return
  258. def _parseKV(body,sep=" ",term="\n"):
  259. res = []
  260. for line in body.split(term):
  261. if not line: continue
  262. print repr(line)
  263. k, v = line.split(sep,1)
  264. res.append((k,v))
  265. return res
  266. def get_option(s,name):
  267. send_message(s,MSG_TYPE.GETCONF,name)
  268. tp,body = receive_reply(s,[MSG_TYPE.CONFVALUE])
  269. return _parseKV(body)
  270. def set_option(s,msg):
  271. send_message(s,MSG_TYPE.SETCONF,msg)
  272. tp,body = receive_reply(s,[MSG_TYPE.DONE])
  273. def get_info(s,name):
  274. send_message(s,MSG_TYPE.GETINFO,name)
  275. tp,body = receive_reply(s,[MSG_TYPE.INFOVALUE])
  276. kvs = body.split("\0")
  277. d = {}
  278. for i in xrange(0,len(kvs)-1,2):
  279. d[kvs[i]] = kvs[i+1]
  280. return d
  281. def set_events(s,events):
  282. send_message(s,MSG_TYPE.SETEVENTS,
  283. "".join([struct.pack("!H", event) for event in events]))
  284. type,body = receive_reply(s,[MSG_TYPE.DONE])
  285. return
  286. def save_conf(s):
  287. send_message(s,MSG_TYPE.SAVECONF)
  288. receive_reply(s,[MSG_TYPE.DONE])
  289. def send_signal(s, sig):
  290. send_message(s,MSG_TYPE.SIGNAL,struct.pack("B",sig))
  291. receive_reply(s,[MSG_TYPE.DONE])
  292. def map_address(s, kv):
  293. msg = [ "%s %s\n"%(k,v) for k,v in kv ]
  294. send_message(s,MSG_TYPE.MAPADDRESS,"".join(msg))
  295. tp, body = receive_reply(s,[MSG_TYPE.DONE])
  296. return _parseKV(body)
  297. def extend_circuit(s, circid, hops):
  298. msg = struct.pack("!L",circid) + ",".join(hops) + "\0"
  299. send_message(s,MSG_TYPE.EXTENDCIRCUIT,msg)
  300. tp, body = receive_reply(s,[MSG_TYPE.DONE])
  301. if len(body) != 4:
  302. raise ProtocolError("Extendcircuit reply too short or long")
  303. return struct.unpack("!L",body)[0]
  304. def redirect_stream(s, streamid, newtarget):
  305. msg = struct.pack("!L",streamid) + newtarget + "\0"
  306. send_message(s,MSG_TYPE.REDIRECTSTREAM,msg)
  307. tp,body = receive_reply(s,[MSG_TYPE.DONE])
  308. def attach_stream(s, streamid, circid):
  309. msg = struct.pack("!LL",streamid, circid)
  310. send_message(s,MSG_TYPE.ATTACHSTREAM,msg)
  311. tp,body = receive_reply(s,[MSG_TYPE.DONE])
  312. def close_stream(s, streamid, reason=0, flags=0):
  313. msg = struct.pack("!LBB",streamid,reason,flags)
  314. send_message(s,MSG_TYPE.CLOSESTREAM,msg)
  315. tp,body = receive_reply(s,[MSG_TYPE.DONE])
  316. def close_circuit(s, circid, flags=0):
  317. msg = struct.pack("!LB",circid,flags)
  318. send_message(s,MSG_TYPE.CLOSECIRCUIT,msg)
  319. tp,body = receive_reply(s,[MSG_TYPE.DONE])
  320. def post_descriptor(s, descriptor):
  321. send_message(s,MSG_TYPE.POSTDESCRIPTOR,descriptor)
  322. tp,body = receive_reply(s,[MSG_TYPE.DONE])
  323. def _unterminate(s):
  324. if s[-1] == '\0':
  325. return s[:-1]
  326. else:
  327. return s
  328. def unpack_event(body):
  329. if len(body)<2:
  330. raise ProtocolError("EVENT body too short.")
  331. evtype, = struct.unpack("!H", body[:2])
  332. body = body[2:]
  333. if evtype == EVENT_TYPE.CIRCSTATUS:
  334. if len(body)<5:
  335. raise ProtocolError("CIRCUITSTATUS event too short.")
  336. status,ident = struct.unpack("!BL", body[:5])
  337. path = _unterminate(body[5:]).split(",")
  338. args = status, ident, path
  339. elif evtype == EVENT_TYPE.STREAMSTATUS:
  340. if len(body)<5:
  341. raise ProtocolError("CIRCUITSTATUS event too short.")
  342. status,ident = struct.unpack("!BL", body[:5])
  343. target = _unterminate(body[5:])
  344. args = status, ident, target
  345. elif evtype == EVENT_TYPE.ORCONNSTATUS:
  346. if len(body)<2:
  347. raise ProtocolError("CIRCUITSTATUS event too short.")
  348. status = ord(body[0])
  349. target = _unterminate(body[1:])
  350. args = status, target
  351. elif evtype == EVENT_TYPE.BANDWIDTH:
  352. if len(body)<8:
  353. raise ProtocolError("BANDWIDTH event too short.")
  354. read, written = struct.unpack("!LL",body[:8])
  355. args = read, written
  356. elif evtype == EVENT_TYPE.OBSOLETE_LOG:
  357. args = (_unterminate(body),)
  358. elif evtype == EVENT_TYPE.NEWDESC:
  359. args = (_unterminate(body).split(","),)
  360. elif EVENT_TYPE.DEBUG_MSG <= evtype <= EVENT_TYPE.ERR_MSG:
  361. args = (EVENT_TYPE.nameOf(evtype), _unterminate(body))
  362. else:
  363. args = (body,)
  364. return evtype, args
  365. def listen_for_events(s):
  366. while(1):
  367. _,type,body = receive_message(s)
  368. print unpack_event(body)
  369. return
  370. def do_main_loop(host,port):
  371. print "host is %s:%d"%(host,port)
  372. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  373. s.connect((host,port))
  374. authenticate(s)
  375. print "nick",`get_option(s,"nickname")`
  376. print get_option(s,"DirFetchPeriod\n")
  377. print `get_info(s,"version")`
  378. #print `get_info(s,"desc/name/moria1")`
  379. print `get_info(s,"network-status")`
  380. print `get_info(s,"addr-mappings/all")`
  381. print `get_info(s,"addr-mappings/config")`
  382. print `get_info(s,"addr-mappings/cache")`
  383. print `get_info(s,"addr-mappings/control")`
  384. print `map_address(s, [("0.0.0.0", "Foobar.com"),
  385. ("1.2.3.4", "foobaz.com"),
  386. ("frebnitz.com", "5.6.7.8"),
  387. (".", "abacinator.onion")])`
  388. print `extend_circuit(s,0,["moria1"])`
  389. print '========'
  390. #print `extend_circuit(s,0,[""])`
  391. print '========'
  392. #send_signal(s,1)
  393. #save_conf(s)
  394. #set_option(s,"1")
  395. #set_option(s,"bandwidthburstbytes 100000")
  396. #set_option(s,"runasdaemon 1")
  397. #set_events(s,[EVENT_TYPE.WARN])
  398. set_events(s,[EVENT_TYPE.OBSOLETE_LOG])
  399. listen_for_events(s)
  400. return
  401. if __name__ == '__main__':
  402. if len(sys.argv) != 2:
  403. print "Syntax: TorControl.py torhost:torport"
  404. sys.exit(0)
  405. sh,sp = parseHostAndPort(sys.argv[1])
  406. do_main_loop(sh,sp)