How to build a network stack in Ruby

Learning about sockets, datagrams, bit-twiddling and more — all from the comfort of a high-level language

Our challenge

What is UDP?

Getting started

$ echo "Hello World" | nc -u 192.168.33.10 4321
HELLO WORLD

Under-the-hood

  • socket()
  • bind()
  • recvfrom()
  • sendto()
# Ruby
Socket.open(:INET, :DGRAM)
/* C */
socket(PF_INET, SOCK_DGRAM, 0);

Socket to me!

My filthy telephone socket!
socket(PF_INET, SOCK_DGRAM, 0);
^ "SOCK_DGRAM" tells the kernel we want UDP
Socket.open(:INET, :RAW, Socket::IPPROTO_UDP)
Socket.open(:PACKET, :RAW)

Binding the socket

request = { name: 'eth1', index: nil }
socket.ioctl(SIOCGIFINDEX, request)
request[:index] # => 0x3

Receiving data

$ echo hello | nc -u 192.168.33.10 4321
0a 00 27 00 00 00 08 00 27 d7 47 6c 08 00 45 c0  |..'.....'.Gl..E.|
00 3e e2 9e 00 00 40 01 d4 04 c0 a8 21 0a c0 a8 |.>....@.....!...|
21 01 03 03 c0 78 00 00 00 00 45 00 00 22 46 89 |!....x....E.."F.|
00 00 40 11 70 e6 c0 a8 21 01 c0 a8 21 0a ca 13 |..@.p...!...!...|
10 e1 00 0e 1d a5 68 65 6c 6c 6f 0a |......hello.|

Bits, bytes, hex — “Oh My!”

These two are easy because both numeral systems can represent them with a single digit:Decimal 0 = Binary 0
Decimal 1 = Binary 1
We've run out of unique digits we can use in binary, so we must add a digit. This is similar to going from 9 to 10 in decimal.Decimal 2 = Binary 10
Decimal 3 = Binary 11
Decimal 4 = Binary 100
Hexadecimal 0 = Binary 0
Hexadecimal F = Binary 1111
Hexadecimal 3 = Binary 0011
Hexadecimal F3 = Binary 1111 0011

Decoding an ethernet frame

https://commons.wikimedia.org/wiki/File:Ethernet_Type_II_Frame_format.svg
0a 00 27 00 00 00 08 00 27 d7 47 6c 08 00 45 c0  |..'.....'.Gl..E.|
00 3e e2 9e 00 00 40 01 d4 04 c0 a8 21 0a c0 a8 |.>....@.....!...|
21 01 03 03 c0 78 00 00 00 00 45 00 00 22 46 89 |!....x....E.."F.|
00 00 40 11 70 e6 c0 a8 21 01 c0 a8 21 0a ca 13 |..@.p...!...!...|
10 e1 00 0e 1d a5 68 65 6c 6c 6f 0a |......hello.|
0a 00 27 00 00 00 - Destination MAC Address
08 00 27 d7 47 6c - Source MAC Address
08 00 - EtherType (IPv4)

IPv4 packet

https://en.wikipedia.org/wiki/IPv4
Before:[0100] 0101 (Decimal 69)
▲ ▲
| |
| +- IHL Field (want to discard)
|
+- Version (want to keep)
Shifting the bits 4 places to the right:0100 (0101) <- These 4 bits get "dropped off" the end
▲▲▲▲
||||
|||+----+
||+----+|
|+----+||
+----+|||
||||
▼▼▼▼
0000 0100
After:0000 [0100] (Decimal 4)
    1111 1001
AND 0110 1111
---------
0110 1001
First Byte:1010 [0101]
^ IHL
Masking over the first 4 bits: 1010 [0101]
AND 0000 1111 (Hexadecimal F)
-----------
0000 0101

UDP datagram

https://en.wikipedia.org/wiki/User_Datagram_Protocol

Further Reading

--

--

Stories, lessons, projects and insights from Geckoboard: a growing SaaS startup building live TV dashboard software to help teams get aligned.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store