Day 34b: Writing curl using my TCP stack
Today I spent a bunch of time writing READMEs for the projects I’ve been working on at Hacker School, and putting together a project page with screenshots and explanations.
While doing that, I discovered that it was impossible to explain my
TCP fun project because it was,
er, mostly not working. So I fixed it up and wrote a finicky and
unreliable version of curl
using it, which made me happy.
The curl
example is quite finicky – it uses ARP spoofing to bypass
the kernel’s TCP stack, which sometimes results in it just Not
Working. Running it a few times sometimes fixes this problem. I found
that if I ran it 5 times then it would work. Mostly.
I ran it using
$ git clone http://github.com/jvns/teeceepee
$ cd teeceepee
$ sudo python examples/curl.py 10.0.4.4 example.com
You’ll notice that I’m supplying an extra local IP address, which
seems like a weird thing to give curl
. The reason for this is that
it needs to bypass the kernel, since normally the TCP one has there
will intercept any incoming packets and reset the connection. So we
listen on a fake IP address and send gratuitous ARPs to the router.
This IP address needs to be in my subnet and should not belong to anyone else, because it would do bad things to them.
Features
- Can connect to hosts, send packets, and reassemble the replies in the correct order
- Will ignore out-of-order packets
Missing features
- Breaking up sent data into more than one packet.
- Resending packets that haven’t been ACKed
- Handling more than one incoming connection at once
bind()
hasn’t been tested in the wild at all, just unit tested. So it probably doesn’t work.- Basically it is a marginally acceptable client and a totally ineffective server
Difficulties
- It needs to run as root because it needs to use raw sockets.
- TCP stacks aren’t really supposed to start and stop. In principle this should really run as a daemon, but it doesn’t.
- It needs to do ARP spoofing in order to receive any packets at all, as I explained earlier
- It’s slow, because Python. If you watch it in Wireshark, it does a hilarious thing where it gets backed up sending ACKs and then sends a load of ACKs at the end and takes forever to close the connection.
- Sometimes the ARP spoofing and packet sniffing doesn’t quite work. Usually if I run it 5 times it will work.