TCP/IP 實作

實作的 source code
https://github.com/fwfly/tcpip

這篇是參考
https://www.saminiir.com/lets-code-tcp-ip-stack-1-ethernet-arp/

原作者的 source code:
https://github.com/saminiir/level-ip

這個實作會從 leyer 2 開始慢慢往上爬
ethernet -> ip -> tcp/ip

從 ethernet 開始

目標 : 實踐 arp

Tap/Tun

文中說使用 /dev/net/tap 但是因為系統裡面似乎已經用 /dev/net/tnu 取代了,所以改用 tnu

這是最原始的 tap 程式
https://github.com/saminiir/level-ip/commit/1b0b7499deb48bd879faeff347a837ae9adf5222

在 reference 有清楚的說明 tun 怎麼使用以及怎麼測試.

Tun

可以透過 tun 裝置去產生一個虛擬網路裝置,可以透過 ifup 跟 route 對這個虛擬網路裝置做啟動.
啟動之後就可以使用 ping 或者其他的方法來測試封包以及分析封包.
https://github.com/saminiir/level-ip/blob/e3d9fecf002aad6e8f3e754fae81de8b81156dd0/src/main.c

ip address add

當使用 ip address add 的時候可以得到 ip,
ping 會直接得到回應,但是程式沒有辦法拿到封包

route add

使用 route add 的時候會不會拿到 ip,
但是在做 ping 的時候是可以拿到封包.

結果

ip link set dev tun0 up
ip address add dev tun0 local 10.0.0.5/24
ip route add 10.0.0.0/24 dev tun0

程式執行後會得到這樣的介面

10: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none
    inet 10.0.0.5/24 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::56d2:c05d:c48f:154f/64 scope link stable-privacy
       valid_lft forever preferred_lft forever

如果 ping 10.0.0.5 會得到 response,但是程式本身抓不到封包

PING 10.0.0.5 (10.0.0.5) 56(84) bytes of data.
64 bytes from 10.0.0.5: icmp_seq=1 ttl=64 time=0.035 ms
64 bytes from 10.0.0.5: icmp_seq=2 ttl=64 time=0.073 ms

不過如果對 10.0.0.x 做 ping 程式會得到封包

$ sudo ./tcpip
3 tun0
ip link set dev tun0 up
ip address add dev tun0 local 10.0.0.5/24
ip route add  10.0.0.0/24 dev tun0
RTNETLINK answers: File exists
ERROR when setting route for if
Recv: 52
Recv: Recv: 52
Recv: Recv: 52
Recv: Recv: 88
Recv: Recv: 88
Recv: Recv: 88

如果單純用string 是沒有辦法 print 出任何東西
所以必須要用計算的方式去 print 出 hex

(gdb) p buf
$3 = "\000\000\b\000E\000\000T\345!@\000@\001A\202\n\000\000\005\n\000\000\001\b\000P\203J\232\003\204I\256>]\000\000\000\000\017\200\003\000\000\000\000\000\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !\"#$%&'()*+,-./01234567\240IUUUU\000\000`\346\377\377"

解析 print_hexdump
print 出來則會是下面的形式

Recv: 88

00 00 08 00 45 00 00 54
d8 b0 40 00 40 01 4d f1
0a 00 00 05 0a 00 00 03
08 00 dd 8c c6 89 00 04
75 a2 41 5d 00 00 00 00
de 12 00 00 00 00 00 00
10 11 ...... data

用 wireshark 去比對可以發現這個封包包含兩個部分
IP 跟 ICMP

這個部分為 IP

45 00 00 54
Version : 45 = 0100 = IPv4
Total length : 00 54 = 84

40 01 4d f1
TTL : 40 = 64
Protocol : 01 = ICMP 

d8 b0 40 00 

這裡為 dest 跟 src IP
0a 00 00 05 0a 00 00 03
從 10.0.0.5 來到 10.0.0.3

這部分為 ICMP

08 00 dd 8c c6 89 00 04
75 a2 41 5d 00 00 00 00
de 12 00 00 00 00 00 00
10 11 ...... data

type 08 : Echo Request
code 00 : Echo reply (ping)
dd 8c : checksum
75 a2 41 5d 00 00 00 00 : timestemp
以下皆為 data

如果單純用 telnet 做連線可以很簡單的得到 tcp 封包,或者說任何一個 tcp 以上的封包都必須先做 3way Handshake

arp

下一步是用 tun 裝置進行 arp 實作
https://github.com/saminiir/level-ip/commit/c8d855507561c15c1074e0781ce6328d4495f9cd

進度:

看完文章還是不太清楚 arp 怎麼用到 tun 裝置

reference

  1. 透過 tap 實作 icmp
    https://blog.csdn.net/ixidof/article/details/10148899

  2. 簡單實作 tun 範例
    https://my.oschina.net/u/174242/blog/70187

  3. 深入研究 tun 跟 ring buffer
    https://blog.csdn.net/dog250/article/details/80414228

  4. IP format
    https://www.techrepublic.com/article/exploring-the-anatomy-of-a-data-packet/

  5. Tun/Tap interface tutorial
    https://backreference.org/2010/03/26/tuntap-interface-tutorial/