This commit is contained in:
Houtworm 2023-06-09 01:15:02 +02:00
commit aea9f4f27c
33 changed files with 1494 additions and 0 deletions

BIN
net_practice/._index.html Normal file

Binary file not shown.

5
net_practice/License Normal file
View File

@ -0,0 +1,5 @@
NetPractice projet - 42
This content is provided to you for educational purpose, as part of your curriculum in 42.
It is not authorized to duplicate or modify or use it in any other context (personal, commercial, public, open source, ...).

View File

@ -0,0 +1,111 @@
/* net Practice CSS */
/* Warning : some parameters are set / modified by script */
body {
font-family: sans-serif;
padding:0px;
margin:0px;
background-image:url("../img/site42-bg.gif");
}
div {
box-sizing: border-box;
}
/* message box in index.html */
.intro_div {
background-color: #00AAAA;
border: 5px solid #00AAAA;
border-radius: 5px;
padding:10px;
width:50%;
margin:auto;
margin-top: 25%;
text-align: center;
}
/* goals div */
.goals_div {
background-color: #00AAAA;
width:100%;
border:5px solid #00AAAA;
border-radius:5px;
padding: 5px;
}
.goals_div h2 {
margin:5px;
font-style:italic;
}
/* SVG layer */
.svg_layer {
z-index:-4;
position:absolute;
top:0px;
left:0px;
}
/* logs window */
.logs_div {
background-color: #FFAAAA;
border:3px solid #FFAAAA;
border-radius:3px;
position:fixed;
bottom:0px;
right:0px;
width:250px;
height:200px;
font-size:70%;
overflow-y: scroll;
}
/* host div (image) */
.host_div {
background-size:contain;
background-repeat: no-repeat;
background-position: center;
/* will be updated by script : position, top, left, width, height, background-image */
}
/* host info (name, route) div */
.host_info_div {
min-width: 170px;
min-height: 50px;
background-color:rgba(150, 150, 255, 0.9);
border: 3px solid rgba(150, 150, 255, 0.9);
border-radius: 3px;
/* will be updated by script : position, top, left */
}
.host_info_div table {
text-align:center;
}
/* interface div */
.itf_div {
min-width: 176px;
height: 70px;
background-color: rgba(150, 150, 150, 0.9);
border: 3px solid rgba(150, 150, 150, 0.9);
border-radius: 3px;
/* will be updated by script : position, top, left */
}
/* intro footnote */
.footnote {
font-size:70%;
font-style:italic;
}

15
net_practice/end.html Normal file
View File

@ -0,0 +1,15 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<meta charset="UTF-8">
</head>
<body>
<div class='intro_div'>
Completed !<br />
Thanks for learning basics of networking with us :) <br />
There are many other network-related topics that you can explore on your own. Stay curious !
<input type=button value="Back to start" onclick='window.location="index.html";'>
</div>
</body>
</html>

BIN
net_practice/img/host.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
net_practice/img/router.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
net_practice/img/switch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

19
net_practice/index.html Normal file
View File

@ -0,0 +1,19 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<script src="js/intro.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div class='intro_div'>
Welcome to 42's NetPractice !<br />
Please enter your intranet login (the moulinette will use it to know your own configuration) : <br />
<input id='input_login' type=text size=8><br />
Or leave empty for a defense : 3 random level from 6 to 10 will be offered to be solved in 15 minutes.<br />
<span class='footnote'>Note: the architecture and addresses used in the following levels are fictionnous and are not connected to real configurations.</span><br />
<input type=button value="Start !" onclick='save_login();'>
</div>
<script>document.getElementById('input_login').value = load_login();</script>
</body>
</html>

25
net_practice/js/intro.js Normal file
View File

@ -0,0 +1,25 @@
function save_login()
{
var login = document.getElementById('input_login').value;
localStorage.setItem("g_my_login", login);
if (login == '')
{
var lvl = Math.round(6 + 4*Math.random());
localStorage.setItem("g_my_eval", JSON.stringify([lvl]));
window.location = "level"+lvl+".html";
}
else
window.location = 'level1.html';
}
function load_login()
{
var login;
if (!(login = localStorage.getItem("g_my_login")))
login = ''; // will means full random during sim.
return (login);
}

31
net_practice/js/level1.js Normal file
View File

@ -0,0 +1,31 @@
var level = 1;
var hosts = [
{'id':'A', 'type':'client', 'name':'my PC', 'geometry':'200x220+250+500', 'img':'host.png', 'labelpos':'0,200'},
{'id':'B', 'type':'client', 'name':'my little brother\'s computer', 'geometry':'200x220+250+100', 'img':'host.png', 'labelpos':'180,30'},
{'id':'C', 'type':'client', 'name':'my Mac', 'geometry':'200x220+700+500', 'img':'host.png', 'labelpos':'0,200'},
{'id':'D', 'type':'client', 'name':'my little sister\'s computer', 'geometry':'200x220+700+100', 'img':'host.png', 'labelpos':'180,30'}
];
// routes are processed in order, first match only is used => default must be last - KEEP routes before interfaces for random reference
var routes = [
];
var ifs = [
{'if':'A1', 'hid':'A', 'ip':'104.93.23.[260-399]a', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'false', 'type':'std', 'pos':'-90,-50'},
{'if':'B1', 'hid':'B', 'ip':'104.[94-99]b.23.12', 'mask':'255.255.255.0', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'110,200'},
{'if':'C1', 'hid':'C', 'ip':'211.191.[1-254]c.75', 'mask':'255.255.0.0', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'-90,-50'},
{'if':'D1', 'hid':'D', 'ip':'211.190.[260-399]d.42', 'mask':'255.255.0.0', 'ip_edit':'true', 'mask_edit':'false', 'type':'std', 'pos':'110,200'}
];
var links = [
{'if1':'A1', 'if2':'B1'},
{'if1':'C1', 'if2':'D1'}
];
var goals = [
{'id':'1', 'type':'reach', 'id1':'A', 'id2':'B'},
{'id':'2', 'type':'reach', 'id1':'C', 'id2':'D'}
];

View File

@ -0,0 +1,63 @@
var level = 10;
var hosts = [
{'id':'H1', 'type':'client', 'name':'Host one', 'geometry':'200x220+900+800', 'img':'host.png', 'labelpos':'0,200'},
{'id':'H2', 'type':'client', 'name':'Host two', 'geometry':'200x220+800+200', 'img':'host.png', 'labelpos':'180,30'},
{'id':'H3', 'type':'client', 'name':'Host three', 'geometry':'200x220+600+1200', 'img':'host.png', 'labelpos':'180,100'},
{'id':'H4', 'type':'client', 'name':'Host four', 'geometry':'200x220+100+1200', 'img':'host.png', 'labelpos':'180,100'},
{'id':'R1', 'type':'router', 'name':'Router one', 'geometry':'200x200+400+500', 'img':'router.png', 'labelpos':'-150,150'},
{'id':'R2', 'type':'router', 'name':'Router two', 'geometry':'200x200+400+900', 'img':'router.png', 'labelpos':'-30,170'},
{'id':'I', 'type':'internet', 'name':'Internet', 'geometry':'200x240+100+200', 'img':'internet.png', 'labelpos':'-50,200'},
{'id':'S1', 'type':'switch', 'name':'Switch one', 'geometry':'150x150+800+500', 'img':'switch.png', 'labelpos':'80,110'}
];
// routes are processed in order, first match only is used => default must be last - KEEP routes before interfaces for random reference
var routes = [
{'hid':'H1', 'rid':'H1r1', 'route':'0.0.0.0/0', 'gate':'[128-170]a.[1-254]b.[1-254]c.1', 'route_edit':'false', 'gate_edit':'false'},
{'hid':'H2', 'rid':'H2r1', 'route':'default', 'gate':'[a].[b].[c].1', 'route_edit':'false', 'gate_edit':'false'},
{'hid':'H3', 'rid':'H3r1', 'route':'0.0.0.0/0', 'gate':'10.0.0.254', 'route_edit':'false', 'gate_edit':'true'},
{'hid':'H4', 'rid':'H4r1', 'route':'default', 'gate':'[a].[b].[c].129', 'route_edit':'false', 'gate_edit':'false'},
{'hid':'R1', 'rid':'R1r1', 'route':'10.0.0.0/8', 'gate':'[a].[b].[c].253', 'route_edit':'true', 'gate_edit':'false'},
{'hid':'R1', 'rid':'R1r2', 'route':'[a].[b].[c].128/26', 'gate':'[a].[b].[c].253', 'route_edit':'false', 'gate_edit':'false'},
{'hid':'R1', 'rid':'R1r3', 'route':'0.0.0.0/0', 'gate':'163.172.250.1', 'route_edit':'false', 'gate_edit':'false'},
{'hid':'R2', 'rid':'R2r1', 'route':'0.0.0.0/0', 'gate':'[a].[b].[c].254', 'route_edit':'false', 'gate_edit':'false'},
{'hid':'I', 'rid':'Ir1', 'route':'[a].[b].[c].0/31', 'gate':'163.172.250.12', 'route_edit':'true', 'gate_edit':'false'}
];
var ifs = [
{'if':'H11', 'hid':'H1', 'ip':'[a].[b].[c].2', 'mask':'255.255.255.0', 'ip_edit':'false', 'mask_edit':'true', 'type':'std', 'pos':'0,-50'},
{'if':'H21', 'hid':'H2', 'ip':'192.168.42.42', 'mask':'255.255.0.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'100,200'},
{'if':'H31', 'hid':'H3', 'ip':'192.168.0.1', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'20,-50'},
{'if':'H41', 'hid':'H4', 'ip':'[a].[b].[c].131', 'mask':'255.255.255.192', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'0,-50'},
{'if':'R11', 'hid':'R1', 'ip':'[a].[b].[c].1', 'mask':'255.255.255.128', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'190,10'},
{'if':'R12', 'hid':'R1', 'ip':'163.172.250.12', 'mask':'255.255.255.240', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'-150,0'},
{'if':'R13', 'hid':'R1', 'ip':'[a].[b].[c].254', 'mask':'255.255.255.0', 'ip_edit':'false', 'mask_edit':'true', 'type':'std', 'pos':'130,140'},
{'if':'R21', 'hid':'R2', 'ip':'[a].[b].[c].253', 'mask':'255.255.255.252', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'0,-50'},
{'if':'R22', 'hid':'R2', 'ip':'10.0.0.254', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'190,90'},
{'if':'R23', 'hid':'R2', 'ip':'8.8.8.8', 'mask':'/18', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'-150,90'},
{'if':'S11', 'hid':'S1', 'ip':'0.0.0.0', 'mask':'/32', 'ip_edit':'false', 'mask_edit':'false', 'pos':'0,0', 'type':'hidden'},
{'if':'I1', 'hid':'I', 'ip':'163.172.250.1', 'mask':'/28', 'ip_edit':'false', 'mask_edit':'false', 'pos':'0,0', 'type':'hidden'}
];
var links = [
{'if1':'I1', 'if2':'R12'},
{'if1':'R11', 'if2':'S11'},
{'if1':'S11', 'if2':'H11'},
{'if1':'S11', 'if2':'H21'},
{'if1':'R13', 'if2':'R21'},
{'if1':'R22', 'if2':'H31'},
{'if1':'R23', 'if2':'H41'}
];
var goals = [
{'id':'1', 'type':'reach', 'id1':'H1', 'id2':'H2'},
{'id':'2', 'type':'reach', 'id1':'H3', 'id2':'H4'},
{'id':'3', 'type':'reach', 'id1':'H1', 'id2':'I'},
{'id':'4', 'type':'reach', 'id1':'H1', 'id2':'H4'},
{'id':'5', 'type':'reach', 'id1':'H2', 'id2':'H3'},
{'id':'6', 'type':'reach', 'id1':'H3', 'id2':'I'},
{'id':'7', 'type':'reach', 'id1':'H4', 'id2':'I'}
];

31
net_practice/js/level2.js Normal file
View File

@ -0,0 +1,31 @@
var level = 2;
var hosts = [
{'id':'A', 'type':'client', 'name':'Computer A', 'geometry':'200x220+200+500', 'img':'host.png', 'labelpos':'0,200'},
{'id':'B', 'type':'client', 'name':'Computer B', 'geometry':'200x220+200+100', 'img':'host.png', 'labelpos':'180,30'},
{'id':'C', 'type':'client', 'name':'Computer C', 'geometry':'200x220+600+500', 'img':'host.png', 'labelpos':'0,200'},
{'id':'D', 'type':'client', 'name':'Computer D', 'geometry':'200x220+600+100', 'img':'host.png', 'labelpos':'180,30'}
];
// routes are processed in order, first match only is used => default must be last - KEEP routes before interfaces for random reference
var routes = [
];
var ifs = [
{'if':'A1', 'hid':'A', 'ip':'192.168.[14-150]a.1', 'mask':'255.255.255.224', 'ip_edit':'true', 'mask_edit':'false', 'type':'std', 'pos':'-90,-50'},
{'if':'B1', 'hid':'B', 'ip':'192.168.[a].222', 'mask':'255.255.255.32', 'ip_edit':'false', 'mask_edit':'true', 'type':'std', 'pos':'110,200'},
{'if':'C1', 'hid':'C', 'ip':'127.0.0.1', 'mask':'255.255.255.252', 'ip_edit':'true', 'mask_edit':'false', 'type':'std', 'pos':'-90,-50'},
{'if':'D1', 'hid':'D', 'ip':'127.0.0.4', 'mask':'/30', 'ip_edit':'true', 'mask_edit':'false', 'type':'std', 'pos':'110,200'}
];
var links = [
{'if1':'A1', 'if2':'B1'},
{'if1':'C1', 'if2':'D1'}
];
var goals = [
{'id':'1', 'type':'reach', 'id1':'B', 'id2':'A'},
{'id':'1', 'type':'reach', 'id1':'D', 'id2':'C'}
];

34
net_practice/js/level3.js Normal file
View File

@ -0,0 +1,34 @@
var level = 3;
var hosts = [
{'id':'A', 'type':'client', 'name':'Host A', 'geometry':'200x220+700+800', 'img':'host.png', 'labelpos':'0,200'},
{'id':'B', 'type':'client', 'name':'Host B', 'geometry':'200x220+600+200', 'img':'host.png', 'labelpos':'180,30'},
{'id':'C', 'type':'client', 'name':'Host C', 'geometry':'200x200+200+500', 'img':'host.png', 'labelpos':'-150,150'},
{'id':'S', 'type':'switch', 'name':'Switch-1', 'geometry':'150x150+600+500', 'img':'switch.png', 'labelpos':'80,110'}
];
// routes are processed in order, first match only is used => default must be last - KEEP routes before interfaces for random reference
var routes = [
];
var ifs = [
{'if':'A1', 'hid':'A', 'ip':'104.198.[1-254]a.125', 'mask':'255.255.255.0', 'ip_edit':'false', 'mask_edit':'true', 'type':'std', 'pos':'0,-50'},
{'if':'B1', 'hid':'B', 'ip':'127.168.42.42', 'mask':'255.255.0.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'100,200'},
{'if':'C1', 'hid':'C', 'ip':'104.198.[a].[260-299]b', 'mask':'255.255.255.128', 'ip_edit':'true', 'mask_edit':'false', 'type':'std', 'pos':'190,10'},
{'if':'S1', 'hid':'S', 'ip':'0.0.0.0', 'mask':'/32', 'ip_edit':'false', 'mask_edit':'false', 'pos':'0,0', 'type':'hidden'}
];
var links = [
{'if1':'C1', 'if2':'S1'},
{'if1':'S1', 'if2':'A1'},
{'if1':'S1', 'if2':'B1'}
];
var goals = [
{'id':'1', 'type':'reach', 'id1':'A', 'id2':'B'},
{'id':'2', 'type':'reach', 'id1':'A', 'id2':'C'},
{'id':'3', 'type':'reach', 'id1':'B', 'id2':'C'}
];

36
net_practice/js/level4.js Normal file
View File

@ -0,0 +1,36 @@
var level = 4;
var hosts = [
{'id':'A', 'type':'client', 'name':'A nice host', 'geometry':'200x220+800+800', 'img':'host.png', 'labelpos':'0,200'},
{'id':'B', 'type':'client', 'name':'Another host', 'geometry':'200x220+700+200', 'img':'host.png', 'labelpos':'180,30'},
{'id':'R', 'type':'router', 'name':'My_Gate', 'geometry':'200x200+300+500', 'img':'router.png', 'labelpos':'-160,120'},
{'id':'S', 'type':'switch', 'name':'Switch-1', 'geometry':'150x150+700+500', 'img':'switch.png', 'labelpos':'80,110'}
];
// routes are processed in order, first match only is used => default must be last - KEEP routes before interfaces for random reference
var routes = [
];
var ifs = [
{'if':'A1', 'hid':'A', 'ip':'[60-125]a.[1-254]b.[110-119]c.132', 'mask':'255.255.255.240', 'ip_edit':'false', 'mask_edit':'true', 'type':'std', 'pos':'0,-50'},
{'if':'B1', 'hid':'B', 'ip':'[a].[b].[120-129]d.193', 'mask':'255.255.0.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'100,200'},
{'if':'R1', 'hid':'R', 'ip':'[a].[b].[c].91', 'mask':'/23', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'190,10'},
{'if':'R2', 'hid':'R', 'ip':'[a].[b].[c].1', 'mask':'255.255.255.128', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'0,190'},
{'if':'R3', 'hid':'R', 'ip':'[a].[b].[c].244', 'mask':'255.255.255.192', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'-170,0'},
{'if':'S1', 'hid':'S', 'ip':'0.0.0.0', 'mask':'/32', 'ip_edit':'false', 'mask_edit':'false', 'pos':'0,0', 'type':'hidden'}
];
var links = [
{'if1':'R1', 'if2':'S1'},
{'if1':'S1', 'if2':'A1'},
{'if1':'S1', 'if2':'B1'}
];
var goals = [
{'id':'1', 'type':'reach', 'id1':'A', 'id2':'B'},
{'id':'2', 'type':'reach', 'id1':'A', 'id2':'R'},
{'id':'3', 'type':'reach', 'id1':'B', 'id2':'R'}
];

34
net_practice/js/level5.js Normal file
View File

@ -0,0 +1,34 @@
var level = 5;
var hosts = [
{'id':'A', 'type':'client', 'name':'Machine A', 'geometry':'200x220+900+800', 'img':'host.png', 'labelpos':'0,200'},
{'id':'B', 'type':'client', 'name':'Machine B', 'geometry':'200x220+800+200', 'img':'host.png', 'labelpos':'180,30'},
{'id':'R', 'type':'router', 'name':'The Mighty Router', 'geometry':'200x200+400+500', 'img':'router.png', 'labelpos':'-200,50'}
];
// routes are processed in order, first match only is used => default must be last - KEEP routes before interfaces for random reference
var routes = [
{'hid':'A', 'rid':'Ar1', 'route':'10..0.0.0/8', 'gate':'192.168.0.254', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'B', 'rid':'Br1', 'route':'default', 'gate':'192.168.0.254', 'route_edit':'false', 'gate_edit':'true'}
];
var ifs = [
{'if':'A1', 'hid':'A', 'ip':'104.198.14.2', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'0,-50'},
{'if':'B1', 'hid':'B', 'ip':'192.168.42.42', 'mask':'/[27-30]g', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'100,200'},
{'if':'R1', 'hid':'R', 'ip':'[15-99]a.[1-254]c.[1-254]e.126', 'mask':'255.255.255.128', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'0,170'},
{'if':'R2', 'hid':'R', 'ip':'[130-170]b.[1-254]d.[1-254]f.254', 'mask':'255.255.192.0', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'190,0'}
];
var links = [
{'if1':'R1', 'if2':'A1'},
{'if1':'R2', 'if2':'B1'}
];
var goals = [
{'id':'1', 'type':'reach', 'id1':'A', 'id2':'R'},
{'id':'2', 'type':'reach', 'id1':'B', 'id2':'R'},
{'id':'3', 'type':'reach', 'id1':'A', 'id2':'B'}
];

37
net_practice/js/level6.js Normal file
View File

@ -0,0 +1,37 @@
var level = 6;
var hosts = [
{'id':'A', 'type':'client', 'name':'webserv.non-real.com', 'geometry':'200x220+900+800', 'img':'host.png', 'labelpos':'0,200'},
{'id':'R', 'type':'router', 'name':'gate.non-real.com', 'geometry':'200x200+400+500', 'img':'router.png', 'labelpos':'-150,150'},
{'id':'I', 'type':'internet', 'name':'Internet', 'geometry':'200x240+100+200', 'img':'internet.png', 'labelpos':'-50,200'},
{'id':'S', 'type':'switch', 'name':'sw-1.non-real.com', 'geometry':'150x150+800+500', 'img':'switch.png', 'labelpos':'80,110'}
];
// routes are processed in order, first match only is used => default must be last - KEEP routes before interfaces for random reference
var routes = [
{'hid':'A', 'rid':'Ar1', 'route':'0.0.0.0/0', 'gate':'[20-120]a.[1-255]b.[1-255]c.1', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'R', 'rid':'Rr1', 'route':'10.0.0.0/8', 'gate':'163.172.250.1', 'route_edit':'true', 'gate_edit':'false'},
{'hid':'I', 'rid':'Ir1', 'route':'[a].[b].[c].0/31', 'gate':'163.172.250.12', 'route_edit':'true', 'gate_edit':'false'}
];
var ifs = [
{'if':'A1', 'hid':'A', 'ip':'[a].[b].[c].227', 'mask':'255.255.255.0', 'ip_edit':'false', 'mask_edit':'true', 'type':'std', 'pos':'0,-50'},
{'if':'R1', 'hid':'R', 'ip':'[a].[b].[c].254', 'mask':'255.255.255.128', 'ip_edit':'true', 'mask_edit':'false', 'type':'std', 'pos':'190,10'},
{'if':'R2', 'hid':'R', 'ip':'163.172.250.12', 'mask':'255.255.255.240', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'-150,0'},
{'if':'S1', 'hid':'S', 'ip':'0.0.0.0', 'mask':'/32', 'ip_edit':'false', 'mask_edit':'false', 'pos':'0,0', 'type':'hidden'},
{'if':'Somewhere on the Net', 'hid':'I', 'ip':'8.8.8.8', 'mask':'/16', 'ip_edit':'false', 'mask_edit':'false', 'pos':'0,-50', 'type':'std'},
{'if':'I1', 'hid':'I', 'ip':'163.172.250.1', 'mask':'/28', 'ip_edit':'false', 'mask_edit':'false', 'pos':'0,0', 'type':'hidden'}
];
var links = [
{'if1':'I1', 'if2':'R2'},
{'if1':'R1', 'if2':'S1'},
{'if1':'S1', 'if2':'A1'}
];
var goals = [
{'id':'1', 'type':'reach_if', 'if_id1':'A1', 'if_id2':'Somewhere on the Net'}
];

38
net_practice/js/level7.js Normal file
View File

@ -0,0 +1,38 @@
var level = 7;
var hosts = [
{'id':'A', 'type':'client', 'name':'dev.non-real.net', 'geometry':'200x220+900+200', 'img':'host.png', 'labelpos':'0,200'},
{'id':'C', 'type':'client', 'name':'accounting.non-real.net', 'geometry':'200x220+900+700', 'img':'host.png', 'labelpos':'180,100'},
{'id':'R1', 'type':'router', 'name':'tech.non-real.net', 'geometry':'200x200+400+200', 'img':'router.png', 'labelpos':'-280,50'},
{'id':'R2', 'type':'router', 'name':'adm.non-real.net', 'geometry':'200x200+400+700', 'img':'router.png', 'labelpos':'-30,170'}
];
// routes are processed in order, first match only is used => default must be last - KEEP routes before interfaces for random reference
var routes = [
{'hid':'A', 'rid':'Ar1', 'route':'0.0.0.0/0', 'gate':'0.0.0.0', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'C', 'rid':'Cr1', 'route':'0.0.0.0/0', 'gate':'0.0.0.0', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'R1', 'rid':'R1r1', 'route':'0.0.0.0/0', 'gate':'0.0.0.0', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'R2', 'rid':'R2r1', 'route':'0.0.0.0/0', 'gate':'0.0.0.0', 'route_edit':'true', 'gate_edit':'true'}
];
var ifs = [
{'if':'A1', 'hid':'A', 'ip':'[90-120]a.198.14.2', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'0,-50'},
{'if':'C1', 'hid':'C', 'ip':'[a].198.14.1', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'20,-50'},
{'if':'R11', 'hid':'R1', 'ip':'[a].198.14.1', 'mask':'255.255.255.0', 'ip_edit':'false', 'mask_edit':'true', 'type':'std', 'pos':'190,10'},
{'if':'R12', 'hid':'R1', 'ip':'[a].198.14.254', 'mask':'255.255.255.0', 'ip_edit':'false', 'mask_edit':'true', 'type':'std', 'pos':'80,160'},
{'if':'R21', 'hid':'R2', 'ip':'[a].198.14.149', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'0,-50'},
{'if':'R22', 'hid':'R2', 'ip':'[a].198.14.252', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'190,90'}
];
var links = [
{'if1':'R11', 'if2':'A1'},
{'if1':'R12', 'if2':'R21'},
{'if1':'R22', 'if2':'C1'}
];
var goals = [
{'id':'1', 'type':'reach', 'id1':'A', 'id2':'C'}
];

46
net_practice/js/level8.js Normal file
View File

@ -0,0 +1,46 @@
var level = 8;
var hosts = [
{'id':'C', 'type':'client', 'name':'office.non-real.com', 'geometry':'200x220+600+900', 'img':'host.png', 'labelpos':'180,100'},
{'id':'D', 'type':'client', 'name':'home.non-real.com', 'geometry':'200x220+100+900', 'img':'host.png', 'labelpos':'180,100'},
{'id':'R1', 'type':'router', 'name':'gate.non-real.com', 'geometry':'200x200+400+200', 'img':'router.png', 'labelpos':'-270,20'},
{'id':'R2', 'type':'router', 'name':'transit.my-isp.org', 'geometry':'200x200+400+600', 'img':'router.png', 'labelpos':'-30,170'},
{'id':'I', 'type':'internet', 'name':'Internet', 'geometry':'200x240+900+175', 'img':'internet.png', 'labelpos':'-50,200'},
];
// routes are processed in order, first match only is used => default must be last - KEEP routes before interfaces for random reference and keep routes in host order
var routes = [
{'hid':'C', 'rid':'Cr1', 'route':'0.0.0.0/0', 'gate':'10.0.0.254', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'D', 'rid':'Dr1', 'route':'default', 'gate':'8.8.8.8', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'R1', 'rid':'R1r2', 'route':'192.168.0.0/26', 'gate':'10.0.0.2', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'R1', 'rid':'R1r3', 'route':'0.0.0.0/0', 'gate':'163.[1-254]a.250.1', 'route_edit':'false', 'gate_edit':'false'},
{'hid':'R2', 'rid':'R2r1', 'route':'10.0.0.0/8', 'gate':'[128-170]b.[1-254]c.[1-254]d.62', 'route_edit':'true', 'gate_edit':'false'},
{'hid':'I', 'rid':'Ir1', 'route':'[b].[c].[d].0/26', 'gate':'163.[a].250.254', 'route_edit':'false', 'gate_edit':'true'}
];
var ifs = [
{'if':'C1', 'hid':'C', 'ip':'192.168.0.1', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'20,-50'},
{'if':'D1', 'hid':'D', 'ip':'8.9.10.11', 'mask':'255.255.255.240', 'ip_edit':'true', 'mask_edit':'false', 'type':'std', 'pos':'0,-50'},
{'if':'R12', 'hid':'R1', 'ip':'163.[a].250.12', 'mask':'255.255.255.240', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'190,20'},
{'if':'R13', 'hid':'R1', 'ip':'10.0.0.1', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'20,160'},
{'if':'R21', 'hid':'R2', 'ip':'10.0.0.2', 'mask':'255.255.0.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'0,-50'},
{'if':'R22', 'hid':'R2', 'ip':'192.168.0.254', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'190,90'},
{'if':'R23', 'hid':'R2', 'ip':'8.8.8.8', 'mask':'/18', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'-150,90'},
{'if':'I1', 'hid':'I', 'ip':'163.[a].250.1', 'mask':'/28', 'ip_edit':'false', 'mask_edit':'false', 'pos':'0,0', 'type':'hidden'}
];
var links = [
{'if1':'I1', 'if2':'R12'},
{'if1':'R13', 'if2':'R21'},
{'if1':'R22', 'if2':'C1'},
{'if1':'R23', 'if2':'D1'}
];
var goals = [
{'id':'1', 'type':'reach', 'id1':'C', 'id2':'D'},
{'id':'2', 'type':'reach', 'id1':'C', 'id2':'I'},
{'id':'3', 'type':'reach', 'id1':'D', 'id2':'I'}
];

64
net_practice/js/level9.js Normal file
View File

@ -0,0 +1,64 @@
var level = 9;
var hosts = [
{'id':'A', 'type':'client', 'name':'meson', 'geometry':'200x220+100+800', 'img':'host.png', 'labelpos':'-50,200'},
{'id':'B', 'type':'client', 'name':'ion', 'geometry':'200x220+100+200', 'img':'host.png', 'labelpos':'180,30'},
{'id':'C', 'type':'client', 'name':'cation', 'geometry':'200x220+1000+800', 'img':'host.png', 'labelpos':'100,190'},
{'id':'D', 'type':'client', 'name':'gluon', 'geometry':'200x220+600+1300', 'img':'host.png', 'labelpos':'180,80'},
{'id':'R1', 'type':'router', 'name':'proton', 'geometry':'200x200+500+500', 'img':'router.png', 'labelpos':'-150,150'},
{'id':'R2', 'type':'router', 'name':'boson', 'geometry':'200x200+600+900', 'img':'router.png', 'labelpos':'-200,100'},
{'id':'I', 'type':'internet', 'name':'Internet', 'geometry':'200x240+800+200', 'img':'internet.png', 'labelpos':'100,200'},
{'id':'S', 'type':'switch', 'name':'neutron', 'geometry':'150x150+200+500', 'img':'switch.png', 'labelpos':'-80,110'}
];
// routes are processed in order, first match only is used => default must be last - KEEP routes before interfaces for random reference
var routes = [
{'hid':'A', 'rid':'Ar1', 'route':'0.0.0.0/0', 'gate':'[11-126]e.198.[1-254]f.1', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'B', 'rid':'Br1', 'route':'8.8.8.8/16', 'gate':'[e].199.[f].1', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'C', 'rid':'Cr1', 'route':'0.0.0.0/0', 'gate':'10.0.0.254', 'route_edit':'false', 'gate_edit':'true'},
{'hid':'D', 'rid':'Dr1', 'route':'10.0.0.0/8', 'gate':'[11-126]a.[1-254]b.[1-254]c.[1-254]d', 'route_edit':'true', 'gate_edit':'false'},
{'hid':'R1', 'rid':'R1r1', 'route':'10.0.0.0/8', 'gate':'[11-126]j.[1-254]k.14.253', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'R1', 'rid':'R1r2', 'route':'192.168.24.12/26', 'gate':'[j].[k].15.253', 'route_edit':'true', 'gate_edit':'true'},
{'hid':'R1', 'rid':'R1r3', 'route':'0.0.0.0/0', 'gate':'163.172.250.1', 'route_edit':'false', 'gate_edit':'false'},
{'hid':'R2', 'rid':'R2r1', 'route':'0.0.0.0/0', 'gate':'[j].[k].16.254', 'route_edit':'false', 'gate_edit':'true'},
{'hid':'I', 'rid':'Ir1', 'route':'[e].198.[f].0/22', 'gate':'163.172.250.12', 'route_edit':'true', 'gate_edit':'false'},
{'hid':'I', 'rid':'Ir2', 'route':'10.0.0.0/27', 'gate':'163.172.250.12', 'route_edit':'true', 'gate_edit':'false'},
{'hid':'I', 'rid':'Ir3', 'route':'default', 'gate':'163.172.250.12', 'route_edit':'true', 'gate_edit':'false'}
];
var ifs = [
{'if':'A1', 'hid':'A', 'ip':'192.168.[1-254]g.2', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'0,-50'},
{'if':'B1', 'hid':'B', 'ip':'192.168.[1-254]h.42', 'mask':'255.255.0.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'100,200'},
{'if':'C1', 'hid':'C', 'ip':'10.0.0.1', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'20,-50'},
{'if':'D1', 'hid':'D', 'ip':'[j].[k].19.131', 'mask':'255.255.255.192', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'0,-50'},
{'if':'R11', 'hid':'R1', 'ip':'192.168.[1-254]i.1', 'mask':'255.255.255.128', 'ip_edit':'true', 'mask_edit':'false', 'type':'std', 'pos':'-150,0'},
{'if':'R12', 'hid':'R1', 'ip':'163.172.250.12', 'mask':'255.255.255.240', 'ip_edit':'false', 'mask_edit':'false', 'type':'std', 'pos':'190,10'},
{'if':'R13', 'hid':'R1', 'ip':'[j].[k].17.254', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'130,140'},
{'if':'R21', 'hid':'R2', 'ip':'[j].[k].18.253', 'mask':'255.255.255.252', 'ip_edit':'true', 'mask_edit':'false', 'type':'std', 'pos':'0,-50'},
{'if':'R22', 'hid':'R2', 'ip':'10.0.0.254', 'mask':'255.255.255.0', 'ip_edit':'true', 'mask_edit':'true', 'type':'std', 'pos':'190,80'},
{'if':'R23', 'hid':'R2', 'ip':'8.8.8.8', 'mask':'/18', 'ip_edit':'true', 'mask_edit':'false', 'type':'std', 'pos':'30,180'},
{'if':'S1', 'hid':'S', 'ip':'0.0.0.0', 'mask':'/32', 'ip_edit':'false', 'mask_edit':'false', 'pos':'0,0', 'type':'hidden'},
{'if':'I1', 'hid':'I', 'ip':'163.172.250.1', 'mask':'/28', 'ip_edit':'false', 'mask_edit':'false', 'pos':'0,0', 'type':'hidden'}
];
var links = [
{'if1':'I1', 'if2':'R12'},
{'if1':'R11', 'if2':'S1'},
{'if1':'S1', 'if2':'A1'},
{'if1':'S1', 'if2':'B1'},
{'if1':'R13', 'if2':'R21'},
{'if1':'R22', 'if2':'C1'},
{'if1':'R23', 'if2':'D1'}
];
var goals = [
{'id':'1', 'type':'reach', 'id1':'A', 'id2':'B'},
{'id':'2', 'type':'reach', 'id1':'C', 'id2':'D'},
{'id':'3', 'type':'reach', 'id1':'A', 'id2':'I'},
{'id':'4', 'type':'reach', 'id1':'A', 'id2':'D'},
{'id':'5', 'type':'reach', 'id1':'B', 'id2':'C'},
{'id':'6', 'type':'reach', 'id1':'C', 'id2':'I'}
];

347
net_practice/js/show.js Normal file
View File

@ -0,0 +1,347 @@
var g_sim_logs = '';
var g_my_login = 0;
var g_rand_prev;
var g_rand_repl = [];
var g_eval_lvls;
function my_console_log(str)
{
// console.log(str);
}
function hash_login(login)
{
var seed = 0;
for (var i = 0; i < login.length; i ++)
{
if (i%2 == 0)
seed += 973 * (login.charCodeAt(i)+i);
else
seed += 5 * login.charCodeAt(i) * i;
}
// console.log("hash login : '"+login+"' -> "+seed);
return (seed);
}
function err(thetype, field)
{
my_console_log("Fatal error in "+thetype+", on field "+field);
throw '';
}
function my_random(a, b)
{
if (g_my_login == '')
return (Math.round(parseInt(a) + (parseInt(b)-parseInt(a))*Math.random()));
var prev = g_rand_prev;
prev ^= prev << 13;
prev ^= prev >> 17;
prev ^= prev << 5;
g_rand_prev = prev;
prev = (prev & 0x7FFFFFFF) % (parseInt(b)-parseInt(a)+1);
return (Math.round(parseInt(a) + prev));
}
function random_repl(str)
{
var regex = /\[(\d+)-(\d+)\]([a-z])/g;
var res;
var str2 = str;
while (res = regex.exec(str))
{
my_console_log(res);
g_rand_repl[res[3]] = my_random(res[1], res[2]);
str2 = str2.replace(res[0], ""+g_rand_repl[res[3]]);
my_console_log(str2);
}
regex = /\[([a-z])\]/g;
while (res = regex.exec(str))
{
my_console_log(res);
if (g_rand_repl[res[1]] != null)
{
str2 = str2.replace(res[0], ""+g_rand_repl[res[1]]);
my_console_log(str2);
}
else
return (null);
}
if (str2 == "default") return (str2);
// check if any non digital, non dot, non slash char, except previous line
regex = /[^\d\.\/]/g;
if (regex.exec(str2))
return (null);
return (str2);
}
function show_host(root, h)
{
if (!h['id']) err("hosts", "id");
if (!h['type']) err("hosts id "+h['id'], "type");
if (!h['name']) err("hosts id "+h['id'], "name");
if (!h['geometry']) err("hosts id "+h['id'], "geometry");
if (!h['img']) err("hosts id "+h['id'], "img");
var tab = h['geometry'].split(/[^0-9]+/);
if (tab.length != 4) err("hosts id "+h['id'], "geometry parsing");
h['w'] = parseInt(tab[0]);
h['h'] = parseInt(tab[1]);
h['x'] = parseInt(tab[2]);
h['y'] = parseInt(tab[3]);
var newelem = document.createElement('div');
newelem.className = 'host_div';
newelem.style.position = "absolute";
newelem.style.width = h['w']+'px';
newelem.style.height = h['h']+'px';
newelem.style.top = h['y'] + 'px';
newelem.style.left = h['x'] + 'px';
newelem.style.backgroundImage = 'url(img/'+h['img']+')';
root.appendChild(newelem);
// label + routes
var tab = h['labelpos'].split(',');
if (tab.length != 2) err("host id "+h['id'], "labelpos parsing");
h['lx'] = parseInt(tab[0]);
h['ly'] = parseInt(tab[1]);
var newelem = document.createElement('div');
newelem.className = 'host_info_div';
newelem.style.position = "absolute";
newelem.style.top = (h['y']+h['ly'])+'px';
newelem.style.left = (h['x']+h['lx'])+'px';
var label = '<table><tr><td>'+h['type']+' '+h['id']+': <i>'+h['name']+'</id></td></tr>';
var str = '';
routes.forEach(r => {if (h['id'] == r['hid']) { str += '<tr><td>'+get_route_info(r)+'</td></tr>\n'; r['h'] = h;}});
if (str != '') label += '<tr><td>Routes :</td></tr>\n'+str;
label += '</table>';
newelem.innerHTML = label;
root.appendChild(newelem);
}
function get_route_info(r)
{
if (!r['rid']) err("route", "rid");
if (!r['hid']) err("route id "+r['rid'], "hid");
if (!r['route']) err("route id "+r['rid'], "route");
if (!r['route_edit']) err("route id "+r['rid'], "route_edit");
if (!r['gate']) err("route id "+r['rid'], "gate");
if (!r['gate_edit']) err("route id "+r['rid'], "gate_edit");
if ((r['route'] = random_repl(r['route'])) == null) err("route id "+r['rid'], "route ip random syntax");
if ((r['gate'] = random_repl(r['gate'])) == null) err("route id "+r['rid'], "gate random syntax");
if (r['route_edit'] == 'true') route_active = ''; else route_active = 'disabled';
if (r['gate_edit'] == 'true') gate_active = ''; else gate_active = 'disabled';
var routestr = '<input size=15 type=text id=route_'+r['rid']+' value="'+r['route']+'" '+route_active+'> =&gt; <input size=15 type=text id=gate_'+r['rid']+' value="'+r['gate']+'" '+gate_active+'>';
// my_console_log("add label route : ##"+routestr);
return (routestr);
}
function show_ifs(root, itf)
{
if (!itf['if']) err("ifs", "if");
if (!itf['hid']) err("ifs "+itf['if'], "hid");
if (!itf['ip']) err("ifs "+itf['if'], "ip");
if (!itf['mask']) err("ifs "+itf['if'], "mask");
if (!itf['ip_edit']) err("ifs "+itf['if'], "ip_edit");
if (!itf['mask_edit']) err("ifs "+itf['if'], "mask_edit");
if (!itf['type']) err("ifs "+itf['if'], "type");
if (!itf['pos']) err("ifs "+itf['if'], "pos");
if ((itf['ip'] = random_repl(itf['ip'])) == null) err("ifs "+itf['if'], "ip random syntax");
if ((itf['mask'] = random_repl(itf['mask'])) == null) err("ifs "+itf['if'], "mask random syntax");
hosts.forEach(h => {if (itf['hid'] == h['id']) itf['h'] = h});
var tab = itf['pos'].split(',');
if (tab.length != 2) err("ifs id "+itf['if'], "pos parsing");
itf['dx'] = parseInt(tab[0]);
itf['dy'] = parseInt(tab[1]);
if (itf['type'] == 'std')
{
var newelem = document.createElement('div');
newelem.className = 'itf_div';
newelem.style.position = "absolute";
newelem.style.top = (itf['h']['y']+itf['dy'])+'px';
newelem.style.left = (itf['h']['x']+itf['dx'])+'px';
if (itf['ip_edit'] == 'true') ip_active = ''; else ip_active = 'disabled';
if (itf['mask_edit'] == 'true') mask_active = ''; else mask_active = 'disabled';
newelem.innerHTML = 'Interface '+itf['if']+'<br />IP : <input size=15 type=text id=ip_'+itf['if']+' value="'+itf['ip']+'" '+ip_active+'><br />Mask : <input size=15 type=text id=mask_'+itf['if']+' value="'+itf['mask']+'" '+mask_active+'>';
root.appendChild(newelem);
}
}
function draw_links(root, l)
{
if (!l['if1'] || !l['if2']) err("links", "id");
ifs.forEach(i => {if (i['if'] == l['if1']) l['e1'] = i});
ifs.forEach(i => {if (i['if'] == l['if2']) l['e2'] = i});
hosts.forEach(h => {if (h['id'] == l['e1']['hid']) l['h1'] = h});
hosts.forEach(h => {if (h['id'] == l['e2']['hid']) l['h2'] = h});
var aLine = document.createElementNS('http://www.w3.org/2000/svg', 'line');
aLine.setAttribute('id', 'link_'+l['if1']+'_'+l['if2']);
aLine.id = 'link_'+l['if1']+'_'+l['if2'];
aLine.setAttribute('x1', ""+(parseInt(l['h1']['x'])+parseInt(l['h1']['w'])/2));
aLine.setAttribute('y1', ""+(parseInt(l['h1']['y'])+parseInt(l['h1']['h'])/2));
aLine.setAttribute('x2', ""+(parseInt(l['h2']['x'])+parseInt(l['h2']['w'])/2));
aLine.setAttribute('y2', ""+(parseInt(l['h2']['y'])+parseInt(l['h2']['h'])/2));
aLine.setAttribute('stroke', "black");
aLine.setAttribute('stroke-width', 3);
(document.getElementById('sl')).appendChild(aLine);
}
function prep_goals(g)
{
if (!g['id']) err("goals", "id");
if (!g['type']) err("goals "+g['id'], "type");
if (g['type'] == 'reach')
{
if (!g['id1']) err("goals "+g['id'], "id1");
if (!g['id2']) err("goals "+g['id'], "id2");
hosts.forEach(h => {if (h['id'] == g['id1']) g['h1'] = h});
hosts.forEach(h => {if (h['id'] == g['id2']) g['h2'] = h});
}
if (g['type'] == 'reach_if')
{
if (!g['if_id1']) err("goals "+g['id'], "if_id1");
if (!g['if_id2']) err("goals "+g['id'], "if_id2");
ifs.forEach(itf => {if (itf['if'] == g['if_id1']) { g['h1'] = itf['h']; g['if1'] = itf;}});
ifs.forEach(itf => {if (itf['if'] == g['if_id2']) { g['h2'] = itf['h']; g['if2'] = itf;}});
}
}
function next_eval()
{
if (g_eval_lvls.length >= 3)
return ('end.html');
var lvl;
do {
lvl = Math.round(6 + 4*Math.random());
} while (g_eval_lvls.includes(lvl))
g_eval_lvls.push(lvl);
localStorage.setItem("g_my_eval", JSON.stringify(g_eval_lvls));
return ('level'+lvl+'.html');
}
function my_download(filename, text)
{
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
function dl_config()
{
var infos = { 'routes':{}, 'ifs':{} };
routes.forEach(elem => { infos['routes'][elem['rid']] = {};
if (elem['route_edit'] == 'true') infos['routes'][elem['rid']]['route'] = document.getElementById('route_'+elem['rid']).value;
if (elem['gate_edit'] == 'true') infos['routes'][elem['rid']]['gate'] = document.getElementById('gate_'+elem['rid']).value;
});
ifs.forEach(elem => { infos['ifs'][elem['if']] = {};
if (elem['ip_edit'] == 'true') infos['ifs'][elem['if']]['ip'] = document.getElementById('ip_'+elem['if']).value;
if (elem['mask_edit'] == 'true') infos['ifs'][elem['if']]['mask'] = document.getElementById('mask_'+elem['if']).value;
});
my_download('level'+level+'.json', JSON.stringify(infos));
}
function show_goals(g)
{
g_sim_logs += '******* Goal ID '+g['id']+' ********\n';
var div = document.getElementById("goals_id");
div.innerHTML += 'Goal '+g['id']+' : ';
if (g['type'] == 'reach')
{
var obj = sim_goal(g);
div.innerHTML += '<i>'+g['h1']['name']+'</i> need to communicate with <i>'+g['h2']['name']+'</i> - Status : '+obj.text;
}
if (g['type'] == 'reach_if')
{
var obj = sim_goal(g);
div.innerHTML += 'Interface <i>'+g['if1']['if']+'</i> need to communicate with interface <i>'+g['if2']['if']+'</i> - Status : '+obj.text;
}
div.innerHTML += '<br />\n';
return (obj.status);
}
function all_goals()
{
if (g_my_login != '')
g_sim_logs = '** generated for login "'+g_my_login+'" **\n';
else
g_sim_logs = '** evaluation mode round '+g_eval_lvls.length+'**\n';
document.getElementById("goals_id").innerHTML = '<h2>Level '+level+' : </h2>\n';
var nb = 0;
goals.forEach(elem => nb += show_goals(elem));
document.getElementById("goals_id").innerHTML += '<input type=button value="Check again" onclick="all_goals();"> <input type=button value="Get my config" onclick="dl_config();">';
if (nb == goals.length)
{
if (g_my_login != '')
{
if (level < 10)
document.getElementById("goals_id").innerHTML += " <input type=button value='Next level' onclick='window.location=\"level"+(level+1)+".html\";'>";
else
document.getElementById("goals_id").innerHTML += " <input type=button value='Complete !' onclick='window.location=\"end.html\";'>";
}
else
{ // defense case
document.getElementById("goals_id").innerHTML += " <input type=button value='Next' onclick='window.location=next_eval();'>";
}
}
document.getElementById("logs_id").innerHTML = g_sim_logs.replace(/\n/g, '<br />');
}
function load_board()
{
if (!(g_my_login = localStorage.getItem("g_my_login")))
g_my_login = ''; // will means evaluation & full random
g_rand_prev = level + hash_login(g_my_login); // initialize replayable pseudo random generator
if (g_my_login == '')
g_eval_lvls = JSON.parse(localStorage.getItem("g_my_eval"));
var root = document.getElementById("root_id");
hosts.forEach(elem => show_host(root, elem));
ifs.forEach(elem => show_ifs(root, elem));
links.forEach(elem => draw_links(root, elem));
goals.forEach(elem => prep_goals(elem));
all_goals();
// only for very first time : don't show any log
document.getElementById("logs_id").innerHTML = 'Logs will be displayed here';
}

378
net_practice/js/sim.js Normal file
View File

@ -0,0 +1,378 @@
var visited_host = [];
var private_subnets = [
{'hid':'__none__', 'rid':'private_class_A', 'route':'10.0.0.0/8', 'gate':'0.0.0.0', 'route_edit':'false', 'gate_edit':'false', 'h':{'type':'internet'}},
{'hid':'__none__', 'rid':'private_class_B', 'route':'172.16.0.0/12', 'gate':'0.0.0.0', 'route_edit':'false', 'gate_edit':'false', 'h':{'type':'internet'}},
{'hid':'__none__', 'rid':'private_class_C', 'route':'192.168.0.0/16', 'gate':'0.0.0.0', 'route_edit':'false', 'gate_edit':'false', 'h':{'type':'internet'}}
];
// simulate network
function ip_to_int(s)
{
var tab = s.split('.');
tab.forEach((el, idx) => {this[idx] = parseInt(el);});
if (tab.length != 4) return (null);
if (isNaN(tab[0]) || tab[0] < 0 || tab[0] > 223 || isNaN(tab[1]) || tab[1] < 0 || tab[1] > 255 ||
isNaN(tab[2]) || tab[2] < 0 || tab[2] > 255 || isNaN(tab[3]) || tab[3] < 0 || tab[3] > 255) return (null);
if (tab[0] == 127) { g_sim_logs += "loopback address detected on outside interface\n"; return (null); } // maybe not the best option to deal with 127/8 loopback addresses...
return ( ( (tab[0] << 24) | (tab[1] << 16) | (tab[2] << 8) | (tab[3]) ) >>> 0);
}
function mask_to_int(s)
{
if (s.length == 0) return (null);
if (s[0] == '/')
{
var cidr = parseInt(s.substring(1));
if (isNaN(cidr) || cidr < 0 || cidr > 32) return (null);
if (cidr == 32) return ((-1)>>>0);
return ( ((((1 << cidr)>>>0)-1) << (32-cidr))>>>0 );
}
var tab = s.split('.');
tab.forEach((el, idx) => {this[idx] = parseInt(el);});
if (tab.length != 4) return (null);
if (isNaN(tab[0]) || tab[0] < 0 || tab[0] > 255 || isNaN(tab[1]) || tab[1] < 0 || tab[1] > 255 ||
isNaN(tab[2]) || tab[2] < 0 || tab[2] > 255 || isNaN(tab[3]) || tab[3] < 0 || tab[3] > 255) return (null);
if (tab[0] != 255 && (tab[1] != 0 || tab[2] != 0 || tab[3] != 0)) return (null);
if (tab[0] == 255 && tab[1] != 255 && (tab[2] != 0 || tab[3] != 0)) return (null);
if (tab[0] == 255 && tab[1] == 255 && tab[2] != 255 && tab[3] != 0) return (null);
// magic trick to check if we have continuity of 1 then 0
var mask = ( ( ( tab[0] << 24) | (( tab[1] ) << 16) | (( tab[2] ) << 8) | ( tab[3] ) ) >>> 0);
if (mask == 0) return (0);
if ( ( ((~mask)+1) & (~mask) ) == 0)
return (mask);
return (null);
}
// mask on interface
function get_if_mask_str(itf)
{
if (itf['mask_edit'] == 'true')
return (document.getElementById('mask_'+itf['if']).value);
return (itf['mask']);
}
function get_if_mask(itf)
{
return (mask_to_int(get_if_mask_str(itf)));
}
// ip on interface
function get_if_ip_str(itf)
{
if (itf['ip_edit'] == 'true')
return (document.getElementById('ip_'+itf['if']).value);
return (itf['ip']);
}
function get_if_ip(itf)
{
var the_ip = ip_to_int(get_if_ip_str(itf));
// check if ip is not the network or broadcast address
var the_mask = get_if_mask(itf);
if ( (the_ip & (~the_mask)) == 0 ||
(the_ip & (~the_mask)) == (~the_mask) )
return (null);
return (the_ip);
}
// route in routes
function get_route_route_str(r)
{
if (r['route_edit'] == 'true')
return (document.getElementById('route_'+r['rid']).value);
return (r['route']);
}
// gate in routes
function get_route_gate_str(r)
{
if (r['gate_edit'] == 'true')
return (document.getElementById('gate_'+r['rid']).value);
return (r['gate']);
}
function get_route_gate(r)
{
return (ip_to_int(get_route_gate_str(r)));
}
function ip_match_if(ip, itf)
{
var iip, imask;
if ((iip = get_if_ip(itf)) === null) { g_sim_logs += 'on interface '+itf['if']+': invalid IP address\n'; return (0); }
if ((imask = get_if_mask(itf)) === null) { g_sim_logs += 'on interface '+itf['if']+': invalid netmask\n'; return (0); }
// my_console_log("## "+iip+" & "+imask+" == "+ip+" & "+imask);
if (iip == ip) { g_sim_logs += "duplicate IP ("+get_if_ip_str(itf)+")\n"; return (0); } // ip_match_if is called only on output, not on arrival
if ((iip & imask) == (ip & imask))
{
// if ip match the interface network, check that the ip is not the network addr or broadcast ?
return (1);
}
return (0);
}
function ip_match_route(ip, r)
{
var str, rip, rmask;
str = get_route_route_str(r);
if (str == 'default') str = '0.0.0.0/0';
// my_console_log("ip_match_route route :"+JSON.stringify(r));
if (r['h']['type'] == "internet" && str == '0.0.0.0/0')
{ g_sim_logs += 'invalid default route on internet '+r['hid']+'\n'; return (0); }
var tab = str.split('/');
// my_console_log("ip_match_route check : "+str+" againt ip "+ip);
if (tab.length != 2)
{ g_sim_logs += 'invalid route on host '+r['hid']+'\n'; return (0); }
if ((rip = ip_to_int(tab[0])) === null)
{ g_sim_logs += 'invalid route on host '+r['hid']+'\n'; return (0); }
if ((rmask = mask_to_int('/'+tab[1])) === null)
{ g_sim_logs += 'invalid route on host '+r['hid']+'\n'; return (0); }
if ((rip & rmask) == (ip & rmask)) return (1);
return (0);
}
function rec_route(ip_dest, local_target, input_itf, h) // return array of dest itf
{
var i, nbif, nb_routes, ret, j;
var itf_ip;
if (input_itf != null)
my_console_log(" ** to "+ip_dest+" / host "+h['id']+" input itf "+input_itf['if']+" / to match local target "+local_target);
else
my_console_log(" ** to "+ip_dest+" / host "+h['id']);
// loop detection here
if (visited_host.includes(h)) { g_sim_logs += "on "+h['id']+' : loop detected\n'; return ([]); }
visited_host.push(h);
// if switch : rec_route to all links
if (h['type'] == 'switch')
{
g_sim_logs += 'on switch '+h['id']+': pass to all connections\n';
ret = [];
links.forEach(l => {if (l['e1']['hid'] == h['id']) ret = ret.concat(rec_route(ip_dest, local_target, l['e2'], l['h2']));
else if (l['e2']['hid'] == h['id']) ret = ret.concat(rec_route(ip_dest, local_target, l['e1'], l['h1']))});
return (ret);
}
// on a host, is my current gate ip == the ip of the input itf ?
if (input_itf != null)
{
if ((itf_ip = get_if_ip(input_itf)) === null) { g_sim_logs += 'on '+h['id']+': invalid IP on input interface '+input_itf['if']+'\n'; return ([]); }
if (itf_ip != local_target) { g_sim_logs += 'on '+h['id']+' : packet not for me\n'; return ([]); }
}
// accepted on host
g_sim_logs += 'on '+h['id']+' : packet accepted\n';
// internet does no route private addresses, so "internet interface" reject private subnets
if (h['type'] == 'internet')
{
if (ip_match_route(ip_dest, private_subnets[0]) || ip_match_route(ip_dest, private_subnets[1]) || ip_match_route(ip_dest, private_subnets[2]))
{ g_sim_logs += 'private subnets not routed over internet\n'; return ([]); }
}
// arrived ? check not only input itf, in case another itf is the target; do not check if input_itf is null (departure host)
if (input_itf != null)
{
ret = [];
ifs.forEach(itf => {if (itf['hid'] == h['id'] && (itf_ip = get_if_ip(itf)) !== null && ip_dest === itf_ip) ret.push(itf);});
if (ret.length > 0) { g_sim_logs += 'on '+h['id']+': destination IP reached\n'; my_console_log(" destination reached !"); return (ret); } // keep multiple : means that 2 interfaces have the same ip
}
// ip_dest match an interface ?
my_console_log('on '+h['id']+': check '+ip_dest+" against all interfaces");
nbif = 0; ret = [];
for (i = 0; i < ifs.length; i++)
{
if (ifs[i]['hid'] == h['id'])
{
my_console_log(" chk with itf "+ifs[i]['if']);
if (ip_match_if(ip_dest, ifs[i]))
{
my_console_log(" match itf "+ifs[i]['if']);
nbif ++;
g_sim_logs += 'on '+h['id']+': send to '+ifs[i]['if']+'\n';
links.forEach(l => {if (l['if1'] == ifs[i]['if']) ret = ret.concat(rec_route(ip_dest, ip_dest, l['e2'], l['h2']));
else if (l['if2'] == ifs[i]['if']) ret = ret.concat(rec_route(ip_dest, ip_dest, l['e1'], l['h1']))});
}
}
}
// force fail if multiple ifs on same subnet
if (nbif > 1) { g_sim_logs += 'on '+h['id']+': error on destination ip - multiple interface match\n'; return ([]); }
if (nbif == 1) return (ret);
// else nbif == 0, no interface match, explore routes
my_console_log(" no itf for ip destination, go through gate");
g_sim_logs += 'on '+h['id']+': destination does not match any interface. pass through routing table\n';
ret = [];
nb_routes = 0;
for (j = 0; j < routes.length; j++)
{
if (routes[j]['hid'] == h['id'])
{
if (ip_match_route(ip_dest, routes[j]))
{
g_sim_logs += 'on '+h['id']+' : route match '+get_route_route_str(routes[j])+'\n';
nb_routes ++;
var ip_gate = get_route_gate(routes[j]);
if (ip_gate === null) { g_sim_logs += "on "+h['id']+": invalid gate IP, route "+get_route_route_str(routes[j])+"\n"; return ([]);}
nbif = 0;
for (i = 0; i < ifs.length; i++)
{
if (ifs[i]['hid'] == h['id'])
{
if (ip_match_if(ip_gate, ifs[i]))
{
my_console_log(" gate ip match itf "+ifs[i]['if']);
g_sim_logs += 'on '+h['id']+': send to gateway '+get_route_gate_str(routes[j])+' through interface '+ifs[i]['if']+'\n';
nbif ++;
links.forEach(l => {if (l['if1'] == ifs[i]['if']) ret = ret.concat(rec_route(ip_dest, ip_gate, l['e2'], l['h2']));
else if (l['if2'] == ifs[i]['if']) ret = ret.concat(rec_route(ip_dest, ip_gate, l['e1'], l['h1']))});
}
}
}
if (nbif > 1) { g_sim_logs += 'on '+h['id']+' : error on gate ip - multiple interface match\n'; return ([]); }
}
}
if (nb_routes > 0) // only first route is explored.
{
if (nbif == 0) g_sim_logs += 'on '+h['id']+' : route match but no interface for gateway '+get_route_gate_str(routes[j])+'\n';
return (ret);
}
}
// no match, fail
g_sim_logs += 'on '+h['id']+': destination does not match any route\n';
return ([]);
}
function sim_reach(g)
{
my_console_log("check reach : "+g['id1']+" -> "+g['id2']);
var ret = [];
var i;
var itf_ip;
for (i = 0; i < ifs.length; i++)
{
if (g['id2'] == ifs[i]['hid'])
{
visited_host = [];
if ((itf_ip = get_if_ip(ifs[i])) === null)
g_sim_logs += "on interface "+ifs[i]['if']+": invalid IP\n";
else
{
g_sim_logs +="forward way : "+g['id1']+" -> "+g['id2']+" ("+get_if_ip_str(ifs[i])+")\n";
ret = ret.concat(rec_route(itf_ip, 0, null, g['h1']));
}
if (ret.length > 0)
break; // if one interface matches, that's enough - if ret > 1 it's because another host matches
}
}
if (ret.length <= 0) return ({text:'KO - No forward way, try again ...', status:0});
if (ret.length > 1) return ({text:'KO - Multiple destination hosts match ... ', status:0});
if (ret[0]['hid'] != g['id2']) return ({text:'KO - Correct IP reached but on wrong host, try again ...', status:0});
// now reverse way
my_console_log("check reach : "+g['id2']+" -> "+g['id1']);
ret = [];
for (i = 0; i < ifs.length; i++)
{
if (g['id1'] == ifs[i]['hid'])
{
visited_host = [];
if ((itf_ip = get_if_ip(ifs[i])) === null)
g_sim_logs += "on interface "+ifs[i]['if']+": invalid IP\n";
else
{
g_sim_logs +="reverse way : "+g['id2']+" -> "+g['id1']+" ("+get_if_ip_str(ifs[i])+")\n";
ret = ret.concat(rec_route(itf_ip, 0, null, g['h2']));
}
if (ret.length > 0)
break; // if one interface matches, that's enough - if ret > 1 it's because another host matches
}
}
if (ret.length <= 0) return ({text:'KO - No reverse way, try again ...', status:0});
if (ret.length > 1) return ({text:'KO - Multiple origin hosts match ... ', status:0});
if (ret[0]['hid'] != g['id1']) return ({text:'KO - Correct IP reached but on wrong host, try again ...', status:0});
return ({text:'OK - Congratulations !!', status:1});
}
function sim_reach_if(g)
{
my_console_log("check reach interface : "+g['if_id1']+" -> "+g['if_id2']);
var ret = [];
var i;
var itf_ip;
for (i = 0; i < ifs.length; i++)
{
if (g['if_id2'] == ifs[i]['if'])
{
visited_host = [];
if ((itf_ip = get_if_ip(ifs[i])) === null)
g_sim_logs += "on inerface "+ifs[i]['if']+": invalid IP\n";
else
{
g_sim_logs +="forward way : "+g['if_id1']+" -> "+g['if_id2']+" ("+get_if_ip_str(ifs[i])+")\n";
ret = ret.concat(rec_route(itf_ip, 0, null, g['h1']));
}
if (ret.length > 0)
break; // if one interface matches, that's enough - if ret > 1 it's because another host matches
}
}
if (ret.length <= 0) return ({text:'KO - No forward way, try again ...', status:0});
if (ret.length > 1) return ({text:'KO - Multiple destination hosts match ... ', status:0});
if (ret[0]['if'] != g['if_id2']) return ({text:'KO - Correct IP reached but wrong interface, try again ...', status:0});
// now reverse way
my_console_log("check reach interface : "+g['if_id2']+" -> "+g['if_id1']);
ret = [];
for (i = 0; i < ifs.length; i++)
{
if (g['if_id1'] == ifs[i]['if'])
{
visited_host = [];
if ((itf_ip = get_if_ip(ifs[i])) === null)
g_sim_logs += "on interface "+ifs[i]['if']+": invalid IP\n";
else
{
g_sim_logs +="reverse way : "+g['if_id2']+" -> "+g['if_id1']+" ("+get_if_ip_str(ifs[i])+")\n";
ret = ret.concat(rec_route(itf_ip, 0, null, g['h2']));
}
if (ret.length > 0)
break; // if one interface matches, that's enough - if ret > 1 it's because another host matches
}
}
if (ret.length <= 0) return ({text:'KO - No reverse way, try again ...', status:0});
if (ret.length > 1) return ({text:'KO - Multiple origin hosts match ... ', status:0});
if (ret[0]['if'] != g['if_id1']) return ({text:'KO - Correct IP reached but wrong interface, try again ...', status:0});
return ({text:'OK - Congratulations !!', status:1});
}
function sim_goal(g)
{
if (g['type'] == 'reach')
return (sim_reach(g));
if (g['type'] == 'reach_if')
return (sim_reach_if(g));
}

18
net_practice/level1.html Normal file
View File

@ -0,0 +1,18 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<script src="js/level1.js"></script>
<script src="js/show.js"></script>
<script src="js/sim.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id='goals_id' class='goals_div'></div>
<div id='root_id'>
<svg class="svg_layer" height="2000px" width="2000px" id="sl"></svg>
</div>
<div id='logs_id' class='logs_div'></div>
<script> load_board(); </script>
</body>
</html>

18
net_practice/level10.html Normal file
View File

@ -0,0 +1,18 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<script src="js/level10.js"></script>
<script src="js/show.js"></script>
<script src="js/sim.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id='goals_id' class='goals_div'></div>
<div id='root_id'>
<svg class="svg_layer" height="2000px" width="2000px" id="sl"></svg>
</div>
<div id='logs_id' class='logs_div'></div>
<script> load_board(); </script>
</body>
</html>

18
net_practice/level2.html Normal file
View File

@ -0,0 +1,18 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<script src="js/level2.js"></script>
<script src="js/show.js"></script>
<script src="js/sim.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id='goals_id' class='goals_div'></div>
<div id='root_id'>
<svg class="svg_layer" height="2000px" width="2000px" id="sl"></svg>
</div>
<div id='logs_id' class='logs_div'></div>
<script> load_board(); </script>
</body>
</html>

18
net_practice/level3.html Normal file
View File

@ -0,0 +1,18 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<script src="js/level3.js"></script>
<script src="js/show.js"></script>
<script src="js/sim.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id='goals_id' class='goals_div'></div>
<div id='root_id'>
<svg class="svg_layer" height="2000px" width="2000px" id="sl"></svg>
</div>
<div id='logs_id' class='logs_div'></div>
<script> load_board(); </script>
</body>
</html>

18
net_practice/level4.html Normal file
View File

@ -0,0 +1,18 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<script src="js/level4.js"></script>
<script src="js/show.js"></script>
<script src="js/sim.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id='goals_id' class='goals_div'></div>
<div id='root_id'>
<svg class="svg_layer" height="2000px" width="2000px" id="sl"></svg>
</div>
<div id='logs_id' class='logs_div'></div>
<script> load_board(); </script>
</body>
</html>

18
net_practice/level5.html Normal file
View File

@ -0,0 +1,18 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<script src="js/level5.js"></script>
<script src="js/show.js"></script>
<script src="js/sim.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id='goals_id' class='goals_div'></div>
<div id='root_id'>
<svg class="svg_layer" height="2000px" width="2000px" id="sl"></svg>
</div>
<div id='logs_id' class='logs_div'></div>
<script> load_board(); </script>
</body>
</html>

18
net_practice/level6.html Normal file
View File

@ -0,0 +1,18 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<script src="js/level6.js"></script>
<script src="js/show.js"></script>
<script src="js/sim.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id='goals_id' class='goals_div'></div>
<div id='root_id'>
<svg class="svg_layer" height="2000px" width="2000px" id="sl"></svg>
</div>
<div id='logs_id' class='logs_div'></div>
<script> load_board(); </script>
</body>
</html>

18
net_practice/level7.html Normal file
View File

@ -0,0 +1,18 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<script src="js/level7.js"></script>
<script src="js/show.js"></script>
<script src="js/sim.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id='goals_id' class='goals_div'></div>
<div id='root_id'>
<svg class="svg_layer" height="2000px" width="2000px" id="sl"></svg>
</div>
<div id='logs_id' class='logs_div'></div>
<script> load_board(); </script>
</body>
</html>

18
net_practice/level8.html Normal file
View File

@ -0,0 +1,18 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<script src="js/level8.js"></script>
<script src="js/show.js"></script>
<script src="js/sim.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id='goals_id' class='goals_div'></div>
<div id='root_id'>
<svg class="svg_layer" height="2000px" width="2000px" id="sl"></svg>
</div>
<div id='logs_id' class='logs_div'></div>
<script> load_board(); </script>
</body>
</html>

18
net_practice/level9.html Normal file
View File

@ -0,0 +1,18 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/netpractice.css">
<script src="js/level9.js"></script>
<script src="js/show.js"></script>
<script src="js/sim.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id='goals_id' class='goals_div'></div>
<div id='root_id'>
<svg class="svg_layer" height="2000px" width="2000px" id="sl"></svg>
</div>
<div id='logs_id' class='logs_div'></div>
<script> load_board(); </script>
</body>
</html>