Networking II - Ports, Layers, Client-Server Architecture, Web Servers
The overall goal of this lab is to complement your knowledge on IP and subnets by bringing applications into the picture and allowing you to see the notions of ports and layers in a concrete example. This will be achieved using the same GNS3-based environment as last week.
Additionally, we will learn more about Docker. Docker is the tool that is used to provision the invididual hosts in out GNS3 environment, but has many use cases beyond that.
Learning Goals
After this lab, you will be able to
- Recognise the importance of ports in networking
- Learn basic Docker principles
- Images and containers
- The Dockerfile
- Basic commands for managing containers
Lab Exercises
Please read each exercise entirely before starting to solve it.
Remember that you should deliver a report after the networking module is finished. It should include the main commands and configurations necessary to complete each exercise. Do not forget to take notes while solving the exercises so you do not have to repeat them.
These exercises should be completed in teams.
Web Server, Ports, HTTP
Initializing the Environment
We will use the same topology as last week, using one host as client and one as server. To get started, close any running instances of GNS3 and launch it again. You can load your project from last time or re-create the two-host topology according to last week's instructions.
Since the underlying Docker images that are used for the hosts have been updated, it is necessary to restart GNS3 for the changes to take effect.
As last week, set compatible IP addresses on the interfaces of the two hosts, for instance 10.0.0.1/24
and 10.0.0.2/24
.
Before you continue, make sure that the two hosts can reach each other by using ping
.
Running a Web Server
- As mentioned before, one host will take the role of the client and one that of the server. On the server (
ubuntu-host-2
with IP10.0.0.2
), navigate to the/var/www
folder and inspect its contents.
- You can run a simple Python-based HTTP server in your current working directory by issuing the command
python3 -m http.server 80
. This will instruct python to run thehttp.server
module with80
as its first argument, indicating which port the HTTP server should listen to. 80 is the standard port number for HTTP. You can learn more about commonly used port numbers here.
You can use the combination Ctrl-C
to stop the server application and regain control of the console.
Interacting with the Web Server
- With the server application running, we can access the content it serves. Instead of using a browser, we can use command line tools like
curl
to connect to the server and download HTML pages or other files that are offered.
- From the host (
ubuntu-host-1
if you're following the same naming and addressing scheme), trycurl 10.0.0.2
(which is shorter but equivalent tocurl http://10.0.0.2/
, more clearly showing the underlying HTTP request process thatcurl
performs; similar to how a browser would automatically prependhttp://
to the URL when you type it into the address bar). Observe the output and relate it to the content you saw in step 1. Investigate how you can download the fileexample.html
.
- On
ubuntu-host-2
, stop the server application, renameexample.html
toindex.html
, and restart the server application. Re-run thecurl
commands from the client from the previous step and discuss the differences in the output. What happens if you try requesting a page that does not exist?
Capturing HTTP Traffic
- Following the instructions from last week, start a traffic capture on the link between the client and the server.
-
With Wireshark open, run the previous
curl
commands again and discuss the HTTP traffic that appears.- What kind of information is exchanged between client and server in the HTTP messages in each direction? You can read about HTTP request methods, HTTP status codes, and HTTP request headers for more information.
- Click on an HTTP packet and check the detailed view in the lower half of the Wireshark window. Taking a look at these details, what can you tell about the protocol stack that is used here? Refer back to chapter 1.5.1 in the book and map the protocols you find to the different layers.
- Compare how the traffic changes when you request
example.html
andlipsum.txt
. What could be the reason?
Compare the size of the two files and recall what we discussed about packets.
Changing Ports
- Going back to the server, stop the application and re-run it using a different port. For instance,
python3 -m http.server 8000
. How does this change the output at the client trying tocurl
? Find out how to pointcurl
to a specific port, e.g., by consulting its manual.
Docker
For this second part, you can quit GNS3 and open a terminal directly on your VM. The CLI prompt should say netlab@netlab-linux:~$
.
Basics
In Docker, we distinguish between images and containers (also called instances). Images are the pre-built templates or snapshots that package all the software that is required for the intended use case. The use case can be a fresh install of a specific Linux distribution, a pre-installed and pre-configured service (web server, mail server, database, ..), or more. For this, an image can include code and configuration files, runtimes and libraries, as well as other dependencies. Based on such an image, we can launch one or multiple running containers that execute the environment defined in the image.
-
To check which images are available on your machine, you can run
docker images
. How many images are listed in your case? -
You can create an instance based on the
ubuntu
image by running
docker run -dit --name my-ubuntu-container ubuntu
docker run -dit --name my-ubuntu-container ubuntu
The output should give you a long ID which is used to uniquely identify that specific instance. For easier reference, we also provided a more memorable name, my-ubuntu-container
.
You can learn more about the options of docker run in the documentation. For now, it is enough to know that docker run -dit
instantiates a container in the background, and allows us to attach to its console later on.
- You can confirm that the instance has been created using
docker ps
(process status). The output contains the ID, base image name, and other high-level information about your running container instances. Following step 2, you can also launch additional instances from the same image and confirm their presence usingdocker ps
.
If you create multiple containers and explicitly provide a name, make sure that the name is unique to avoid errors.
- With the containers running, you can attach to them via
docker exec -itbash
docker exec -it <containerID> bash
Your prompt should change from netlab@netlab-linux:~$
to root@fa00f8e10813:/#
, indicating that you are now logged in as root on the container with the respective ID. Create some files or folders inside the container.
In this case, the containerID
can be either the ID from the outputs in the previous step (the first few characters are enough as long as they are enough to uniquely identify your container), or the name you chose when running the container.
- Try running
cat /etc/os-release
inside your container, thenexit
back to your netlab VM and run the same command to compare the operating system versions. What can you observe?
This step illustrates some of the power of using containers. The Docker image we used as the basis for our container uses a different version of the same operating system and, as we shall see later, it is even possible to run different Linux distributions in our containers, regardless of the main host's distribution.
-
To clean up, you can stop and remove containers using
docker stop <containerID>
followed bydocker rm <containerID>
. -
Re-create one of the containers according to step 2. What happened to the files/folders you created in step 4? Discuss how this relates to the concepts of images and containers.
Building Our Own Image
We can also define our own image to create containers which run our desired software. As an example, we will create the web server from the fist part of today's lab. To this end, we will use the ubuntu
image as a starting point and extend it to fit our needs. The Docker way of doing this involves a Dockerfile which you can think of as a recipe for building images.
-
Download an exemplary Dockerfile project from
https://folk.ntnu.no/stanisll/2024/ttm4175/ttm4175-webserver.zip
using the command line. For this, you can usecurl
(it will complain, but will point you to relevant flags) or can consultapropos
or a web search to find other command line tools that can be used instead. Mention and explain the command you used in your report. -
Extract the zip archive using
unzip ttm4175-webserver.zip
and navigate into the newly createdttm4175-webserver
folder. -
Read through the commented
Dockerfile
and try to understand what it does. You do not need to execute the commands in that file.
You can refer to the Dockerfile manual if you want to learn more about the different Dockerfile-specific instructions like FROM
, RUN
, and EXPOSE
. For more information about the apt software package manager, you can use man apt
.
-
Extend the Dockerfile to not only copy the
example.html
file, but alsolipsum.txt
. You can use thenano
editor for this. -
To build an image based on the Dockerfile, execute
docker build -t ttm4175-webserver .
(don't forget the dot). This will instruct docker to scan the current directory (.
) for a Dockerfile and build an image calledttm4175-webserver
. -
Confirm that the build was successful by checking
docker images
. Then launch an instance of thettm4175-webserver
and attach to it (cf. steps 2 and 4 in the Docker basics part). -
Within the container,
- Find out its IP address using tools you already know and note it in your report.
- Navigate to the
/var/www
directory and confirm that the files you specified in theCOPY
part of the Dockerfile are present. - As in the web server exercise, launch a web server on port 80.
- Open a web browser in your VM (not on your laptop) and navigate to the IP address of the container. What do you see? Take a screenshot and include it in your report.
-
Stop and remove all running containers. Can you find a way of doing it with a single command? Search online!