=====[ Practicing networking with just one machine ]==== On Linux and MacOS X you can create a virtual interface that will appear to your kernel as an Ethernet device (so-called "TAP" virtual interface) or an endpoint of an IP tunnel (so-called "TUN" virtual interface). This interface will have an IP address and you can set routes associated with it: for TAP, a LAN subnet behind it, for TUN, a remote IP. Every IP packet that matches these routes will be "sent" to that interface as per normal routing rules if that interface is "up". Having that interface "up" means having a process open that device (typically, the same program will create and configure it first, by making a series of system calls) and reading from it. The packets routed to that device will be read as byte buffers (as by libpcap or a raw socket). That way you'll see ARP and ICMP echo requests (for TAP) or just ICMP requests (for TUN). Byte buffers written to it will look to the kernel as packets that arrived from the LAN attached to that interface (for TAP) or from the remote endpoint IP (for TUN). The kernel will handle them as it normally does with incoming packets, e.g., respond to ICMP echo requests, forward based on destination IP and the routing table (if in forwarding mode), etc. This is done with a couple of special drivers. They are similar to normal drivers for physical devices (and register the same callbacks with the kernel), but there's no physical device, only emulation based on byte buffers and queues. See below about these drivers. That way you can emulated other machines with your program that creates/reads that virtual device. With TAP, you can emulate an entire network, or, if you set your routing that way, any Internet hosts (people do that when they don't want their machine to access some hosts on the Internet, but rather want to emulate them). My code at http://netfluke.org/ (redirects to github) emulates a LAN behind a TAP interface. It uses Scapy to craft "responses" from the emulated hosts to a few protocols (ARP and ICMP pings, mostly). -----------------[ Netfluke scipts ]----------------- Read the pong.py and tcp.py scripts. They make heavy use of Scapy to parse and construct packets. You may find the following links useful: "Cheat sheets:" http://media.packetlife.net/media/library/36/scapy.pdf http://www.packetlevel.ch/html/scapy/docs/scapy_sans.pdf Tutorials: http://wikihead.wordpress.com/2011/01/09/packet-crafting-using-scapy/ http://theitgeekchronicles.files.wordpress.com/2012/05/scapyguide1.pdf I prefer to work with Scapy at command line, trying things out before I commit them to a script. Just run scapy without arguments and use it to capture real packets. NOTE that Scapy's send and receive functions (e.g., sendp() and sr()) WILL NOT WORK with a TUN/TAP driver. You must use os.read() and os.write() instead. Recall that from the kernel's point of view, sending a packet out of your virtual TAP interface means queuing it to be read by your script that has the TAP device open; whatever your script writes to that device the kernel feeds to the same entry point for all packets coming in from from the outside networks, netif_rx_ni(). So Scapy's sendp() called from your script for your TAP interface would cause the script to send packets back to itself, not to the kernel, which would be pointless. Don't use these, use os.read() instead to get the packets sent by the kernel to your emulated LAN, and os.write() to send the responses from your emulated hosts back to your kernel (and, hence, via the kernel, to your programs such as ping, netcat (nc), browsers, etc.) ----------------[ TUN/TAP driver]-------------- On either Linux or OS X you will need the TUN/TAP driver. This driver creates two kinds of devices: those that deal with IP packets _without_ the Ethernet header (TUN) and full Ethernet frames (TAP). We will use TAP exclusively, because we are interested in fully emulating an Ethernet interface and an Ethernet LAN behind it. TUN is mostly useful for building VPNs (e.g., OpenVPN typically uses TUN, not TAP). On Linux, TUN/TAP is already available in most distributions. Load it with "modprobe tun". The actual file lives in /lib/modules/ // Now packets for 10.10.0.3 do show up in ./utun-demo: 45 00 00 54 74 28 00 00 40 01 f2 69 0a 0a 00 01 0a 0a 00 03 08 00 18 6e e4 75 00 00 58 05 bc 18 00 0d fb ed 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 45 00 00 54 0e c5 00 00 40 01 57 cd 0a 0a 00 01 0a 0a 00 03 08 00 13 a8 e4 75 00 01 58 05 bc 19 00 0e 00 b1 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 45 00 00 54 e2 59 00 00 40 01 84 38 0a 0a 00 01 0a 0a 00 03 08 00 0c ca e4 75 00 02 58 05 bc 1a 00 0e 07 8d 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 // Of course, pings still time out, because // ./utun-demo does not respond to pings, only // reads & prints them. But now it could create responses, // and they'll be heard if written back. // Request packets can also now be seen with tcpdump: # tcpdump -i utun1 -n tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on utun1, link-type NULL (BSD loopback), capture size 65535 bytes 02:10:53.388399 IP 10.10.0.1 > 10.10.0.3: ICMP echo request, id 61301, seq 18, length 64 02:10:54.393594 IP 10.10.0.1 > 10.10.0.3: ICMP echo request, id 61301, seq 19, length 64 02:10:55.396734 IP 10.10.0.1 > 10.10.0.3: ICMP echo request, id 61301, seq 20, length 64 ----[[ Practice: ]]---- 1. Write Scapy scripts to respond to ICMP pings for any address in the subnet behind (i.e., routed through) the virtual interface. (For TAP, your script needs to respond to ARPs and create Ethernet/IP/... packets. For TUN, you only need to create IP packets, without Ethernet headers.) 2. Write Scapy scripts to emulate a DNS server on the virtual LAN behind the TAP interface. You DNS server should reply to DNS queries with meaningful responses. Test it with the "dig" tool (e.g., "dig @10.5.0.53 some-domain-name" to query the DNS server at 10.5.0.53). The DNS protocol is explained in this tutorial about the famous Kaminsky attack on DNS: http://unixwiz.net/techtips/iguide-kaminsky-dns-vuln.html It explains a lot about the DNS protocol; refer to the RFC 1035, RFC 1123, and RFC 2181 for complete reference, https://en.wikipedia.org/wiki/Domain_Name_System for an overview. You can implement a scapy DNS server that takes requests, runs them against an actual server (say, Google's 8.8.8.8), and then responds to the original request (perhaps with some modification---like returning Bing's IP address for Google's, or some such). An example on using Scapy with DNS: http://www.packetlevel.ch/html/scapy/scapydns.html -----[ Beyond DNS ]----- On Linux, configure DNAT on your kernel to hand packets arriving over your internet connection to different "hosts" on your emulated network based on their destination port. For example, forward any packet to UDP port 53 to 10.5.0.53 , any packets to TCP port 80 to 10.5.0.80, and any packets to TCP port 22 to 10.5.0.22 . Set up some responses for those packets -- for port 53 (DNS queries), respond with some names, for port 80 with some simple fixed HTTP response with a basic webpage. For port 22 you can try to implement the start of the SSH protocol. This protocol is complex, but its first few steps are easy enough (e.g., http://www.slashroot.in/secure-shell-how-does-ssh-work). For example, you can try to force a connection to use no encryption. Note that the supported ciphers are negotiated in plaintext at the start of an SSH connection.