tor-control.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #!/usr/bin/python2
  2. #$Id$
  3. import socket
  4. import struct
  5. import sys
  6. MSG_TYPE_ERROR = 0x0000
  7. MSG_TYPE_DONE = 0x0001
  8. MSG_TYPE_SETCONF = 0x0002
  9. MSG_TYPE_GETCONF = 0x0003
  10. MSG_TYPE_CONFVALUE = 0x0004
  11. MSG_TYPE_SETEVENTS = 0x0005
  12. MSG_TYPE_EVENT = 0x0006
  13. MSG_TYPE_AUTH = 0x0007
  14. MSG_TYPE_SAVECONF = 0x0008
  15. MSG_TYPE_SIGNAL = 0x0009
  16. MSG_TYPE_MAPADDRESS = 0x000A
  17. MSG_TYPE_GETINFO = 0x000B
  18. MSG_TYPE_INFOVALUE = 0x000C
  19. MSG_TYPE_EXTENDCIRCUIT = 0x000D
  20. MSG_TYPE_ATTACHSTREAM = 0x000E
  21. MSG_TYPE_POSTDESCRIPTOR = 0x000F
  22. MSG_TYPE_FRAGMENTHEADER = 0x0010
  23. MSG_TYPE_FRAGMENT = 0x0011
  24. MSG_TYPE_REDIRECTSTREAM = 0x0012
  25. MSG_TYPE_CLOSESTREAM = 0x0013
  26. MSG_TYPE_CLOSECIRCUIT = 0x0014
  27. EVENT_TYPE_CIRCSTATUS = 0x0001
  28. EVENT_TYPE_STREAMSTATUS = 0x0002
  29. EVENT_TYPE_ORCONNSTATUS = 0x0003
  30. EVENT_TYPE_BANDWIDTH = 0x0004
  31. EVENT_TYPE_WARN = 0x0005
  32. EVENT_TYPE_NEWDESC = 0x0006
  33. ERR_CODES = {
  34. 0x0000 : "Unspecified error",
  35. 0x0001 : "Internal error",
  36. 0x0002 : "Unrecognized message type",
  37. 0x0003 : "Syntax error",
  38. 0x0004 : "Unrecognized configuration key",
  39. 0x0005 : "Invalid configuration value",
  40. 0x0006 : "Unrecognized byte code",
  41. 0x0007 : "Unauthorized",
  42. 0x0008 : "Failed authentication attempt",
  43. 0x0009 : "Resource exhausted",
  44. 0x000A : "No such stream",
  45. 0x000B : "No such circuit",
  46. 0x000C : "No such OR"
  47. }
  48. class TorCtlError(Exception):
  49. pass
  50. class ProtocolError(TorCtlError):
  51. pass
  52. class ErrorReply(TorCtlError):
  53. pass
  54. def parseHostAndPort(h):
  55. host, port = "localhost", 9051
  56. if ":" in h:
  57. i = h.index(":")
  58. host = h[:i]
  59. try:
  60. port = int(h[i+1:])
  61. except ValueError:
  62. print "Bad hostname %r"%h
  63. sys.exit(1)
  64. elif h:
  65. try:
  66. port = int(h)
  67. except ValueError:
  68. host = h
  69. return host, port
  70. def _receive_msg(s):
  71. body = ""
  72. header = s.recv(4)
  73. length,type = struct.unpack("!HH",header)
  74. if length:
  75. body = s.recv(length)
  76. return length,type,body
  77. def receive_message(s):
  78. length, tp, body = _receive_msg(s)
  79. if tp != MSG_TYPE_FRAGMENTHEADER:
  80. return length, tp, body
  81. if length < 6:
  82. raise ProtocolError("FRAGMENTHEADER message too short")
  83. realType,realLength = struct.unpack("!HL", body[:6])
  84. data = [ body[6:] ]
  85. soFar = len(data[0])
  86. while 1:
  87. length, tp, body = _receive_msg(s)
  88. if tp != MSG_TYPE_FRAGMENT:
  89. raise ProtocolError("Missing FRAGMENT message")
  90. soFar += length
  91. data.append(body)
  92. if soFar == realLength:
  93. return realLength, realType, "".join(data)
  94. elif soFar > realLengtH:
  95. raise ProtocolError("FRAGMENT message too long!")
  96. _event_handler = None
  97. def receive_reply(s, expected=None):
  98. while 1:
  99. _, tp, body = receive_message(s)
  100. if tp == MSG_TYPE_EVENT:
  101. if _event_handler is not None:
  102. _event_handler(tp, body)
  103. elif tp == MSG_TYPE_ERROR:
  104. if len(body)<2:
  105. raise ProtocolError("(Truncated error message)")
  106. errCode, = struct.unpack("!H", body[:2])
  107. raise ErrorReply((errCode,
  108. ERR_CODES.get(errCode,"[unrecognized]"),
  109. body[2:]))
  110. elif (expected is not None) and (tp not in expected):
  111. raise ProtocolError("Unexpected message type 0x%04x"%tp)
  112. else:
  113. return tp, body
  114. def pack_message(type, body=""):
  115. length = len(body)
  116. if length < 65536:
  117. reqheader = struct.pack("!HH", length, type)
  118. return "%s%s"%(reqheader,body)
  119. fragheader = struct.pack("!HHHL",
  120. 65535, MSG_TYPE_FRAGMENTHEADER, type, length)
  121. msgs = [ fragheader, body[:65535-6] ]
  122. body = body[65535-6:]
  123. while body:
  124. if len(body) > 65535:
  125. fl = 65535
  126. else:
  127. fl = len(body)
  128. fragheader = struct.pack("!HH", MSG_TYPE_FRAGMENT, fl)
  129. msgs.append(fragheader)
  130. msgs.append(body[:fl])
  131. body = body[fl:]
  132. return "".join(msgs)
  133. def send_message(s, type, body=""):
  134. s.sendall(pack_message(type, body))
  135. def authenticate(s):
  136. send_message(s,MSG_TYPE_AUTH)
  137. type,body = receive_reply(s)
  138. return
  139. def _parseKV(body,sep=" ",term="\n"):
  140. res = []
  141. for line in body.split(term):
  142. if not line: continue
  143. print repr(line)
  144. k, v = line.split(sep,1)
  145. res.append((k,v))
  146. return res
  147. def get_option(s,name):
  148. send_message(s,MSG_TYPE_GETCONF,name)
  149. tp,body = receive_reply(s,[MSG_TYPE_CONFVALUE])
  150. return _parseKV(body)
  151. def set_option(s,msg):
  152. send_message(s,MSG_TYPE_SETCONF,msg)
  153. tp,body = receive_reply(s,[MSG_TYPE_DONE])
  154. def get_info(s,name):
  155. send_message(s,MSG_TYPE_GETINFO,name)
  156. tp,body = receive_reply(s,[MSG_TYPE_INFOVALUE])
  157. kvs = body.split("\0")
  158. d = {}
  159. for i in xrange(0,len(kvs)-1,2):
  160. d[kvs[i]] = kvs[i+1]
  161. return d
  162. def set_events(s,events):
  163. send_message(s,MSG_TYPE_SETEVENTS,
  164. "".join([struct.pack("!H", event) for event in events]))
  165. type,body = receive_reply(s,[MSG_TYPE_DONE])
  166. return
  167. def save_conf(s):
  168. send_message(s,MSG_TYPE_SAVECONF)
  169. receive_reply(s,[MSG_TYPE_DONE])
  170. def send_signal(s, sig):
  171. send_message(s,MSG_TYPE_SIGNAL,struct.pack("B",sig))
  172. receive_reply(s,[MSG_TYPE_DONE])
  173. def map_address(s, kv):
  174. msg = [ "%s %s\n"%(k,v) for k,v in kv ]
  175. send_message(s,MSG_TYPE_MAPADDRESS,"".join(msg))
  176. tp, body = receive_reply(s,[MSG_TYPE_DONE])
  177. return _parseKV(body)
  178. def extend_circuit(s, circid, hops):
  179. msg = struct.pack("!L",circid) + ",".join(hops) + "\0"
  180. send_message(s,MSG_TYPE_EXTENDCIRCUIT,msg)
  181. tp, body = receive_reply(s,[MSG_TYPE_DONE])
  182. return body
  183. def listen_for_events(s):
  184. while(1):
  185. _,type,body = receive_message(s)
  186. print "event",type
  187. return
  188. def do_main_loop(host,port):
  189. print "host is %s:%d"%(host,port)
  190. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  191. s.connect((host,port))
  192. authenticate(s)
  193. print "nick",`get_option(s,"nickname")`
  194. print get_option(s,"DirFetchPeriod\n")
  195. print `get_info(s,"version")`
  196. #print `get_info(s,"desc/name/moria1")`
  197. print `get_info(s,"network-status")`
  198. print `get_info(s,"addr-mappings/all")`
  199. print `get_info(s,"addr-mappings/config")`
  200. print `get_info(s,"addr-mappings/cache")`
  201. print `get_info(s,"addr-mappings/control")`
  202. print `map_address(s, [("0.0.0.0", "Foobar.com"),
  203. ("1.2.3.4", "foobaz.com"),
  204. ("frebnitz.com", "5.6.7.8"),
  205. (".", "abacinator.onion")])`
  206. print `extend_circuit(s,0,["moria1"])`
  207. send_signal(s,1)
  208. #save_conf(s)
  209. #set_option(s,"1")
  210. #set_option(s,"bandwidthburstbytes 100000")
  211. #set_option(s,"runasdaemon 1")
  212. #set_events(s,[EVENT_TYPE_WARN])
  213. set_events(s,[EVENT_TYPE_WARN,EVENT_TYPE_STREAMSTATUS])
  214. listen_for_events(s)
  215. return
  216. if __name__ == '__main__':
  217. if len(sys.argv) != 2:
  218. print "Syntax: tor-control.py torhost:torport"
  219. sys.exit(0)
  220. sh,sp = parseHostAndPort(sys.argv[1])
  221. do_main_loop(sh,sp)