網路概論 Lesson 2

  1. 預期你會學到什麼

    你能明白你當你訪問一個網站,你的電腦到底做了什麼,以及會用一些工具來檢查網路狀態。

  2. 網路模型

    國際標準化組織提出了 OSI 的 7 層網路模型,不過 7 層分太多了,我們這邊用簡化成四層的 TCP/IP 模型:

    我們上次稍微帶過了,你的封包(資料)是怎麼在網路世界中傳遞的,這其實是在網路層和鏈接層的工作,而更上面的傳送層與應用層,會是我們今天的重點。

    先講一下這四層分別在做什麼:

    • 應用層:各個應用程式,例如你的遊覽器,或是 Youtube 的網站伺服器,這些提供應用服務的,都在應用層。
    • 傳輸層:傳輸層顧名思義,他協助你傳輸,應用層決定你要傳什麼,傳輸層決定你要怎麼傳,傳輸層最重要的就是 TCP,TCP 會建立一個可靠的連線,幫助你確保你的資料有正確的傳送到目的地,當中沒有丟包、亂序,當然 TCP 不只這個功能。
    • 網路層:網路層會把 IP 位置等資訊和運輸層傳下來的資料打包成一個封包,然後會決定這個封包應該要怎麼走,也就是所謂的路由。
    • 連結層:連結層負責把封包傳遞到下一台電腦,至於應該要往哪一台電腦,是由網路層決定,連結層只負責做發送到目標電腦。

    所以回到我們上一次的內容:

    假設我要從 PC1 想要發一個 mail 給 PC4,其實會經過這樣的步驟:

    1. PC1 電腦上的郵件服務程式(應用層)會打包一封 Mail 的資料,之後會把這個 message 往下交給傳輸層。
    2. 傳輸層在這邊會使用 TCP,來確保信件可以確實給對方收到,把 TCP 的一些參數和 message 一起打包成一個 segment,再把這個 segment 往下交給網路層。
    3. 網路層會把 PC1 的 IP 地址、PC4 的 IP 地址等資料和 segment 一起打包,打包成一個 datagram,之後再把 datagram 往下交給連結層。然後 PC1 會發現他的封包下一個目的地應該要是 Router0。
    4. 連結層會打包 datagram,讓 src mac-addr 是 PC1,dst mac-addr 是 Router 0,之後將封包發到 Router0 所在的介面。

    之後 Router0 會做這樣的事情:

    1. 當每個封包流入 Router0 時候, Router0 會先把連結層的包裝拆掉,看到網路層打包的 datagram,之後發現這個封包的目的地按照 Router 0 的 Routing Table(路由表)應該要轉發到 PC4。
    2. 他會重新打包一層 Link-Layer 的包裝,src mac-addr 變成 Router0,dst mac-addr 變成 PC4,並且把封包發到 PC4 所在的介面。

    之後 PC4 就會收到封包,會一層一層的解析:

    1. 看連結層的資訊,他知道這個封包是由 Router0 交給他。
    2. 看網路層的資訊,他知道這個封包來自於 PC1。
    3. 看傳輸層的資訊,他知道這個封包是要給哪一個 port,就知道要給哪一隻程式處理。
    4. 看應用層的資訊,他就知道他收到的信件內容為何了。

    而每一層其實都在做這件事情:

    把上一層傳下來的資料和自己這一層的資料打包,再發給下一層。而上一層傳下來的東西,就是這一層需要負責傳遞的東西,就稱之為 payload,而這一層的資訊,就稱之為 header,而這樣子打包完的東西,再往下傳(然後會成為下一層的 payload,下一層又會有自己的 header,再打包,再往下傳)。

    最終,就成為了我們看到的樣子。

    此時,我們有能力更細的看一下每一層傳遞了什麼,稍微了解一下即可:

    1. 傳輸層:

      這是 TCP 的 Header,我們先只看 2 個欄位: Source Port 和 Destination Port,顧名思義,從這台電腦的某個 Port 想要往目標電腦的某個目標 Port。

      而 Sequence Number、ACK Number、Checksum 是為了確保資料的完整性,而 Window 是做壅塞控制(Congestion Control),防止一下子傳送一大堆東西把網路塞爆。

    2. 網路層:

      這邊我們看最重要的兩個,分別是 Source Address 和 Dest Address,代表你的電腦 IP 以及目標電腦 IP。

    3. 連結層:

      這邊也只看最重要的 dest mac-addr 和 src mac-addr,代表當前封包要從哪一台電腦傳遞到哪一台電腦(每傳過一台設備這個就會變的不一樣)。

    這樣子,我們應該已經能大致上明白個層在做哪一個步驟的事了,接下來我們就來進入今天的主題,傳輸層與應用層。

  3. 傳輸層

    傳輸層最重要的兩個協定,分別是 TCP 和 UDP。

    TCP 會建立一個可靠的通道,然後資料在這個通道當作以 stream 的方式來傳遞(你傳遞 "abcdefg",他可能會先傳遞 "ab" 再傳 "cdefg";也有可能先傳 "abcd",再傳 "efg";他並不太在意這些),然後還要很重要的 Congestion Control 和 Flow Control,粗淺理解前者是不把網路塞爆,後者是不把對方電腦塞爆。

    UDP 會把資料發出去,發出去了就好,他不會做其他任何事。

    這兩種傳遞資料的方式各有利弊,即有不同應用:TCP 適合用在對錯誤的容忍度很低的時候,比如聊天軟體、電子郵件;UDP 適合用在對錯誤不敏感,但對時間敏感的時候,例如實況、遊戲、通話。

    而雖然說比起 TCP 這種「可靠」傳輸,UDP 是「不可靠」的,但你仍然可以在應用層做一些防護措施,甚至你可以在應用層做一套完整的錯誤偵測、流量監測⋯⋯,來做到幾乎不亞於 TCP 的可靠度(那你為何不直接用 TCP?)。

  4. 應用層常見的服務

    1. 網頁服務

      我們有許多應用,例如你在訪問網站的時候,用的是 HTTP(HyperText Transfer Protocol)。HTTP 伺服器按照慣例會佔用 80 port,是最常見的網路服務。

      在 Linux 系統上,最常見的是用 Apache 或是 NGINX 這兩種程式來架設網站服務。

      而 HTTP 是未經過加密的,不適合傳遞敏感資訊,如密碼、信用卡⋯⋯,所以就有了 HTTPS(HTTP Secure),他就是加密過的 HTTPS,但其實他做的事情不只加密,還有就是確認對方的憑證(有公信力的人頒發給某台伺服器,用來確定這台伺服器是貨真價實的)來防止其他人偽裝成目標伺服器。例如防止某人偽裝成 facebook.com 來騙取你的臉書帳號密碼。

      當你訪問一個 HTTP 網站或是憑證過期的網站時,遊覽器會跳出警告來告訴你,請勿輸入機密資訊,如果是 HTTP 網站,代表所有中間人都可以讀取你的資料;如果是憑證無效,代表可能是中間有人偽裝成目標伺服器來和你要資料,後者當然傳輸其實仍是安全的,不會被竊聽,但你可能根本就講給了錯誤的人聽。而 HTTPS 的慣用 port 是 443 port。

      而毫無疑問,這是基於 TCP。

      我們可以用 chrome 這個工具來測試網站服務:

      當然我們也可以在 CLI 介面下,使用 curl 這個指令:

      我們下載到了密密麻麻的網頁原始碼。

      我們也可以用 curl 來看一看和 http server 建立連線的過程:

      我們可以看到我們發出的 HTTP Request(>開頭的行)、以及他回傳的 Header(<開頭的行)。

      我們甚至可以用 curl 來做到提交表單、夾帶資料、測試時間之類的事情,curl 的是一個非常完備的 http client,可以用 curl 測試 http server 設置等,相當萬用。

      還有一些方便的網站,例如 ifconfig.me:

    2. 網域系統(Domain Name System)

      比起容易記憶的 google.com,我想應該沒有幾個人會去記 172.217.24.14 這組 IP,而 Domain Name System 就因此而生。

      一個網域(domain name)會由很多級組成,例如:www.google.com

      • www 是三級 domain
      • google 是二級 domain
      • com 則是頂級 domain(top level domain)

      而每一個網域都會有一些 DNS 紀錄(Record),有數種類別,這邊只介紹兩個:

      1. A:讓這個網域指向到某個 IP,例如 google.com 指向到 172.217.24.14。
      2. CNAME:讓一個網域指向到另一個網域,但這限制蠻多的,通常只是為了方便而用。

      而其實 DNS 的用處不只是方便,他還有其他功用,比如認證,或是做 Load Balancing(將流量導到很多伺服器,避免單一伺服器承受太高的流量)。

      例如 Youtube 有很多台伺服器會在做 load balancing 和防止某一台掛掉服務就掛掉(高可用性):

      而依照慣例,www.google.com 代表 google 這家公司所提供網路服務的主機,但由於人們最常用的就是 www 服務,所以連 google.com 或 youtube.com 都會幫你導向或是直接讓你用(直接指向同一台伺服器)。

      我們可以透過指令 dig 來查詢某個 Domain Name:

      我們還可以透過它來向特定的 DNS Server 查詢:

      這是 Google 的 DNS Server(8.8.8.8):

      這是 Cloudflare 的 DNS Server(1.1.1.1):

      我們會發現得到的 IP 不同,這其實就是一種 Load Balancing。

    3. Secure Shell(SSH)

      SSH 可在不安全的網路中為網路服務提供安全的傳輸環境,其實原理和 HTTPS 一樣,都是經由加密傳輸內容。SSH 絕大多數的用途都是幫助我們遠端登入一台伺服器,然後可以在這台伺服器上面作業(要知道很多時候伺服器不會接螢幕,所以要連上去工作也是用 SSH 比較方便)。

      在沒有 SSH 以前,人們會用 telnet 來連到遠端伺服器,但是 telnet 本身不會進行加密,所以不安全。

      而 SSH 伺服器的慣用 port 是 22。

      在 Linux 系統當中,SSH 的指令是這樣的:

      $ ssh userName@hostName
      

      而在 Windows 中,SSH 指令是這樣的:

      $ ssh -l userName hostName
      
    4. 其他

      像是早期很常被使用的 ftp(現在用 sftp 更方便),或是像是 NFS,都是很常拿來架 NAS 的服務。

      還有例如 SMTP、LMAP 是拿來架設 Mail 服務的,但這邊就不多做介紹了。

  5. 網路小工具

    Linux 為例:

    1. ifconfig ifconfig 會列出這台電腦上每一張網卡以及網卡的狀態:

      $ ifconfig
      
      enp2s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
      	inet 192.168.1.110  netmask 255.255.255.0  broadcast 192.168.1.255
      	inet6 fe80::54f0:2bc7:782e:f637  prefixlen 64  scopeid 0x20<link>
      	ether fc:aa:14:26:11:f6  txqueuelen 1000  (Ethernet)
      	RX packets 7152971  bytes 7759364541 (7.7 GB)
      	RX errors 0  dropped 0  overruns 0  frame 0
      	TX packets 2023952  bytes 182372428 (182.3 MB)
      	TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
      	device interrupt 18
      
      lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
      	inet 127.0.0.1  netmask 255.0.0.0
      	inet6 ::1  prefixlen 128  scopeid 0x10<host>
      	loop  txqueuelen 1000  (Local Loopback)
      	RX packets 4525636  bytes 432627990 (432.6 MB)
      	RX errors 0  dropped 0  overruns 0  frame 0
      	TX packets 4525636  bytes 432627990 (432.6 MB)
      	TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
      

      例如這台電腦有兩張網卡,第一張網卡是 enp2s0,這張網卡有一個 ip 為 192.168.1.110/24;第二張網卡是 loopback 網卡,代表封包進來之後不會發出去,會回到自己身上,然後 ip 位置是 127.0.0.1/8。

      他還可以把一張網卡關閉、啟用,或是對網卡做設定,詳情請看 ifconfig(8)

    2. ip

      ip 指令提供了很多功能,比如查看每一張網卡的資訊:

      $ ip addr
      
      1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
      	link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
      	inet 127.0.0.1/8 scope host lo
      	   valid_lft forever preferred_lft forever
      	inet6 ::1/128 scope host
      	   valid_lft forever preferred_lft forever
      2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
      	link/ether fc:aa:14:26:11:f6 brd ff:ff:ff:ff:ff:ff
      	inet 192.168.1.110/24 brd 192.168.1.255 scope global dynamic noprefixroute enp2s0
      	   valid_lft 471sec preferred_lft 471sec
      	inet6 fe80::54f0:2bc7:782e:f637/64 scope link noprefixroute
      	   valid_lft forever preferred_lft forever
      

      或是查看 routing table:

      $ ip route
      default via 192.168.1.254 dev enp2s0 proto dhcp metric 100
      10.5.5.0/24 dev wg0 proto kernel scope link src 10.5.5.1
      169.254.0.0/16 dev enp2s0 scope link metric 1000
      172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
      192.168.1.0/24 dev enp2s0 proto kernel scope link src 192.168.1.110 metric 100
      
    3. traceroute

      可以看往某個特定 IP 的路徑:

      $ traceroute 8.8.8.8
      
      traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
       1  router.lan (192.168.1.254)  0.717 ms  0.640 ms  0.605 ms
       2  gateway-140-113-138-0.dorm12.nctu.edu.tw (140.113.138.254)  3.311 ms  3.055 ms  3.229 ms
       3  172.16.82.2 (172.16.82.2)  5.354 ms  5.324 ms  5.293 ms
       4  not-a-legal-address (140.113.0.170)  1.303 ms  1.262 ms  1.223 ms
       5  not-a-legal-address (140.113.0.74)  1.595 ms  1.555 ms  1.716 ms
       6  140-113-254-10.dorm-f2.nctu.edu.tw (140.113.254.10)  4.614 ms  4.457 ms  3.740 ms
       7  10.23.209.126 (10.23.209.126)  3.423 ms  3.609 ms 10.23.209.94 (10.23.209.94)  4.300 ms
       8  dns.google (8.8.8.8)  2.956 ms  3.086 ms  2.889 ms
      
    4. ping

      大家最常用的 ping,這個和剛才的 traceroute 是屬於 ICMP,是網路層當中用來診斷、評估網路狀況的。

      你 ping 一台主機,對方可能會 pond 回來,如此一次,我們可以檢查網路是否通以及延遲。

      $ ping 8.8.8.8 -c 4
      
      PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
      64 bytes from 8.8.8.8: icmp_seq=1 ttl=58 time=3.00 ms
      64 bytes from 8.8.8.8: icmp_seq=2 ttl=58 time=2.95 ms
      64 bytes from 8.8.8.8: icmp_seq=3 ttl=58 time=2.93 ms
      64 bytes from 8.8.8.8: icmp_seq=4 ttl=58 time=2.91 ms
      
      --- 8.8.8.8 ping statistics ---
      4 packets transmitted, 4 received, 0% packet loss, time 3003ms
      rtt min/avg/max/mdev = 2.916/2.953/3.005/0.050 ms
      
    5. tcpdump

      我們可以用 tcpdump 來側錄一張網卡所流過的所有封包:

      $ sudo tcpdump -i enp2s0
      
      tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
      listening on enp2s0, link-type EN10MB (Ethernet), capture size 262144 bytes
      09:16:11.959997 IP server.ssh > 192.168.1.108.60337: Flags [P.], seq 4163186129:4163186317, ack 16794405, win 501, options [nop,nop,TS val 1186279657 ecr 1013510781], length 188
      09:16:11.961013 IP server.47507 > router.lan.domain: 50241+ PTR? 108.1.168.192.in-addr.arpa. (44)
      09:16:11.961286 IP 192.168.1.108.60337 > server.ssh: Flags [.], ack 188, win 2045, options [nop,nop,TS val 1013510852 ecr 1186279657], length 0
      09:16:11.961769 IP router.lan.domain > server.47507: 50241 NXDomain 0/0/0 (44)
      09:16:11.962582 IP server.45784 > router.lan.domain: 38211+ PTR? 110.1.168.192.in-addr.arpa. (44)
      09:16:11.963204 IP router.lan.domain > server.45784: 38211 NXDomain 0/0/0 (44)
      09:16:11.963945 IP server.ssh > 192.168.1.108.60337: Flags [P.], seq 188:408, ack 1, win 501, options [nop,nop,TS val 1186279661 ecr 1013510852], length 220
      09:16:11.964453 IP server.ssh > 192.168.1.108.60337: Flags [P.], seq 408:972, ack 1, win 501, options [nop,nop,TS val 1186279662 ecr 1013510852], length 564
      

      例如我們在這個例子當中側錄到了 ssh 的封包,我們當然可以把詳細的封包資訊也輸出出來:

      $ tcpdump -i enp2s0 -X
      

      還可以下 -w 將結果寫到檔案裡面,而這個檔案是可為 wireshark 所讀取的。

    6. netcat

      你可以用 netcat 來建立一個網路連線,例如我用 netcat 來監聽 5000 port:

      然後我用 curl 去建立連線,curl 就會發送一個 HTTP Request,netcat 在與 curl 建立連線後,我便看得到來自於 curl 的 http request header。

      網路瑞士刀 netcat

    7. telnet

      telnet 也是很常見的工具,可以與別人建立連線,例如我用 netcat 和 telnet 來建立一個兩人聊天室:

      有時候例如測試 Mail Server 或是測試什麼服務,都還算方便,另外,你還可以用 telnet 去連 ptt:

      而可以看到他說:「注意,您使用的連線方式並不安全!」就是指 telnet 未經過加密。