TorControl.py 12 KB

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