Browse Source

Merge remote-tracking branch 'old/master'. Brings the github version to parity with the online version.

Conflicts:
	header.inc.php
	index.php
	js/bindings.js
	js/devicescripts.js
	levels/01 Basics/level04.html
	levels/04 Attacks/attacks02.json
	levels/login/login.html
	listing.inc.php
	login.inc.php
	register.php
Erinn 8 years ago
parent
commit
32560f2dd2

+ 6 - 4
header.inc.php

@@ -15,22 +15,24 @@
 
 	<link href="css/jquery-ui.min.css" rel="stylesheet">
 	<style type="text/css">
+	* { font-family:Arial, Helvetica, sans-serif; }
+
 	html {
-		height:100%;
 		margin:0;
+		min-height:100%;
 	}
 
 	body {
 		background:#DDD;
 		background:linear-gradient(#DDD, #FFF);
 		margin:0;
-		height:100%;
+		min-height:100%;
 	}
 
 	#content {
 		background-color:#FFF;
 		width:800px;
-		height:90%;
+		min-height:90%;
 		margin-left:auto;
 		margin-right:auto;
 		padding:30px;
@@ -43,5 +45,5 @@
 <body>
 <div id="content">
 
-<h1>CS4G Netsim</h1>
+<h1>Netsim</h1>
 

BIN
includes/fireworks.gif


BIN
includes/thumbs/0.png


BIN
includes/thumbs/1.png


BIN
includes/thumbs/10.png


BIN
includes/thumbs/11.png


BIN
includes/thumbs/12.png


BIN
includes/thumbs/13.png


BIN
includes/thumbs/2.png


BIN
includes/thumbs/3.png


BIN
includes/thumbs/4.png


BIN
includes/thumbs/5.png


BIN
includes/thumbs/6.png


BIN
includes/thumbs/7.png


BIN
includes/thumbs/8.png


BIN
includes/thumbs/9.png


BIN
includes/thumbs/check.png


+ 20 - 1
index.php

@@ -9,7 +9,25 @@ if (LOGGEDIN && !isset($_GET['level'])) {
 	$l = (int)$_GET['level'];
 	$q = $db->query("SELECT * FROM level WHERE id = ".$l);
 	$leveldata = $q->fetchArray();
-	if (!$leveldata) exit('no such level');
+	if (!$leveldata) {
+		include 'header.inc.php';
+		?>
+		<div style="text-align:center; min-height:100%;">
+			<h3>Congratulations!</h3>
+			<p>You beat the last level in the game!</p>
+
+			<p><img src="./includes/fireworks.gif"></p>
+
+			<p>You may want to go <a href="./">look over the levels</a> to make sure you didn't miss any.</p>
+
+			<p>Otherwise, give yourself a pat on the back! You're a real hacker now!</p>
+
+			<div style="height:150px;"></div>
+		</div>
+		<?php
+		include 'footer.inc.php';
+		exit();
+	}
 } else {
 	$leveldata = array('id' => -1, 'filename' => 'login/login', 'name' => 'CS4G Netsim');
 }
@@ -29,6 +47,7 @@ if (LOGGEDIN && !isset($_GET['level'])) {
 
 	<link href="css/jquery-ui.min.css" rel="stylesheet">
 	<style type="text/css">
+		* { font-family:Arial, Helvetica, sans-serif; }
 		body { margin: 0; overflow:hidden; }
 	</style>
 </head>

+ 2 - 1
js/bindings.js

@@ -1,6 +1,7 @@
 
 function onDeviceClick() {
-	$("#subpane").html("<h3>Device info</h3><p><img src=\"./includes/"+(this.image||'imac')+".png\"></p><p>IP address: "+this.id+"</p>");
+	var ip = this.hasOwnProperty("secret") && this.secret ? "<i>secret</i>" : this.id;
+	$("#subpane").html("<h3>Device info</h3><p><img src=\"./includes/"+(this.image||'imac')+".png\"></p><p>IP address: "+ip+"</p>");
 	$("#subpane").show();
 	$("#subpane_close").show();
 	$("#leveldescrip").hide();

+ 37 - 2
js/devicescripts.js

@@ -1,9 +1,31 @@
 var deviceScripts = {
 	manualRouter: {
-		onPacketReceived: function(device, packet) {
+		onPacketReceived: function(device, packet, portNum) {
+			var newpkt = JSON.parse(JSON.stringify(packet));
+
+			if (packet.hasOwnProperty("transport") && packet.transport.hasOwnProperty("proto") && packet.transport.proto == "ICMP" && packet.transport.hasOwnProperty("ttl")) {
+				if (packet.transport.ttl > 0) {
+					newpkt.transport.ttl--;
+				} else {
+					newpkt.network.srcip = device.id;
+					newpkt.network.dstip = packet.network.srcip;
+					newpkt.transport.proto = "ICMP_ERROR";
+					sendPacket(device.id, portNum, newpkt);
+					return;
+				}
+			}
+
+			if (packet.hasOwnProperty("network") && packet.network.hasOwnProperty("dstip") && packet.network.dstip == device.id &&
+			    packet.hasOwnProperty("transport") && packet.transport.hasOwnProperty("proto") && packet.transport.proto == "ICMP") {
+			    	newpkt.network.srcip = device.id;
+				newpkt.network.dstip = packet.network.srcip;
+				sendPacket(device.id, portNum, newpkt);
+				return;
+			}
+
 			for (var i = 0; i < device.rules.length; i++) {
 				if (device.rules[i].dstip == packet.network.dstip) {
-					sendPacket(device.id, device.rules[i].portNum, packet);
+					sendPacket(device.id, device.rules[i].portNum, newpkt);
 				}
 			}
 		}
@@ -15,6 +37,19 @@ var deviceScripts = {
 		}
 	},
 
+	// proxy device for attacks1. again, this is quick'n'dirty for the workshop
+	proxy: {
+		onPacketReceived: function(device, packet, portNum) {
+			var newpkt = JSON.parse(JSON.stringify(packet));
+
+			if (packet.network.dstip == "Proxy") {
+				newpkt.network.dstip = "Blocked Site";
+			}
+
+			sendPacket(device.id, portNum == 0 ? 1 : 0, newpkt);
+		}
+	},
+
     ping: {
 		onPacketReceived: function(device, packet) {
                     if(packet.hasOwnProperty("transport") && packet["transport"].hasOwnProperty("proto")){

+ 3 - 2
levels/04 Attacks/attacks02.json

@@ -43,7 +43,7 @@
 			ports:2,
 			x:0.6,
 			y:0.2,
-                        script: deviceScripts.modem
+                        script: deviceScripts.proxy
 		}
 	],
 	links:[
@@ -94,5 +94,6 @@
 				network:{srcip:"Alice",dstip:"Blocked Site"}
 			}
 		}
-        ]
+        ],
+	nextLevel:13
 }

+ 13 - 0
levels/04 Attacks/attacks03.html

@@ -0,0 +1,13 @@
+
+<p>In this level, the routers use the <strong>time to live (TTL)</strong> field.  The TTL field is designed to keep packets from getting trapped in infinite loops: each router decreases the TTL value by one, and if it ever reaches zero, it stops forwarding the packet and returns an error message instead.<p>
+
+<p>We have hidden the IP addresses of the routers in this level.  Your job is to figure out who they are!</p>
+
+<p><i><strong>Fun fact:</strong> This trick is called "tracerouting", and you can do it for real to see the routers between you and anyone else. Ask a TA to show you how!</i></p>
+
+<h3>Level Objectives</h3>
+
+<ul>
+	<li>Figure out how to use TTLs to figure out the IP addresses of routers</li>
+	<li>Send a ping to <strong>each</strong> of the four routers between Alice and Google</li>
+</ul>

+ 155 - 0
levels/04 Attacks/attacks03.json

@@ -0,0 +1,155 @@
+{
+	devices:[
+		{
+			id:"Alice",
+			ports:1,
+			x:0.1,
+			y:0.3,
+                        player: true
+		},
+		{
+			id:"Waterloo",
+                        image: "router",
+			ports:2,
+			x:0.25,
+			y:0.6,
+                        script: deviceScripts.manualRouter,
+			rules:[
+				{dstip:"Alice", portNum:0},
+				{dstip:"Toronto", portNum:1},
+				{dstip:"New York", portNum:1},
+				{dstip:"Mountain View", portNum:1},
+                                {dstip:"Google", portNum:1}
+			],
+			secret: true
+		},
+		{
+			id:"Toronto",
+                        image: "router",
+			ports:2,
+			x:0.4,
+			y:0.3,
+                        script: deviceScripts.manualRouter,
+			rules:[
+				{dstip:"Alice", portNum:0},
+				{dstip:"Waterloo", portNum:0},
+				{dstip:"New York", portNum:1},
+				{dstip:"Mountain View", portNum:1},
+                                {dstip:"Google", portNum:1}
+			],
+			secret: true
+		},
+		{
+			id:"New York",
+                        image: "router",
+			ports:2,
+			x:0.55,
+			y:0.6,
+                        script: deviceScripts.manualRouter,
+			rules:[
+				{dstip:"Alice", portNum:0},
+				{dstip:"Toronto", portNum:0},
+				{dstip:"Waterloo", portNum:0},
+				{dstip:"Mountain View", portNum:1},
+                                {dstip:"Google", portNum:1}
+			],
+			secret: true
+		},
+		{
+			id:"Mountain View",
+                        image: "router",
+			ports:2,
+			x:0.7,
+			y:0.3,
+                        script: deviceScripts.manualRouter,
+			rules:[
+				{dstip:"Alice", portNum:0},
+				{dstip:"Waterloo", portNum:0},
+				{dstip:"Toronto", portNum:0},
+				{dstip:"New York", portNum:0},
+                                {dstip:"Google", portNum:1}
+			],
+			secret: true
+		},
+		{
+			id:"Google",
+                        image: "server",
+			ports:1,
+			x:0.85,
+			y:0.6,
+			script: deviceScripts.ping
+		}
+	],
+	links:[
+		{
+			src:"Alice", srcport:0,
+			dst:"Waterloo", dstport:0
+		},
+		{
+			src:"Waterloo", srcport:1,
+			dst:"Toronto", dstport:0
+		},
+		{
+			src:"Toronto", srcport:1,
+			dst:"New York", dstport:0
+		},
+		{
+			src:"New York", srcport:1,
+			dst:"Mountain View", dstport:0
+		},
+		{
+			src:"Mountain View", srcport:1,
+			dst:"Google", dstport:0
+		}
+	],
+	timeline:[
+		{
+			type:"packet",
+			at:1000,
+			from:"Alice",
+			payload:{
+				network:{srcip:"Alice",dstip:"Google"},
+				transport:{proto:"ICMP", ttl:256}
+			}
+		},
+		{
+			type:"packet",
+			at:2000,
+			from:"Alice",
+			payload:{
+				network:{srcip:"Alice",dstip:"Google"},
+				transport:{proto:"ICMP", ttl:256}
+			}
+		}
+	],
+	triggers:[
+		{
+			type:"packet",
+			device:"Waterloo",
+			payload:{
+				network:{srcip:"Alice",dstip:"Waterloo"}, transport:{proto:"ICMP"}
+			}
+		},
+		{
+			type:"packet",
+			device:"Toronto",
+			payload:{
+				network:{srcip:"Alice",dstip:"Toronto"}, transport:{proto:"ICMP"}
+			}
+		},
+		{
+			type:"packet",
+			device:"New York",
+			payload:{
+				network:{srcip:"Alice",dstip:"New York"}, transport:{proto:"ICMP"}
+			}
+		},
+		{
+			type:"packet",
+			device:"Mountain View",
+			payload:{
+				network:{srcip:"Alice",dstip:"Mountain View"}, transport:{proto:"ICMP"}
+			}
+		}
+        ]
+}

+ 10 - 0
levels/login/login.html

@@ -22,3 +22,13 @@
 	<input type="submit" value="Log in">
 	<a href="./register.php">Register</a>
 </form>
+
+<br><br><br><br>
+
+<p><small>Netsim was created by 
+	<a href="https://erinn.io/">Erinn Atwater</a> based on a project with 
+	<a href="https://cs.uwaterloo.ca/~cbocovic">Cecylia Bocovich</a>.
+	Some device images were designed by 
+	<a href="http://www.flaticon.com/authors/madebyoliver">madebyoliver</a> from Flaticon.
+	View Netsim's source code on <a href="https://github.com/errorinn/netsim">Github</a>, or tip the creator on <a href="https://www.patreon.com/errorinn">Patreon</a>.
+</small></p>

+ 18 - 4
listing.inc.php

@@ -2,18 +2,32 @@
 
 <div style="float:right;"><input type="button" value="Log out" onclick="location.href='./?logout'"></div>
 
+<p>Welcome to Netsim!  If this is your first time playing, we recommend you start from the first level below, and work your way forward.<p>
+
+<p>Please note that this project is still in <strong>beta</strong>. If you find any bugs, you can report them to <a href="https://twitter.com/errorinn">@errorinn</a> or open an issue on <a href="https://github.com/errorinn/netsim/issues">Github</a>.</p>
+
 <?php
 
 $res = $db->query("SELECT * FROM category ORDER BY orderby");
 
 while ($row = $res->fetchArray()) {
-	echo "<h3>".$row['name']."</h3>\n";
+	echo "<h3 style=\"clear:both;;\">".$row['name']."</h3>\n";
 	$res2 = $db->query("SELECT * FROM level WHERE category_id = ".$row['id']." ORDER BY orderby");
 	while ($row2 = $res2->fetchArray()) {
-		echo "[";
-		echo levelComplete($row2['id']) ? "X" : "&nbsp;";
-		echo "] <a href=\"./?level=".$row2['id']."\">".$row2['name']."</a><br>\n";
+		$complete = levelComplete($row2['id']);
+		echo "<div style=\"float:left;position:relative;border-radius:0 0 10px 10px;border:solid 1px #AAA;margin:10px;padding:5px\">";
+		echo "<a href=\"./?level=".$row2['id']."\">\n";
+		echo "\t<img".($complete ? " style=\"opacity:0.3\"" : "")." src=\"includes/thumbs/".(file_exists("includes/thumbs/".$row2['id'].".png") ? $row2['id'] : 0).".png\">\n";
+		if ($complete) echo "\t<img src=\"includes/thumbs/check.png\" style=\"position:absolute;top:80px;left:70px;\">\n";
+		echo "</a><br>\n";
+		echo "<a href=\"./?levels=".$row2['id']."\" style=\"color:#000;text-decoration:none;\">".$row2['name']."</a>\n";
+		echo "</div>\n";
+		//echo "[";
+		//echo levelComplete($row2['id']) ? "X" : "&nbsp;";
+		//echo "] <a href=\"./?level=".$row2['id']."\">".$row2['name']."</a><br>\n";
 	}
+
+	echo "<div style=\"clear:both;margin-bottom:30px;\"></div>";
 }
 
 function levelComplete($l) {

+ 1 - 1
login.inc.php

@@ -14,7 +14,7 @@ if (!file_exists(DB_FILE)) {
 		$db->exec("CREATE TABLE category (id integer PRIMARY KEY,name text,orderby integer)");
 		$db->exec("INSERT INTO category (name, orderby) VALUES('Basics', 1),('Spoofs', 2),('Denial of Service', 3),('Attacks', 4)");
 		$db->exec("CREATE TABLE level (id integer PRIMARY KEY,category_id integer,name text,orderby integer,filename text)");
-		$db->exec("INSERT INTO level (category_id, name, orderby, filename) VALUES(1, 'Basics 1', 1, '01 Basics/level01'),(1, 'Basics 2', 2, '01 Basics/level02'),(1, 'Basics 3', 3, '01 Basics/level03'),(1, 'Basics 4', 4, '01 Basics/level04'),(1, 'Basics 5', 5, '01 Basics/level05'),(2, 'Spoofs 1', 1, '02 Spoofs/spoofs01'),(2, 'Spoofs 2', 2, '02 Spoofs/spoofs02'),(3, 'DoS 1', 1, '03 DoS/dos01'),(3, 'DoS 2', 2, '03 DoS/dos02'),(3, 'DoS 3', 3, '03 DoS/dos03'),(4, 'Attacks 1', 1, '04 Attacks/attacks01'),(4, 'Attacks 2', 2, '04 Attacks/attacks02')");
+		$db->exec("INSERT INTO level (category_id, name, orderby, filename) VALUES(1, 'Getting started', 1, '01 Basics/level01'),(1, 'Packet fields', 2, '01 Basics/level02'),(1, 'Ping', 3, '01 Basics/level03'),(1, 'Routing', 4, '01 Basics/level04'),(1, 'Modems', 5, '01 Basics/level05'),(2, 'IP Spoofing', 1, '02 Spoofs/spoofs01'),(2, 'Stealing packets', 2, '02 Spoofs/spoofs02'),(3, 'Basic DoS', 1, '03 DoS/dos01'),(3, 'Distributed DoS', 2, '03 DoS/dos02'),(3, 'Smurf attack', 3, '03 DoS/dos03'),(4, 'Man-in-the-middle', 1, '04 Attacks/attacks01'),(4, 'Censorship', 2, '04 Attacks/attacks02'), (4, 'Traceroute', 3, '04 Attacks/attacks03')");
 		$db->exec("CREATE TABLE solns (id integer PRIMARY KEY,user_id integer,level_id integer,completed integer,json text)");
 
 		echo "<p>The database was initialized successfully! <a href=\"./\">Continue...</a></p>\n";

+ 4 - 0
register.php

@@ -31,6 +31,8 @@ include 'header.inc.php';
 
 <h3>Register</h3>
 
+<p>User accounts are only used to track your progress through levels. Please note that Netsim is still in <strong>beta</strong>, so we may need to reset the user database from time to time.</p>
+
 <?=(isset($login_error) ? "<p>".$login_error."</p>\n" : "")?>
 
 <form method="post" action="register.php" onsubmit="if (document.getElementById('reg_password').value == document.getElementById('confirm_password').value) return true; else { alert('Passwords don\'t match!'); return false; }">
@@ -43,6 +45,8 @@ include 'header.inc.php';
 	<p><input type="submit" value="Register"></p>
 </form>
 
+<div style="height:150px;"></div>
+
 <script type="text/javascript">$('.reg_username').focus();</script>
 
 <?php include 'footer.inc.php'; ?>

+ 31 - 0
todo

@@ -0,0 +1,31 @@
+basics
+- game completion message
+- autofocus on register
+- attribution on listing, register
+- beta message
+- pressing enter on "add packet" dialog
+
+nice to have
+- method to work on test levels
+- resize game on resize viewport (attempt at this at top of ui.js but it's laggy)
+- differentiate launcher buttons
+- coloured packets
+- only preload used device sprites
+- move levels to database
+- level editor
+
+long term
+- non-php version
+--- load json/html via ajax
+--- remove login system
+--- remove saving
+--- add warning screen about that
+- paid-hosting version?
+- wireless
+- patreon
+
+level ideas
+- ping, tracert
+- privacy (see ISPs, who can read data, etc)
+- how protocols work (HTTP, DNS, email, DHCP...)
+