------------[ Basic IP connectivity and routing ]------------ NOTE: For all exercises below, you will need to disable Linux's Network Manager. With it running (check with "ps ax | grep -i net"), nothing will work, because Network Manager will continually interfere with your interface configuration. Just like systemd, it is an intrusive piece of software written to make Linux behave like Windows or MacOS, and purposefully incompatible with other Linux configuration mechanisms or design principles. After you stopped and disabled the Network Manager, kill any DCHP client processes such as dhclient or dhcpcd (check for them with, e.g., "ps ax | grep dhc") For these exercises, you will need a Linux machine with two Ethernet interfaces (to serve as a router/gateway), and another Linux machine. You can try to make do with virtual machines and a virtual switch (see virtual-nets.txt for how I did it), but it'll be easier for you to team up and get an extra USB interface. You must be root on the machine to set any networking configurations. 1. Basic IP/Ethernet link. Connect two computers to a switch. Configure them with private IP addresses. For example, use 192.168.57.1 on the router machine, and 192.168.57.100 on the other machine, which we'll call the client machine. Disable any other interfaces on the client and the server (e.g., "ifconfig eth1 down" to bring down interface called eth1). Check that you can ping both ways. Assuming you are connecting eth0 on your router machine, to the switch, you can use "ifconfig eth0 192.168.57.1 up". This will get you the standard netmask for 192.168.* networks, 255.255.255.0 aka /24, and the route for 192.168.57.0/24 to eth0. For example: # ifconfig eth0 192.168.57.1 up # route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.57.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 Now configure the client for 192.168.57.100 and ping both ways. Run "tcpdump -i eth0 -n" on the router and observe the pings from the client. Now from the client ping a different IP, say 192.168.57.200. In the router's tcpdump output, you should see ARP requests for this IP, sent by the client, but no ICMP echo request packets. Observe the error messages on the client. Now send some crafted ARP responses to the client from the router. If your responses are correct, you should then see some ICMP echo requests reach the router. Now from the client ping a different IP outside of the private 192.168.57.0/24 network that you just created (say, 10.10.0.1). Observe how it fails. You should see "No route to network" or "No route to host". Set 192.168.57.1 as the default gateway on the client (on Linux, e.g., "route add default gw 192.168.57.1 dev eth0"). Repeat the ping. You should see the ICMP packets coming in, and an occasional ARP request from the client for the route IP, and the router's response. The default route matches any address not matched by a routing rule with a longer matching prefix (modulo a bitwise AND with the netmask). Note that the default route's mask is 0.0.0.0: # route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.57.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 0.0.0.0 192.168.57.1 0.0.0.0 UG 0 0 0 eth0 This means that any packets not matched by other routes are sent to the gateway, using the gateway's Ethernet MAC address (but the target's IP). Look at these packets in Wireshark. IMPORTANT: in IP routing, the rule is that the rule with the longest matching prefix wins, i.e., the more specific the match is, the better. Put differently, between two matching routes, the netmask with more 1s in it wins. You can have a gateway not just for all IPs, but also for a particular network. For example, if you delete the default route on the client (say, "route del default gw 192.168.57.1 dev eth0") and add one specifically for 10.10.0.0/16 (aka netmask 255.255.0.0) "route add -net 10.10.0.0 netmask 255.255.0.0 gw 192.168.57.1 dev eth0" your pings to addresses 10.10.x.x. should reach the router, but pings to other addresses like 10.20.x.x won't. 2. Forwarding for the client. With a default route on the client properly configured, packets for outside IP addresses would reach the router (gateway), but it needs to forward them on. Two things need to happen for this to work: the router machine must have an upstream access via another interface, and it must be forwarding the packets. The latter is trivial to configure. It's a property of the Linux kernel, and is set via the /proc filesystem (you must be root!) echo 1 > /proc/sys/net/ipv4/ip_forward That will make the machine accept the packets with IPs other than its own, and attempt to send them along the best matching route (if any). For the former, you need another interface. On that interface, you will need an IP address that whatever network you connect it to will route for. The simplest thing is to connect to a network port in the lab, and obtain an IP address via DHCP. Say, your additional interface on the router is called eth1: "dhclient -v eth1" This should get your packets forwarded on to the lab network. Use "tcpdump -i eth1 -n" to make sure you can see them leaving. You should get an address in the 129.170.212-215.x range, with the default gateway of 129.170.212.1 . Something like # route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.57.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 129.170.212.0 0.0.0.0 255.255.252.0 U 0 0 0 eth1 0.0.0.0 129.170.212.1 0.0.0.0 UG 0 0 0 eth1 Now pinging an external address like 8.8.8.8 (Google's public DNS server) should succeed on the router (check with "tcpdump -i eth1 -n icmp"!), but not of the client. If you do this on the client, you will see packets from 192.168.57.100 to 8.8.8.8 leaving through eth1 on the router, but no responses coming back. 3. Configuring Network Address Translation (NAT). There is still a problem: your packets are leaving, but they receive no responses. This is because addresses like 192.168.x.x (192.168./16 prefix) 10.x.x.x (10/8 prefix), and 172.16-31.x.x (172.16/12 prefix) are private (see RFC 1918) and IP packets with these source addresses will be dropped by any upstream routers. To route for a private network that only has a public routable IP on its gateway, you need a trick known as Network Address Translation (NAT). The router will rewrite your packets as if they came from the router's public IP, receive responses (if any), and then rewrite them back, putting the private destination address in the response packets' IP dst field. In Linux, this can be done with the IPtables/Netfilter firewall. Read about it at http://netfilter.org/documentation/index.html, in the following order: "Networking Concepts HOWTO", "Packet Filtering HOWTO", "NAT HOWTO", and "Netfilter Hacking HOWTO". A typical command to enable NAT for the client machine on the router would be # iptables -t nat -A POSTROUTING -o eth1 -s 192.168.57.0/24 -j MASQUERADE (read about all these options!) This roughly means: for any packet routed to leave out of eth1 and with its src IP matching 192.168.57.0/24, rewrite its src IP to be that of eth1 (and make a note of the actual src IP and some other parameters of the packet in the "nat" table, so that packets coming back and matching these parameters will have their dst IP rewritten back to what their remembered src was). NAT rewriting is essentially heuristic. The heuristics are protocol-specific (as are protocol parameters that NAT can go by to determine what is a response to what). They work well for TCP, UDP, ICMP, and other classic protocols, but for new protocols (such as VoIP) new heuristics (modules) had to be added to NAT firewalls. Exercises: - observe ping and HTTP packets being rewritten on the router for the client, back and forth. Note the source and destination IP and MAC addresses in the same packet on eth0 and eth1. - read about DNAT and configure a webserver running on the client so that it is reachable from the outside at the IP address of the router. This is called "port forwarding" (the router "forwards" its port 80 to the client). We'll do more with Netfilter in the next task.