#!/usr/bin/env python3 import os import docker import ipaddress from twisted.protocols.basic import LineReceiver from twisted.internet.protocol import Factory, Protocol from twisted.internet.endpoints import TCP4ServerEndpoint from twisted.internet import reactor class SLBRManager(Protocol): def __init__(self, config): self.client_addr = None self.config = config def suicide(self): slbr_containers = self.config['docker_client'].containers.list( filters = {'label': 'description=SLBR User Container'} ) for container in slbr_containers: if container.attrs['NetworkSettings']['Networks']['slbr']['IPAddress'] == self.client_addr: container.remove(force=True) def connectionMade(self): self.client_addr = self.transport.getPeer().host if ( ipaddress.ip_address(self.client_addr) not in ipaddress.ip_network(self.config['docker_netmask']) ): print('Dropping client {} not in docker network'.format(self.client_addr)) self.transport.loseConnection() def dataReceived(self, data): message = data.decode('utf8').split(' ') command = message[0].replace('\n', '') if len(message) > 1: args = message[1:] if command == 'LOG': entry = '[{}]: {}'.format(self.client_addr, ' '.join(args)) print(entry) elif command == 'DEAD': print('Killing {}'.format(self.client_addr)) self.suicide() self.transport.loseConnection() elif command == 'SCORE': message = 'PLAYER | CHALLENGES COMPLETED\n' + ('-' * 30) + '\n' slbr_containers = self.config['docker_client'].containers.list( filters = {'label': 'description=SLBR User Container'} ) for player_addr in os.listdir('./scores'): player_name = 'err' for container in slbr_containers: if container.attrs['NetworkSettings']['Networks']['slbr']['IPAddress'] == player_addr: player_name = container.attrs['Config']['Image'].replace('slbr:', '') break message += player_name + ': ' with open('./scores/{}'.format(player_addr)) as score_file: completed_challenges = ', '.join(score_file.readlines()).replace('\n', '') message += completed_challenges + '\n' self.transport.write(bytes(message, 'utf8')) self.transport.loseConnection() elif command == 'SUBMIT' and len(args) == 2: try: challenge_num = int(args[0]) except ValueError: self.transport.loseConnection() return submitted_solution = args[1].replace('\n', '') with open(self.config['solutions_file']) as solutions_file: correct_solutions = solutions_file.readlines() correct_solutions = list(map(lambda x: x.replace('\n', ''), correct_solutions)) num_solutions = len(correct_solutions) print( '{} submitted \"{}\" as solution for challenge {}'.format( self.client_addr, submitted_solution, challenge_num ) ) game_ended = False if challenge_num <= num_solutions: print('(Correct answer is {})'.format(correct_solutions[challenge_num -1])) if correct_solutions[challenge_num -1] == submitted_solution: message = 'w00t! You got the right answer!!!' with open( '{}/{}'.format( self.config['scores_folder'], self.client_addr ), 'a+' ) as score_file: score_file.seek(0) completed_challenges = score_file.readlines() completed_challenges = list( map(lambda x: x.replace('\n', ''), completed_challenges) ) if str(challenge_num) in completed_challenges: message = 'You already submitted the correct answer for that challenge!' else: score_file.write(str(challenge_num) + '\n') if len(completed_challenges) + 1 == num_solutions: message = ( 'w00t! You got the right answer!!!\n' + 'Hey! thats all {}! that means YOU WIN!\n'.format(num_solutions) + '!!!!!!!CONGRATULATIONS!!!!!!!\n' + 'THIS CONTAINER WILL NOW SELF DESTRUCT' ) game_ended = True else: message = '|X_x| answer was rejected!!!.' else: message = ('What? You tried to submit a solution for challenge ' + '{} but there are only {} challenges!'.format( challenge_num, num_solutions )) print(message.replace('You', 'User')) self.transport.write(bytes(message + '\n', 'utf8')) self.transport.loseConnection() if game_ended: self.suicide() class SLBRManagerFactory(Factory): def __init__(self, config): self.config = config def buildProtocol(self, addr): return SLBRManager(self.config) docker_client = docker.from_env() endpoint = TCP4ServerEndpoint(reactor, 1337) endpoint.listen(SLBRManagerFactory({ 'docker_client': docker_client, 'docker_netmask': '172.19.0.0/16', 'scores_folder': './scores', 'solutions_file': './solutions.txt', 'log_file': './log.txt' })) reactor.run()