Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

293 rader
9.0 KiB

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import sys
  4. import mechanize
  5. import cookielib
  6. import struct
  7. import ssl
  8. import base64
  9. import collections
  10. import zlib
  11. import HTMLParser
  12. if hasattr(ssl, '_create_unverified_context'):
  13. ssl._create_default_https_context = ssl._create_unverified_context
  14. # 0013 - Message
  15. def decode_0013(buf):
  16. ret = collections.defaultdict(list)
  17. while (len(buf) >= 12):
  18. length, cmd, out = decode_packet(buf)
  19. buf = buf[length:]
  20. ret[cmd].append(out)
  21. return ret
  22. # 0012 - u32
  23. def decode_0012(buf):
  24. return struct.unpack(">I", buf)
  25. # 0ce4 - encapsulation
  26. def decode_0ce4(buf):
  27. ret = collections.defaultdict(list)
  28. while (len(buf) >= 12):
  29. length, cmd, out = decode_packet(buf)
  30. buf = buf[length:]
  31. ret[cmd].append(out)
  32. return ret
  33. # 0ce5 - string without hex prefixer
  34. def decode_0ce5(buf):
  35. return struct.unpack(str(len(buf)) + "s", buf)
  36. # 0ce7 - string with hex prefixer
  37. def decode_0ce7(buf):
  38. _, s = struct.unpack(">I" + str(len(buf) - 4) + "s", buf)
  39. return s
  40. # 0cf0 - encapsulation
  41. def decode_0cf0(buf):
  42. ret = dict()
  43. cmd, _, out = decode_packet(buf)
  44. ret[cmd] = out
  45. return ret
  46. # 0cf1 - string without hex prefixer
  47. def decode_0cf1(buf):
  48. return struct.unpack(str(len(buf)) + "s", buf)
  49. # 0cf3 - u32
  50. def decode_0cf3(buf):
  51. return struct.unpack(">I", buf)
  52. def decode_packet(buf):
  53. cmd, _1, _2, length, _3 = struct.unpack(">IBBHI", buf[:12])
  54. if (length < 12):
  55. raise Exception("Invalid packet")
  56. data = buf[12:length]
  57. if cmd == 0x0013:
  58. data = decode_0013(data)
  59. elif cmd == 0x0012:
  60. data = decode_0012(data)
  61. elif cmd == 0x0ce4:
  62. data = decode_0ce4(data)
  63. elif cmd == 0x0ce5:
  64. data = decode_0ce5(data)
  65. elif cmd == 0x0ce7:
  66. data = decode_0ce7(data)
  67. elif cmd == 0x0cf0:
  68. data = decode_0cf0(data)
  69. elif cmd == 0x0cf1:
  70. data = decode_0cf1(data)
  71. elif cmd == 0x0cf3:
  72. data = decode_0cf3(data)
  73. else:
  74. data = None
  75. return length, cmd, data
  76. def encode_packet(cmd, align, buf):
  77. if (align > 1 and (len(buf) + 12) % align):
  78. buf += struct.pack(str(align - len(buf) % align) + "x")
  79. return struct.pack(">IBBHI", cmd, 0xc0, 0x00, len(buf) + 12, 0x0000583) + buf
  80. # 0013 - Message
  81. def encode_0013(buf):
  82. return encode_packet(0x0013, 4, buf)
  83. # 0012 - u32
  84. def encode_0012(i):
  85. return encode_packet(0x0012, 1, struct.pack("<I", i))
  86. # 0ce4 - encapsulation
  87. def encode_0ce4(buf):
  88. return encode_packet(0x0ce4, 4, buf)
  89. # 0ce5 - string without hex prefixer
  90. def encode_0ce5(s):
  91. return encode_packet(0x0ce5, 1, struct.pack(str(len(s)) + "s", s))
  92. # 0ce7 - string with hex prefixer
  93. def encode_0ce7(s):
  94. return encode_packet(0x0ce7, 1, struct.pack(">I" + str(len(s)) + "sx",
  95. 0x00058316, s))
  96. # 0cf0 - encapsulation
  97. def encode_0cf0(buf):
  98. return encode_packet(0x0cf0, 4, buf)
  99. # 0cf1 - string without hex prefixer
  100. def encode_0cf1(s):
  101. return encode_packet(0x0ce5, 1, struct.pack(str(len(s)) + "s", s))
  102. # 0cf3 - u32
  103. def encode_0cf3(i):
  104. return encode_packet(0x0013, 1, struct.pack("<I", i))
  105. class tncc(object):
  106. def __init__(self, vpn_host):
  107. self.vpn_host = vpn_host
  108. self.br = mechanize.Browser()
  109. self.cj = cookielib.LWPCookieJar()
  110. self.br.set_cookiejar(self.cj)
  111. # Browser options
  112. self.br.set_handle_equiv(True)
  113. self.br.set_handle_redirect(True)
  114. self.br.set_handle_referer(True)
  115. self.br.set_handle_robots(False)
  116. # Follows refresh 0 but not hangs on refresh > 0
  117. self.br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(),
  118. max_time=1)
  119. # Want debugging messages?
  120. self.br.set_debug_http(True)
  121. self.br.set_debug_redirects(True)
  122. self.br.set_debug_responses(True)
  123. self.user_agent = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1'
  124. self.br.addheaders = [('User-agent', self.user_agent)]
  125. def find_cookie(self, name):
  126. for cookie in self.cj:
  127. if cookie.name == name:
  128. return cookie
  129. return None
  130. def parse_response(self):
  131. # Read in key/token fields in HTTP response
  132. response = dict()
  133. last_key = ''
  134. for line in self.r.readlines():
  135. line = line.strip()
  136. # Note that msg is too long and gets wrapped, handle it special
  137. if last_key == 'msg' and len(line):
  138. response['msg'] += line
  139. else:
  140. key = ''
  141. try:
  142. key, val = line.split('=', 1)
  143. response[key] = val
  144. except:
  145. pass
  146. last_key = key
  147. return response
  148. def get_msg_contents(self, msg_value):
  149. # msg has the stuff we want, it's base64 encoded
  150. msg_raw = base64.b64decode(msg_value)
  151. _1, _2, msg_decoded = decode_packet(msg_raw)
  152. # Within msg, there is a field of data
  153. compressed = msg_decoded[0x0ce4][0][0x0ce7][0]
  154. # That field has a field that is compressed, decompress it
  155. typ, length, data = compressed.split(':', 2)
  156. if typ == 'COMPRESSED':
  157. data = zlib.decompress(data)
  158. else:
  159. raise Exception("Unknown storage type", typ)
  160. return data
  161. def parse_msg(self, msg_data):
  162. # The decompressed data is HTMLish, decode it. The value="" of each
  163. # tag is the data we want.
  164. objs = []
  165. class ParamHTMLParser(HTMLParser.HTMLParser):
  166. def handle_starttag(self, tag, attrs):
  167. for key, value in attrs:
  168. if key == 'value':
  169. # It's made up of a bunch of key=value pairs separated
  170. # by semicolons
  171. d = dict()
  172. for field in value.split(';'):
  173. field = field.strip()
  174. try:
  175. key, value = field.split('=', 1)
  176. d[key] = value
  177. except:
  178. pass
  179. objs.append(d)
  180. p = ParamHTMLParser()
  181. p.feed(msg_data)
  182. p.close()
  183. return objs
  184. def get_cookie(self, dspreauth=None, dssignin=None):
  185. if (dspreauth is None or dssignin is None):
  186. self.r = self.br.open('https://' + self.vpn_host)
  187. else:
  188. self.cj.set_cookie(dspreauth)
  189. self.cj.set_cookie(dssignin)
  190. msg_raw = encode_0013(encode_0ce4(encode_0ce7('policy request')) +
  191. encode_0ce5('Accept-Language: en'))
  192. msg = base64.b64encode(msg_raw)
  193. post_data = 'connId=0;msg=' + msg + ';firsttime=1;'
  194. self.r = self.br.open('https://' + self.vpn_host + '/dana-na/hc/tnchcupdate.cgi', post_data)
  195. # Parse the data returned into a key/value dict
  196. response = self.parse_response()
  197. # Pull the compressed data block out of msg
  198. data = self.get_msg_contents(response['msg'])
  199. # Pull the data out of the 'value' key in the htmlish stuff returned
  200. objs = self.parse_msg(data)
  201. # Make a set of policies
  202. policies = set()
  203. for entry in objs:
  204. if 'policy' in entry:
  205. policies.add(entry['policy'])
  206. # Everything is OK, this may need updating if OK isn't the right answer
  207. policy_report = ""
  208. for policy in policies:
  209. policy_report += '\npolicy:' + policy + '\nstatus:OK\n'
  210. msg_raw = encode_0013(encode_0ce4(encode_0ce7(policy_report)) +
  211. encode_0ce5('Accept-Language: en'))
  212. msg = base64.b64encode(msg_raw)
  213. post_data = 'connId=1;msg=' + msg + ';firsttime=1;'
  214. self.r = self.br.open('https://' + self.vpn_host + '/dana-na/hc/tnchcupdate.cgi', post_data)
  215. # We have a new DSPREAUTH cookie
  216. return self.find_cookie('DSPREAUTH')
  217. if __name__ == "__main__":
  218. vpn_host = sys.argv[1]
  219. if len(sys.argv) == 4:
  220. dspreauth = sys.argv[2]
  221. dssignin = sys.argv[3]
  222. dspreauth_cookie = cookielib.Cookie(version=0, name='DSPREAUTH', value=dspreauth,
  223. port=None, port_specified=False, domain='',
  224. domain_specified=False, domain_initial_dot=False, path='/',
  225. path_specified=False, secure=False, expires=None, discard=True,
  226. comment=None, comment_url=None, rest=None, rfc2109=False)
  227. dssignin_cookie = cookielib.Cookie(version=0, name='DSSIGNIN', value=dssignin,
  228. port=None, port_specified=False, domain='',
  229. domain_specified=False, domain_initial_dot=False, path='/',
  230. path_specified=False, secure=False, expires=None, discard=True,
  231. comment=None, comment_url=None, rest=None, rfc2109=False)
  232. else:
  233. dspreauth_cookie = None
  234. dssignin_cookie = None
  235. t = tncc(vpn_host)
  236. print t.get_cookie(dspreauth_cookie, dssignin_cookie).value