def sendall(self, data): data_more = None if self.connected == 0: logger.debug('hxsocks send connect request') self.cipher = encrypt.AEncryptor(keys[self.serverid][1], self.method, salt, ctx, 0) pt = struct.pack('>I', int(time.time())) + chr(len( self._address)) + self._address + data if len(pt) > 65500: pt, data_more = pt[:65500], pt[65500] ct, mac = self.cipher.encrypt(pt) self._sock.sendall( self.pskcipher.encrypt( chr(11) + keys[self.serverid][0] + struct.pack('>H', len(ct))) + ct + mac) if data and self._data_bak is None: self._data_bak = data self.connected = 1 else: if len(data) > 65500: data, data_more = data[:65500], data[65500] padding_len = random.randint(64, 255) if len(data) < 256 else 0 padding = (b'\x00' * padding_len) if padding_len else b'' data = chr(padding_len) + data + padding ct, mac = self.cipher.encrypt(data) data = self.pskcipher.encrypt(struct.pack('>H', len(ct))) + ct + mac self._sock.sendall(data) if data_more: self.sendall(data_more)
def handle(self): try: self.connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) pskcipher = encrypt.Encryptor(self.server.PSK, self.server.method) self.connection.settimeout(self.timeout) data = self.rfile.read(pskcipher.iv_len) pskcipher.decrypt(data) while True: try: data = self.rfile.read(1) self.connection.settimeout(self.timeout) cmd = ord(pskcipher.decrypt(data)) except Exception as e: logging.error( 'cmd Exception: server %s %r from %s:%s' % (self.server.server_address[1], e, self.client_address[0], self.client_address[1])) break if cmd == 10: # client key exchange rint = random.randint(64, 255) req_len = pskcipher.decrypt(self.rfile.read(2)) req_len = struct.unpack('>H', req_len)[0] data = pskcipher.decrypt(self.rfile.read(req_len)) data = io.BytesIO(data) ts = data.read(4) if abs(struct.unpack('>I', ts)[0] - time.time()) > 120: # possible replay attack logging.error('bad timestamp. client_ip: %s' % self.client_address[0]) break pklen = ord(data.read(1)) client_pkey = data.read(pklen) client_auth = data.read(32) def _send(data): data = struct.pack('>H', len(data)) + data self.wfile.write(pskcipher.encrypt(data)) client = None for user, passwd in USER_PASS.items(): h = hmac.new(passwd.encode(), ts + client_pkey + user.encode(), hashlib.sha256).digest() if compare_digest(h, client_auth): client = user break else: logging.error('user not found. client_ip: %s' % self.client_address[0]) break pkey, passwd = KeyManager.create_key( client, client_pkey, pskcipher.key_len) if pkey: logging.info('new key exchange. client: %s, ip: %s' % (client, self.client_address[0])) h = hmac.new(passwd.encode(), client_pkey + pkey + client.encode(), hashlib.sha256).digest() scert = SERVER_CERT.get_pub_key() signature = SERVER_CERT.sign(h, self.server.hash_algo) data = chr(0) + chr(len(pkey)) + chr(len(scert)) + chr( len(signature) ) + pkey + h + scert + signature + os.urandom(rint) _send(data) continue else: logging.error( 'Private_key already registered. client: %s, ip: %s' % (client, self.client_address[0])) # KeyManager.del_key(hashlib.md5(client_pkey).digest()) break elif cmd == 11: # a connect request client_pkey = pskcipher.decrypt(self.rfile.read(16)) rint = random.randint(64, 2048) def _send(code, cipher): if code == 1: data = os.urandom(rint) data = pskcipher.encrypt(struct.pack('>H', rint)) + data self.wfile.write(data) else: ct = cipher.encrypt( chr(code) + os.urandom(rint - 1)) data = pskcipher.encrypt(struct.pack( '>H', len(ct))) + ct self.wfile.write(data) if KeyManager.check_key(client_pkey): logging.error( 'client key not exist or expired. client ip: %s' % self.client_address[0]) ctlen = struct.unpack( '>H', pskcipher.decrypt(self.rfile.read(2)))[0] self.rfile.read(ctlen) _send(1, None) continue user = KeyManager.get_user_by_pubkey(client_pkey) cipher = encrypt.AEncryptor( KeyManager.get_skey_by_pubkey(client_pkey), self.server.method, CTX) ctlen = struct.unpack( '>H', pskcipher.decrypt(self.rfile.read(2)))[0] ct = self.rfile.read(ctlen) data = cipher.decrypt(ct) buf = io.BytesIO(data) ts = buf.read(4) if abs(struct.unpack('>I', ts)[0] - time.time()) > 120: logging.error( 'bad timestamp, possible replay attrack. client ip: %s' % self.client_address[0]) # KeyManager.del_key(client_pkey) # _send(1, None) break host_len = ord(buf.read(1)) addr = buf.read(host_len) port = struct.unpack('>H', buf.read(2))[0] if self._request_is_loopback( (addr, port)) and port not in self.server.forward: logging.info( 'server %d access localhost:%d denied. from %s:%d, %s' % (self.server.server_address[1], port, self.client_address[0], self.client_address[1], user)) _send(2, cipher) continue try: logging.info('server %d request %s:%d from %s:%d, %s' % (self.server.server_address[1], addr, port, self.client_address[0], self.client_address[1], user)) remote = create_connection((addr, port), timeout=10, proxy=self.server.proxy) remote.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) _send(0, cipher) # self.remote.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) except (IOError, OSError) as e: # Connection refused logging.warning( 'server %s:%d %r on connecting %s:%d' % (self.server.server_address[0], self.server.server_address[1], e, addr, port)) _send(2, cipher) continue if self.forward_tcp(self.connection, remote, cipher, pskcipher, timeout=60): break self.connection.settimeout(60) logging.debug( 'hxsocks connect reusable, except next connection') elif cmd in (1, 3, 4, 17, 19, 20): # A shadowsocks request if not self.server.ss: logging.warning( 'shadowsocks not enabled for this server. port: %d' % self.server.server_address[1]) break ota = cmd & 16 if cmd & 15 == 1: _addr = pskcipher.decrypt(self.rfile.read(4)) addr = socket.inet_ntoa(_addr) elif cmd & 15 == 3: _addr = pskcipher.decrypt(self.rfile.read(1)) addr = pskcipher.decrypt(self.rfile.read(ord(_addr))) _addr += addr elif cmd & 15 == 4: _addr = socket.AF_INET6, pskcipher.decrypt( self.rfile.read(16)) addr = socket.inet_ntop(_addr) port = struct.unpack('>H', pskcipher.decrypt( self.rfile.read(2)))[0] # verify if ota: header = chr(cmd) + _addr + struct.pack('>H', port) self._ota_chunk_idx = 0 rmac = pskcipher.decrypt(self.rfile.read(10)) key = pskcipher.decipher_iv + pskcipher.key mac = hmac.new(key, header, hashlib.sha1).digest()[:10] if not compare_digest(rmac, mac): logging.error("OTA Failed!!") break if self._request_is_loopback( (addr, port)) and port not in self.server.forward: logging.info( 'server %d access localhost:%d denied. from %s:%d' % (self.server.server_address[1], port, self.client_address[0], self.client_address[1])) break try: remote = None logging.info( 'server %d SS request %s:%d from %s:%d %s' % (self.server.server_address[1], addr, port, self.client_address[0], self.client_address[1], 'with ota' if ota else '')) remote = create_connection((addr, port), timeout=10, proxy=self.server.proxy) if ota: return self.ssforward_tcp_ota(self.connection, remote, pskcipher, timeout=60) return self.ssforward_tcp(self.connection, remote, pskcipher, timeout=60) except (IOError, OSError) as e: # Connection refused logging.warn( 'server %s:%d %r on connecting %s:%d' % (self.server.server_address[0], self.server.server_address[1], e, addr, port)) return else: logging.warning('unknown cmd %d, bad encryption key?' % cmd) break ins, _, _ = select.select([self.connection], [], [], 1) while ins: data = self.connection.recv(self.bufsize) if not data: break ins, _, _ = select.select([self.connection], [], [], 1) except Exception as e: logging.error(repr(e)) logging.error(traceback.format_exc())
def getKey(self): with newkey_lock[self.serverid]: if self.serverid not in keys: for _ in range(2): logger.debug('hxsocks getKey') host, port, usn, psw = (self.hxsServer.hostname, self.hxsServer.port, self.hxsServer.username, self.hxsServer.password) if self._sock is None: logger.debug('hxsocks connect') from connection import create_connection self._sock = create_connection( (host, port), self.timeout, parentproxy=self.parentproxy, tunnel=True) self.pskcipher = encrypt.Encryptor( self.PSK, self.method) self._rfile = self._sock.makefile('rb') self._header_sent = False self._header_received = False acipher = ECC(self.pskcipher.key_len) pubk = acipher.get_pub_key() logger.debug('hxsocks send key exchange request') ts = struct.pack('>I', int(time.time())) padding_len = random.randint(64, 255) data = b''.join([ ts, chr(len(pubk)).encode('latin1'), pubk, hmac.new(psw.encode(), ts + pubk + usn.encode(), hashlib.sha256).digest(), b'\x00' * padding_len ]) data = chr(10).encode() + struct.pack('>H', len(data)) + data self._sock_sendall(self.pskcipher.encrypt(data)) resp_len = 2 if self.pskcipher.decipher else self.pskcipher.iv_len + 2 resp_len = self.pskcipher.decrypt( self._rfile_read(resp_len)) resp_len = struct.unpack('>H', resp_len)[0] data = self.pskcipher.decrypt(self._rfile_read(resp_len)) data = io.BytesIO(data) resp_code = byte2int(data.read(1)) if resp_code == 0: logger.debug('hxsocks read key exchange respond') pklen = byte2int(data.read(1)) scertlen = byte2int(data.read(1)) siglen = byte2int(data.read(1)) server_key = data.read(pklen) auth = data.read(32) server_cert = data.read(scertlen) signature = data.read(siglen) # TODO: ask user if a certificate should be accepted or not. if host not in known_hosts: logger.info( 'hxs: server %s new cert %s saved.' % (host, hashlib.sha256(server_cert).hexdigest()[:8])) with open('./.hxs_known_hosts/' + host + '.cert', 'wb') as f: f.write(server_cert) known_hosts[host] = server_cert elif known_hosts[host] != server_cert: logger.error( 'hxs: server %s certificate mismatch! PLEASE CHECK!' % host) raise OSError(0, 'hxs: bad certificate') if auth == hmac.new(psw.encode(), pubk + server_key + usn.encode(), hashlib.sha256).digest(): if ECC.verify_with_pub_key(server_cert, auth, signature, self.hash_algo): shared_secret = acipher.get_dh_key(server_key) keys[self.serverid] = ( hashlib.md5(pubk).digest(), shared_secret) self.cipher = encrypt.AEncryptor( keys[self.serverid][1], self.method, SALT, CTX, 0, MAC_LEN) logger.debug('hxs key exchange success') return else: logger.error( 'hxs getKey Error: server auth failed, bad signature' ) else: logger.error( 'hxs getKey Error: server auth failed, bad username or password' ) else: logger.error( 'hxs getKey Error. bad password or timestamp.') else: raise IOError(0, 'hxs getKey Error') else: self.cipher = encrypt.AEncryptor(keys[self.serverid][1], self.method, SALT, CTX, 0, MAC_LEN)