# 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/