added reachabilty check
This commit is contained in:
parent
5407ba8987
commit
1f91fd2334
1 changed files with 244 additions and 12 deletions
256
server.py
256
server.py
|
@ -1,11 +1,16 @@
|
||||||
from flask import Flask, request, redirect, url_for
|
from flask import Flask, request, redirect, url_for
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import ipaddress
|
||||||
|
import random
|
||||||
|
import subprocess
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
# where player are stored
|
# where player are stored
|
||||||
dir= "./players"
|
DB_DIR= "./db"
|
||||||
|
PLAYER_DIR = os.path.join(DB_DIR, "players")
|
||||||
|
NET_DIR = os.path.join(DB_DIR, "networks")
|
||||||
|
|
||||||
REGULAR_PAGE = """
|
REGULAR_PAGE = """
|
||||||
<html>
|
<html>
|
||||||
|
@ -20,17 +25,20 @@ IPv6 games?
|
||||||
If you want to register, simply submit your name below.
|
If you want to register, simply submit your name below.
|
||||||
Obviously, your name and IPv6 address will be publicly recorded.
|
Obviously, your name and IPv6 address will be publicly recorded.
|
||||||
|
|
||||||
|
<p>You are player: {player}
|
||||||
|
|
||||||
<h2>Register</h2>
|
<h2>Register</h2>
|
||||||
<form action="/" method=post>
|
<form action="/" method=post>
|
||||||
Your name: <input type="text" name="name">
|
Your name: <input type="text" name="name">
|
||||||
<input type="submit" value="Submit">
|
<input type="submit" value="Submit">
|
||||||
</form>
|
</form>
|
||||||
|
<p>Afterwards <a href="/net">register your network</a>
|
||||||
|
and then <a href="/check_addr">make your random ip reachable</a>.
|
||||||
|
|
||||||
|
|
||||||
<h2>Interested in playing IPv6 games are... </h2>
|
<h2>Interested in playing IPv6 games are... </h2>
|
||||||
<ul>
|
<ul>
|
||||||
{}
|
{player_list}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>Open Source</h2>
|
<h2>Open Source</h2>
|
||||||
|
@ -41,49 +49,273 @@ you can find the source code on
|
||||||
</html>
|
</html>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
NET_PAGE = """
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Register your network</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Register your network</h1>
|
||||||
|
For playing IPv6 games, you should have a free /64 network to play around with.
|
||||||
|
Use the format <b>2001:db8::/64</b>.
|
||||||
|
|
||||||
|
<h2>Register</h2>
|
||||||
|
<form action="/net" method=post>
|
||||||
|
Your network: <input type="text" name="network">
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
ADDR_CHECK_PAGE = """
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Check your network</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Check your network</h1>
|
||||||
|
To be able to prove that you control a network, we selected a random IP in it.
|
||||||
|
Only if you can make that IPv6 address <b>ping6-able</b>, then we believe that
|
||||||
|
you really control it.
|
||||||
|
|
||||||
|
<p>You are: {player}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Your registered random IPv6 address in your network is {random_ip}.
|
||||||
|
The result of the check is: {returncode} (0 mean s reachable, everything else is an error)
|
||||||
|
and the output of the ping command is:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
{output}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
(we should really convert to jinja2 now)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
NO_NETWORK = """Sorry, this is not an IPv6 network"""
|
||||||
|
NO_SLASH_64 = """Sorry, this is not a /64 IPv6 network"""
|
||||||
|
NO_USER = """Sorry, you are not a user, you cannot check your IPv6 address. Register first"""
|
||||||
|
|
||||||
|
def player_exists_at_address(address):
|
||||||
|
fname = os.path.join(PLAYER_DIR, address)
|
||||||
|
exists = False
|
||||||
|
|
||||||
|
if os.path.exists(fname):
|
||||||
|
exists = True
|
||||||
|
|
||||||
|
return exists
|
||||||
|
|
||||||
def addresses():
|
def addresses():
|
||||||
address_list = []
|
address_list = []
|
||||||
|
|
||||||
if os.path.isdir(dir):
|
if os.path.isdir(PLAYER_DIR):
|
||||||
address_list = os.listdir(dir)
|
address_list = os.listdir(PLAYER_DIR)
|
||||||
|
|
||||||
return address_list
|
return address_list
|
||||||
|
|
||||||
|
def networks():
|
||||||
|
network_list = []
|
||||||
|
|
||||||
|
if os.path.isdir(NET_DIR):
|
||||||
|
network_list = os.listdir(NET_DIR)
|
||||||
|
|
||||||
|
return network_list
|
||||||
|
|
||||||
|
|
||||||
|
def get_player_from_network(network):
|
||||||
|
fname = os.path.join(NET_DIR, network, "address")
|
||||||
|
|
||||||
|
with open(fname,"r") as fd:
|
||||||
|
address = fd.readlines()[0].strip()
|
||||||
|
|
||||||
|
return address
|
||||||
|
|
||||||
|
|
||||||
|
def get_player_network(address):
|
||||||
|
network = None
|
||||||
|
|
||||||
|
for net in networks():
|
||||||
|
fname = os.path.join(NET_DIR, net, "address")
|
||||||
|
|
||||||
|
with open(fname,"r") as fd:
|
||||||
|
net_address = fd.readlines()[0].strip()
|
||||||
|
|
||||||
|
if net_address == address:
|
||||||
|
network = net
|
||||||
|
|
||||||
|
return network
|
||||||
|
|
||||||
|
def get_player_ip(address):
|
||||||
|
random_ip = None
|
||||||
|
|
||||||
|
network = get_player_network(address)
|
||||||
|
|
||||||
|
if not network:
|
||||||
|
return None
|
||||||
|
|
||||||
|
fname = os.path.join(NET_DIR, network, "random_ip")
|
||||||
|
if os.path.exists(fname):
|
||||||
|
with open(fname,"r") as fd:
|
||||||
|
random_ip = fd.readlines()[0].strip()
|
||||||
|
|
||||||
|
return random_ip
|
||||||
|
|
||||||
def get_player_name(address):
|
def get_player_name(address):
|
||||||
fname = os.path.join(dir, address)
|
fname = os.path.join(PLAYER_DIR, address)
|
||||||
with open(fname, "r") as fd:
|
with open(fname, "r") as fd:
|
||||||
name = fd.readlines()
|
name = fd.readlines()
|
||||||
|
|
||||||
return name[0].strip()
|
return name[0].strip()
|
||||||
|
|
||||||
def save_player(name, address):
|
def save_player(name, address):
|
||||||
fname = os.path.join(dir, address)
|
fname = os.path.join(PLAYER_DIR, address)
|
||||||
|
|
||||||
with open(fname, "w+") as fd:
|
with open(fname, "w+") as fd:
|
||||||
fd.write("{}\n".format(name))
|
fd.write("{}\n".format(name))
|
||||||
|
|
||||||
|
def is_v6_network(network):
|
||||||
|
is_network = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
net = ipaddress.IPv6Network(network)
|
||||||
|
except:
|
||||||
|
is_network = False
|
||||||
|
|
||||||
|
return is_network
|
||||||
|
|
||||||
|
def is_v6_slash_64(network):
|
||||||
|
is_64 = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
net = ipaddress.IPv6Network(network)
|
||||||
|
print("{} {}".format(net, network))
|
||||||
|
|
||||||
|
if not net.prefixlen == 64:
|
||||||
|
is_64 = False
|
||||||
|
except:
|
||||||
|
is_64 = False
|
||||||
|
|
||||||
|
return is_64
|
||||||
|
|
||||||
|
def get_random_ip(network):
|
||||||
|
net = ipaddress.IPv6Network(network)
|
||||||
|
addr_offset = random.randrange(2**64)
|
||||||
|
addr = net[0] + addr_offset
|
||||||
|
|
||||||
|
return addr
|
||||||
|
|
||||||
|
def save_network(address, network):
|
||||||
|
if not is_v6_network(network):
|
||||||
|
return NO_NETWORK
|
||||||
|
|
||||||
|
if not is_v6_slash_64(network):
|
||||||
|
return NO_SLASH_64
|
||||||
|
|
||||||
|
if not os.path.isdir(NET_DIR):
|
||||||
|
os.mkdir(NET_DIR)
|
||||||
|
|
||||||
|
# get filesystem friendly name
|
||||||
|
net_name = str(ipaddress.IPv6Network(network)[0])
|
||||||
|
dirname = os.path.join(NET_DIR, net_name)
|
||||||
|
if not os.path.isdir(dirname):
|
||||||
|
os.mkdir(dirname)
|
||||||
|
|
||||||
|
fname = os.path.join(dirname, "address")
|
||||||
|
with open(fname, "w+") as fd:
|
||||||
|
fd.write("{}\n".format(address))
|
||||||
|
|
||||||
|
fname = os.path.join(dirname, "network")
|
||||||
|
with open(fname, "w+") as fd:
|
||||||
|
fd.write("{}\n".format(network))
|
||||||
|
|
||||||
|
random_ip = get_random_ip(network)
|
||||||
|
print("ip={}".format(random_ip))
|
||||||
|
fname = os.path.join(dirname, "random_ip")
|
||||||
|
with open(fname, "w+") as fd:
|
||||||
|
fd.write("{}\n".format(random_ip))
|
||||||
|
|
||||||
|
return redirect(url_for('net'))
|
||||||
|
|
||||||
|
|
||||||
|
def identify_user(address):
|
||||||
|
""" Find user by connecting IPv6 address """
|
||||||
|
|
||||||
|
player = None
|
||||||
|
|
||||||
|
# found the player
|
||||||
|
if player_exists_at_address(address):
|
||||||
|
return address
|
||||||
|
|
||||||
|
# check whether player is connecting from a registered network
|
||||||
|
v6_addr = ipaddress.IPv6Address(address)
|
||||||
|
|
||||||
|
for net in networks():
|
||||||
|
v6_net = ipaddress.IPv6Network("{}/64".format(net))
|
||||||
|
|
||||||
|
if v6_addr in v6_net:
|
||||||
|
player = get_player_from_network(net)
|
||||||
|
break
|
||||||
|
|
||||||
|
return player
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/check_addr', methods=['GET'])
|
||||||
|
def check_addr():
|
||||||
|
address = request.remote_addr
|
||||||
|
player = identify_user(address)
|
||||||
|
|
||||||
|
if not player:
|
||||||
|
return NO_USER
|
||||||
|
|
||||||
|
random_ip = get_player_ip(player)
|
||||||
|
|
||||||
|
s = subprocess.run(["ping", "-c1", random_ip], capture_output=True)
|
||||||
|
|
||||||
|
return ADDR_CHECK_PAGE.format(player=player,
|
||||||
|
random_ip=random_ip,
|
||||||
|
returncode=s.returncode,
|
||||||
|
output=s.stdout.decode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/net', methods=['GET', 'POST' ])
|
||||||
|
def net():
|
||||||
|
if request.method == 'GET':
|
||||||
|
return NET_PAGE
|
||||||
|
else:
|
||||||
|
network = request.form['network']
|
||||||
|
address = request.remote_addr
|
||||||
|
|
||||||
|
return save_network(address, network)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/', methods=['GET', 'POST' ])
|
@app.route('/', methods=['GET', 'POST' ])
|
||||||
def main():
|
def main():
|
||||||
|
address = request.remote_addr
|
||||||
|
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
html = []
|
html = []
|
||||||
|
|
||||||
|
player = identify_user(address)
|
||||||
|
|
||||||
for address in addresses():
|
for address in addresses():
|
||||||
name = get_player_name(address)
|
name = get_player_name(address)
|
||||||
html.append("<li> {}@{}".format(name,address))
|
network = get_player_network(address)
|
||||||
|
random_ip = get_player_ip(address)
|
||||||
|
|
||||||
return REGULAR_PAGE.format("\n".join(html))
|
html.append("<li> {}@{}: net: {} random_ip: {}".format(name,address, network, random_ip))
|
||||||
|
|
||||||
|
return REGULAR_PAGE.format(player_list="\n".join(html), player=player)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
name = request.form['name']
|
name = request.form['name']
|
||||||
address = request.remote_addr
|
|
||||||
save_player(name, address)
|
save_player(name, address)
|
||||||
return redirect(url_for('main'))
|
return redirect(url_for('main'))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if not os.path.isdir(dir):
|
if not os.path.isdir(DB_DIR):
|
||||||
print("Please create player directory {} before starting".format(dir))
|
os.mkdir(DB_DIR)
|
||||||
sys.exit(1)
|
|
||||||
app.run(host="::", debug=True)
|
app.run(host="::", debug=True)
|
||||||
|
|
Loading…
Reference in a new issue