1
0

PGet.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. import sys, time, getopt, socket, threading, base64
  2. # CONFIG
  3. CONFIG_LISTENING = '0.0.0.0:8799'
  4. CONFIG_PASS = 'pwd.pwd'
  5. class Logger:
  6. logLock = threading.Lock()
  7. LOG_INFO = 1
  8. LOG_WARN = 2
  9. LOG_ERROR = 3
  10. def printWarn(self, log):
  11. self.log(log)
  12. def printInfo(self, log):
  13. self.log(log)
  14. def printError(self, log):
  15. self.log(log)
  16. def printLog(self, log, logLevel):
  17. if logLevel == Logger.LOG_INFO:
  18. self.printInfo('<-> ' + log)
  19. elif logLevel == Logger.LOG_WARN:
  20. self.printWarn('<!> ' + log)
  21. elif logLevel == Logger.LOG_ERROR:
  22. self.printError('<#> ' + log)
  23. def log(self, log):
  24. with Logger.logLock:
  25. print log
  26. class PasswordSet:
  27. FILE_EXEMPLE = 'master=passwd123\n127.0.0.1:22=pwd321;321pawd\n1.23.45.67:443=pass123'
  28. def __init__(self, masterKey=None):
  29. self.masterKey = masterKey
  30. def parseFile(self, fileName):
  31. isValid = False
  32. with open(fileName) as f:
  33. content = f.readlines()
  34. content = [x.strip() for x in content]
  35. content = [item for item in content if not str(item).startswith('#')]
  36. if len(content) > 0:
  37. masterKey = content[0]
  38. if self.splitParam(masterKey, '=') is not None and masterKey.startswith('master'):
  39. self.masterKey = self.splitParam(masterKey, '=')[1]
  40. isValid = True
  41. self.map = dict()
  42. for i, v in enumerate(content[1:]):
  43. hostAndPass = self.splitParam(v, '=')
  44. if hostAndPass is not None:
  45. self.map[hostAndPass[0]] = hostAndPass[1].split(';')
  46. return isValid
  47. def isValidKey(self, key, target):
  48. valid = False
  49. if not self.masterKey == key:
  50. if hasattr(self, 'map'):
  51. if self.map.has_key(target):
  52. valid = key in self.map[target]
  53. else:
  54. valid = True
  55. return valid
  56. def splitParam(self, param, c):
  57. index = param.find(c)
  58. ret = None
  59. if index != -1:
  60. ret = []
  61. ret.append(param[0:index])
  62. ret.append(param[index+1:])
  63. return ret
  64. class ClientRequest:
  65. MAX_LEN_CLIENT_REQUEST = 1024 * 100
  66. HEADER_CONTENT_LENGTH = 'Content-Length'
  67. HEADER_ACTION = 'X-Action'
  68. ACTION_CLOSE = 'close'
  69. ACTION_DATA = 'data'
  70. def __init__(self, socket):
  71. self.socket = socket
  72. self.readConent = False
  73. def parse(self):
  74. line = ''
  75. count = 0
  76. self.isValid = False
  77. self.data = None
  78. self.contentLength = None
  79. self.action = None
  80. while line != '\r\n' and count < ClientRequest.MAX_LEN_CLIENT_REQUEST:
  81. line = self.readHttpLine()
  82. if line is None:
  83. break
  84. if line.startswith(ClientRequest.HEADER_ACTION):
  85. self.action = self.getHeaderVal(line)
  86. if not self.action is None:
  87. if self.action == ClientRequest.ACTION_CLOSE or self.action == ClientRequest.ACTION_DATA:
  88. self.isValid = True
  89. count += len(line)
  90. if self.readConent:
  91. if self.contentLength > 0 and self.contentLength < ClientRequest.MAX_LEN_CLIENT_REQUEST:
  92. self.data = self.readFully(self.contentLength)
  93. return self.isValid
  94. def readHttpLine(self):
  95. line = ''
  96. count = 0
  97. socket = self.socket
  98. b = socket.recv(1)
  99. if not b:
  100. return None
  101. while count < ClientRequest.MAX_LEN_CLIENT_REQUEST:
  102. count += 1
  103. line += b
  104. if b == '\r':
  105. b = socket.recv(1)
  106. count += 1
  107. if not b:
  108. break
  109. line += b
  110. if b == '\n':
  111. break
  112. b = socket.recv(1)
  113. if not b:
  114. break
  115. if not b:
  116. return None
  117. return line
  118. def getHeaderVal(self, header):
  119. ini = header.find(':')
  120. if ini == -1:
  121. return None
  122. ini += 2
  123. fim = header.find('\r\n')
  124. if fim == -1:
  125. header = header[ini:]
  126. return header[ini:fim]
  127. def readFully(self, n):
  128. count = 0
  129. data = ''
  130. while count < n:
  131. packet = self.socket.recv(n - count)
  132. if not packet:
  133. break
  134. count += len(packet)
  135. data += packet
  136. class Client(threading.Thread):
  137. ACTION_DATA = 'data'
  138. BUFFER_SIZE = 4096
  139. def __init__(self, id, readSocket, target):
  140. super(Client, self).__init__()
  141. self.targetHostPort = target
  142. self.id = id
  143. self.readSocket = readSocket
  144. self.logger = Logger()
  145. self.isStopped = False
  146. self.onCloseFunction = None
  147. self.closeLock = threading.Lock()
  148. self.threadEndCount = 0
  149. self.writeSocket = None
  150. def connectTarget(self):
  151. aux = self.targetHostPort.find(':')
  152. host = self.targetHostPort[:aux]
  153. port = int(self.targetHostPort[aux + 1:])
  154. self.target = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  155. self.target.connect((host, port))
  156. def run(self):
  157. try:
  158. self.connectTarget()
  159. request = ClientRequest(self.readSocket)
  160. request.readConent = False
  161. if not request.parse() or not Client.ACTION_DATA == request.action:
  162. raise Exception('client sends invalid request')
  163. threadRead = ThreadRelay(self.readSocket, self.target, self.finallyClose)
  164. threadRead.logFunction = self.log
  165. threadRead.start()
  166. threadWrite = ThreadRelay(self.target, self.writeSocket, self.finallyClose)
  167. threadWrite.logFunction = self.log
  168. threadWrite.start()
  169. except Exception as e:
  170. self.log('connection error - ' + str(type(e)) + ' - ' + str(e), Logger.LOG_ERROR)
  171. self.close()
  172. def finallyClose(self):
  173. with self.closeLock:
  174. self.threadEndCount += 1
  175. if self.threadEndCount == 2:
  176. self.close()
  177. def close(self):
  178. if not self.isStopped:
  179. self.isStopped = True
  180. if hasattr(self, 'target'):
  181. try:
  182. self.target.close()
  183. except:
  184. pass
  185. if hasattr(self, 'writeSocket'):
  186. try:
  187. self.writeSocket.close()
  188. except:
  189. pass
  190. if hasattr(self, 'readSocket'):
  191. try:
  192. self.readSocket.close()
  193. except:
  194. pass
  195. self.onClose()
  196. self.log('closed', Logger.LOG_INFO)
  197. def onClose(self):
  198. if not self.onCloseFunction is None:
  199. self.onCloseFunction(self)
  200. def log(self, msg, logLevel):
  201. msg = 'Client ' + str(self.id) + ': ' + msg
  202. self.logger.printLog(msg, logLevel)
  203. class ThreadRelay(threading.Thread):
  204. def __init__(self, readSocket, writeSocket, closeFunction=None):
  205. super(ThreadRelay, self).__init__()
  206. self.readSocket = readSocket
  207. self.writeSocket = writeSocket
  208. self.logFunction = None
  209. self.closeFuntion = closeFunction
  210. def run(self):
  211. try:
  212. while True:
  213. data = self.readSocket.recv(Client.BUFFER_SIZE)
  214. if not data:
  215. break
  216. self.writeSocket.sendall(data)
  217. self.writeSocket.shutdown(socket.SHUT_WR)
  218. except Exception as e:
  219. if not self.logFunction is None:
  220. self.logFunction('threadRelay error: ' + str(type(e)) + ' - ' + str(e), Logger.LOG_ERROR)
  221. finally:
  222. if not self.closeFuntion is None:
  223. self.closeFuntion()
  224. class AcceptClient(threading.Thread):
  225. MAX_QTD_BYTES = 5000
  226. HEADER_BODY = 'X-Body'
  227. HEADER_ACTION = 'X-Action'
  228. HEADER_TARGET = 'X-Target'
  229. HEADER_PASS = 'X-Pass'
  230. HEADER_ID = 'X-Id'
  231. ACTION_CREATE = 'create'
  232. ACTION_COMPLETE = 'complete'
  233. MSG_CONNECTION_CREATED = 'Created'
  234. MSG_CONNECTION_COMPLETED = 'Completed'
  235. ID_COUNT = 0
  236. ID_LOCK = threading.Lock()
  237. def __init__(self, socket, server, passwdSet=None):
  238. super(AcceptClient, self).__init__()
  239. self.server = server
  240. self.passwdSet = passwdSet
  241. self.socket = socket
  242. def run(self):
  243. needClose = True
  244. try:
  245. head = self.readHttpRequest()
  246. bodyLen = self.getHeaderVal(head, AcceptClient.HEADER_BODY)
  247. if not bodyLen is None:
  248. try:
  249. self.readFully(int(bodyLen))
  250. except ValueError:
  251. pass
  252. action = self.getHeaderVal(head, AcceptClient.HEADER_ACTION)
  253. if action is None:
  254. self.log('client sends no action header', Logger.LOG_WARN)
  255. self.socket.sendall('HTTP/1.1 400 NoActionHeader!\r\nServer: GetTunnelServer\r\n\r\n')
  256. return
  257. if action == AcceptClient.ACTION_CREATE:
  258. target = self.getHeaderVal(head, AcceptClient.HEADER_TARGET)
  259. if not self.passwdSet is None:
  260. passwd = self.getHeaderVal(head, AcceptClient.HEADER_PASS)
  261. try:
  262. passwd = base64.b64decode(passwd)
  263. except:
  264. passwd = None
  265. pass
  266. if passwd is None or not self.passwdSet.isValidKey(passwd, target):
  267. self.log('client sends wrong key', Logger.LOG_WARN)
  268. self.socket.sendall('HTTP/1.1 403 Forbidden\r\nServer: GetTunnelServer\r\n\r\n')
  269. return
  270. if target is not None and self.isValidHostPort(target):
  271. id = self.generateId()
  272. client = Client(id, self.socket, target)
  273. client.onCloseFunction = self.server.removeClient
  274. self.server.addClient(client)
  275. self.socket.sendall('HTTP/1.1 200 '+ AcceptClient.MSG_CONNECTION_CREATED + '\r\nServer: GetTunnelServer\r\nX-Id: ' + str(id) + '\r\nContent-Type: text/plain\r\nContent-Length: 0\r\nConnection: Keep-Alive\r\n\r\n')
  276. self.log('connection created - ' + str(id), Logger.LOG_INFO)
  277. needClose = False
  278. else:
  279. self.log('client sends no valid target', Logger.LOG_WARN)
  280. self.socket.sendall('HTTP/1.1 400 Target!\r\nServer: GetTunnelServer\r\n\r\n')
  281. elif action == AcceptClient.ACTION_COMPLETE:
  282. id = self.getHeaderVal(head, AcceptClient.HEADER_ID)
  283. if not id is None:
  284. client = self.server.getClient(id)
  285. if not client is None:
  286. client.writeSocket = self.socket
  287. self.log('connection completed - ' + str(id), Logger.LOG_INFO)
  288. self.socket.sendall('HTTP/1.1 200 ' + AcceptClient.MSG_CONNECTION_COMPLETED + '\r\nServer: GetTunnelServer\r\nConnection: Keep-Alive\r\n\r\n')
  289. client.start()
  290. needClose = False
  291. else:
  292. self.log('client try to complete non existing connection', Logger.LOG_WARN)
  293. self.socket.sendall('HTTP/1.1 400 CreateFirst!\r\nServer: GetTunnelServer\r\n\r\n')
  294. else:
  295. self.log('client sends no id header', Logger.LOG_WARN)
  296. self.socket.sendall('HTTP/1.1 400 NoID!\r\nServer: GetTunnelServer\r\n\r\n')
  297. else:
  298. self.log('client sends invalid action', Logger.LOG_WARN)
  299. self.socket.sendall('HTTP/1.1 400 InvalidAction!\r\nServer: GetTunnelServer\r\n\r\n')
  300. except Exception as e:
  301. self.log('connection error - ' + str(type(e)) + ' - ' + str(e), Logger.LOG_ERROR)
  302. finally:
  303. if needClose:
  304. try:
  305. self.socket.close()
  306. except:
  307. pass
  308. def log(self, msg, logLevel):
  309. self.server.log(msg, logLevel)
  310. def readHttpRequest(self):
  311. request = ''
  312. linha = ''
  313. count = 0
  314. while linha != '\r\n' and count < AcceptClient.MAX_QTD_BYTES:
  315. linha = self.readHttpLine()
  316. if linha is None:
  317. break
  318. request += linha
  319. count += len(linha)
  320. return request
  321. def readHttpLine(self):
  322. line = ''
  323. count = 0
  324. socket = self.socket
  325. b = socket.recv(1)
  326. if not b:
  327. return None
  328. while count < AcceptClient.MAX_QTD_BYTES:
  329. count += 1
  330. line += b
  331. if b == '\r':
  332. b = socket.recv(1)
  333. count += 1
  334. if not b:
  335. break
  336. line += b
  337. if b == '\n':
  338. break
  339. b = socket.recv(1)
  340. if not b:
  341. break
  342. if not b:
  343. return None
  344. return line
  345. def getHeaderVal(self, head, header):
  346. if not head.startswith('\r\n'):
  347. header = '\r\n' + header
  348. if not header.endswith(': '):
  349. header = header + ': '
  350. ini = head.find(header)
  351. if ini == -1:
  352. return None
  353. end = head.find('\r\n', ini+2)
  354. ini += len(header)
  355. if end == -1 or ini > end or ini >= len(head):
  356. return None
  357. return head[ini:end]
  358. def readFully(self, n):
  359. count = 0
  360. while count < n:
  361. packet = self.socket.recv(n - count)
  362. if not packet:
  363. break
  364. count += len(packet)
  365. def isValidHostPort(self, hostPort):
  366. aux = hostPort.find(':')
  367. if aux == -1 or aux >= len(hostPort) -1:
  368. return False
  369. try:
  370. int(hostPort[aux+1:])
  371. return True
  372. except ValueError:
  373. return False
  374. def generateId(self):
  375. with AcceptClient.ID_LOCK:
  376. AcceptClient.ID_COUNT += 1
  377. return AcceptClient.ID_COUNT
  378. class Server(threading.Thread):
  379. def __init__(self, listening, passwdSet=None):
  380. super(Server, self).__init__()
  381. self.listening = listening
  382. self.passwdSet = passwdSet
  383. self.running = False
  384. self.logger = Logger()
  385. self.isStopped = False
  386. self.clientsLock = threading.Lock()
  387. self.clients = []
  388. def run(self):
  389. try:
  390. self.soc = socket.socket(socket.AF_INET)
  391. self.soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  392. self.soc.settimeout(2)
  393. self.soc.bind((self.listening[:self.listening.find(':')], int(self.listening[self.listening.find(':') + 1:])))
  394. self.soc.listen(0)
  395. self.log('running on ' + self.listening, Logger.LOG_INFO)
  396. self.running = True
  397. while self.running:
  398. try:
  399. c, addr = self.soc.accept()
  400. c.setblocking(1)
  401. self.log('opennig connection - ' + str(addr), Logger.LOG_INFO)
  402. self.acceptClient(c)
  403. except socket.timeout:
  404. continue
  405. except Exception as e:
  406. self.log('connection error - ' + str(type(e)) + ' - ' + str(e), Logger.LOG_ERROR)
  407. finally:
  408. self.running = False
  409. self.close()
  410. def acceptClient(self, socket):
  411. accept = AcceptClient(socket, self, self.passwdSet)
  412. accept.start()
  413. def addClient(self, client):
  414. with self.clientsLock:
  415. self.clients.append(client)
  416. def removeClient(self, client):
  417. with self.clientsLock:
  418. self.clients.remove(client)
  419. def getClient(self, id):
  420. client = None
  421. with self.clientsLock:
  422. for c in self.clients:
  423. if str(c.id) == str(id):
  424. client = c
  425. break
  426. return client
  427. def close(self):
  428. if not self.isStopped:
  429. self.isStopped = True
  430. if hasattr(self, 'soc'):
  431. try:
  432. self.soc.close()
  433. except:
  434. pass
  435. with self.clientsLock:
  436. clientsCopy = self.clients[:]
  437. for c in clientsCopy:
  438. c.close()
  439. self.log('closed', Logger.LOG_INFO)
  440. def log(self, msg, logLevel):
  441. msg = 'Server: ' + msg
  442. self.logger.printLog(msg, logLevel)
  443. def print_usage():
  444. print '\nUsage : python get.py -b listening -p pass'
  445. print 'Ex. : python get.py -b 0.0.0.0:80 -p pass123'
  446. print ' : python get.py -b 0.0.0.0:80 -p passFile.pwd\n'
  447. print '___Password file ex.:___'
  448. print PasswordSet.FILE_EXEMPLE
  449. def parse_args(argv):
  450. global CONFIG_LISTENING
  451. global CONFIG_PASS
  452. try:
  453. opts, args = getopt.getopt(argv, "hb:p:", ["bind=", "pass="])
  454. except getopt.GetoptError:
  455. print_usage()
  456. sys.exit(2)
  457. for opt, arg in opts:
  458. if opt == '-h':
  459. print_usage()
  460. sys.exit()
  461. elif opt in ('-b', '--bind'):
  462. CONFIG_LISTENING = arg
  463. elif opt in ('-p', '--pass'):
  464. CONFIG_PASS = arg
  465. def main():
  466. print '\n-->GetTunnelPy - Server v.' + '25/06/2017' + '\n'
  467. print '-->Listening: ' + CONFIG_LISTENING
  468. pwdSet = None
  469. if not CONFIG_PASS is None:
  470. if CONFIG_PASS.endswith('.pwd'):
  471. pwdSet = PasswordSet()
  472. try:
  473. isValidFile = pwdSet.parseFile(CONFIG_PASS)
  474. except IOError as e:
  475. print '--#Error reading file: ' + str(type(e)) + ' - ' + str(e)
  476. sys.exit()
  477. if not isValidFile:
  478. print '--#Error on parsing file!\n'
  479. print_usage()
  480. return
  481. print '-->Pass file: ' + CONFIG_PASS + '\n'
  482. else:
  483. if (len(CONFIG_PASS) > 0):
  484. print '-->Pass : yes\n'
  485. pwdSet = PasswordSet(CONFIG_PASS)
  486. else:
  487. print '-->Pass : no\n'
  488. server = Server(CONFIG_LISTENING)
  489. server.passwdSet = pwdSet
  490. server.start()
  491. while True:
  492. try:
  493. time.sleep(2)
  494. except KeyboardInterrupt:
  495. print '<-> Stopping server...'
  496. server.running = False
  497. break
  498. if __name__ == '__main__':
  499. parse_args(sys.argv[1:])
  500. main()