IPv4 Forwarding
Table of Content
- Introduction
- Internetworks for Experiments
- Experiments and Demonstration
- Appendix I. Network Configuration Files
- Appendix II. (Possible) ScaPy Bug in Version 2.4.0
Introduction
The Internet Protocol provides a best effortd datagram service between two end systems on the Internet. In between the two end systems, there are forwarding nodes that we often call routers. The end systems and these forwarding nodes forwards IP packets from one linke (the incoming link) to another link (the outgoing link) independently from each other based on the information in the IP packet header, specifically, the source and the destination IP addresses and a forwarding table on the forwarding node (including the end systems) that we often call a routing table depending on how we present it.
Internetworks for Experiments
To understand this concept, we design internetworks with four Linux virtual machines with two different topologies, and observe packet forwarding on the internetworks. For ease of discussion, we name the four Linux virtual machines, as bushwick, eastny flatbush, and midwood, and we call the two topologies the diamond topology and the line topology.
Setting up Diamond and Line Ethernets
-
We add two Ethernet NICs to each of the four Linux virtual machines and connect one of the two NICs to the same Ethernet that we call the “DiamondEthernet” VirtualBox Internal Networks, and the other “LineEthernet”. We can complete this via the VirtualBox GUI interface or via the following commands on the command line. However, since you can only access 4 of the 8 NICs a VM can have via VirtualBox’s GUI, you cannot have both the diamond Ethernets and the line Ethernets simultaneously.
#!/bin/bash -x vms=(Bushwick EastNewYork Flatbush Midwood) for vm in "${vms[@]}"; do vboxmanage controlvm DebianLnx${vm} poweroff done # Diamond Ethernets # DiamondMidwoodFlatbush (3 - 3) vboxmanage modifyvm DebianLnxMidwood --nic3 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxMidwood --intnet3 "DiamondMidwoodFlatbush" [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxFlatbush --nic3 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxFlatbush --intnet3 "DiamondMidwoodFlatbush" [ $? -eq 0 ] || exit $? # DiamondMidwoodBushwick (4 - 3) vboxmanage modifyvm DebianLnxMidwood --nic4 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxMidwood --intnet4 "DiamondMidwoodBushwick" [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxBushwick --nic3 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxBushwick --intnet3 "DiamondMidwoodBushwick" [ $? -eq 0 ] || exit $? # DiamondFlatbushEastNY (4 - 3) vboxmanage modifyvm DebianLnxFlatbush --nic4 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxFlatbush --intnet4 "DiamondFlatbushEastNY" [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxEastNewYork --nic3 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxEastNewYork --intnet3 "DiamondFlatbushEastNY" [ $? -eq 0 ] || exit $? # DiamondBushwickEastNY (4 - 4) vboxmanage modifyvm DebianLnxBushwick --nic4 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxBushwick --intnet4 "DiamondBushwickEastNY" [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxEastNewYork --nic4 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxEastNewYork --intnet4 "DiamondBushwickEastNY" [ $? -eq 0 ] || exit $? # Line Ethernets # LineMidwoodFlatbush (5 - 5) vboxmanage modifyvm DebianLnxMidwood --nic5 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxMidwood --intnet5 "LineMidwoodFlatbush" [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxFlatbush --nic5 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxFlatbush --intnet5 "LineMidwoodFlatbush" [ $? -eq 0 ] || exit $? # LineFlatbushBushwick (6 - 5) vboxmanage modifyvm DebianLnxFlatbush --nic6 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxFlatbush --intnet6 "LineFlatbushBushwick" [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxBushwick --nic5 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxBushwick --intnet5 "LineFlatbushBushwick" [ $? -eq 0 ] || exit $? # LineBushwickEastNY (6 - 5) vboxmanage modifyvm DebianLnxBushwick --nic6 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxBushwick --intnet6 "LineBushwickEastNY" [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxEastNewYork --nic5 intnet [ $? -eq 0 ] || exit $? vboxmanage modifyvm DebianLnxEastNewYork --intnet5 "LineBushwickEastNY" [ $? -eq 0 ] || exit $? for vm in "${vms[@]}"; do vboxmanage startvm DebianLnx${vm} --type headless done
If you insist on using GUI to set up this, you can only set up one internetwork at a time. In the GUI, make sure you choose right adapter, select “internal network” as “Attach to”, select or enter the correct Ethernet name to attach to.
Verifying Diamond and Line Ethernets Setup
We need to configure 8 NICs on 4 VM s to set up 4 Ethernets for the Diamond ethernets, and 6 NICs on 4 VMs for the Line ethernets. It is easy to make a mistake during the process. It is important to verify the Ethernet setup. This takes a few steps.
-
Query Ethernet NIC information. For instance, on VM Flatbush, we run the following,
brooklyn@flatbush:~$ ip link show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:45:bf:a2 brd ff:ff:ff:ff:ff:ff 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:59:ef:a7 brd ff:ff:ff:ff:ff:ff 4: enp0s9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:cb:67:1d brd ff:ff:ff:ff:ff:ff 5: enp0s10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:29:17:39 brd ff:ff:ff:ff:ff:ff 6: enp0s16: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:e9:34:5f brd ff:ff:ff:ff:ff:ff 7: enp0s17: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:d5:de:96 brd ff:ff:ff:ff:ff:ff brooklyn@flatbush:~$
Similarly, on VM Midwood, we do
brooklyn@midwood:~$ ip link show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:5a:ff:ec brd ff:ff:ff:ff:ff:ff 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:a1:33:b4 brd ff:ff:ff:ff:ff:ff 4: enp0s9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:08:0d:a1 brd ff:ff:ff:ff:ff:ff 5: enp0s10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:a2:b4:f0 brd ff:ff:ff:ff:ff:ff 6: enp0s16: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:a3:d1:e4 brd ff:ff:ff:ff:ff:ff brooklyn@midwood:~$
-
We now need to verify that one NIC on VM midwood and one on Flatbush on the DiamondMidwoodFlatbush Ethernet as designed.
In VirtualBox we can identify a NIC by a number or a name like “nic1” or “adapter1”, but a VM names each NIC indepently. Because of this, we use a NIC’s Ethernet address to identify it.
For instance, from Virtubox’s UI or from the command line on the host, we can retrieve the Ethernet address of the NIC tapped on the DiamondMidwoodFlatbush Ethernet on VM midwood,
$ vboxmanage showvminfo DebianLnxMidwood | grep DiamondMidwoodFlatbush NIC 3: MAC: 080027080DA1, Attachment: Internal Network 'Di amondMidwoodFlatbush', Cable connected: on, Trace: off (file: none), Type: 82540 EM, Reported speed: 0 Mbps, Boot priority: 0, Promisc Policy: deny, Bandwidth gr oup: none
where it shows that the Ethernet’s address of NIC 3 is 080027080DA1. Comparing with the information of the NICs on VM midwood queried in Step 1, we see that NIC enp0s9 has the same address (shown as 08:00:27:08:0d:a1).
Similarly, from Virtubox’s UI or from the command line on the host, we can the Ethernet address of the NIC tapped on the DiamondMidwoodFlatbush Ethernet on VM Flatbush,
$ vboxmanage showvminfo DebianLnxFlatbush | grep DiamondMidwoodFlatbush NIC 3: MAC: 080027CB671D, Attachment: Internal Network 'Di amondMidwoodFlatbush', Cable connected: on, Trace: off (file: none), Type: 82540 EM, Reported speed: 0 Mbps, Boot priority: 0, Promisc Policy: deny, Bandwidth gr oup: none
Likewise, we observe that the Ethernet address of VM Flatbush’s NIC enp0s9 matches NIC 3’s address that we retrieved on the host from VirtualBox in Step 1.
We should examine every Ethernet (DiamondMidwoodFlatbush, DiamondMidwoodBushwick, and …, i.e., 4 Diamond Ethernets and 3 Line Ethernets) to make sure we have set them up correctly.
-
To be sure, we now transmit Ethernet frames from a NIC on an Ethernet we set up. Conceptually, we can view an Ethernet as a physical link that NICs can tap on it. When we transmit an Ethernet frame via one NIC on an Ethernet, any other NICs tapped on the same Ethernet should “see” the frame. However, any other NICs that aren’t on the Ethernet won’t “see” it.
For instance, in the following, we transmit an Ethernet frame via NIC enp0s9 on midwood. Since the only other NIC among all the NICs of the 4 VMs is also on the same Etherneet on which midwood’s enp0s9 is tapped is enp0s9 on Flatbush. We can only capture this frame on Flatbush from the very NIC (enp0s9), not from any other NIC on Flatbush, and not from any NICs (other than enp0s9 on Flatbush and enp0s9 on Midwood) on other VMs.
The following steps are to do and to verify just that. Notice that we do this step on 3 VMs, midwood, flatbush, and bushwick.
-
Prepare flatbush for sniffing packets.
brooklyn@flatbush:~$ hostname flatbush brooklyn@flatbush:~$ ip link show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:45:bf:a2 brd ff:ff:ff:ff:ff:ff 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:59:ef:a7 brd ff:ff:ff:ff:ff:ff 4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:cb:67:1d brd ff:ff:ff:ff:ff:ff 5: enp0s10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:29:17:39 brd ff:ff:ff:ff:ff:ff 6: enp0s16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:e9:34:5f brd ff:ff:ff:ff:ff:ff 7: enp0s17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:d5:de:96 brd ff:ff:ff:ff:ff:ff brooklyn@flatbush:~$ sudo ip link set enp0s9 up brooklyn@flatbush:~$ sudo ip link set enp0s10 up brooklyn@flatbush:~$ sudo ip link set enp0s16 up brooklyn@flatbush:~$ sudo ip link set enp0s17 up brooklyn@flatbush:~$ sudo scapy3 >>> get_if_list() ['enp0s17', 'enp0s10', 'enp0s9', 'enp0s3', 'enp0s8', 'lo', 'enp0s16'] >>> packets = sniff(prn=lambda p:p.summary(), filter='ether host 08:00:27:cb:67: ...:1d', iface='enp0s9')
-
Prepare bushwick for sniffing packets.
brooklyn@bushwick:~$ hostname bushwick brooklyn@bushwick:~$ ip link show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:47:cb:70 brd ff:ff:ff:ff:ff:ff 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:4c:b6:a8 brd ff:ff:ff:ff:ff:ff 4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:3d:c4:e4 brd ff:ff:ff:ff:ff:ff 5: enp0s10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:6f:89:e6 brd ff:ff:ff:ff:ff:ff 6: enp0s16: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:70:e7:16 brd ff:ff:ff:ff:ff:ff 7: enp0s17: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:53:90:ff brd ff:ff:ff:ff:ff:ff brooklyn@bushwick:~$ sudo ip link set enp0s9 up brooklyn@bushwick:~$ sudo ip link set enp0s10 up brooklyn@bushwick:~$ sudo ip link set enp0s16 up brooklyn@bushwick:~$ sudo ip link set enp0s17 up brooklyn@bushwick:~$ sudo scapy3 >>> packets = sniff(prn=lambda p:p.summary(), filter='ether host 08:00:27:cb:67: ...:1d')
-
Prepare eastny for sniffing packets.
brooklyn@eastny:~$ hostname eastny brooklyn@eastny:~$ sudo ip link show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:17:a1:40 brd ff:ff:ff:ff:ff:ff 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:ee:90:20 brd ff:ff:ff:ff:ff:ff 4: enp0s9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:1e:20:a8 brd ff:ff:ff:ff:ff:ff 5: enp0s10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:34:ea:d3 brd ff:ff:ff:ff:ff:ff 6: enp0s16: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:d4:f5:25 brd ff:ff:ff:ff:ff:ff brooklyn@eastny:~$ sudo ip link set enp0s9 up brooklyn@eastny:~$ sudo ip link set enp0s10 up brooklyn@eastny:~$ sudo ip link set enp0s16 up brooklyn@eastny:~$ sudo scapy3 >>> packets = sniff(prn=lambda p:p.summary(), filter='ether host 08:00:27:cb:67: ...:1d')
-
Prepare midwood for sending packets.
brooklyn@midwood:~$ hostname midwood brooklyn@midwood:~$ ip link show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:5a:ff:ec brd ff:ff:ff:ff:ff:ff 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:a1:33:b4 brd ff:ff:ff:ff:ff:ff 4: enp0s9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:08:0d:a1 brd ff:ff:ff:ff:ff:ff 5: enp0s10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:a2:b4:f0 brd ff:ff:ff:ff:ff:ff 6: enp0s16: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:a3:d1:e4 brd ff:ff:ff:ff:ff:ff brooklyn@midwood:~$ sudo ip link set enp0s9 up brooklyn@midwood:~$ sudo ip link set enp0s10 up brooklyn@midwood:~$ sudo ip link set enp0s16 up brooklyn@midwood:~$ sudo scapy3 >>> get_if_list() ['enp0s8', 'enp0s16', 'enp0s10', 'enp0s9', 'lo', 'enp0s3'] >>> get_if_hwaddr(enp0s9) '08:00:27:08:0d:a1' >>> packet = Ether()/'Hello, Flatbush. I am tapping on DiamondMidwoodFlatbush' >>> packet.dst = '08:00:27:cb:67:1d' >>> packet.src = '08:00:27:08:0d:a1' >>> hexdump(packet) 0000 080027CB671D080027080DA190004865 ..'.g...'.....He 0010 6C6C6F2C20466C6174627573682E2049 llo, Flatbush. I 0020 20616D2074617070696E67206F6E2044 am tapping on D 0030 69616D6F6E644D6964776F6F64466C61 iamondMidwoodFla 0040 7462757368 tbush >>> sendp(packet, iface='enp0s9') . Sent 1 packets. >>>
-
Return to flatbush, we should observe,
>>> packets = sniff(prn=lambda p:p.summary(), filter='ether host 08:00:27:cb:67: ...:1d', iface='enp0s9') 08:00:27:08:0d:a1 > 08:00:27:cb:67:1d (0x9000) / Raw ^C>>> hexdump(packets[0]) 0000 080027CB671D080027080DA190004865 ..'.g...'.....He 0010 6C6C6F2C20466C6174627573682E2049 llo, Flatbush. I 0020 20616D2074617070696E67206F6E2044 am tapping on D 0030 69616D6F6E644D6964776F6F64466C61 iamondMidwoodFla 0040 7462757368 tbush >>>
- On other two VMs, bushwick and eastny, we should observe that we don’t see those packets.
-
A few variants of packet sniffing scenario provide how these physical links work including capturing packets from “all” interface and a designated interface other than enp0s9, e.g.,
>>> packets = sniff(prn=lambda p:p.summary(), filter='ether host 08:00:27:cb:67: ...:1d') 08:00:27:08:0d:a1 > 08:00:27:cb:67:1d (0x9000) / Raw >>> packets = sniff(prn=lambda p:p.summary(), filter='ether host 08:00:27:cb:67: ...:1d', iface='enp0s10') which shows the packet indeed arrives at the NIC tapped on the ethernet because we would not see such a packet if we only capture traffic comes to a NIC tapped on a different Ethernet.
-
Setting up Diamond IP Network
It is important to remember all of the setup below wouldn’t survive a reboot. A prudent approach would be to save each command in a shell script, and you can easily repeat without retyping them.
Perhaps, a related question is how we configure the host so that the setup via the length commands would survive the reboot. Appendix I provides a gist of of the answer to the question.
It is also important to note that this section does not contain all the commands to set up the Diamond IP network as we envisioned completely. But it gives you all the ingredients you need to finish “cooking” by yourself.
-
We plan to deploy the following IP networks to the Diamond Ethernets.
Ethernet IPv4 Network IPv4 Broadcast Address DiamondMidwoodFlatbush 10.1.1.0/28 10.1.1.15 DiamondMidwoodbushwick 10.1.1.16/28 10.1.1.31 DiamondFlatbushEastNY 10.1.1.32/28 10.1.1.47 DiamondBushwickEastNY 10.1.1.48/28 10.1.1.63 Following the above plan, we have the following IPv4 address assignments to the NICs on the four VMs.
Host name NIC:IP Address Linux Command midwood enp0s9: 10.1.1.1 ip address add 10.1.1.1/28 broadcast 10.1.1.15 dev enp0s9 midwood enp0s10: 10.1.1.17 ip address add 10.1.1.17/28 broadcast 10.1.1.31 dev enp0s10 flatbush enp0s9: 10.1.1.2 ip address add 10.1.1.2/28 broadcast 10.1.1.15 dev enp0s9 flatbush enp0s10: 10.1.1.33 ip address add 10.1.1.33/28 broadcast 10.1.1.47 dev enp0s10 bushwick enp0s9: 10.1.1.18 bushwick enp0s10: 10.1.1.49 eastny enp0s9: 10.1.1.34 ip address add 10.1.1.34/28 broadcast 10.1.1.47 dev enp0s9 eastny enp0s10: 10.1.1.50 ip address add 10.1.1.50/28 broadcast 10.1.1.63 dev enp0s10 -
We realize these using the commands in the able on the VMs, for instance, on midwood, as follows,
brooklyn@midwood:~$ sudo ip address add 10.1.1.1/28 broadcast 10.1.1.15 dev enp0s9 brooklyn@midwood:~$ sudo ip address add 10.1.1.17/28 broadcast 10.1.1.31 dev enp0s10 brooklyn@midwood:~$ ip address show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 08:00:27:5a:ff:ec brd ff:ff:ff:ff:ff:ff inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3 valid_lft 83644sec preferred_lft 83644sec inet6 fe80::a00:27ff:fe5a:ffec/64 scope link valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 08:00:27:a1:33:b4 brd ff:ff:ff:ff:ff:ff inet 192.168.56.103/24 brd 192.168.56.255 scope global dynamic enp0s8 valid_lft 591sec preferred_lft 591sec inet6 fe80::a00:27ff:fea1:33b4/64 scope link valid_lft forever preferred_lft forever 4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 08:00:27:08:0d:a1 brd ff:ff:ff:ff:ff:ff inet 10.1.1.1/28 brd 10.1.1.15 scope global enp0s9 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe08:da1/64 scope link valid_lft forever preferred_lft forever 5: enp0s10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 08:00:27:a2:b4:f0 brd ff:ff:ff:ff:ff:ff inet 10.1.1.17/28 brd 10.1.1.31 scope global enp0s10 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fea2:b4f0/64 scope link valid_lft forever preferred_lft forever 6: enp0s16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 08:00:27:a3:d1:e4 brd ff:ff:ff:ff:ff:ff inet6 fe80::a00:27ff:fea3:d1e4/64 scope link valid_lft forever preferred_lft forever brooklyn@midwood:~$
-
For a packet originated at midwood to reach eastny (2 hops away), we need to configure flatbush to act as a forwarding node.
brooklyn@flatbush:~$ sudo sysctl -w net.ipv4.ip_forward=1 net.ipv4.ip_forward = 1 brooklyn@flatbush:~$
-
We also need to update the forwarding table at midwood, and the forwarding table at eastny. Without the former, midwood does not know where it should transmit a packet whose destination is on eastny. Without the later, easny does not know where to transmit a reply.
-
At midwood, we do
sudo ip route add 10.1.1.32/28 via 10.1.1.2
-
At eastny, we do
sudo ip route add 10.1.1.0/28 via 10.1.1.33
-
-
It’s the time to see we can send an IP packet from midwood to eastny and get a reply from it. So at midwood, we do
brooklyn@midwood:~$ sudo scapy3 >>> reply = sr1(IP(dst='10.1.1.34')/ICMP()) Begin emission: ..Finished sending 1 packets. .* Received 4 packets, got 1 answers, remaining 0 packets >>> reply <IP version=4 ihl=5 tos=0x0 len=28 id=36717 flags= frag=0 ttl=63 proto=icmp chksum=0xd64f src=10.1.1.34 dst=10.1.1.1 options=[] |<ICMP type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |<Padding load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>> >>> reply.summary() 'IP / ICMP 10.1.1.34 > 10.1.1.1 echo-reply 0 / Padding' >>>
Experiments and Demonstration
Setting up Diamond or Line IP Network
This is your exercise and exploration. Review the steps we carry out for the Diamond IP network, and repeat them for the Line IP network.
Observing IP Forwarding
With these two networks, we can observe how IP forwarding works. To view the forwarding table, for instance, on host midwood, we do,
ip route show
Observing Packet Fragmentation and Reassembly
Before attempting this exercise, please review Appendix II. Below we consider two scenraios.
-
Sending a large packet from the source, and the packet will be fragmented at the source. We do this in ScaPy,
>>> packet = IP(dst='10.1.1.34')/Raw("A"*5000) >>> send(packet) . Sent 1 packets. >>>
Before you send the packet, you should prepare packet capturing; otherwise, you will miss the chance of observing IP packet fragmentation.
-
Sending a packet that will be fragmented at a forwarding node along the path.
For this, we need to set the MTU of the forwarding node to a smaller value with a commmand like,
ip link set dev YOUR_NIC mtu 1400
Using this command set a smaller MTU at a forwarding node, and observe how an IPv4 packet is fragmented and forwarded, e.g.,
brooklyn@flatbush:~$ sudo ip link set dev enp0s10 mtu 1280 brooklyn@flatbush:~$
After you complete this, like before, you will set up packet capturing at along the path, craft an IP packet larger than the MTU (like larger than 1280 bytes), and send the packet.
Appendix I. Network Configuration Files
On Debian Linux, we can configure host with the steps outlined in the above in a configuration file, and the configuration file would come into effect when the system boots.
Enabling or Disabling IPv4 Forwarding
In /etc/sysct.conf
, uncomment to enable or comment the following line to
disable IPv4 forwarding,
#net.ipv4.ip_forward=1
Setting up IP Address and Routes
In /etc/network/interfaces
file, add a section of configuration code
for each network interface you wish to set up, e.g., for enps09 on
midwood, we may append the following lines to it,
auto enps09
iface enps09 inet static
address 10.1.1.1/28
post−up ip route add 10.1.1.32/28 via 10.1.1.2
pre−down ip route del 10.1.1.32/28 via 10.1.1.2
Appendix II. (Possible) ScaPy Bug in Version 2.4.0
It appears that is a bug in ScaPy verison 2.4.0 that prevents any IP packet larger than MTU to be sent successfully. The error is like the following,
brooklyn@flatbush:~$ sudo scapy3
aSPY//YASa
apyyyyCY//////////YCa |
sY//////YSpcs scpCY//Pp | Welcome to Scapy
ayp ayyyyyyySCP//Pp syY//C | Version 2.4.0
AYAsAYYYYYYYY///Ps cY//S |
pCCCCY//p cSSps y//Y | https://github.com/secdev/scapy
SPPPP///a pP///AC//Y |
A//A cyP////C | Have fun!
p///Ac sC///a |
P////YCpc A//A | Craft packets like I craft my beer.
scccccp///pSP///p p//Y | -- Jean De Clerck
sY/////////y caa S//P |
cayCyayP//Ya pY/Ya
sY/PsY////YCc aC//Yp
sc sccaCY//PCypaapyCP//YSs
spCPY//////YPSps
ccaacs
using IPython 5.8.0
>>> packet = IP(dst='10.1.1.1')/Raw("A"*5000)
>>> send(packet)
---------------------------------------------------------------------------
OSError Traceback (most recent call last)
/usr/lib/python3/dist-packages/scapy/arch/linux.py in send(self, x)
485 try:
--> 486 self.outs.sendto(sx, sdto)
487 except socket.error as msg:
OSError: [Errno 90] Message too long
During handling of the above exception, another exception occurred:
TypeError Traceback (most recent call last)
<ipython-input-2-b8a536fe3f5f> in <module>()
----> 1 send(packet)
/usr/lib/python3/dist-packages/scapy/sendrecv.py in send(x, inter, loop, count, verbose, realtime, return_packets, socket, *args, **kargs)
300 socket = conf.L3socket(*args, **kargs)
301 return __gen_send(socket, x, inter=inter, loop=loop, count=count,verbose=verbose,
--> 302 realtime=realtime, return_packets=return_packets)
303
304 @conf.commands.register
/usr/lib/python3/dist-packages/scapy/sendrecv.py in __gen_send(s, x, inter, loop, count, verbose, realtime, return_packets, *args, **kargs)
274 else:
275 dt0 = ct-p.time
--> 276 s.send(p)
277 if return_packets:
278 sent_packets.append(p)
/usr/lib/python3/dist-packages/scapy/arch/linux.py in send(self, x)
486 self.outs.sendto(sx, sdto)
487 except socket.error as msg:
--> 488 if msg[0] == 22 and len(sx) < conf.min_pkt_size:
489 self.outs.send(sx + b"\x00" * (conf.min_pkt_size - len(sx)))
490 elif conf.auto_fragment and msg[0] == 90:
TypeError: 'OSError' object is not subscriptable
>>>
The bug does not appear in versions 2.4.3 and 2.4.4. To resolve this issue, on the Virtual Machine you intend to use it as the sending node, do the following to upgrade ScaPy to version 2.4.4,
sudo apt-get install --no-install-recommends python3-pip
sudo python -m pip install scapy --upgrade
sudo python -m pip install pyparsing --upgrade
sudo python -m pip install prompt_toolkit --upgrade
sudo python -m pip install IPython --upgrade
This isn’t the recommended method to upgrade a Python package since we installed Python and Python packages via the Operating System’s package manager. It is preferable that you do these on a clone, other than the original. In this case, if you discover something isn’t working due to this upgrade, you can always create a new clone.