mirror of https://github.com/dirtbags/moth.git
Merge branch 'master' of cfl.lanl.gov:/var/projects/gctf
This commit is contained in:
commit
b0815fdb9f
|
@ -2,7 +2,9 @@
|
||||||
*.pyc
|
*.pyc
|
||||||
*.dat
|
*.dat
|
||||||
*.swp
|
*.swp
|
||||||
|
*.tce
|
||||||
passwd
|
passwd
|
||||||
|
fake
|
||||||
target/
|
target/
|
||||||
puzzler/
|
puzzler/
|
||||||
ctf.tce
|
ctf.tce
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -17,6 +17,9 @@ all: ctf.tce
|
||||||
|
|
||||||
target: $(PYC)
|
target: $(PYC)
|
||||||
$(INSTALL) -d --mode=0755 --owner=100 $(DESTDIR)/var/lib/ctf
|
$(INSTALL) -d --mode=0755 --owner=100 $(DESTDIR)/var/lib/ctf
|
||||||
|
|
||||||
|
$(INSTALL) -d --mode=0755 --owner=100 $(DESTDIR)/var/lib/ctf/survey
|
||||||
|
|
||||||
$(INSTALL) -d $(DESTDIR)/var/lib/ctf/disabled
|
$(INSTALL) -d $(DESTDIR)/var/lib/ctf/disabled
|
||||||
touch $(DESTDIR)/var/lib/ctf/disabled/survey
|
touch $(DESTDIR)/var/lib/ctf/disabled/survey
|
||||||
|
|
||||||
|
@ -25,6 +28,7 @@ target: $(PYC)
|
||||||
|
|
||||||
$(INSTALL) -d $(DESTDIR)/usr/sbin
|
$(INSTALL) -d $(DESTDIR)/usr/sbin
|
||||||
$(INSTALL) ctfd.py $(DESTDIR)/usr/sbin
|
$(INSTALL) ctfd.py $(DESTDIR)/usr/sbin
|
||||||
|
$(INSTALL) new-contest $(DESTDIR)/usr/sbin
|
||||||
|
|
||||||
$(INSTALL) -d $(WWWDIR)
|
$(INSTALL) -d $(WWWDIR)
|
||||||
$(INSTALL) index.html intro.html ctf.css grunge.png $(WWWDIR)
|
$(INSTALL) index.html intro.html ctf.css grunge.png $(WWWDIR)
|
||||||
|
|
|
@ -40,6 +40,7 @@ class Gyopi(irc.Bot):
|
||||||
self._lvl = 0
|
self._lvl = 0
|
||||||
self._flag.set_flag( self.FLAG_DEFAULT )
|
self._flag.set_flag( self.FLAG_DEFAULT )
|
||||||
|
|
||||||
|
self._tokens = []
|
||||||
self._lastAttempt = {}
|
self._lastAttempt = {}
|
||||||
self._affiliations = {}
|
self._affiliations = {}
|
||||||
self._newPuzzle()
|
self._newPuzzle()
|
||||||
|
@ -62,7 +63,7 @@ class Gyopi(irc.Bot):
|
||||||
self.last_tb = '%s %s %s' % (t, v, infostr)
|
self.last_tb = '%s %s %s' % (t, v, infostr)
|
||||||
print(self.last_tb)
|
print(self.last_tb)
|
||||||
|
|
||||||
def cmd_join(self, sender, forum, addl):
|
def cmd_JOIN(self, sender, forum, addl):
|
||||||
"""On join, announce who has the flag."""
|
"""On join, announce who has the flag."""
|
||||||
if sender.name() in self.nicks:
|
if sender.name() in self.nicks:
|
||||||
self._tellFlag(forum)
|
self._tellFlag(forum)
|
||||||
|
@ -150,11 +151,11 @@ class Gyopi(irc.Bot):
|
||||||
self._tokens[user].remove(token)
|
self._tokens[user].remove(token)
|
||||||
|
|
||||||
|
|
||||||
def cmd_privmsg(self, sender, forum, addl):
|
def cmd_PRIVMSG(self, sender, forum, addl):
|
||||||
text = addl[0]
|
text = addl[0]
|
||||||
who = sender.name()
|
who = sender.name()
|
||||||
if text.startswith('!'):
|
if text.startswith('!'):
|
||||||
parts = text[1:].lower().split(' ', 1)
|
parts = text[1:].split(' ', 1)
|
||||||
cmd = parts[0]
|
cmd = parts[0]
|
||||||
if len(parts) > 1:
|
if len(parts) > 1:
|
||||||
args = parts[1]
|
args = parts[1]
|
||||||
|
@ -179,6 +180,7 @@ class Gyopi(irc.Bot):
|
||||||
elif cmd.startswith('h'):
|
elif cmd.startswith('h'):
|
||||||
# Help
|
# Help
|
||||||
forum.msg('Goal: Help me with my math homework, FROM ANOTHER DIMENSION!')
|
forum.msg('Goal: Help me with my math homework, FROM ANOTHER DIMENSION!')
|
||||||
|
forum.msg('Order of operations is always left to right.')
|
||||||
#forum.msg('Goal: The current winner gets to control the contest music.')
|
#forum.msg('Goal: The current winner gets to control the contest music.')
|
||||||
forum.msg('Commands: !help, !flag, !register [TEAM], !solve SOLUTION,!? EQUATION, !ops, !problem, !who')
|
forum.msg('Commands: !help, !flag, !register [TEAM], !solve SOLUTION,!? EQUATION, !ops, !problem, !who')
|
||||||
elif cmd.startswith('prob'):
|
elif cmd.startswith('prob'):
|
||||||
|
@ -208,11 +210,15 @@ class Gyopi(irc.Bot):
|
||||||
# self._giveToken(who, sender)
|
# self._giveToken(who, sender)
|
||||||
self._saveState()
|
self._saveState()
|
||||||
else:
|
else:
|
||||||
forum.msg('%s: %s != %s' % (who, attempt, answer))
|
|
||||||
forum.msg('%s: That is not correct.' % who)
|
forum.msg('%s: That is not correct.' % who)
|
||||||
|
|
||||||
# Test a simple one op command.
|
# Test a simple one op command.
|
||||||
elif cmd.startswith('?'):
|
elif cmd.startswith('?'):
|
||||||
|
if not args:
|
||||||
|
forum.msg('%s: Give me an easier problem, and I\'ll '
|
||||||
|
'give you the answer.' % who)
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tokens = badmath.parse(''.join(args))
|
tokens = badmath.parse(''.join(args))
|
||||||
except (ValueError) as msg:
|
except (ValueError) as msg:
|
||||||
|
@ -253,7 +259,7 @@ if __name__ == '__main__':
|
||||||
help='Flag server password')
|
help='Flag server password')
|
||||||
p.add_option('-d', '--path', dest='path', default='/var/lib/badmath',
|
p.add_option('-d', '--path', dest='path', default='/var/lib/badmath',
|
||||||
help='Path to where we can store state info.')
|
help='Path to where we can store state info.')
|
||||||
p.add_option('-c', '--channel', dest='channel', default='+badmath',
|
p.add_option('-c', '--channel', dest='channel', default='#badmath',
|
||||||
help='Which channel to join')
|
help='Which channel to join')
|
||||||
|
|
||||||
opts, args = p.parse_args()
|
opts, args = p.parse_args()
|
||||||
|
|
Binary file not shown.
|
@ -10,5 +10,6 @@ dev=16,ino=87557238,mode=40755,uid=0,gid=0,nlink=2,rdev=0
|
||||||
dev=16,ino=87557239,mode=40755,uid=0,gid=0,nlink=2,rdev=0
|
dev=16,ino=87557239,mode=40755,uid=0,gid=0,nlink=2,rdev=0
|
||||||
dev=16,ino=87557240,mode=40755,uid=0,gid=0,nlink=2,rdev=0
|
dev=16,ino=87557240,mode=40755,uid=0,gid=0,nlink=2,rdev=0
|
||||||
dev=16,ino=87573208,mode=100755,uid=0,gid=0,nlink=1,rdev=0
|
dev=16,ino=87573208,mode=100755,uid=0,gid=0,nlink=1,rdev=0
|
||||||
|
dev=16,ino=87573213,mode=100755,uid=0,gid=0,nlink=1,rdev=0
|
||||||
|
dev=16,ino=87573285,mode=100755,uid=0,gid=0,nlink=1,rdev=0
|
||||||
dev=16,ino=87573433,mode=100755,uid=0,gid=0,nlink=1,rdev=0
|
dev=16,ino=87573433,mode=100755,uid=0,gid=0,nlink=1,rdev=0
|
||||||
dev=16,ino=87573456,mode=100755,uid=0,gid=0,nlink=1,rdev=0
|
|
||||||
|
|
|
@ -5,4 +5,4 @@
|
||||||
DATA_PATH=/var/lib/badmath
|
DATA_PATH=/var/lib/badmath
|
||||||
mkdir -p $DATA_PATH
|
mkdir -p $DATA_PATH
|
||||||
|
|
||||||
exec envuidgid ctf python3.0 usr/lib/ctf/badmath/Gyopi.py --data=$DATA_PATH
|
exec envuidgid ctf python3 /usr/lib/ctf/badmath/Gyopi.py --path=$DATA_PATH
|
||||||
|
|
16
ctf.css
16
ctf.css
|
@ -77,3 +77,19 @@ p {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
color: #f4f4f4;
|
color: #f4f4f4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.solved {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.pollster {
|
||||||
|
margin-left: 5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.pollster td {
|
||||||
|
padding: 2px 1em 2px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.pollster thead {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
|
@ -37,6 +37,10 @@ else:
|
||||||
'house_team': 'dirtbags',
|
'house_team': 'dirtbags',
|
||||||
'passwd': '/var/lib/ctf/passwd',
|
'passwd': '/var/lib/ctf/passwd',
|
||||||
'team_colors': team_colors,
|
'team_colors': team_colors,
|
||||||
|
'poll_interval': 60,
|
||||||
|
'poll_timeout': 0.5,
|
||||||
|
'heartbeat_dir': '/var/lib/pollster',
|
||||||
|
'poll_dir': '/var/lib/www',
|
||||||
},
|
},
|
||||||
'puzzler':
|
'puzzler':
|
||||||
{'dir': '/usr/lib/www/puzzler',
|
{'dir': '/usr/lib/www/puzzler',
|
||||||
|
@ -66,3 +70,23 @@ def datafile(filename):
|
||||||
|
|
||||||
def url(path):
|
def url(path):
|
||||||
return base_url + path
|
return base_url + path
|
||||||
|
|
||||||
|
def start_html(title):
|
||||||
|
if os.environ.get('GATEWAY_INTERFACE'):
|
||||||
|
print('Content-type: text/html')
|
||||||
|
print()
|
||||||
|
print('''<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE html PUBLIC
|
||||||
|
"-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>%s</title>
|
||||||
|
<link rel="stylesheet" href="%s" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>%s</h1>
|
||||||
|
''' % (title, css, title))
|
||||||
|
|
||||||
|
def end_html():
|
||||||
|
print('</body></html>')
|
||||||
|
|
|
@ -142,6 +142,8 @@ class FlagServer(asynchat.async_chat):
|
||||||
self.inbuf.append(data)
|
self.inbuf.append(data)
|
||||||
|
|
||||||
def set_flag(self, team):
|
def set_flag(self, team):
|
||||||
|
if not self.cat:
|
||||||
|
return
|
||||||
self.flag = team
|
self.flag = team
|
||||||
self.submitter.set_flag(self.cat, team)
|
self.submitter.set_flag(self.cat, team)
|
||||||
f = open(os.path.join(flags_dir, self.cat), 'w')
|
f = open(os.path.join(flags_dir, self.cat), 'w')
|
||||||
|
|
|
@ -27,7 +27,7 @@ cat_re = re.compile(r'^[a-z]+$')
|
||||||
points_re = re.compile(r'^[0-9]+$')
|
points_re = re.compile(r'^[0-9]+$')
|
||||||
|
|
||||||
def dbg(*vals):
|
def dbg(*vals):
|
||||||
print('<--: \nContent-type: text/html\n\n--><pre>')
|
print('<!--: \nContent-type: text/html\n\n--><pre>')
|
||||||
print(*vals)
|
print(*vals)
|
||||||
print('</pre>')
|
print('</pre>')
|
||||||
|
|
||||||
|
@ -59,8 +59,6 @@ passwd = f.getfirst('w', passwd)
|
||||||
key = f.getfirst('k')
|
key = f.getfirst('k')
|
||||||
|
|
||||||
def start_html(title):
|
def start_html(title):
|
||||||
if os.environ.get('GATEWAY_INTERFACE'):
|
|
||||||
print('Content-type: text/html')
|
|
||||||
if team or passwd:
|
if team or passwd:
|
||||||
c = http.cookies.SimpleCookie()
|
c = http.cookies.SimpleCookie()
|
||||||
if team:
|
if team:
|
||||||
|
@ -68,23 +66,9 @@ def start_html(title):
|
||||||
if passwd:
|
if passwd:
|
||||||
c['passwd'] = passwd
|
c['passwd'] = passwd
|
||||||
print(c)
|
print(c)
|
||||||
print()
|
config.start_html(title)
|
||||||
print('''<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE html PUBLIC
|
|
||||||
"-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<title>%s</title>
|
|
||||||
<link rel="stylesheet" href="%s" type="text/css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>%s</h1>
|
|
||||||
''' % (title, config.css, title))
|
|
||||||
|
|
||||||
def end_html():
|
|
||||||
print('</body></html>')
|
|
||||||
|
|
||||||
|
end_html = config.end_html
|
||||||
|
|
||||||
def safe_join(*args):
|
def safe_join(*args):
|
||||||
safe = list(args[:1])
|
safe = list(args[:1])
|
||||||
|
@ -125,7 +109,17 @@ def show_puzzles(cat, cat_dir):
|
||||||
if puzzles:
|
if puzzles:
|
||||||
print('<ul>')
|
print('<ul>')
|
||||||
for p in puzzles:
|
for p in puzzles:
|
||||||
print('<li><a href="%s/%s/%d">%d</a></li>' % (base_url, cat, p, p))
|
cls = ''
|
||||||
|
try:
|
||||||
|
if p in points_by_team[(team, cat)]:
|
||||||
|
cls = 'solved'
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
print('<li><a href="%(base)s/%(cat)s/%(points)d" class="%(class)s">%(points)d</a></li>' %
|
||||||
|
{'base': base_url,
|
||||||
|
'cat': cat,
|
||||||
|
'points': p,
|
||||||
|
'class': cls})
|
||||||
if p > opened:
|
if p > opened:
|
||||||
break
|
break
|
||||||
print('</ul>')
|
print('</ul>')
|
||||||
|
|
|
@ -7,6 +7,22 @@ import string
|
||||||
from . import teams
|
from . import teams
|
||||||
from . import config
|
from . import config
|
||||||
|
|
||||||
|
def head(title):
|
||||||
|
return '''<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Team Registration</title>
|
||||||
|
<link rel="stylesheet" href="%s" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>%s</h1>
|
||||||
|
''' % (config.css, title)
|
||||||
|
|
||||||
|
def foot():
|
||||||
|
return '''</body></html>'''
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print('Content-type: text/html')
|
print('Content-type: text/html')
|
||||||
print()
|
print()
|
||||||
|
@ -17,17 +33,8 @@ def main():
|
||||||
pw = f.getfirst('pw')
|
pw = f.getfirst('pw')
|
||||||
confirm_pw = f.getfirst('confirm_pw')
|
confirm_pw = f.getfirst('confirm_pw')
|
||||||
|
|
||||||
html = string.Template('''<?xml version="1.0" encoding="UTF-8" ?>
|
html = string.Template(config.start_html('Team Registration') +
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
('''
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
||||||
<head>
|
|
||||||
<title>Team Registration</title>
|
|
||||||
<link rel="stylesheet" href="%s" type="text/css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Team Registration</h1>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Pick a short team name: you'll be typing it a lot.
|
Pick a short team name: you'll be typing it a lot.
|
||||||
</p>
|
</p>
|
||||||
|
@ -50,10 +57,8 @@ def main():
|
||||||
|
|
||||||
<input type="submit" value="Register" />
|
<input type="submit" value="Register" />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>''' % config.url('register.cgi')) +
|
||||||
</body>
|
config.end_html())
|
||||||
</html>
|
|
||||||
''' % (config.css, config.url('register.cgi')))
|
|
||||||
|
|
||||||
if not (team and pw and confirm_pw): # If we're starting from the beginning?
|
if not (team and pw and confirm_pw): # If we're starting from the beginning?
|
||||||
html = html.substitute(team_error='',
|
html = html.substitute(team_error='',
|
||||||
|
@ -66,7 +71,9 @@ def main():
|
||||||
pw_match_error='Passwords do not match')
|
pw_match_error='Passwords do not match')
|
||||||
else:
|
else:
|
||||||
teams.add(team, pw)
|
teams.add(team, pw)
|
||||||
html = 'Team registered.'
|
html = (config.start_html('Team registered') +
|
||||||
|
('<p>Congratulations, <samp>%s</samp> is now registered. Go <a href="%s">back to the front page</a> and start playing!</p>' % (team, config.url(''))) +
|
||||||
|
config.end_html())
|
||||||
|
|
||||||
print(html)
|
print(html)
|
||||||
|
|
||||||
|
|
14
ctf/teams.py
14
ctf/teams.py
|
@ -28,9 +28,7 @@ def build_teams():
|
||||||
f = open(passwdfn)
|
f = open(passwdfn)
|
||||||
for line in f:
|
for line in f:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
team, passwd = [unquote(v) for v in line.strip().split('\t')]
|
team, passwd, color = map(unquote, line.strip().split('\t'))
|
||||||
color = team_colors.pop(0)
|
|
||||||
team_colors.append(color)
|
|
||||||
teams[team] = (passwd, color)
|
teams[team] = (passwd, color)
|
||||||
except IOError:
|
except IOError:
|
||||||
pass
|
pass
|
||||||
|
@ -53,10 +51,15 @@ def exists(team):
|
||||||
return team in teams
|
return team in teams
|
||||||
|
|
||||||
def add(team, passwd):
|
def add(team, passwd):
|
||||||
|
build_teams()
|
||||||
|
color = team_colors[len(teams)%len(team_colors)]
|
||||||
|
|
||||||
|
assert team not in teams, "Team already exists."
|
||||||
|
|
||||||
f = open(passwdfn, 'a')
|
f = open(passwdfn, 'a')
|
||||||
fcntl.lockf(f, fcntl.LOCK_EX)
|
fcntl.lockf(f, fcntl.LOCK_EX)
|
||||||
f.seek(0, 2)
|
f.seek(0, 2)
|
||||||
f.write('%s\t%s\n' % (quote(team), quote(passwd)))
|
f.write('%s\t%s\t%s\n' % (quote(team), quote(passwd), quote(color)))
|
||||||
|
|
||||||
def color(team):
|
def color(team):
|
||||||
t = teams.get(team)
|
t = teams.get(team)
|
||||||
|
@ -66,6 +69,3 @@ def color(team):
|
||||||
if not t:
|
if not t:
|
||||||
return '888888'
|
return '888888'
|
||||||
return t[1]
|
return t[1]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
2
ctfd.py
2
ctfd.py
|
@ -4,6 +4,7 @@ import asyncore
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import optparse
|
import optparse
|
||||||
|
import signal
|
||||||
from ctf import pointsd
|
from ctf import pointsd
|
||||||
from ctf import flagd
|
from ctf import flagd
|
||||||
from ctf import histogram
|
from ctf import histogram
|
||||||
|
@ -38,6 +39,7 @@ def main():
|
||||||
pointsrv = pointsd.start()
|
pointsrv = pointsd.start()
|
||||||
flagsrv = flagd.start()
|
flagsrv = flagd.start()
|
||||||
|
|
||||||
|
signal.signal(signal.SIGCHLD, sigchld)
|
||||||
s = pointsrv.store
|
s = pointsrv.store
|
||||||
slen = 0
|
slen = 0
|
||||||
while True:
|
while True:
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<h1>Welcome</h1>
|
<h1>Welcome</h1>
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<li><a href="intro.html">Read the introduction</a> to this event</li>
|
<li><a href="intro.html">Read the introduction and rules</a></li>
|
||||||
<li><a href="register.cgi">Register</a> your team</li>
|
<li><a href="register.cgi">Register</a> your team</li>
|
||||||
<li><a href="scoreboard.cgi">View the score board</a></li>
|
<li><a href="scoreboard.cgi">View the score board</a></li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#! /bin/sh -e
|
||||||
|
|
||||||
|
ctime () {
|
||||||
|
stat -c %z $1 | awk '{ print $1; }'
|
||||||
|
}
|
||||||
|
|
||||||
|
rotate () {
|
||||||
|
mv $1 $1.$(ctime $1)
|
||||||
|
}
|
||||||
|
|
||||||
|
rotate /var/lib/ctf/puzzler.dat
|
||||||
|
rotate /var/lib/ctf/scores.dat
|
||||||
|
rotate /var/lib/ctf/passwd
|
||||||
|
rm -f /var/lib/ctf/flags/* || true
|
||||||
|
|
||||||
|
echo "Things you may want to tweak:"
|
||||||
|
find /var/lib/ctf/disabled
|
||||||
|
find /var/lib/kevin/tokens
|
|
@ -0,0 +1,8 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
case "$REMOTEADDR" in
|
||||||
|
10.0.0.[2-254])
|
||||||
|
touch /var/lib/pollster/$REMOTEADDR
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
|
@ -0,0 +1,249 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import socket
|
||||||
|
import traceback
|
||||||
|
import threading
|
||||||
|
import queue
|
||||||
|
|
||||||
|
from ctf import config
|
||||||
|
from ctf import pointscli
|
||||||
|
|
||||||
|
DEBUG = False
|
||||||
|
POLL_INTERVAL = config.get('poll_interval')
|
||||||
|
IP_DIR = config.get('heartbeat_dir')
|
||||||
|
REPORT_PATH = config.get('poll_dir')
|
||||||
|
SOCK_TIMEOUT = config.get('poll_timeout')
|
||||||
|
|
||||||
|
class PointSubmitter(threading.Thread):
|
||||||
|
''' Pulls point allocations from the queue and submits them. '''
|
||||||
|
def __init__(self, point_queue):
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
self.point_queue = point_queue
|
||||||
|
self.sock = pointscli.makesock('localhost')
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# loop forever
|
||||||
|
while(True):
|
||||||
|
cat, team, score = self.point_queue.get()
|
||||||
|
if None in [cat, team, score]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
pointscli.submit(cat, team, score, sock=self.sock)
|
||||||
|
except ValueError:
|
||||||
|
print('pollster: error submitting score (%s, %s, %d)' % (cat, team, score))
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
def socket_poll(ip, port, msg, prot, max_recv=1):
|
||||||
|
''' Connect via socket to the specified <ip>:<port> using the
|
||||||
|
specified <prot>, send the specified <msg> and return the
|
||||||
|
response or None if something went wrong. <max_recvs> specifies
|
||||||
|
how many times to read from the socket (default to once). '''
|
||||||
|
|
||||||
|
# create a socket
|
||||||
|
try:
|
||||||
|
sock = socket.socket(socket.AF_INET, prot)
|
||||||
|
except Exception as e:
|
||||||
|
print('pollster: create socket failed (%s)' % e)
|
||||||
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
sock.settimeout(SOCK_TIMEOUT)
|
||||||
|
|
||||||
|
# connect
|
||||||
|
try:
|
||||||
|
sock.connect((ip, port))
|
||||||
|
except socket.timeout as e:
|
||||||
|
print('pollster: attempt to connect to %s:%d timed out (%s)' % (ip, port, e))
|
||||||
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print('pollster: attempt to connect to %s:%d failed (%s)' % (ip, port, e))
|
||||||
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
# send something
|
||||||
|
sock.send(msg)
|
||||||
|
|
||||||
|
# get a response
|
||||||
|
resp = ''
|
||||||
|
try:
|
||||||
|
# first read
|
||||||
|
data = sock.recv(1024)
|
||||||
|
resp += data.decode('utf-8')
|
||||||
|
max_recv -= 1
|
||||||
|
|
||||||
|
# remaining reads as necessary until timeout or socket closes
|
||||||
|
while(len(data) > 0 and max_recv > 0):
|
||||||
|
data = sock.recv(1024)
|
||||||
|
resp += data.decode('utf-8')
|
||||||
|
max_recv -= 1
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
except socket.timeout as e:
|
||||||
|
print('pollster: timed out waiting for a response from %s:%d (%s)' % (ip, port, e))
|
||||||
|
traceback.print_exc()
|
||||||
|
except Exception as e:
|
||||||
|
print('pollster: receive from %s:%d failed (%s)' % (ip, port, e))
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if len(resp) == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
# PUT POLLS FUNCTIONS HERE
|
||||||
|
# Each function should take an IP address and return a team name or None
|
||||||
|
# if (a) the service is not up, (b) it doesn't return a valid team name.
|
||||||
|
|
||||||
|
def poll_fingerd(ip):
|
||||||
|
''' Poll the fingerd service. Returns None or a team name. '''
|
||||||
|
resp = socket_poll(ip, 79, b'flag\n', socket.SOCK_STREAM)
|
||||||
|
if resp is None:
|
||||||
|
return None
|
||||||
|
return resp.strip('\r\n')
|
||||||
|
|
||||||
|
def poll_noted(ip):
|
||||||
|
''' Poll the noted service. Returns None or a team name. '''
|
||||||
|
resp = socket_poll(ip, 4000, b'rflag\n', socket.SOCK_STREAM)
|
||||||
|
if resp is None:
|
||||||
|
return None
|
||||||
|
return resp.strip('\r\n')
|
||||||
|
|
||||||
|
def poll_catcgi(ip):
|
||||||
|
''' Poll the cat.cgi web service. Returns None or a team name. '''
|
||||||
|
request = bytes('GET /cat.cgi/flag HTTP/1.1\r\nHost: %s\r\n\r\n' % ip, 'ascii')
|
||||||
|
resp = socket_poll(ip, 80, request, socket.SOCK_STREAM, 3)
|
||||||
|
if resp is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
content = resp.split('\r\n\r\n')
|
||||||
|
if len(content) < 3:
|
||||||
|
return None
|
||||||
|
|
||||||
|
content = content[1].split('\r\n')
|
||||||
|
|
||||||
|
try:
|
||||||
|
content_len = int(content[0])
|
||||||
|
except Exception as e:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if content_len <= 0:
|
||||||
|
return None
|
||||||
|
return content[1].strip('\r\n')
|
||||||
|
|
||||||
|
def poll_tftpd(ip):
|
||||||
|
''' Poll the tftp service. Returns None or a team name. '''
|
||||||
|
resp = socket_poll(ip, 69, b'\x00\x01' + b'flag' + b'\x00' + b'octet' + b'\x00', socket.SOCK_DGRAM)
|
||||||
|
if resp is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if len(resp) <= 5:
|
||||||
|
return None
|
||||||
|
|
||||||
|
resp = resp.split('\n')[0]
|
||||||
|
return resp[4:].strip('\r\n')
|
||||||
|
|
||||||
|
# PUT POLL FUNCTIONS IN HERE OR THEY WONT BE POLLED
|
||||||
|
POLLS = {
|
||||||
|
'fingerd' : poll_fingerd,
|
||||||
|
'noted' : poll_noted,
|
||||||
|
'catcgi' : poll_catcgi,
|
||||||
|
'tftpd' : poll_tftpd,
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_re = re.compile('(\d{1,3}\.){3}\d{1,3}')
|
||||||
|
|
||||||
|
# start point submitter thread
|
||||||
|
point_queue = queue.Queue()
|
||||||
|
t = PointSubmitter(point_queue)
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
# loop forever
|
||||||
|
while True:
|
||||||
|
|
||||||
|
t_start = time.time()
|
||||||
|
|
||||||
|
# gather the list of IPs to poll
|
||||||
|
try:
|
||||||
|
ips = os.listdir(IP_DIR)
|
||||||
|
except Exception as e:
|
||||||
|
print('pollster: could not list dir %s (%s)' % (IP_DIR, e))
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.remove(REPORT_PATH)
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
out = open(REPORT_PATH, 'w')
|
||||||
|
except Exception as e:
|
||||||
|
out = None
|
||||||
|
pass
|
||||||
|
|
||||||
|
if out is not None:
|
||||||
|
out.write('<html>\n<head>\n')
|
||||||
|
out.write('<title>Pollster Results</title>\n')
|
||||||
|
out.write('<link rel="stylesheet" href="ctf.css" type="text/css" media="all" />\n')
|
||||||
|
out.write('</head><body>\n<h1>Polling Results</h1>\n')
|
||||||
|
|
||||||
|
for ip in ips:
|
||||||
|
|
||||||
|
# check file name format is ip
|
||||||
|
if ip_re.match(ip) is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# remove the file
|
||||||
|
try:
|
||||||
|
os.remove(os.path.join(IP_DIR, ip))
|
||||||
|
except Exception as e:
|
||||||
|
print('pollster: could not remove %s' % os.path.join(IP_DIR, ip))
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
|
||||||
|
if DEBUG is True:
|
||||||
|
print('ip: %s' % ip)
|
||||||
|
|
||||||
|
if out is not None:
|
||||||
|
out.write('<h2>%s</h2>\n' % ip)
|
||||||
|
out.write('<table class="pollster">\n<thead><tr><td>Service Name</td></td>')
|
||||||
|
out.write('<td>Flag Holder</td></tr></thead>\n')
|
||||||
|
|
||||||
|
# perform polls
|
||||||
|
for service,func in POLLS.items():
|
||||||
|
team = func(ip)
|
||||||
|
if team is None:
|
||||||
|
team = 'dirtbags'
|
||||||
|
|
||||||
|
if DEBUG is True:
|
||||||
|
print('\t%s - %s' % (service, team))
|
||||||
|
|
||||||
|
if out is not None:
|
||||||
|
out.write('<tr><td>%s</td><td>%s</td>\n' % (service, team))
|
||||||
|
|
||||||
|
point_queue.put((service, team, 1))
|
||||||
|
|
||||||
|
if out is not None:
|
||||||
|
out.write('</table>\n')
|
||||||
|
|
||||||
|
if DEBUG is True:
|
||||||
|
print('+-----------------------------------------+')
|
||||||
|
|
||||||
|
t_end = time.time()
|
||||||
|
exec_time = int(t_end - t_start)
|
||||||
|
sleep_time = POLL_INTERVAL - exec_time
|
||||||
|
|
||||||
|
if out is not None:
|
||||||
|
out.write('<p><b>Next poll in: %ds</b></p>\n' % sleep_time)
|
||||||
|
out.write('</body>\n</html>\n')
|
||||||
|
out.close()
|
||||||
|
|
||||||
|
# sleep until its time to poll again
|
||||||
|
time.sleep(sleep_time)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
exec udpsvd 0 9 /usr/sbin/in.heartbeatd
|
|
@ -0,0 +1,108 @@
|
||||||
|
Safe to ex<b>e</b>cute.
|
||||||
|
|
||||||
|
<img width="20" height="20" src="data:image;base64,
|
||||||
|
cjd7PTw9PDw8DQ0NDQ0NDQ8PDA0MDAwMzE5KQnYNDQ1lYmJiYmJiDTk5GRke
|
||||||
|
HjY2Kg0UFBISEhImJiYNObm9tYEBBQ3tDQ0N7e3t7ejo6A0JCQkJCgoKCh4M
|
||||||
|
DAwYmZ2VgQAEBRYWFhYFBQUFAQ0NDQwMDAwNDQ0NDQ0NDQ2NiYGBjYmBAQUF
|
||||||
|
BYWBgQ0ICAgICBgYGBkNDQ2NiYmJCZ2ZBYURFR0dHBwcGAwMDAoKCgoKGhoN
|
||||||
|
Dw8PD5ufn58LmZ2VAZWRmVFRUQ3FxcXFw8PDw8cNDQ0JCQkJISAgDSWkoKiA
|
||||||
|
AQUNLQ0NDS0tLS0pKSkNCQkJCVi9ya2tDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQsN
|
||||||
|
DQ0JCQkJJkojb0AsSGUJYA57AyNQPxEjIyMnJycNHR0dHRwcHBxbQxYWFhYW
|
||||||
|
FhQUFA0PDw8PCgoKCgkNDQ0LCwsLDg4ODQ8PDw8MDAwMDA0NDQ0NDQ0MDAwN
|
||||||
|
DQ0NDQ0NDQ0JDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDSMNDQ0NDQ0Np6amDR8fHx9d
|
||||||
|
XV1dXQ0NDdDQ0NDCwsINPj4+PmLm4uruDQ0NHBwSEhMTEw0NDQ0NDQ0NDS0N
|
||||||
|
DQ0YGBgYGBgYDQ0NDQ0tLS0tLVIYbjFjBmEIew9oGlk1VCdUMUJCUg1qB2gG
|
||||||
|
WSpeP38LVAsLZw5sDyF+ET8JCXkMeAsLUhtUC3gMaAFvMHgLbgoKVQpmD21u
|
||||||
|
MUI2VyVRDmMCZAoKTQFICkkWJCMTExMTERETExINDQ0NDQ0NDAwNDSkpKSk5
|
||||||
|
OTk5OQ0NDR10HRAQEBINWVlZWVlZWVkFmJyUkpeXl/tuagUCAwMDc+bi6u0P
|
||||||
|
Dw9a0za1WVG5bGxsbIQwMDAw2IaHh4dOjY1yRyOYnJRrTiazt7+/DQ0N8te7
|
||||||
|
LioiSg0NDQ3kBPsE+wQoWM3JwamhoaGh5DTLNMv6F0nAIY5qmsqezKRw8/cF
|
||||||
|
be1uamIzZQ1ljoqCaqVapVquPp3IQaT3Hx8fHx9W1xRndXV1J6wv8Q7xDotL
|
||||||
|
Pz3CElUOxwSUBJTBSK2OYmrq11fCxs7OeXadgg95efo6Pq7SR0NLtGbHuy4J
|
||||||
|
AYqaH824U5WQjRgcFBXcH5ZgNYRh4g4Gpzejp6+ISDwlnZ2dnZ0YzbmpKsbK
|
||||||
|
ojKmogX6KqltffCGhk/OXs6bEvd0mJAT6RmadmoCYubi6uXHOMc48TJn7gta
|
||||||
|
DF/cMDzU1NTUDVbXFMbX19c/4fMM83793SLdIq+evkG+QciNfVSEPMoL8/HI
|
||||||
|
Dn1r4tpTpVpO/Hc6yuP0snOKiLF/9gx+42CkqPOt8jv4cfuuJ8KVw5B4eHgN
|
||||||
|
DVbXFJWEhIQJjq5RrlHcZ0e4R/LbI+IaGJt3e/Z9gmls/AMXoO5t8wx5jmZI
|
||||||
|
SEhIy8nFnsCfVpUFlcCEYTJg21vPy8NijRkdFf70eQ8PjObiHc1GRcY+wbT5
|
||||||
|
ofoz8KUsyZpyDQ0NDVbXFA8eHg1dtQP9Av2k/zbOzs7Nzc3NzMzODUQwEHkK
|
||||||
|
KktrB2IUcR1kRCBBOBhiF2MQeR14eHh4DQ0N8g3yDQ0NDQ3yDfINDQ0NDQ0N
|
||||||
|
DQ0MDAwMKCgoDQEBAQF5+//3+g0NDTG1sbm9vb0NRcTAyM3Nzc0ZjIiAhoaG
|
||||||
|
hvJzdwUPDw8PUVFRUVoNDQ0dHR0dCAgIDQ0NDQ0ODg4ObpiclJaWlpaGhoYN
|
||||||
|
GRkZGQgICAgfDQ0NZefj6/r6+g1t7+vj8fHx8fkNDQ0eHh4eFhYWDfMM85zc
|
||||||
|
XlpSrfINYmNjY2OTbJNiUNLW3t7e3t7eDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0N
|
||||||
|
DQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ2ZDQkFBQUFBQUFBQWjj4uDNbez
|
||||||
|
u7u7uw0NDQ0NgRURGRlKCUpwUHg/cSQNLR4wBCocPA4+DjsLPw87GzNhBGAt
|
||||||
|
ZQRwUGNNeVdhIBgxMTF2NXZMbCViLHlQcENtWXc7GykZKR8vGysfLQVXMlZ2
|
||||||
|
Pl8rCz4QJAo8ESkAAABKCUpwUHg/cSQNLR4wBCocPA4+DjsLPw87GzNhBGAt
|
||||||
|
ZQRwUGNNeVdhIBkwMDB3NHdNbSViLHlQcENtWXc7GykZKR8vGysfLQVXMlZ2
|
||||||
|
Pl8rCz4QJAo8ESgBAQFKCUpwUHg/cSQNLR4wBCocPA4+DjsLPw87GzNhBGAt
|
||||||
|
ZQRwUGNNeVdhIBkwMDB3NHdNbSViLHlQcENtWXc7GykZKR8vGysfLQVXMlZ2
|
||||||
|
Pl8rCz4QJAo8ESkAAAAjUClEMFEzMx1ueQt/Hnx8UiFJOnkLfx58fFI7VSFo
|
||||||
|
GmpqRCpFMVR6TA5Hah5/GBg2Xmwfd3dZPUQqWSBgYE4qUz1OOkhII0QqX3EH
|
||||||
|
YhBjCmIMDCJFK15wBmN/DGUKZDtJSWcVaAQqTjdZWXcFYGFPP1MnJwlgDmd5
|
||||||
|
eVcjRj5KSmQCZApjY00/UDRVIWxsQidPEHYEZQhoaEYlUT5MPz8RaR1yAHNz
|
||||||
|
XTdUJg0jRz5QMVw1VlYjRCtfX3EWeQ0jfRFlZUsvTjpbWyNBMkFBbwxjDmNo
|
||||||
|
BnJycnJycnJyDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0N
|
||||||
|
DRYWFg0MDAwMDg4ODhqMiICUlZWVhoaGDQ0NDQ0NDQ0NDA0NDQ0NDQ0uLi4N
|
||||||
|
CgoKCggICAggjIiAqKmpqYmJiQ0NDQ0NDQ0NDQkNDQ0NDQ0NPDw8DQgICAgK
|
||||||
|
CgoKQoyIgMjJycnl5eUNCQkJCQkJCQkNDQ0NCQkJCT4+Pg0GBgYGBAQEBHCM
|
||||||
|
iID09fX1lZWVDQgICAgJCQkJDQ0NDR0dHR0iIiINDg4ODgwMDAzYjIiAVFVV
|
||||||
|
VQsLCw0NDQ0NDQ0NDQwNDQ0NDQ0NSkpKDfIN8p2fn5+frY+Lg7Gzs7O/v78N
|
||||||
|
CQkJCQkJCQkLDQ0NDw8PD1tbWw3zDPOcnp6ent6Pi4PDwcHB4eHhDQgICAgJ
|
||||||
|
CQkJDQ0NDQ0NDQ1ubm4NBAQEBAYGBgZmj4uD4+Hh4enp6Q0JCQkJCQkJCQ0N
|
||||||
|
DQ0FBQUFaWlpDQQEBAQGBgYGbo+Lg+vp6en5+fkNCQkJCQICAgIGDQ0NBQUF
|
||||||
|
BXBwcA0MDAwMCgoKCnKPi4P7+fn57u7uDQ0NDQ0NDQ0NCQ0NDQ0NDQ19fX0N
|
||||||
|
DAwMDAoKCgqaj4uDExERESEhIQ0NDQ0NDQ0NDQkNDQ0JCQkJcnJyDQwMDAwK
|
||||||
|
CgoKyo+Lg0NBQUE9PDwNDQ0NDQ0NDQ0JDQ0NDQ0NDYyMjA0MDAwMCgoKCjaJ
|
||||||
|
jYW5vb29p6enDQ0NDQ0NDQ0NCQ0NDQ0NDQ2KiooNDAwMDA4ODg5WiY2F3dnZ
|
||||||
|
2fr6+g0NDQ0NDQ0NDQkNDQ0NDQ0NgoKCDQwMDAwODg4OcomNhfn9/f35+fkN
|
||||||
|
DQ0NDQ0NDQ0JDQ0NDQ0NDZSUlA0MDAwMDw8PD4+ZnZUVERERGRkZDQ0NDQ0N
|
||||||
|
DQ0NCQ0NDQ0NDQ2tra0NDAwMDA8PDw+HmZ2VHRkZGREREQ0NDQ0NDQ0NDQkN
|
||||||
|
DQ0NDQ0NqqqqDQwMDAwPDw8Pn5mdlQUBAQEFBQUNDQ0NDQ0NDQ0JDQ0NDQ0N
|
||||||
|
DaGhoQ0LCwsLCAgICJyZnZUBBQUFzc3NDQgICAgICAgIDA0NDQUFBQWwsLAN
|
||||||
|
DAwMDA8PDw9TmJyUyM3NzcnJyQ0NDQ0NDQ0NDQkNDQ0JCQkJs7OzDQwMDAwP
|
||||||
|
Dw8Pb5iclPTx8fHl5eUNDQ0NDQ0NDQ0JDQ0NCQkJCcrKyg0MDAwMDw8PD3uY
|
||||||
|
nJTg5eXl6enpDQ0NDQ0NDQ0NCQ0NDQ0NDQ3ExMQNBQUFBQYGBgaGmJyUFBER
|
||||||
|
ERUVFQ0NDQ0NDQ0NDQkNDQ0NDQ0Nw8PDDQwMDAwMDAwMDA0NDY2IiIiGh4cN
|
||||||
|
DQ0NDQ0NDQ0MDQ0NDQ0NDRwcHA0ODg4ODg4ODg4NDQ2DhYWFUlJSDQ0NDQ0N
|
||||||
|
DQ0NDA0NDQ0NDQ0MDAwNDw8PDw8PDw8PDQ0Nxc7Ozq6qqg0WFhYWOjo6Oj4N
|
||||||
|
DQ0dHR0dFBQUDQ4ODg4ODg4ODg0NDSU1NTUBAwMNDQ0NDQ0NDQ0MDQ0NDQ0N
|
||||||
|
DQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NGZicBQUFBQUGBgcHBw0NDSWkoKioqKgN
|
||||||
|
Dg4MDAwMDAxEjIiAgICAgIODgA0NDQ0Nefj89PQNDQ0ODgoKCgoKDdlYXFRU
|
||||||
|
VFRUVw0ICAgICAg6uLwFBQUFBQYGAAAADQ0NTc/Lw8PDww0ODgkJCQkJCWmP
|
||||||
|
i4ODg4ODgICIDQ0NDQ1l5+Pr6w0NDQ4OBwcHBwcNdffz+/v7+/v4DQcHBwcH
|
||||||
|
B5cVEQUFBQUFBgYNDQ0NDQ3NT0tDQ0NDDQ4OAgICAgICPomNhYWFhYWGhosN
|
||||||
|
DQ0NDVXR1d3dDQ0NDg4AAAAAAA1x9fH5+fn5+foNAgICAgICghYSBQUFBQUG
|
||||||
|
BhYWFg0NDYURFR0dHR0NDg4fHx8fHx+PmZ2VlZWVlZaWhA0NDQ0NmQ0JAQEN
|
||||||
|
DQ0ODh0dHR0dDVHEwMjIyMjIyw0ZGRkZGRl57OgFBQUFBQYGExMTDQ0Neezo
|
||||||
|
4ODg4A0ODhgYGBgYGJiYnJSUlJSUl5eADQ0NDQ0NDQ0NDQ0NDQ4OFhYWFhYN
|
||||||
|
DQ0NDQ0NDQ0ODRQUFBQUFBQUFA0NDQ0NDg4UFBQNDQ0NDQ0NDQ0NDQ4OFRUU
|
||||||
|
FBQU8I+Lg4ODg4OBgY0NHBwcHBwcHBwcDQ0NCQn4BxsbGw2NGR0VFRUVFRQN
|
||||||
|
HR03Nzc3vysvBQUFBQUEBBUVLQ0NDZ0JDQUFBQUNDAweHltbW1snmJyUlJSU
|
||||||
|
lJWVgw1ERERExFFVXVwNDQ0MDBsbTk5ODQWGgoqKioqKiA0BAWpqampW1dEF
|
||||||
|
BQUFBQcHCwsaDQ0NDQ0NDQ0NDQ0JCfgHcHBwcPSZnZWVlZWVlJSEDYmJiYkF
|
||||||
|
kZWdnQ0NDQwMHR2MjIwNcfXx+fn5+fn4DQICnZ2dnQ2ZnQUFBQUFBAQWFr0N
|
||||||
|
DQ0VkZWdnZ2dDQ8PAwPCwsLCwg0NDQ0NDQ0JCfjyOjo6Oq46PjY2DQ0NHBwP
|
||||||
|
D97e3g1V0dXd2dnZ2cgNAwPb29vbW8/LBQUFBQUVF+YZ8A0NDXXg5Ozs7OwN
|
||||||
|
HB4ICP7+/v4qjoqCwMDAwNLS3g0LCgoKCgoKCqAMDAweHh4eCAkJDXX38/v7
|
||||||
|
+/v76Q0HBxsaGhraWFwFBQUFBRcXGxs4DAwMjBgcFBQUFA0dH+4RJyYmJqaO
|
||||||
|
ioLQ0NDQwsLODUtKSkrKX1tTUw0NDR0d7BNBQEANZebi6vLy8vLgDQEBVldX
|
||||||
|
V1dXVw3Q0NDQwsLCwrYMDAyMGBwUFBQUDR0f7hGUlZWV4ZiclJSUlJS0tKIN
|
||||||
|
nZycnKAkICgoDQ0NHx8SEoSFhQ2NGR0VFRUVFQUP/gGrqqqqKr+7BQUFBQUV
|
||||||
|
FeQbqgwMDGz5/fX19fUNHBwJCc7Pz89LmJyUlJSUlISEdfI+Pz8/vysvJycN
|
||||||
|
DQ0dH+4Rzs/PDVHV0dnd3d3dzA0DA+3s7OyYDQkFBQUFBRUVAwP4DAwMDAwM
|
||||||
|
DAwMDA0tLS0tIiAgIKCZnZWVlZWVhYd28tfV1dXV1dXV1Q0NDS0tLS0tTi9h
|
||||||
|
DVI1WDdZBnUBbB5qagl7D3wIfWsNI0BAH0ADVxhfAEwFVgJdAgJdUhZCDV8A
|
||||||
|
TAVWAlINDVINRwRWCUVEF0McQ0MzHS0tbgFsHHAVYQRgTjw8YzxYN2gPYwxv
|
||||||
|
DmI9WS1CMEMcbBlhYQd1FHkcQ2kccRxlZTplJnJCEE8KRABfAABfUhZCDV8A
|
||||||
|
RQtPEFJSDVIURgdKD1BIBkIdQkIdQghLXwBFC08QT08QT2kGWT5SPV8+Ug1u
|
||||||
|
GnUHdCtKP0dHeRxvGzVWVglNFEMCTwZFRRp8DFNlEhJNEnQdcxpFbB5sDXQr
|
||||||
|
TiBERFINaRp1KkIjTSlhBARbBGgBYwBfbh1oN1E4Vj8/T3gMfz9/OHQ9fzxS
|
||||||
|
YE5+fiFIJk87DVIhVTRGMjJtMmsCbAVaO0k7WiNSIVU0RjIybTJeZAZlOlkq
|
||||||
|
XwBpB2QQEE8QcgFyLV55GGoeHnMSexUVUg1hCGoJViVRMH8LVDlYMV8fXxhB
|
||||||
|
CEoJVmRKenolUjtVPEgXdgR2F3QrTiBERCBBNVRSIVU0RjIybQtiYwoKVQp6
|
||||||
|
CG0EamQQTy5cLk82aQxjBwdYPVk4TC0tUhVZFlQVWQZJD0sYXQlWAkMBTQhS
|
||||||
|
Ug1oBmJiPWILYwp+IUAyQCFYB34KaxltbTJ7NGt+Cm4HaTZDMFUxDVINaQh8
|
||||||
|
HUIxRWweamo1fwlWBGFqA3AEYRNQPF0ufhtoaDdoGGoPZmMKfiFAMkAhWAd+
|
||||||
|
CmsZbW0ybQpnYgxTIFQ1RzNsMw0=" alt="Santa's helpers binary" />
|
|
@ -0,0 +1 @@
|
||||||
|
It is a lovely day outside
|
|
@ -0,0 +1,2 @@
|
||||||
|
Recovery, while not strictly necessary, may be tremendously helpful.
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
This is our world now... the world of the electron and the switch, the beauty of the baud.
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
Actually, Werner, we're all tickled to here you say that. Frankly, watchin' Donny beat Nazis to death is is the closest we ever get to goin' to the movies.
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
extra special text
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
Now think real hard. You been bird-doggin' this township awhile now. They wouldn't mind a corpse of you. Now, you can luxuriate in a nice jail cell, but if your hand touches metal, I swear by my pretty floral bonnet, I will end you.
|
|
@ -1,6 +1,8 @@
|
||||||
#! /usr/bin/env python3
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
import cgi
|
import cgi
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
f = cgi.FieldStorage()
|
f = cgi.FieldStorage()
|
||||||
if f.getfirst('submit'):
|
if f.getfirst('submit'):
|
||||||
|
@ -8,6 +10,13 @@ if f.getfirst('submit'):
|
||||||
print()
|
print()
|
||||||
print('Thanks for filling in the survey.')
|
print('Thanks for filling in the survey.')
|
||||||
print()
|
print()
|
||||||
|
try:
|
||||||
|
fn = '/var/lib/ctf/survey/%s.%d.%d.txt' % (time.strftime('%Y-%m-%d'), time.time(), os.getpid())
|
||||||
|
o = open(fn, 'w')
|
||||||
|
for k in f.keys():
|
||||||
|
o.write('%s: %r\n' % (k, f.getlist(k)))
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
print('The key is:')
|
print('The key is:')
|
||||||
print(' quux blorb frotz')
|
print(' quux blorb frotz')
|
||||||
else:
|
else:
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE html PUBLIC
|
||||||
|
"-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>Survey</title>
|
||||||
|
<link rel="stylesheet" href="%s" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form method="post" action=",submit.cgi">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Did you have any trouble figuring out how to play?
|
||||||
|
<select name="getting-started">
|
||||||
|
<option>A lot of trouble</option>
|
||||||
|
<option selected="selected">Not much trouble</option>
|
||||||
|
<option>No trouble</option>
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
How difficult were the puzzles?
|
||||||
|
<select name="puzzle-strength">
|
||||||
|
<option>Too hard</option>
|
||||||
|
<option selected="selected">About right</option>
|
||||||
|
<option>Too easy</option>
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Please use the provided space for any additional comments.
|
||||||
|
</p>
|
||||||
|
<textarea name="comments" style="height: 5em; width: 40em;"></textarea>
|
||||||
|
<p>
|
||||||
|
Thanks for your feedback! We hope you had fun and learned
|
||||||
|
something!
|
||||||
|
</p>
|
||||||
|
<input type="submit" name="submit" value="Submit survey" />
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -4,38 +4,7 @@
|
||||||
recieve a key redeemable for <b>ONE MILLION POINTS</b>.
|
recieve a key redeemable for <b>ONE MILLION POINTS</b>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<fieldset>
|
<object data=",survey.html" type="text/html"
|
||||||
<legend>Survey</legend>
|
style="width: 100%; height: 40em;">
|
||||||
|
<a href=",survey.html">Survey</a>
|
||||||
<form method="post" action="submit.cgi">
|
</object>
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
Did you have any trouble figuring out how to play?
|
|
||||||
<select name="getting-started">
|
|
||||||
<option>A lot of trouble</option>
|
|
||||||
<option selected="selected">Not much trouble</option>
|
|
||||||
<option>No trouble</option>
|
|
||||||
</select>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
How difficult were the puzzles?
|
|
||||||
<select name="puzzle-strength">
|
|
||||||
<option>Too hard</option>
|
|
||||||
<option selected="selected">About right</option>
|
|
||||||
<option>Too easy</option>
|
|
||||||
</select>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Please use the provided space for any additional comments.
|
|
||||||
</p>
|
|
||||||
<textarea name="comments" style="height: 5em; width: 40em;"></textarea>
|
|
||||||
<p>
|
|
||||||
Thanks for your feedback! We hope you had fun and learned
|
|
||||||
something!
|
|
||||||
</p>
|
|
||||||
<input type="submit" name="submit" value="Submit survey" />
|
|
||||||
</form>
|
|
||||||
</fieldset>
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ TARGET = $(CURDIR)/target
|
||||||
FAKE = fakeroot -s $(CURDIR)/fake -i $(CURDIR)/fake
|
FAKE = fakeroot -s $(CURDIR)/fake -i $(CURDIR)/fake
|
||||||
INSTALL = $(FAKE) install
|
INSTALL = $(FAKE) install
|
||||||
|
|
||||||
all: 99-pwnables.tce
|
all: pwnables.tce
|
||||||
|
|
||||||
99-pwnables.tce: target
|
pwnables.tce: target
|
||||||
$(FAKE) sh -c 'cd target && tar -czf - --exclude=placeholder --exclude=*~ .' > $@
|
$(FAKE) sh -c 'cd target && tar -czf - --exclude=placeholder --exclude=*~ .' > $@
|
||||||
|
|
||||||
target:
|
target:
|
||||||
|
@ -17,13 +17,5 @@ target:
|
||||||
|
|
||||||
$(MAKE) -C daemons TARGET=$(TARGET) install
|
$(MAKE) -C daemons TARGET=$(TARGET) install
|
||||||
|
|
||||||
$(INSTALL) -d $(TARGET)/usr/lib/www
|
|
||||||
$(INSTALL) $(CGI) $(TARGET)/usr/lib/www
|
|
||||||
|
|
||||||
$(INSTALL) -D flag $(TARGET)/var/lib/tftp/flag
|
|
||||||
$(INSTALL) -D flag $(TARGET)/var/lib/notes/flag
|
|
||||||
$(INSTALL) -D flag $(TARGET)/home/flag/.plan
|
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf target
|
rm -rf target pwnables.tce
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
all: in.fingerd
|
|
|
@ -1,38 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv)
|
|
||||||
{
|
|
||||||
char user[256];
|
|
||||||
char path[512];
|
|
||||||
char *data;
|
|
||||||
FILE *f;
|
|
||||||
size_t count;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (NULL == gets(user)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for (data = user; *data; data += 1) {
|
|
||||||
if ('\r' == *data) {
|
|
||||||
*data = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (0 == user[0]) {
|
|
||||||
printf("Nobody's home.\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(path, "/home/%s/.plan", user);
|
|
||||||
f = fopen(path, "r");
|
|
||||||
if (NULL == f) {
|
|
||||||
printf("No such user.\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = path;
|
|
||||||
while (count = fread(data, sizeof(*data), 1, f)) {
|
|
||||||
fwrite(data, count, 1, stdout);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
#! /bin/sh
|
|
||||||
|
|
||||||
exec tcpsvd 0 79 /usr/sbin/in.fingerd
|
|
|
@ -0,0 +1 @@
|
||||||
|
dirtbags
|
|
@ -0,0 +1 @@
|
||||||
|
/var/lib/cat/flag
|
|
@ -0,0 +1 @@
|
||||||
|
dirtbags
|
|
@ -0,0 +1 @@
|
||||||
|
dirtbags
|
|
@ -0,0 +1 @@
|
||||||
|
dirtbags
|
|
@ -0,0 +1,9 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
# Busybox netcat doesn't support UDP unless you compile in desktop mode.
|
||||||
|
# No problem, traceroute can send a UDP packet too.
|
||||||
|
while true; do
|
||||||
|
# Apparently traceroute adds 1 to the base port (-p)
|
||||||
|
traceroute -m 2 -q 1 -p 8 10.0.0.1 2>/dev/null >/dev/null
|
||||||
|
sleep 10
|
||||||
|
done
|
|
@ -1,3 +0,0 @@
|
||||||
#! /bin/sh
|
|
||||||
|
|
||||||
exec udpsvd 0 69 tftpd /var/lib/tftp
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
exec logger -t ctfd
|
|
@ -3,12 +3,16 @@ INSTALL = $(FAKE) install -o 100
|
||||||
|
|
||||||
all: tanks.tce
|
all: tanks.tce
|
||||||
|
|
||||||
|
push: tanks.tce
|
||||||
|
netcat -l -q 0 -p 3333 < tanks.tce
|
||||||
|
|
||||||
tanks.tce: target
|
tanks.tce: target
|
||||||
$(FAKE) sh -c 'cd target && tar -czf - .' > $@
|
$(FAKE) sh -c 'cd target && tar -czf - .' > $@
|
||||||
|
|
||||||
target:
|
target:
|
||||||
$(INSTALL) -d target/var/lib/tanks/
|
$(INSTALL) -d target/var/lib/tanks/
|
||||||
$(INSTALL) -d target/var/lib/tanks/results/
|
$(INSTALL) -d target/var/lib/tanks/results/
|
||||||
|
$(INSTALL) -d target/var/lib/tanks/errors/
|
||||||
$(INSTALL) -d target/var/lib/tanks/ai/easy
|
$(INSTALL) -d target/var/lib/tanks/ai/easy
|
||||||
$(INSTALL) -d target/var/lib/tanks/ai/medium
|
$(INSTALL) -d target/var/lib/tanks/ai/medium
|
||||||
$(INSTALL) -d target/var/lib/tanks/ai/hard
|
$(INSTALL) -d target/var/lib/tanks/ai/hard
|
||||||
|
@ -17,15 +21,16 @@ target:
|
||||||
$(INSTALL) AI/medium/* target/var/lib/tanks/ai/medium/
|
$(INSTALL) AI/medium/* target/var/lib/tanks/ai/medium/
|
||||||
$(INSTALL) AI/hard/* target/var/lib/tanks/ai/hard/
|
$(INSTALL) AI/hard/* target/var/lib/tanks/ai/hard/
|
||||||
|
|
||||||
$(INSTALL) -d target/var/lib/www/tanks/
|
$(INSTALL) -d target/usr/lib/www/tanks/
|
||||||
$(INSTALL) www/* target/var/lib/www/tanks/
|
$(INSTALL) www/* target/usr/lib/www/tanks/
|
||||||
$(FAKE) ln -s target/var/lib/tanks/ target/var/lib/www/data
|
|
||||||
|
ln -s /var/lib/tanks/results target/usr/lib/www/tanks/results
|
||||||
|
|
||||||
$(INSTALL) -d target/usr/lib/python2.6/site-packages/tanks/
|
$(INSTALL) -d target/usr/lib/python2.6/site-packages/tanks/
|
||||||
$(INSTALL) lib/* target/usr/lib/python2.6/site-packages/tanks/
|
$(INSTALL) lib/* target/usr/lib/python2.6/site-packages/tanks/
|
||||||
|
|
||||||
$(INSTALL) -d target/var/service/tanks
|
$(INSTALL) -d target/var/service/tanks
|
||||||
$(INSTALL) run target/var/service/tanks/run
|
$(INSTALL) run run_tanks.py target/var/service/tanks/
|
||||||
|
|
||||||
$(INSTALL) -d target/var/service/tanks/log/
|
$(INSTALL) -d target/var/service/tanks/log/
|
||||||
$(INSTALL) log.run target/var/service/tanks/log/run
|
$(INSTALL) log.run target/var/service/tanks/log/run
|
||||||
|
|
|
@ -48,7 +48,7 @@ def displacePoly(points, disp, limits, coordSequence=False):
|
||||||
maxX, maxY = limits
|
maxX, maxY = limits
|
||||||
basePoints = []
|
basePoints = []
|
||||||
for point in points:
|
for point in points:
|
||||||
x,y = point[0] + disp[0], point[1] + disp[1]
|
x,y = int(point[0] + disp[0]), int(point[1] + disp[1])
|
||||||
|
|
||||||
# Check if duplication is needed on each axis
|
# Check if duplication is needed on each axis
|
||||||
if x > maxX:
|
if x > maxX:
|
||||||
|
|
|
@ -9,19 +9,12 @@ from urllib import unquote, quote
|
||||||
|
|
||||||
from PIL import Image, ImageColor, ImageDraw
|
from PIL import Image, ImageColor, ImageDraw
|
||||||
|
|
||||||
try:
|
|
||||||
from ctf import teams
|
|
||||||
except:
|
|
||||||
import sys
|
|
||||||
path = '/home/pflarr/repos/gctf/'
|
|
||||||
sys.path.append(path)
|
|
||||||
from ctf import teams
|
|
||||||
teams.build_teams()
|
|
||||||
|
|
||||||
import Tank
|
import Tank
|
||||||
|
|
||||||
class Pflanzarr:
|
class Pflanzarr:
|
||||||
|
|
||||||
|
TEAMS_FILE = '/var/lib/ctf/passwd'
|
||||||
|
|
||||||
FRAME_DELAY = 15
|
FRAME_DELAY = 15
|
||||||
|
|
||||||
SPACING = 150
|
SPACING = 150
|
||||||
|
@ -42,12 +35,14 @@ class Pflanzarr:
|
||||||
if not os.path.exists(self._gameDir):
|
if not os.path.exists(self._gameDir):
|
||||||
os.mkdir(self._gameDir)
|
os.mkdir(self._gameDir)
|
||||||
|
|
||||||
|
colors = self._getColors()
|
||||||
|
|
||||||
tmpPlayers = os.listdir(self._playerDir)
|
tmpPlayers = os.listdir(self._playerDir)
|
||||||
players = []
|
players = []
|
||||||
for p in tmpPlayers:
|
for p in tmpPlayers:
|
||||||
p = unquote(p)
|
p = unquote(p)
|
||||||
if not (p.startswith('.') or p.endswith('#') or p.endswith('~'))\
|
if not (p.startswith('.') or p.endswith('#') or p.endswith('~'))\
|
||||||
and p in teams.teams:
|
and p in colors:
|
||||||
players.append(p)
|
players.append(p)
|
||||||
|
|
||||||
AIs = {}
|
AIs = {}
|
||||||
|
@ -73,7 +68,7 @@ class Pflanzarr:
|
||||||
self._board = (cols*self.SPACING, rows*self.SPACING)
|
self._board = (cols*self.SPACING, rows*self.SPACING)
|
||||||
|
|
||||||
while len(players) < cols*rows:
|
while len(players) < cols*rows:
|
||||||
players.append('#default')
|
players.append(None)
|
||||||
|
|
||||||
self._tanks = []
|
self._tanks = []
|
||||||
for i in range(cols):
|
for i in range(cols):
|
||||||
|
@ -82,13 +77,13 @@ class Pflanzarr:
|
||||||
startY = j*self.SPACING + self.SPACING/2
|
startY = j*self.SPACING + self.SPACING/2
|
||||||
player = random.choice(players)
|
player = random.choice(players)
|
||||||
players.remove(player)
|
players.remove(player)
|
||||||
if player == '#default':
|
if player == None:
|
||||||
color = '#a0a0a0'
|
color = '#a0a0a0'
|
||||||
else:
|
else:
|
||||||
color = '#%s' % teams.teams[player][1]
|
color = colors[player]
|
||||||
tank = Tank.Tank( player, (startX, startY), color,
|
tank = Tank.Tank( player, (startX, startY), color,
|
||||||
self._board, testMode=True)
|
self._board, testMode=True)
|
||||||
if player == '#default':
|
if player == None:
|
||||||
tank.program(random.choice(defaultAIs))
|
tank.program(random.choice(defaultAIs))
|
||||||
else:
|
else:
|
||||||
tank.program(AIs[player])
|
tank.program(AIs[player])
|
||||||
|
@ -156,10 +151,12 @@ class Pflanzarr:
|
||||||
if tank in kills[tank]:
|
if tank in kills[tank]:
|
||||||
kills[tank].remove(tank)
|
kills[tank].remove(tank)
|
||||||
|
|
||||||
self._saveResults(kills)
|
|
||||||
for tank in self._tanks:
|
for tank in self._tanks:
|
||||||
self._outputErrors(tank)
|
self._outputErrors(tank)
|
||||||
self._makeMovie()
|
self._makeMovie()
|
||||||
|
# This needs to go after _makeMovie; the web scripts look for these
|
||||||
|
# files to see if the game has completed.
|
||||||
|
self._saveResults(kills)
|
||||||
|
|
||||||
def _killTanks(self, tanks, reason):
|
def _killTanks(self, tanks, reason):
|
||||||
for tank in tanks:
|
for tank in tanks:
|
||||||
|
@ -204,22 +201,32 @@ class Pflanzarr:
|
||||||
break
|
break
|
||||||
winner = random.choice(winners)
|
winner = random.choice(winners)
|
||||||
|
|
||||||
html = ['<html><body>',
|
html = ['<html>',
|
||||||
|
'<head><title>Game %d results</title>',
|
||||||
|
'<link href="/ctf.css" rel="stylesheet" type="text/css">',
|
||||||
|
'</head>',
|
||||||
|
'<body>',
|
||||||
'<table><tr><th>Team<th>Kills<th>Cause of Death']
|
'<table><tr><th>Team<th>Kills<th>Cause of Death']
|
||||||
for tank in tanks:
|
for tank in tanks:
|
||||||
if tank is winner:
|
if tank is winner:
|
||||||
rowStyle = 'style="color:red;"'
|
rowStyle = 'style="font-weight:bold; '\
|
||||||
|
'background-color:%s"' % tank.color
|
||||||
else:
|
else:
|
||||||
rowStyle = ''
|
rowStyle = 'style="background-color:%s"' % tank.color
|
||||||
|
if tank.name:
|
||||||
|
name = xml.sax.saxutils.escape(tank.name)
|
||||||
|
else:
|
||||||
|
name = '#default'
|
||||||
html.append('<tr %s><td>%s<td>%d<td>%s' %
|
html.append('<tr %s><td>%s<td>%d<td>%s' %
|
||||||
(rowStyle,
|
(rowStyle,
|
||||||
xml.sax.saxutils.escape(tank.name),
|
name,
|
||||||
len(kills[tank]),
|
len(kills[tank]),
|
||||||
xml.sax.saxutils.escape(tank.deathReason)))
|
xml.sax.saxutils.escape(tank.deathReason)))
|
||||||
|
|
||||||
html.append('</table><body></html>')
|
html.append('</table><body></html>')
|
||||||
|
|
||||||
if winner.name != '#default':
|
# Write a blank file if the winner is a default tank..
|
||||||
|
if winner.name != None:
|
||||||
winnerFile.write(tanks[0].name)
|
winnerFile.write(tanks[0].name)
|
||||||
winnerFile.close()
|
winnerFile.close()
|
||||||
|
|
||||||
|
@ -243,14 +250,14 @@ class Pflanzarr:
|
||||||
clearFrames = ['rm', '-rf', '%s' % self._imageDir]
|
clearFrames = ['rm', '-rf', '%s' % self._imageDir]
|
||||||
|
|
||||||
print 'Making Movie'
|
print 'Making Movie'
|
||||||
subprocess.call(movieCmd)
|
# subprocess.call(movieCmd)
|
||||||
# subprocess.call(movieCmd, stderr=open('/dev/null', 'w'),
|
subprocess.call(movieCmd, stderr=open('/dev/null', 'w'),
|
||||||
# stdout=open('/dev/null', 'w'))
|
stdout=open('/dev/null', 'w'))
|
||||||
subprocess.call(clearFrames)
|
subprocess.call(clearFrames)
|
||||||
|
|
||||||
def _outputErrors(self, tank):
|
def _outputErrors(self, tank):
|
||||||
"""Output errors for each team."""
|
"""Output errors for each team."""
|
||||||
if tank.name == '#default':
|
if tank.name == None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if tank._program.errors:
|
if tank._program.errors:
|
||||||
|
@ -379,6 +386,26 @@ class Pflanzarr:
|
||||||
|
|
||||||
return defaultAIs
|
return defaultAIs
|
||||||
|
|
||||||
|
def _getColors(self):
|
||||||
|
"""Get the team colors from the passwd file. The passwd file location
|
||||||
|
is set by self.TEAMS_FILE. Returns a dictionary of players->color"""
|
||||||
|
errorColor = '#ffffff'
|
||||||
|
|
||||||
|
try:
|
||||||
|
file = open(self.TEAMS_FILE)
|
||||||
|
except:
|
||||||
|
return {}.fromkeys(players, errorColor)
|
||||||
|
|
||||||
|
colors = {}
|
||||||
|
for line in file:
|
||||||
|
try:
|
||||||
|
team, passwd, color = map(unquote, line.split('\t'))
|
||||||
|
colors[team] = '#%s' % color
|
||||||
|
except:
|
||||||
|
colors[team] = errorColor
|
||||||
|
|
||||||
|
return colors
|
||||||
|
|
||||||
def _getGameNum(self):
|
def _getGameNum(self):
|
||||||
"""Figure out what game number this is from the past games played."""
|
"""Figure out what game number this is from the past games played."""
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ class Tank(object):
|
||||||
else:
|
else:
|
||||||
self._tAngle = tAngle
|
self._tAngle = tAngle
|
||||||
|
|
||||||
self._color = color
|
self.color = color
|
||||||
|
|
||||||
# You can't fire until fireReady is 0.
|
# You can't fire until fireReady is 0.
|
||||||
self._fireReady = self.FIRE_RATE
|
self._fireReady = self.FIRE_RATE
|
||||||
|
@ -466,7 +466,7 @@ class Tank(object):
|
||||||
|
|
||||||
# The base body rectangle.
|
# The base body rectangle.
|
||||||
for poly in gm.displacePoly(hood, self.pos, self._limits):
|
for poly in gm.displacePoly(hood, self.pos, self._limits):
|
||||||
d.polygon( poly, fill=self._color )
|
d.polygon( poly, fill=self.color )
|
||||||
|
|
||||||
# The treads
|
# The treads
|
||||||
for poly in gm.displacePoly(tread1, self.pos, self._limits) + \
|
for poly in gm.displacePoly(tread1, self.pos, self._limits) + \
|
||||||
|
@ -475,7 +475,7 @@ class Tank(object):
|
||||||
|
|
||||||
# The turret circle
|
# The turret circle
|
||||||
for poly in gm.displacePoly(self.body, self.pos, self._limits):
|
for poly in gm.displacePoly(self.body, self.pos, self._limits):
|
||||||
d.ellipse( poly, fill=self._color, outline='black')
|
d.ellipse( poly, fill=self.color, outline='black')
|
||||||
|
|
||||||
self._drawLaser(d)
|
self._drawLaser(d)
|
||||||
|
|
||||||
|
@ -491,7 +491,7 @@ class Tank(object):
|
||||||
if self._fired:
|
if self._fired:
|
||||||
laser = gm.rotatePoly( self.laser, self._angle + self._tAngle )
|
laser = gm.rotatePoly( self.laser, self._angle + self._tAngle )
|
||||||
for poly in gm.displacePoly(laser, self.pos, self._limits):
|
for poly in gm.displacePoly(laser, self.pos, self._limits):
|
||||||
drawing.polygon(poly, fill=self._color)
|
drawing.polygon(poly, fill=self.color)
|
||||||
|
|
||||||
self._fired = False
|
self._fired = False
|
||||||
|
|
||||||
|
@ -522,7 +522,7 @@ class Tank(object):
|
||||||
if self._sensorState[i]:
|
if self._sensorState[i]:
|
||||||
color = '#000000'
|
color = '#000000'
|
||||||
else:
|
else:
|
||||||
color = self._color
|
color = self.color
|
||||||
|
|
||||||
r, angle, width, tAttached = self._sensors[i]
|
r, angle, width, tAttached = self._sensors[i]
|
||||||
r = int(r)
|
r = int(r)
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
|
|
||||||
[ -f /var/lib/ctf/disabled/tanks ] && exit 0
|
[ -f /var/lib/ctf/disabled/tanks ] && exit 0
|
||||||
|
|
||||||
envuidgid ctf python2.6 run_tanks.py /var/lib/tanks/ easy 100 &
|
exec envuidgid ctf python2.6 run_tanks.py /var/lib/tanks/ easy 100 2>&1
|
||||||
envuidgid ctf report_score.py
|
#envuidgid ctf report_score.py 2>&1
|
||||||
|
|
|
@ -1,20 +1,93 @@
|
||||||
|
#! /usr/bin/python
|
||||||
|
|
||||||
|
import asynchat
|
||||||
|
import asyncore
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import socket
|
||||||
import time
|
import time
|
||||||
from tanks import Pflanzarr
|
from tanks import Pflanzarr
|
||||||
import sys
|
|
||||||
|
|
||||||
T = 60*5
|
T = 60*5
|
||||||
|
MAX_HIST = 30
|
||||||
|
HIST_STEP = 100
|
||||||
|
key = 'tanks:::2bac5e912ff2e1ad559b177eb5aeecca'
|
||||||
|
|
||||||
try:
|
class Flagger(asynchat.async_chat):
|
||||||
while 1:
|
"""Use to connect to flagd and submit the current flag holder."""
|
||||||
start = time.time()
|
|
||||||
p = Pflanzarr(sys.argv[1], sys.argv[2])
|
|
||||||
p.run(int(sys.argv[3]))
|
|
||||||
|
|
||||||
diff = time.time() - start
|
def __init__(self, addr, auth):
|
||||||
if diff - T > 0:
|
asynchat.async_chat.__init__(self)
|
||||||
time.sleep( diff - T )
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.connect((addr, 6668))
|
||||||
|
self.push(auth + '\n')
|
||||||
|
self.flag = None
|
||||||
|
|
||||||
except:
|
def handle_read(self):
|
||||||
print 'Usage: python2.6 run_tanks.py data_dir easy|medium|hard max_turns'
|
msg = self.recv(4096)
|
||||||
|
raise ValueError("Flagger died: %r" % msg)
|
||||||
|
|
||||||
|
def handle_error(self):
|
||||||
|
# If we lose the connection to flagd, nobody can score any
|
||||||
|
# points. Terminate everything.
|
||||||
|
asyncore.close_all()
|
||||||
|
asynchat.async_chat.handle_error(self)
|
||||||
|
|
||||||
|
def set_flag(self, team):
|
||||||
|
if team:
|
||||||
|
eteam = team
|
||||||
|
else:
|
||||||
|
eteam = ''
|
||||||
|
self.push(eteam + '\n')
|
||||||
|
self.flag = team
|
||||||
|
|
||||||
|
|
||||||
|
def run_tanks(args, turns, flagger):
|
||||||
|
p = Pflanzarr.Pflanzarr(args[0], args[1])
|
||||||
|
p.run(turns)
|
||||||
|
|
||||||
|
path = os.path.join(args[0], 'results')
|
||||||
|
files = os.listdir(path)
|
||||||
|
gameNums = []
|
||||||
|
for file in files:
|
||||||
|
try:
|
||||||
|
gameNums.append( int(file) )
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
gameNums.sort(reverse=True)
|
||||||
|
highest = gameNums[0]
|
||||||
|
for num in gameNums:
|
||||||
|
if highest - MAX_HIST > num and not (num % HIST_STEP == 0):
|
||||||
|
shutil.rmtree(os.path.join(path, str(num)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
winner = open('/var/lib/tanks/winner').read().strip()
|
||||||
|
except:
|
||||||
|
winner = None
|
||||||
|
flagger.set_flag(winner)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = optparse.OptionParser('DATA_DIR easy|medium|hard MAX_TURNS')
|
||||||
|
opts, args = parser.parse_args()
|
||||||
|
if (len(args) != 3) or (args[1] not in ('easy', 'medium', 'hard')):
|
||||||
|
parser.error('Wrong number of arguments')
|
||||||
|
try:
|
||||||
|
turns = int(args[2])
|
||||||
|
except:
|
||||||
|
parser.error('Invalid number of turns')
|
||||||
|
|
||||||
|
|
||||||
|
flagger = Flagger('localhost', key)
|
||||||
|
lastrun = 0
|
||||||
|
while True:
|
||||||
|
asyncore.loop(60, count=1)
|
||||||
|
now = time.time()
|
||||||
|
if now - lastrun >= 60:
|
||||||
|
run_tanks(args, turns, flagger)
|
||||||
|
lastrun = now
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print >> sys.stderr, 'hello'
|
|
@ -7,7 +7,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from Tanks import Program, setup, conditions, actions, docs
|
from tanks import Program, setup, conditions, actions, docs
|
||||||
except:
|
except:
|
||||||
path = os.getcwd().split('/')
|
path = os.getcwd().split('/')
|
||||||
path.pop()
|
path.pop()
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python3
|
||||||
|
|
||||||
print """Content-Type: text/html\n\n"""
|
print("""Content-Type: text/html\n\n""")
|
||||||
print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">\n\n"""
|
print("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">\n\n""")
|
||||||
import cgi
|
import cgi
|
||||||
import cgitb; cgitb.enable()
|
import cgitb; cgitb.enable()
|
||||||
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import Config
|
import Config
|
||||||
|
@ -16,18 +17,17 @@ except:
|
||||||
try:
|
try:
|
||||||
from ctf import teams
|
from ctf import teams
|
||||||
except:
|
except:
|
||||||
import sys
|
|
||||||
path = '/home/pflarr/repos/gctf/'
|
path = '/home/pflarr/repos/gctf/'
|
||||||
sys.path.append(path)
|
sys.path.append(path)
|
||||||
from ctf import teams
|
from ctf import teams
|
||||||
teams.build_teams()
|
teams.build_teams()
|
||||||
|
|
||||||
head = open('head.html').read() % "Error Report"
|
head = open('head.html').read() % "Error Report"
|
||||||
print head
|
print(head)
|
||||||
print open('links.html').read()
|
print(open('links.html').read())
|
||||||
|
|
||||||
def done():
|
def done():
|
||||||
print '</body></html>'
|
print('</body></html>')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
fields = cgi.FieldStorage()
|
fields = cgi.FieldStorage()
|
||||||
|
@ -38,25 +38,25 @@ if team and passwd and \
|
||||||
path = os.path.join(Config.DATA_PATH, 'errors', quote(team))
|
path = os.path.join(Config.DATA_PATH, 'errors', quote(team))
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
errors = open(path).readlines()
|
errors = open(path).readlines()
|
||||||
print '<p>Your latest errors:'
|
print('<p>Your latest errors:')
|
||||||
print '<div class=errors>'
|
print('<div class=errors>')
|
||||||
if errors:
|
if errors:
|
||||||
print '<BR>\n'.join(errors)
|
print('<BR>\n'.join(errors))
|
||||||
else:
|
else:
|
||||||
print 'There were no errors.'
|
print('There were no errors.')
|
||||||
print '</div>'
|
print('</div>')
|
||||||
else:
|
else:
|
||||||
print '<p>No error file found.'
|
print('<p>No error file found.')
|
||||||
|
|
||||||
done()
|
done()
|
||||||
|
|
||||||
if team and team not in teams.teams:
|
if team and team not in teams.teams:
|
||||||
print '<p>Invalid team.'
|
print('<p>Invalid team.')
|
||||||
|
|
||||||
if team and team in teams.teams and passwd != teams.teams[team][0]:
|
if team and team in teams.teams and passwd != teams.teams[team][0]:
|
||||||
print '<p>Invalid password.'
|
print('<p>Invalid password.')
|
||||||
|
|
||||||
print '''
|
print('''
|
||||||
<form action="errors.cgi" method="get">
|
<form action="errors.cgi" method="get">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Error report request:</legend>
|
<legend>Error report request:</legend>
|
||||||
|
@ -64,6 +64,6 @@ print '''
|
||||||
Password: <input type="text" name="passwd"><BR>
|
Password: <input type="text" name="passwd"><BR>
|
||||||
<button type="get my errors">Submit</button>
|
<button type="get my errors">Submit</button>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>'''
|
</form>''')
|
||||||
|
|
||||||
done()
|
done()
|
||||||
|
|
|
@ -28,22 +28,28 @@ except:
|
||||||
|
|
||||||
if not games:
|
if not games:
|
||||||
print "<p>No games have occurred yet."
|
print "<p>No games have occurred yet."
|
||||||
|
|
||||||
gameNums = []
|
gameNums = []
|
||||||
for game in games:
|
for game in games:
|
||||||
try:
|
try:
|
||||||
num = int(game)
|
gameNums.append( int(game) )
|
||||||
path = os.path.join( 'results', game, 'results.html')
|
|
||||||
if os.path.exists( path ):
|
|
||||||
gameNums.append( int(num) )
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
gameNums.sort(reverse=True)
|
gameNums.sort(reverse=True)
|
||||||
|
|
||||||
|
# Don't include games that haven't completed
|
||||||
|
i = 0
|
||||||
|
num = str(gameNums[i])
|
||||||
|
for i in range(len(gameNums)):
|
||||||
|
path = os.path.join( 'results', str(gameNums[i]), 'results.html') )
|
||||||
|
if os.path.exists( path ):
|
||||||
|
break
|
||||||
|
gameNums = gameNums[i:]
|
||||||
|
|
||||||
for num in gameNums:
|
for num in gameNums:
|
||||||
print '<p>%d - ' % num,
|
print '<p>%d - ' % num,
|
||||||
print '<a href="results/%d/game.avi">v</a>' % num,
|
print '<a href="results/%d/game.avi">v</a>' % num,
|
||||||
print '<a href="results/%d/results.html">r</a>' % num
|
print '<a href="results/%d/results.html">r</a>' % num
|
||||||
|
|
||||||
|
print '</body></html>'
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
print("Content-Type: text/html\n\n")
|
||||||
|
print("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">\n\n""")
|
||||||
import cgi
|
import cgi
|
||||||
import cgitb; cgitb.enable()
|
import cgitb; cgitb.enable()
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
import Config
|
import Config
|
||||||
|
|
||||||
|
@ -14,21 +17,18 @@ except:
|
||||||
try:
|
try:
|
||||||
from ctf import teams
|
from ctf import teams
|
||||||
except:
|
except:
|
||||||
import sys
|
|
||||||
path = '/home/pflarr/repos/gctf/'
|
path = '/home/pflarr/repos/gctf/'
|
||||||
sys.path.append(path)
|
sys.path.append(path)
|
||||||
from ctf import teams
|
from ctf import teams
|
||||||
teams.build_teams()
|
teams.build_teams()
|
||||||
|
|
||||||
print """Content-Type: text/html\n\n"""
|
|
||||||
print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">\n\n"""
|
|
||||||
head = open('head.html').read() % "Submission Results"
|
head = open('head.html').read() % "Submission Results"
|
||||||
print head
|
print(head)
|
||||||
print "<H1>Results</H1>"
|
print("<H1>Results</H1>")
|
||||||
print open('links.html').read()
|
print(open('links.html').read())
|
||||||
|
|
||||||
def done():
|
def done():
|
||||||
print '</body></html>'
|
print('</body></html>')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
fields = cgi.FieldStorage()
|
fields = cgi.FieldStorage()
|
||||||
|
@ -36,21 +36,23 @@ team = fields.getfirst('team', '').strip()
|
||||||
passwd = fields.getfirst('passwd', '').strip()
|
passwd = fields.getfirst('passwd', '').strip()
|
||||||
code = fields.getfirst('code', '')
|
code = fields.getfirst('code', '')
|
||||||
if not team:
|
if not team:
|
||||||
print '<p>No team specified'; done()
|
print('<p>No team specified'); done()
|
||||||
elif not passwd:
|
elif not passwd:
|
||||||
print '<p>No password given'; done()
|
print('<p>No password given'); done()
|
||||||
elif not code:
|
elif not code:
|
||||||
print '<p>No program given.'; done()
|
print('<p>No program given.'); done()
|
||||||
|
|
||||||
if team not in teams.teams:
|
if team not in teams.teams:
|
||||||
print '<p>Team is not registered.'; done()
|
print('<p>Team is not registered.'); done()
|
||||||
|
|
||||||
if passwd != teams.teams[team][0]:
|
if passwd != teams.teams[team][0]:
|
||||||
print '<p>Invalid password.'; done()
|
print('<p>Invalid password.'); done()
|
||||||
|
|
||||||
path = os.path.join(Config.DATA_PATH, 'ai/players', encode(team) )
|
path = os.path.join(Config.DATA_PATH, 'ai/players', quote(team) )
|
||||||
file = open(path, 'w')
|
file = open(path, 'w')
|
||||||
file.write(code)
|
file.write(code)
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
print("<P>Submission Successful")
|
||||||
|
|
||||||
done()
|
done()
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
FAKE = fakeroot -s fake -i fake
|
||||||
|
INSTALL = $(FAKE) install -o 100
|
||||||
|
|
||||||
|
all: tanksFlagger.tce
|
||||||
|
|
||||||
|
push: tanksFlagger.tce
|
||||||
|
netcat -l -q 0 -p 3333 < tanksFlagger.tce
|
||||||
|
|
||||||
|
tanksFlagger.tce: target
|
||||||
|
$(FAKE) sh -c 'cd target && tar -czf - .' > $@
|
||||||
|
|
||||||
|
target:
|
||||||
|
$(INSTALL) -d target/var/service/tanksFlagger
|
||||||
|
$(INSTALL) run report_score.py target/var/service/tanksFlagger/
|
||||||
|
|
||||||
|
$(INSTALL) -d target/var/service/tanksFlagger/log/
|
||||||
|
$(INSTALL) log.run target/var/service/tanksFlagger/log/run
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf target tanksFlagger.tce fake
|
|
@ -0,0 +1,3 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
exec logger -t tanksFlagger
|
|
@ -0,0 +1,5 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
[ -f /var/lib/ctf/disabled/tanks ] && exit 0
|
||||||
|
|
||||||
|
exec envuidgid ctf python3 report_score.py 2>&1
|
Loading…
Reference in New Issue