SUICIDE LINUX: BATTLE ROYALE
http://slbr.tildeverse.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
6.0 KiB
145 lines
6.0 KiB
#!/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()
|
|
|