You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
4.1 KiB

  1. from http.server import BaseHTTPRequestHandler, HTTPServer
  2. import kiss
  3. from urllib.parse import urlparse
  4. import hashlib
  5. import time
  6. import gzip
  7. import signal
  8. call = "VA1QLE-A".encode()
  9. server = "VA1QLE".encode()
  10. #Bytes that mean stuff
  11. ESC = b'\x05' #Used for escaping bytes that appear in data
  12. ACK = b'\x06'
  13. PAGE_REQUEST = b'\x07'
  14. PAGE_RESPONSE = b'\x08'
  15. PAGE_RESPONSE_END = b'\x09'
  16. CHECKSUM = b'\x10' #Splits md5 checksum from HTML
  17. RESEND_PACKET = b'\x11'
  18. k = kiss.TCPKISS(host='localhost', port=8001)
  19. k.start()
  20. lastPathRequested = '' #Because some browsers will keep trying to connect if the first time fails.
  21. def escapeData(data): #Not very pretty
  22. return data.replace(
  23. ACK,
  24. ESC + ACK
  25. ).replace(
  26. PAGE_REQUEST,
  27. ESC + PAGE_REQUEST
  28. ).replace(
  29. PAGE_RESPONSE,
  30. ESC + PAGE_RESPONSE
  31. ).replace(
  32. PAGE_RESPONSE_END,
  33. ESC + PAGE_RESPONSE_END
  34. ).replace(
  35. CHECKSUM,
  36. ESC + CHECKSUM
  37. ).replace(
  38. RESEND_PACKET,
  39. ESC + RESEND_PACKET
  40. )
  41. def signal_handler(signum, frame):
  42. raise TimeoutError
  43. signal.signal(signal.SIGALRM, signal_handler)
  44. def unescapeData(data):
  45. out = b''
  46. i = 0
  47. while i < len(data):
  48. if data[i] == ESC[0] and i + 1 < len(data):
  49. if data[i + 1] in (ACK[0], PAGE_REQUEST[0], PAGE_RESPONSE[0], PAGE_RESPONSE_END[0], CHECKSUM[0], RESEND_PACKET[0]):
  50. out += bytes([data[i + 1]])
  51. i += 1 # Skips over the next byte
  52. else:
  53. out += bytes([data[i]])
  54. else:
  55. out += bytes([data[i]])
  56. i += 1
  57. return out
  58. def sendPacket(data):
  59. k.write(call + b'>' + server + data)
  60. busyReq = False
  61. def requestPage(path):
  62. global busyReq
  63. busyReq = True
  64. global lastPathRequested
  65. if urlparse(path).netloc:
  66. if lastPathRequested != path:
  67. lastPathRequested = path
  68. sendPacket(PAGE_REQUEST + path.encode())
  69. fullbody = b''
  70. signal.alarm(30)
  71. try:
  72. while (not fullbody.endswith(PAGE_RESPONSE_END) or fullbody.endswith(ESC + PAGE_RESPONSE_END)):
  73. r = b''
  74. while not PAGE_RESPONSE in r: #Keep trying until there's a page_response. Sometimes there'll be sufficient loopback
  75. #And the packet sent will be received. This prevents that from interfering.
  76. #TODO: Add a universal delimiter between callsigns and data
  77. #This will allow safer splitting, and will allow ignoring
  78. #Packets that aren't meant for us(If multiple people are on one frequency)
  79. x = k.read(readmode=False)
  80. r = b''.join(x)[1:]
  81. signal.alarm(0)
  82. #Split apart the data. Single packet
  83. (calls, data) = r.split(PAGE_RESPONSE, 1)
  84. (body, checksum) = data.rsplit(CHECKSUM, 1) #Splits on last delimiter
  85. (src, dest) = calls.split(b'>', 1)
  86. if dest == call:
  87. print(checksum)
  88. print(hashlib.md5(body).hexdigest().encode())
  89. print(body)
  90. #print(body)
  91. if checksum == hashlib.md5(body).hexdigest().encode(): #Does unescape belong? TODO
  92. fullbody += body#[:-1]#body.replace(b'\n', b'')
  93. #Request next
  94. sendPacket(ACK + b'GarbageData') #Direwolf needs packets of at least 15 bytes
  95. else:
  96. sendPacket(RESEND_PACKET + b'GarbageData')
  97. print(fullbody)
  98. print(unescapeData(fullbody[:-1]))
  99. #Break apart the full multi-packet data
  100. fullbody = gzip.decompress(unescapeData(fullbody[:-1])) #Decompress. Ignore last byte - It'll be the PAGE_RESPONSE_END delimiter
  101. rspCode = int.from_bytes(fullbody[0:1], 'big') #First two bytes are the response code
  102. rspBody = fullbody[2:] #Remove bytes for code, and PAGE_RESPONSE_END at the end
  103. busyReq = False
  104. return (rspCode, rspBody)
  105. except TimeoutError:
  106. return(500, b"Timeout while connecting to packet node")
  107. else:
  108. busyReq = False
  109. return (500, b'')
  110. else:
  111. return (200, "ERROR: This is a proxy server! Don't try to connect directly!".encode()) #Change 200 to a different number
  112. class httpRequestHandler(BaseHTTPRequestHandler):
  113. #GET Request
  114. def do_GET(self):
  115. global busyReq
  116. while busyReq:
  117. time.sleep(250)
  118. (code, response) = requestPage(self.path)
  119. print(code)
  120. self.send_response(code)
  121. self.wfile.write(response)
  122. #print(requestPage("https://example.com"))
  123. httpd = HTTPServer(('127.0.0.1', 8081), httpRequestHandler)
  124. print('HTTP Server started.')
  125. httpd.serve_forever()