def run(self): if self.action == 'set': addr = Address.deserialize( re.search(r'Connection:(?P<addr>\S+):alive', self.channel).group('addr')) connection = DB.Connection(addr) logging.debug( "ClusterWorker responding to 'set' on connection '%s' alive status", addr) user = connection.user vpn = connection.vpn cluster = DB.Cluster(user, vpn.chal) if connection.alive: if user.status == 'active': self.ensure_cluster_up(user, vpn, cluster, connection) else: raise ValueError("Invalid state {} for user {}".format( user.status, user.id)) else: if user.status == 'active': logging.info("Removed connection %s for active user %s", connection.id, user.id) if user.status == 'disconnected': self.ensure_cluster_stopped(user, vpn, cluster) connection.delete() else: logging.debug("ClusterWorker not responding to '%s' event", self.action)
def register_vpn(): env = get_env() chal = DB.Challenge(env['NAUM_CHAL']) if len(chal.files) == 0: chal.files.extend(env['NAUM_FILES']) vpn = DB.Vpn(env['HOSTNAME']) vpn.update(veth=env['NAUM_VETHHOST'], veth_state='down', chal=chal) DB.vpns.add(vpn)
def run(self): if self.action == 'set': addr = Address.deserialize( re.search(r'Connection:(?P<addr>\S+):alive', self.channel).group('addr')) logging.debug( "VlanWorker responding to 'set' on connection '%s' alive status", addr) connection = DB.Connection(addr) # If this connection is not alive, this worker reacted to the connection being killed if connection.alive: user = connection.user vpn = connection.vpn ensure_veth_up(vpn) vlan_if = vlan_if_name(vpn.veth, user.vlan) link_status = vpn.links[user.vlan] if link_status == 'bridged': logging.info( "New connection %s traversing existing vlan link %s", connection.id, vlan_if) else: if not link_status or link_status == 'down': self.bring_up_link(vpn, user) self.bridge_cluster(vpn, user) else: logging.debug("VlanWorker not responding to '%s' event", self.action)
def client_disconnect(): env = get_env() client = '{TRUSTED_IP}:{TRUSTED_PORT}'.format(**env) connection = DB.Connection(Address(env['TRUSTED_IP'], env['TRUSTED_PORT'])) try: connection.user.connections.remove(connection) # That's a mouthful if len(connection.user.connections) == 0: connection.user.status = 'disconnected' connection.alive = False except RedisKeyError: logging.warn( "Connection {} removed from Redis prior to disconnect".format( client))
def client_connect(ccname): env = get_env() vpn = DB.Vpn(env['HOSTNAME']) if not vpn in DB.vpns: register_vpn() user = DB.users[env['COMMON_NAME']] if user: user.status = 'active' else: user = create_user(vpn, env) addr = Address(env['TRUSTED_IP'], env['TRUSTED_PORT']) connection = DB.Connection(addr) connection.update(addr=addr, vpn=vpn, user=user, alive=True) user.connections.add(connection) logging.info("New connection from {cn}@{ip}:{port} on vlan {vlan}".format( cn=env['COMMON_NAME'], vlan=user.vlan, ip=addr.ip, port=addr.port)) with open(args.ccname, 'w') as ccfile: ccfile.write(CCTEMPLATE.format(vlan=user.vlan))
def bridge_cluster(self, vpn, user): cluster = DB.Cluster(user, vpn.chal) vlan_if = vlan_if_name(vpn.veth, user.vlan) if cluster.exists() and cluster.status == 'up': bridge_id = get_bridge_id(cluster.id) BrctlCmd(BrctlCmd.ADDIF, bridge_id, vlan_if).run() vpn.links[user.vlan] = 'bridged' logging.info("Added %s to bridge %s for cluster %s", vlan_if, bridge_id, cluster.id) else: logging.info( "Cluster %s not up. Defering addition of %s to a bridge", cluster.id, vlan_if)
def create_user(vpn, env): existing_vlans = vpn.links.keys() vlan = None while not vlan: vlan = random.randint(10, 4000) if vlan in existing_vlans: vlan = None # Common name must be formatted as if it were a dns name user_id = env['COMMON_NAME'].lower() user = DB.User(user_id) user.update(vlan=vlan, cn=env['COMMON_NAME'], status='active') DB.users[env['COMMON_NAME']] = user logging.info("Welcome to new user {}".format(env['COMMON_NAME'])) return user
def create_user(vpn, env): existing_vlans = vpn.links.keys() vlan = None while not vlan: vlan = random.randint(10, 4000) if vlan in existing_vlans: vlan = None # This is currently implemented as a security measure; Never want user data possibly injected into control info # e.g. what if a user called themselves "Vpn:xxxxxxxxxxxx", taht could trigger I listener # .... well actually it wouldn't, and I can't think of any dangerous examples, so maybe I'll ditch this for readability user_id = base64.b32encode( env['COMMON_NAME'].encode('utf-8')).decode('utf-8').lower().strip('=') user = DB.User(user_id) user.update(vlan=vlan, cn=env['COMMON_NAME'], status='active') DB.users[env['COMMON_NAME']] = user logging.info("Welcome to new user {}".format(env['COMMON_NAME'])) return user
def run(self): if self.action == 'set': vpn = DB.Vpn( re.search(r'Vpn:(?P<id>\S+):veth', self.channel).group('id')) ensure_veth_up(vpn, True)