H3C利用python开socks5
H3C利用python开socks5
#!/usr/bin/env python
from SocketServer import BaseServer, ThreadingTCPServer, StreamRequestHandler
from socket import socket, AF_INET, SOCK_STREAM
import signal
import struct
import sys
import thread
import os
'''
exec(base64.b64decode(""))
'''
__author__ = 'Youchao Feng'
def byte_to_int(b):
return b & 0xFF
def port_from_byte(b1, b2):
return byte_to_int(b1) << 8 | byte_to_int(b2)
def host_from_ip(a, b, c, d):
a = byte_to_int(a)
b = byte_to_int(b)
c = byte_to_int(c)
d = byte_to_int(d)
return "%d.%d.%d.%d" % (a, b, c, d)
def get_command_name(value):
if value == 1:
return 'CONNECT'
elif value == 2:
return 'BIND'
elif value == 3:
return 'UDP_ASSOCIATE'
else:
return None
def build_command_response(reply):
start = b'\x05%s\x00\x01\x00\x00\x00\x00\x00\x00'
return start % reply.get_byte_string()
def close_session(session):
session.get_client_socket().close()
print ("Session[%s] closed" % session.get_id())
def run_daemon_process(stdout='./proxy-null', stderr=None, stdin='./proxy-null', start_msg='started with pid %s'):
open(stdout,'w').close()
open(stdin,'w').close()
# flush io
sys.stdout.flush()
sys.stderr.flush()
# Do first fork.
try:
if os.fork() > 0:
sys.exit(0) # Exit first parent.
except OSError, e:
sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
sys.exit(1)
# Decouple from parent environment.
os.chdir("./")
os.umask(0)
os.setsid()
# Do second fork.
try:
if os.fork() > 0:
sys.exit(0) # Exit second parent.
except OSError, e:
sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
sys.exit(1)
# Open file descriptors and print start message
if not stderr:
stderr = stdout
si = file(stdin, 'r')
so = file(stdout, 'a+')
se = file(stderr, 'a+', 0) # unbuffered
pid = str(os.getpid())
sys.stderr.write(start_msg % pid)
sys.stderr.flush()
# Redirect standard file descriptors.
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
class Session(object):
index = 0
def __init__(self, client_socket):
Session.index += 1
self.__id = Session.index
self.__client_socket = client_socket
self._attr = {}
def get_id(self):
return self.__id
def set_attr(self, key, value):
self._attr[key] = value
def get_client_socket(self):
return self.__client_socket
class AddressType(object):
IPV4 = 1
DOMAIN_NAME = 3
IPV6 = 4
class SocksCommand(object):
CONNECT = 1
BIND = 2
UDP_ASSOCIATE = 3
class SocksMethod(object):
NO_AUTHENTICATION_REQUIRED = 0
GSS_API = 1
USERNAME_PASSWORD = 2
class ServerReply(object):
def __init__(self, value):
self.__value = value
def get_byte_string(self):
if self.__value == 0:
return b'\x00'
elif self.__value == 1:
return b'\x01'
elif self.__value == 2:
return b'\x02'
elif self.__value == 3:
return b'\x03'
elif self.__value == 4:
return b'\x04'
elif self.__value == 5:
return b'\x05'
elif self.__value == 6:
return b'\x06'
elif self.__value == 7:
return b'\x07'
elif self.__value == 8:
return b'\x08'
def get_value(self):
return self.__value
class ReplyType(object):
SUCCEEDED = ServerReply(0)
GENERAL_SOCKS_SERVER_FAILURE = ServerReply(1)
CONNECTION_NOT_ALLOWED_BY_RULESET = ServerReply(2)
NETWORK_UNREACHABLE = ServerReply(3)
HOST_UNREACHABLE = ServerReply(4)
CONNECTION_REFUSED = ServerReply(5)
TTL_EXPIRED = ServerReply(6)
COMMAND_NOT_SUPPORTED = ServerReply(7)
ADDRESS_TYPE_NOT_SUPPORTED = ServerReply(8)
class SocketPipe(object):
BUFFER_SIZE = 1024 * 1024
def __init__(self, socket1, socket2):
self._socket1 = socket1
self._socket2 = socket2
self.__running = False
def __transfer(self, socket1, socket2):
while self.__running:
try:
data = socket1.recv(self.BUFFER_SIZE)
if len(data) > 0:
socket2.sendall(data)
else:
break
except IOError:
self.stop()
self.stop()
def start(self):
self.__running = True
thread.start_new_thread(self.__transfer, (self._socket1, self._socket2))
thread.start_new_thread(self.__transfer, (self._socket2, self._socket1))
def stop(self):
self._socket1.close()
self._socket2.close()
self.__running = False
def is_running(self):
return self.__running
class CommandExecutor(object):
def __init__(self, remote_server_host, remote_server_port, session):
self.__proxy_socket = socket(AF_INET, SOCK_STREAM)
self.__remote_server_host = remote_server_host
self.__remote_server_port = remote_server_port
self.__client = session.get_client_socket()
self.__session = session
def do_connect(self):
"""
Do SOCKS CONNECT method
:return: None
"""
result = self.__proxy_socket.connect_ex(self.__get_address())
if result == 0:
self.__client.send(build_command_response(ReplyType.SUCCEEDED))
socket_pipe = SocketPipe(self.__client, self.__proxy_socket)
socket_pipe.start()
while socket_pipe.is_running():
pass
elif result == 60:
self.__client.send(build_command_response(ReplyType.TTL_EXPIRED))
elif result == 61:
self.__client.send(build_command_response(ReplyType.NETWORK_UNREACHABLE))
else:
print('Connection Error:[%s] is unknown' % result)
self.__client.send(build_command_response(ReplyType.NETWORK_UNREACHABLE))
def do_bind(self):
pass
def do_udp_associate(self):
pass
def __get_address(self):
return self.__remote_server_host, self.__remote_server_port
class User(object):
def __init__(self, username, password):
self.__username = username
self.__password = password
def get_username(self):
return self.__username
def get_password(self):
return self.__password
def __repr__(self):
return '<user: username=%s, password=%s>' % (self.get_username(), self.__password)
class UserManager(object):
def __init__(self):
self.__users = {}
def add_user(self, user):
self.__users[user.get_username()] = user
def remove_user(self, username):
if username in self.__users:
del self.__users[username]
def check(self, username, password):
if username in self.__users and self.__users[username].get_password() == password:
return True
else:
return False
def get_user(self, username):
return self.__users[username]
def get_users(self):
return self.__users
class Socks5RequestHandler(StreamRequestHandler):
def __init__(self, request, client_address, server):
StreamRequestHandler.__init__(self, request, client_address, server)
def handle(self):
session = Session(self.connection)
print('Create session[%s] for %s:%d' % (1, self.client_address[0], self.client_address[1]))
client = self.connection
client.recv(1)
method_num, = struct.unpack('b', client.recv(1))
methods = struct.unpack('b' * method_num, client.recv(method_num))
auth = self.server.is_auth()
if methods.__contains__(SocksMethod.NO_AUTHENTICATION_REQUIRED) and not auth:
client.send(b"\x05\x00")
elif methods.__contains__(SocksMethod.USERNAME_PASSWORD) and auth:
client.send(b"\x05\x02")
if not self.__do_username_password_auth():
print('Session[%d] authentication failed' % session.get_id())
close_session(session)
return
else:
client.send(b"\x05\xFF")
return
version, command, reserved, address_type = struct.unpack('b' * 4, client.recv(4))
host = None
port = None
if address_type == AddressType.IPV4:
ip_a, ip_b, ip_c, ip_d, p1, p2 = struct.unpack('b' * 6, client.recv(6))
host = host_from_ip(ip_a, ip_b, ip_c, ip_d)
port = port_from_byte(p1, p2)
elif address_type == AddressType.DOMAIN_NAME:
host_length, = struct.unpack('b', client.recv(1))
host = client.recv(host_length)
p1, p2 = struct.unpack('b' * 2, client.recv(2))
port = port_from_byte(p1, p2)
else: # address type not support
client.send(build_command_response(ReplyType.ADDRESS_TYPE_NOT_SUPPORTED))
command_executor = CommandExecutor(host, port, session)
if command == SocksCommand.CONNECT:
print("Session[%s] Request connect %s:%d" % (session.get_id(), host, port))
command_executor.do_connect()
close_session(session)
def __do_username_password_auth(self):
client = self.connection
client.recv(1)
length = byte_to_int(struct.unpack('b', client.recv(1))[0])
username = client.recv(length)
length = byte_to_int(struct.unpack('b', client.recv(1))[0])
password = client.recv(length)
user_manager = self.server.get_user_manager()
if user_manager.check(username, password):
client.send(b"\x01\x00")
return True
else:
client.send(b"\x01\x01")
return False
class Socks5Server(ThreadingTCPServer):
"""
SOCKS5 proxy server
"""
def __init__(self, port, auth=False, user_manager=UserManager()):
ThreadingTCPServer.__init__(self, ('', port), Socks5RequestHandler)
self.__port = port
self.__users = {}
self.__auth = auth
self.__user_manager = user_manager
self.__sessions = {}
def serve_forever(self, poll_interval=0.5):
print("Create SOCKS5 server at port %d" % self.__port)
ThreadingTCPServer.serve_forever(self, poll_interval)
def finish_request(self, request, client_address):
BaseServer.finish_request(self, request, client_address)
def is_auth(self):
return self.__auth
def set_auth(self, auth):
self.__auth = auth
def get_all_managed_session(self):
return self.__sessions
def get_bind_port(self):
return self.__port
def get_user_manager(self):
return self.__user_manager
def set_user_manager(self, user_manager):
self.__user_manager = user_manager
def main():
port = 1080
auth = False
user_manager = UserManager()
Socks5Server.allow_reuse_address = True
socks5_server = Socks5Server(port, auth, user_manager)
try:
if True:
run_daemon_process(start_msg='Start SOCKS5 server at pid %s\n')
socks5_server.serve_forever()
except KeyboardInterrupt:
socks5_server.server_close()
socks5_server.shutdown()
print("SOCKS5 server shutdown")
if __name__ == '__main__':
main()
POC
python exec(base64.b64decode("IyEvdXNyL2Jpbi9lbnYgcHl0aG9uCmZyb20gU29ja2V0U2VydmVyIGltcG9ydCBCYXNlU2VydmVyLCBUaHJlYWRpbmdUQ1BTZXJ2ZXIsIFN0cmVhbVJlcXVlc3RIYW5kbGVyCmZyb20gc29ja2V0IGltcG9ydCBzb2NrZXQsIEFGX0lORVQsIFNPQ0tfU1RSRUFNCmltcG9ydCBzaWduYWwKaW1wb3J0IHN0cnVjdAppbXBvcnQgc3lzCmltcG9ydCB0aHJlYWQKaW1wb3J0IG9zCgonJycKZXhlYyhiYXNlNjQuYjY0ZGVjb2RlKCIiKSkKJycnCgpfX2F1dGhvcl9fID0gJ1lvdWNoYW8gRmVuZycKCmRlZiBieXRlX3RvX2ludChiKToKICAgIHJldHVybiBiICYgMHhGRgoKCmRlZiBwb3J0X2Zyb21fYnl0ZShiMSwgYjIpOgogICAgcmV0dXJuIGJ5dGVfdG9faW50KGIxKSA8PCA4IHwgYnl0ZV90b19pbnQoYjIpCgoKZGVmIGhvc3RfZnJvbV9pcChhLCBiLCBjLCBkKToKICAgIGEgPSBieXRlX3RvX2ludChhKQogICAgYiA9IGJ5dGVfdG9faW50KGIpCiAgICBjID0gYnl0ZV90b19pbnQoYykKICAgIGQgPSBieXRlX3RvX2ludChkKQogICAgcmV0dXJuICIlZC4lZC4lZC4lZCIgJSAoYSwgYiwgYywgZCkKCgpkZWYgZ2V0X2NvbW1hbmRfbmFtZSh2YWx1ZSk6CiAgICBpZiB2YWx1ZSA9PSAxOgogICAgICAgIHJldHVybiAnQ09OTkVDVCcKICAgIGVsaWYgdmFsdWUgPT0gMjoKICAgICAgICByZXR1cm4gJ0JJTkQnCiAgICBlbGlmIHZhbHVlID09IDM6CiAgICAgICAgcmV0dXJuICdVRFBfQVNTT0NJQVRFJwogICAgZWxzZToKICAgICAgICByZXR1cm4gTm9uZQoKCmRlZiBidWlsZF9jb21tYW5kX3Jlc3BvbnNlKHJlcGx5KToKICAgIHN0YXJ0ID0gYidceDA1JXNceDAwXHgwMVx4MDBceDAwXHgwMFx4MDBceDAwXHgwMCcKICAgIHJldHVybiBzdGFydCAlIHJlcGx5LmdldF9ieXRlX3N0cmluZygpCgoKZGVmIGNsb3NlX3Nlc3Npb24oc2Vzc2lvbik6CiAgICBzZXNzaW9uLmdldF9jbGllbnRfc29ja2V0KCkuY2xvc2UoKQogICAgcHJpbnQgKCJTZXNzaW9uWyVzXSBjbG9zZWQiICUgc2Vzc2lvbi5nZXRfaWQoKSkKCgpkZWYgcnVuX2RhZW1vbl9wcm9jZXNzKHN0ZG91dD0nLi9wcm94eS1udWxsJywgc3RkZXJyPU5vbmUsIHN0ZGluPScuL3Byb3h5LW51bGwnLCBzdGFydF9tc2c9J3N0YXJ0ZWQgd2l0aCBwaWQgJXMnKToKICAgIG9wZW4oc3Rkb3V0LCd3JykuY2xvc2UoKQogICAgb3BlbihzdGRpbiwndycpLmNsb3NlKCkKICAgICMgZmx1c2ggaW8KICAgIHN5cy5zdGRvdXQuZmx1c2goKQogICAgc3lzLnN0ZGVyci5mbHVzaCgpCiAgICAjIERvIGZpcnN0IGZvcmsuCiAgICB0cnk6CiAgICAgICAgaWYgb3MuZm9yaygpID4gMDoKICAgICAgICAgICAgc3lzLmV4aXQoMCkgICMgRXhpdCBmaXJzdCBwYXJlbnQuCiAgICBleGNlcHQgT1NFcnJvciwgZToKICAgICAgICBzeXMuc3RkZXJyLndyaXRlKCJmb3JrICMxIGZhaWxlZDogKCVkKSAlc1xuIiAlIChlLmVycm5vLCBlLnN0cmVycm9yKSkKICAgICAgICBzeXMuZXhpdCgxKQogICAgIyBEZWNvdXBsZSBmcm9tIHBhcmVudCBlbnZpcm9ubWVudC4KICAgIG9zLmNoZGlyKCIuLyIpCiAgICBvcy51bWFzaygwKQogICAgb3Muc2V0c2lkKCkKICAgICMgRG8gc2Vjb25kIGZvcmsuCiAgICB0cnk6CiAgICAgICAgaWYgb3MuZm9yaygpID4gMDoKICAgICAgICAgICAgc3lzLmV4aXQoMCkgICMgRXhpdCBzZWNvbmQgcGFyZW50LgogICAgZXhjZXB0IE9TRXJyb3IsIGU6CiAgICAgICAgc3lzLnN0ZGVyci53cml0ZSgiZm9yayAjMiBmYWlsZWQ6ICglZCkgJXNcbiIgJSAoZS5lcnJubywgZS5zdHJlcnJvcikpCiAgICAgICAgc3lzLmV4aXQoMSkKICAgICMgT3BlbiBmaWxlIGRlc2NyaXB0b3JzIGFuZCBwcmludCBzdGFydCBtZXNzYWdlCiAgICBpZiBub3Qgc3RkZXJyOgogICAgICAgIHN0ZGVyciA9IHN0ZG91dAogICAgICAgIHNpID0gZmlsZShzdGRpbiwgJ3InKQogICAgICAgIHNvID0gZmlsZShzdGRvdXQsICdhKycpCiAgICAgICAgc2UgPSBmaWxlKHN0ZGVyciwgJ2ErJywgMCkgICMgdW5idWZmZXJlZAogICAgICAgIHBpZCA9IHN0cihvcy5nZXRwaWQoKSkKICAgICAgICBzeXMuc3RkZXJyLndyaXRlKHN0YXJ0X21zZyAlIHBpZCkKICAgICAgICBzeXMuc3RkZXJyLmZsdXNoKCkKICAgICMgUmVkaXJlY3Qgc3RhbmRhcmQgZmlsZSBkZXNjcmlwdG9ycy4KICAgIG9zLmR1cDIoc2kuZmlsZW5vKCksIHN5cy5zdGRpbi5maWxlbm8oKSkKICAgIG9zLmR1cDIoc28uZmlsZW5vKCksIHN5cy5zdGRvdXQuZmlsZW5vKCkpCiAgICBvcy5kdXAyKHNlLmZpbGVubygpLCBzeXMuc3RkZXJyLmZpbGVubygpKQoKCmNsYXNzIFNlc3Npb24ob2JqZWN0KToKICAgIGluZGV4ID0gMAoKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBjbGllbnRfc29ja2V0KToKICAgICAgICBTZXNzaW9uLmluZGV4ICs9IDEKICAgICAgICBzZWxmLl9faWQgPSBTZXNzaW9uLmluZGV4CiAgICAgICAgc2VsZi5fX2NsaWVudF9zb2NrZXQgPSBjbGllbnRfc29ja2V0CiAgICAgICAgc2VsZi5fYXR0ciA9IHt9CgogICAgZGVmIGdldF9pZChzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5fX2lkCgogICAgZGVmIHNldF9hdHRyKHNlbGYsIGtleSwgdmFsdWUpOgogICAgICAgIHNlbGYuX2F0dHJba2V5XSA9IHZhbHVlCgogICAgZGVmIGdldF9jbGllbnRfc29ja2V0KHNlbGYpOgogICAgICAgIHJldHVybiBzZWxmLl9fY2xpZW50X3NvY2tldAoKCmNsYXNzIEFkZHJlc3NUeXBlKG9iamVjdCk6CiAgICBJUFY0ID0gMQogICAgRE9NQUlOX05BTUUgPSAzCiAgICBJUFY2ID0gNAoKCmNsYXNzIFNvY2tzQ29tbWFuZChvYmplY3QpOgogICAgQ09OTkVDVCA9IDEKICAgIEJJTkQgPSAyCiAgICBVRFBfQVNTT0NJQVRFID0gMwoKCmNsYXNzIFNvY2tzTWV0aG9kKG9iamVjdCk6CiAgICBOT19BVVRIRU5USUNBVElPTl9SRVFVSVJFRCA9IDAKICAgIEdTU19BUEkgPSAxCiAgICBVU0VSTkFNRV9QQVNTV09SRCA9IDIKCgpjbGFzcyBTZXJ2ZXJSZXBseShvYmplY3QpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIHZhbHVlKToKICAgICAgICBzZWxmLl9fdmFsdWUgPSB2YWx1ZQoKICAgIGRlZiBnZXRfYnl0ZV9zdHJpbmcoc2VsZik6CiAgICAgICAgaWYgc2VsZi5fX3ZhbHVlID09IDA6CiAgICAgICAgICAgIHJldHVybiBiJ1x4MDAnCiAgICAgICAgZWxpZiBzZWxmLl9fdmFsdWUgPT0gMToKICAgICAgICAgICAgcmV0dXJuIGInXHgwMScKICAgICAgICBlbGlmIHNlbGYuX192YWx1ZSA9PSAyOgogICAgICAgICAgICByZXR1cm4gYidceDAyJwogICAgICAgIGVsaWYgc2VsZi5fX3ZhbHVlID09IDM6CiAgICAgICAgICAgIHJldHVybiBiJ1x4MDMnCiAgICAgICAgZWxpZiBzZWxmLl9fdmFsdWUgPT0gNDoKICAgICAgICAgICAgcmV0dXJuIGInXHgwNCcKICAgICAgICBlbGlmIHNlbGYuX192YWx1ZSA9PSA1OgogICAgICAgICAgICByZXR1cm4gYidceDA1JwogICAgICAgIGVsaWYgc2VsZi5fX3ZhbHVlID09IDY6CiAgICAgICAgICAgIHJldHVybiBiJ1x4MDYnCiAgICAgICAgZWxpZiBzZWxmLl9fdmFsdWUgPT0gNzoKICAgICAgICAgICAgcmV0dXJuIGInXHgwNycKICAgICAgICBlbGlmIHNlbGYuX192YWx1ZSA9PSA4OgogICAgICAgICAgICByZXR1cm4gYidceDA4JwoKICAgIGRlZiBnZXRfdmFsdWUoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuX192YWx1ZQoKCmNsYXNzIFJlcGx5VHlwZShvYmplY3QpOgogICAgU1VDQ0VFREVEID0gU2VydmVyUmVwbHkoMCkKICAgIEdFTkVSQUxfU09DS1NfU0VSVkVSX0ZBSUxVUkUgPSBTZXJ2ZXJSZXBseSgxKQogICAgQ09OTkVDVElPTl9OT1RfQUxMT1dFRF9CWV9SVUxFU0VUID0gU2VydmVyUmVwbHkoMikKICAgIE5FVFdPUktfVU5SRUFDSEFCTEUgPSBTZXJ2ZXJSZXBseSgzKQogICAgSE9TVF9VTlJFQUNIQUJMRSA9IFNlcnZlclJlcGx5KDQpCiAgICBDT05ORUNUSU9OX1JFRlVTRUQgPSBTZXJ2ZXJSZXBseSg1KQogICAgVFRMX0VYUElSRUQgPSBTZXJ2ZXJSZXBseSg2KQogICAgQ09NTUFORF9OT1RfU1VQUE9SVEVEID0gU2VydmVyUmVwbHkoNykKICAgIEFERFJFU1NfVFlQRV9OT1RfU1VQUE9SVEVEID0gU2VydmVyUmVwbHkoOCkKCgpjbGFzcyBTb2NrZXRQaXBlKG9iamVjdCk6CiAgICBCVUZGRVJfU0laRSA9IDEwMjQgKiAxMDI0CgogICAgZGVmIF9faW5pdF9fKHNlbGYsIHNvY2tldDEsIHNvY2tldDIpOgogICAgICAgIHNlbGYuX3NvY2tldDEgPSBzb2NrZXQxCiAgICAgICAgc2VsZi5fc29ja2V0MiA9IHNvY2tldDIKICAgICAgICBzZWxmLl9fcnVubmluZyA9IEZhbHNlCgogICAgZGVmIF9fdHJhbnNmZXIoc2VsZiwgc29ja2V0MSwgc29ja2V0Mik6CiAgICAgICAgd2hpbGUgc2VsZi5fX3J1bm5pbmc6CiAgICAgICAgICAgIHRyeToKICAgICAgICAgICAgICAgIGRhdGEgPSBzb2NrZXQxLnJlY3Yoc2VsZi5CVUZGRVJfU0laRSkKICAgICAgICAgICAgICAgIGlmIGxlbihkYXRhKSA+IDA6CiAgICAgICAgICAgICAgICAgICAgc29ja2V0Mi5zZW5kYWxsKGRhdGEpCiAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgIGV4Y2VwdCBJT0Vycm9yOgogICAgICAgICAgICAgICAgc2VsZi5zdG9wKCkKICAgICAgICBzZWxmLnN0b3AoKQoKICAgIGRlZiBzdGFydChzZWxmKToKICAgICAgICBzZWxmLl9fcnVubmluZyA9IFRydWUKICAgICAgICB0aHJlYWQuc3RhcnRfbmV3X3RocmVhZChzZWxmLl9fdHJhbnNmZXIsIChzZWxmLl9zb2NrZXQxLCBzZWxmLl9zb2NrZXQyKSkKICAgICAgICB0aHJlYWQuc3RhcnRfbmV3X3RocmVhZChzZWxmLl9fdHJhbnNmZXIsIChzZWxmLl9zb2NrZXQyLCBzZWxmLl9zb2NrZXQxKSkKCiAgICBkZWYgc3RvcChzZWxmKToKICAgICAgICBzZWxmLl9zb2NrZXQxLmNsb3NlKCkKICAgICAgICBzZWxmLl9zb2NrZXQyLmNsb3NlKCkKICAgICAgICBzZWxmLl9fcnVubmluZyA9IEZhbHNlCgogICAgZGVmIGlzX3J1bm5pbmcoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuX19ydW5uaW5nCgoKY2xhc3MgQ29tbWFuZEV4ZWN1dG9yKG9iamVjdCk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgcmVtb3RlX3NlcnZlcl9ob3N0LCByZW1vdGVfc2VydmVyX3BvcnQsIHNlc3Npb24pOgogICAgICAgIHNlbGYuX19wcm94eV9zb2NrZXQgPSBzb2NrZXQoQUZfSU5FVCwgU09DS19TVFJFQU0pCiAgICAgICAgc2VsZi5fX3JlbW90ZV9zZXJ2ZXJfaG9zdCA9IHJlbW90ZV9zZXJ2ZXJfaG9zdAogICAgICAgIHNlbGYuX19yZW1vdGVfc2VydmVyX3BvcnQgPSByZW1vdGVfc2VydmVyX3BvcnQKICAgICAgICBzZWxmLl9fY2xpZW50ID0gc2Vzc2lvbi5nZXRfY2xpZW50X3NvY2tldCgpCiAgICAgICAgc2VsZi5fX3Nlc3Npb24gPSBzZXNzaW9uCgogICAgZGVmIGRvX2Nvbm5lY3Qoc2VsZik6CiAgICAgICAgIiIiCiAgICAgICAgRG8gU09DS1MgQ09OTkVDVCBtZXRob2QKICAgICAgICA6cmV0dXJuOiBOb25lCiAgICAgICAgIiIiCiAgICAgICAgcmVzdWx0ID0gc2VsZi5fX3Byb3h5X3NvY2tldC5jb25uZWN0X2V4KHNlbGYuX19nZXRfYWRkcmVzcygpKQogICAgICAgIGlmIHJlc3VsdCA9PSAwOgogICAgICAgICAgICBzZWxmLl9fY2xpZW50LnNlbmQoYnVpbGRfY29tbWFuZF9yZXNwb25zZShSZXBseVR5cGUuU1VDQ0VFREVEKSkKICAgICAgICAgICAgc29ja2V0X3BpcGUgPSBTb2NrZXRQaXBlKHNlbGYuX19jbGllbnQsIHNlbGYuX19wcm94eV9zb2NrZXQpCiAgICAgICAgICAgIHNvY2tldF9waXBlLnN0YXJ0KCkKICAgICAgICAgICAgd2hpbGUgc29ja2V0X3BpcGUuaXNfcnVubmluZygpOgogICAgICAgICAgICAgICAgcGFzcwogICAgICAgIGVsaWYgcmVzdWx0ID09IDYwOgogICAgICAgICAgICBzZWxmLl9fY2xpZW50LnNlbmQoYnVpbGRfY29tbWFuZF9yZXNwb25zZShSZXBseVR5cGUuVFRMX0VYUElSRUQpKQogICAgICAgIGVsaWYgcmVzdWx0ID09IDYxOgogICAgICAgICAgICBzZWxmLl9fY2xpZW50LnNlbmQoYnVpbGRfY29tbWFuZF9yZXNwb25zZShSZXBseVR5cGUuTkVUV09SS19VTlJFQUNIQUJMRSkpCiAgICAgICAgZWxzZToKICAgICAgICAgICAgcHJpbnQoJ0Nvbm5lY3Rpb24gRXJyb3I6WyVzXSBpcyB1bmtub3duJyAlIHJlc3VsdCkKICAgICAgICAgICAgc2VsZi5fX2NsaWVudC5zZW5kKGJ1aWxkX2NvbW1hbmRfcmVzcG9uc2UoUmVwbHlUeXBlLk5FVFdPUktfVU5SRUFDSEFCTEUpKQoKICAgIGRlZiBkb19iaW5kKHNlbGYpOgogICAgICAgIHBhc3MKCiAgICBkZWYgZG9fdWRwX2Fzc29jaWF0ZShzZWxmKToKICAgICAgICBwYXNzCgogICAgZGVmIF9fZ2V0X2FkZHJlc3Moc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuX19yZW1vdGVfc2VydmVyX2hvc3QsIHNlbGYuX19yZW1vdGVfc2VydmVyX3BvcnQKCgpjbGFzcyBVc2VyKG9iamVjdCk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgdXNlcm5hbWUsIHBhc3N3b3JkKToKICAgICAgICBzZWxmLl9fdXNlcm5hbWUgPSB1c2VybmFtZQogICAgICAgIHNlbGYuX19wYXNzd29yZCA9IHBhc3N3b3JkCgogICAgZGVmIGdldF91c2VybmFtZShzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5fX3VzZXJuYW1lCgogICAgZGVmIGdldF9wYXNzd29yZChzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5fX3Bhc3N3b3JkCgogICAgZGVmIF9fcmVwcl9fKHNlbGYpOgogICAgICAgIHJldHVybiAnPHVzZXI6IHVzZXJuYW1lPSVzLCBwYXNzd29yZD0lcz4nICUgKHNlbGYuZ2V0X3VzZXJuYW1lKCksIHNlbGYuX19wYXNzd29yZCkKCgpjbGFzcyBVc2VyTWFuYWdlcihvYmplY3QpOgogICAgZGVmIF9faW5pdF9fKHNlbGYpOgogICAgICAgIHNlbGYuX191c2VycyA9IHt9CgogICAgZGVmIGFkZF91c2VyKHNlbGYsIHVzZXIpOgogICAgICAgIHNlbGYuX191c2Vyc1t1c2VyLmdldF91c2VybmFtZSgpXSA9IHVzZXIKCiAgICBkZWYgcmVtb3ZlX3VzZXIoc2VsZiwgdXNlcm5hbWUpOgogICAgICAgIGlmIHVzZXJuYW1lIGluIHNlbGYuX191c2VyczoKICAgICAgICAgICAgZGVsIHNlbGYuX191c2Vyc1t1c2VybmFtZV0KCiAgICBkZWYgY2hlY2soc2VsZiwgdXNlcm5hbWUsIHBhc3N3b3JkKToKICAgICAgICBpZiB1c2VybmFtZSBpbiBzZWxmLl9fdXNlcnMgYW5kIHNlbGYuX191c2Vyc1t1c2VybmFtZV0uZ2V0X3Bhc3N3b3JkKCkgPT0gcGFzc3dvcmQ6CiAgICAgICAgICAgIHJldHVybiBUcnVlCiAgICAgICAgZWxzZToKICAgICAgICAgICAgcmV0dXJuIEZhbHNlCgogICAgZGVmIGdldF91c2VyKHNlbGYsIHVzZXJuYW1lKToKICAgICAgICByZXR1cm4gc2VsZi5fX3VzZXJzW3VzZXJuYW1lXQoKICAgIGRlZiBnZXRfdXNlcnMoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuX191c2VycwoKCmNsYXNzIFNvY2tzNVJlcXVlc3RIYW5kbGVyKFN0cmVhbVJlcXVlc3RIYW5kbGVyKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCByZXF1ZXN0LCBjbGllbnRfYWRkcmVzcywgc2VydmVyKToKICAgICAgICBTdHJlYW1SZXF1ZXN0SGFuZGxlci5fX2luaXRfXyhzZWxmLCByZXF1ZXN0LCBjbGllbnRfYWRkcmVzcywgc2VydmVyKQoKICAgIGRlZiBoYW5kbGUoc2VsZik6CiAgICAgICAgc2Vzc2lvbiA9IFNlc3Npb24oc2VsZi5jb25uZWN0aW9uKQogICAgICAgIHByaW50KCdDcmVhdGUgc2Vzc2lvblslc10gZm9yICVzOiVkJyAlICgxLCBzZWxmLmNsaWVudF9hZGRyZXNzWzBdLCBzZWxmLmNsaWVudF9hZGRyZXNzWzFdKSkKICAgICAgICBjbGllbnQgPSBzZWxmLmNvbm5lY3Rpb24KICAgICAgICBjbGllbnQucmVjdigxKQogICAgICAgIG1ldGhvZF9udW0sID0gc3RydWN0LnVucGFjaygnYicsIGNsaWVudC5yZWN2KDEpKQogICAgICAgIG1ldGhvZHMgPSBzdHJ1Y3QudW5wYWNrKCdiJyAqIG1ldGhvZF9udW0sIGNsaWVudC5yZWN2KG1ldGhvZF9udW0pKQogICAgICAgIGF1dGggPSBzZWxmLnNlcnZlci5pc19hdXRoKCkKICAgICAgICBpZiBtZXRob2RzLl9fY29udGFpbnNfXyhTb2Nrc01ldGhvZC5OT19BVVRIRU5USUNBVElPTl9SRVFVSVJFRCkgYW5kIG5vdCBhdXRoOgogICAgICAgICAgICBjbGllbnQuc2VuZChiIlx4MDVceDAwIikKICAgICAgICBlbGlmIG1ldGhvZHMuX19jb250YWluc19fKFNvY2tzTWV0aG9kLlVTRVJOQU1FX1BBU1NXT1JEKSBhbmQgYXV0aDoKICAgICAgICAgICAgY2xpZW50LnNlbmQoYiJceDA1XHgwMiIpCiAgICAgICAgICAgIGlmIG5vdCBzZWxmLl9fZG9fdXNlcm5hbWVfcGFzc3dvcmRfYXV0aCgpOgogICAgICAgICAgICAgICAgcHJpbnQoJ1Nlc3Npb25bJWRdIGF1dGhlbnRpY2F0aW9uIGZhaWxlZCcgJSBzZXNzaW9uLmdldF9pZCgpKQogICAgICAgICAgICAgICAgY2xvc2Vfc2Vzc2lvbihzZXNzaW9uKQogICAgICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgZWxzZToKICAgICAgICAgICAgY2xpZW50LnNlbmQoYiJceDA1XHhGRiIpCiAgICAgICAgICAgIHJldHVybgogICAgICAgIHZlcnNpb24sIGNvbW1hbmQsIHJlc2VydmVkLCBhZGRyZXNzX3R5cGUgPSBzdHJ1Y3QudW5wYWNrKCdiJyAqIDQsIGNsaWVudC5yZWN2KDQpKQogICAgICAgIGhvc3QgPSBOb25lCiAgICAgICAgcG9ydCA9IE5vbmUKICAgICAgICBpZiBhZGRyZXNzX3R5cGUgPT0gQWRkcmVzc1R5cGUuSVBWNDoKICAgICAgICAgICAgaXBfYSwgaXBfYiwgaXBfYywgaXBfZCwgcDEsIHAyID0gc3RydWN0LnVucGFjaygnYicgKiA2LCBjbGllbnQucmVjdig2KSkKICAgICAgICAgICAgaG9zdCA9IGhvc3RfZnJvbV9pcChpcF9hLCBpcF9iLCBpcF9jLCBpcF9kKQogICAgICAgICAgICBwb3J0ID0gcG9ydF9mcm9tX2J5dGUocDEsIHAyKQogICAgICAgIGVsaWYgYWRkcmVzc190eXBlID09IEFkZHJlc3NUeXBlLkRPTUFJTl9OQU1FOgogICAgICAgICAgICBob3N0X2xlbmd0aCwgPSBzdHJ1Y3QudW5wYWNrKCdiJywgY2xpZW50LnJlY3YoMSkpCiAgICAgICAgICAgIGhvc3QgPSBjbGllbnQucmVjdihob3N0X2xlbmd0aCkKICAgICAgICAgICAgcDEsIHAyID0gc3RydWN0LnVucGFjaygnYicgKiAyLCBjbGllbnQucmVjdigyKSkKICAgICAgICAgICAgcG9ydCA9IHBvcnRfZnJvbV9ieXRlKHAxLCBwMikKICAgICAgICBlbHNlOiAgIyBhZGRyZXNzIHR5cGUgbm90IHN1cHBvcnQKICAgICAgICAgICAgY2xpZW50LnNlbmQoYnVpbGRfY29tbWFuZF9yZXNwb25zZShSZXBseVR5cGUuQUREUkVTU19UWVBFX05PVF9TVVBQT1JURUQpKQoKICAgICAgICBjb21tYW5kX2V4ZWN1dG9yID0gQ29tbWFuZEV4ZWN1dG9yKGhvc3QsIHBvcnQsIHNlc3Npb24pCiAgICAgICAgaWYgY29tbWFuZCA9PSBTb2Nrc0NvbW1hbmQuQ09OTkVDVDoKICAgICAgICAgICAgcHJpbnQoIlNlc3Npb25bJXNdIFJlcXVlc3QgY29ubmVjdCAlczolZCIgJSAoc2Vzc2lvbi5nZXRfaWQoKSwgaG9zdCwgcG9ydCkpCiAgICAgICAgICAgIGNvbW1hbmRfZXhlY3V0b3IuZG9fY29ubmVjdCgpCiAgICAgICAgY2xvc2Vfc2Vzc2lvbihzZXNzaW9uKQoKICAgIGRlZiBfX2RvX3VzZXJuYW1lX3Bhc3N3b3JkX2F1dGgoc2VsZik6CiAgICAgICAgY2xpZW50ID0gc2VsZi5jb25uZWN0aW9uCiAgICAgICAgY2xpZW50LnJlY3YoMSkKICAgICAgICBsZW5ndGggPSBieXRlX3RvX2ludChzdHJ1Y3QudW5wYWNrKCdiJywgY2xpZW50LnJlY3YoMSkpWzBdKQogICAgICAgIHVzZXJuYW1lID0gY2xpZW50LnJlY3YobGVuZ3RoKQogICAgICAgIGxlbmd0aCA9IGJ5dGVfdG9faW50KHN0cnVjdC51bnBhY2soJ2InLCBjbGllbnQucmVjdigxKSlbMF0pCiAgICAgICAgcGFzc3dvcmQgPSBjbGllbnQucmVjdihsZW5ndGgpCiAgICAgICAgdXNlcl9tYW5hZ2VyID0gc2VsZi5zZXJ2ZXIuZ2V0X3VzZXJfbWFuYWdlcigpCiAgICAgICAgaWYgdXNlcl9tYW5hZ2VyLmNoZWNrKHVzZXJuYW1lLCBwYXNzd29yZCk6CiAgICAgICAgICAgIGNsaWVudC5zZW5kKGIiXHgwMVx4MDAiKQogICAgICAgICAgICByZXR1cm4gVHJ1ZQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIGNsaWVudC5zZW5kKGIiXHgwMVx4MDEiKQogICAgICAgICAgICByZXR1cm4gRmFsc2UKCgpjbGFzcyBTb2NrczVTZXJ2ZXIoVGhyZWFkaW5nVENQU2VydmVyKToKICAgICIiIgogICAgU09DS1M1IHByb3h5IHNlcnZlcgogICAgIiIiCgogICAgZGVmIF9faW5pdF9fKHNlbGYsIHBvcnQsIGF1dGg9RmFsc2UsIHVzZXJfbWFuYWdlcj1Vc2VyTWFuYWdlcigpKToKICAgICAgICBUaHJlYWRpbmdUQ1BTZXJ2ZXIuX19pbml0X18oc2VsZiwgKCcnLCBwb3J0KSwgU29ja3M1UmVxdWVzdEhhbmRsZXIpCiAgICAgICAgc2VsZi5fX3BvcnQgPSBwb3J0CiAgICAgICAgc2VsZi5fX3VzZXJzID0ge30KICAgICAgICBzZWxmLl9fYXV0aCA9IGF1dGgKICAgICAgICBzZWxmLl9fdXNlcl9tYW5hZ2VyID0gdXNlcl9tYW5hZ2VyCiAgICAgICAgc2VsZi5fX3Nlc3Npb25zID0ge30KCiAgICBkZWYgc2VydmVfZm9yZXZlcihzZWxmLCBwb2xsX2ludGVydmFsPTAuNSk6CiAgICAgICAgcHJpbnQoIkNyZWF0ZSBTT0NLUzUgc2VydmVyIGF0IHBvcnQgJWQiICUgc2VsZi5fX3BvcnQpCiAgICAgICAgVGhyZWFkaW5nVENQU2VydmVyLnNlcnZlX2ZvcmV2ZXIoc2VsZiwgcG9sbF9pbnRlcnZhbCkKCiAgICBkZWYgZmluaXNoX3JlcXVlc3Qoc2VsZiwgcmVxdWVzdCwgY2xpZW50X2FkZHJlc3MpOgogICAgICAgIEJhc2VTZXJ2ZXIuZmluaXNoX3JlcXVlc3Qoc2VsZiwgcmVxdWVzdCwgY2xpZW50X2FkZHJlc3MpCgogICAgZGVmIGlzX2F1dGgoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuX19hdXRoCgogICAgZGVmIHNldF9hdXRoKHNlbGYsIGF1dGgpOgogICAgICAgIHNlbGYuX19hdXRoID0gYXV0aAoKICAgIGRlZiBnZXRfYWxsX21hbmFnZWRfc2Vzc2lvbihzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi5fX3Nlc3Npb25zCgogICAgZGVmIGdldF9iaW5kX3BvcnQoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuX19wb3J0CgogICAgZGVmIGdldF91c2VyX21hbmFnZXIoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYuX191c2VyX21hbmFnZXIKCiAgICBkZWYgc2V0X3VzZXJfbWFuYWdlcihzZWxmLCB1c2VyX21hbmFnZXIpOgogICAgICAgIHNlbGYuX191c2VyX21hbmFnZXIgPSB1c2VyX21hbmFnZXIKCmRlZiBtYWluKCk6CiAgICBwb3J0ID0gMTA4MAogICAgYXV0aCA9IEZhbHNlCiAgICB1c2VyX21hbmFnZXIgPSBVc2VyTWFuYWdlcigpCgogICAgU29ja3M1U2VydmVyLmFsbG93X3JldXNlX2FkZHJlc3MgPSBUcnVlCiAgICBzb2NrczVfc2VydmVyID0gU29ja3M1U2VydmVyKHBvcnQsIGF1dGgsIHVzZXJfbWFuYWdlcikKICAgIHRyeToKICAgICAgICBpZiBUcnVlOgogICAgICAgICAgICBydW5fZGFlbW9uX3Byb2Nlc3Moc3RhcnRfbXNnPSdTdGFydCBTT0NLUzUgc2VydmVyIGF0IHBpZCAlc1xuJykKICAgICAgICBzb2NrczVfc2VydmVyLnNlcnZlX2ZvcmV2ZXIoKQogICAgZXhjZXB0IEtleWJvYXJkSW50ZXJydXB0OgogICAgICAgIHNvY2tzNV9zZXJ2ZXIuc2VydmVyX2Nsb3NlKCkKICAgICAgICBzb2NrczVfc2VydmVyLnNodXRkb3duKCkKICAgICAgICBwcmludCgiU09DS1M1IHNlcnZlciBzaHV0ZG93biIpCgppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogICAgbWFpbigpCg=="))