網路概論 Lesson 2
-
預期你會學到什麼
你能明白你當你訪問一個網站,你的電腦到底做了什麼,以及會用一些工具來檢查網路狀態。
-
網路模型
國際標準化組織提出了 OSI 的 7 層網路模型,不過 7 層分太多了,我們這邊用簡化成四層的 TCP/IP 模型:
我們上次稍微帶過了,你的封包(資料)是怎麼在網路世界中傳遞的,這其實是在網路層和鏈接層的工作,而更上面的傳送層與應用層,會是我們今天的重點。
先講一下這四層分別在做什麼:
- 應用層:各個應用程式,例如你的遊覽器,或是 Youtube 的網站伺服器,這些提供應用服務的,都在應用層。
- 傳輸層:傳輸層顧名思義,他協助你傳輸,應用層決定你要傳什麼,傳輸層決定你要怎麼傳,傳輸層最重要的就是 TCP,TCP 會建立一個可靠的連線,幫助你確保你的資料有正確的傳送到目的地,當中沒有丟包、亂序,當然 TCP 不只這個功能。
- 網路層:網路層會把 IP 位置等資訊和運輸層傳下來的資料打包成一個封包,然後會決定這個封包應該要怎麼走,也就是所謂的路由。
- 連結層:連結層負責把封包傳遞到下一台電腦,至於應該要往哪一台電腦,是由網路層決定,連結層只負責做發送到目標電腦。
所以回到我們上一次的內容:
假設我要從 PC1 想要發一個 mail 給 PC4,其實會經過這樣的步驟:
- PC1 電腦上的郵件服務程式(應用層)會打包一封 Mail 的資料,之後會把這個 message 往下交給傳輸層。
- 傳輸層在這邊會使用 TCP,來確保信件可以確實給對方收到,把 TCP 的一些參數和 message 一起打包成一個 segment,再把這個 segment 往下交給網路層。
- 網路層會把 PC1 的 IP 地址、PC4 的 IP 地址等資料和 segment 一起打包,打包成一個 datagram,之後再把 datagram 往下交給連結層。然後 PC1 會發現他的封包下一個目的地應該要是 Router0。
- 連結層會打包 datagram,讓 src mac-addr 是 PC1,dst mac-addr 是 Router 0,之後將封包發到 Router0 所在的介面。
之後 Router0 會做這樣的事情:
- 當每個封包流入 Router0 時候, Router0 會先把連結層的包裝拆掉,看到網路層打包的 datagram,之後發現這個封包的目的地按照 Router 0 的 Routing Table(路由表)應該要轉發到 PC4。
- 他會重新打包一層 Link-Layer 的包裝,src mac-addr 變成 Router0,dst mac-addr 變成 PC4,並且把封包發到 PC4 所在的介面。
之後 PC4 就會收到封包,會一層一層的解析:
- 看連結層的資訊,他知道這個封包是由 Router0 交給他。
- 看網路層的資訊,他知道這個封包來自於 PC1。
- 看傳輸層的資訊,他知道這個封包是要給哪一個 port,就知道要給哪一隻程式處理。
- 看應用層的資訊,他就知道他收到的信件內容為何了。
而每一層其實都在做這件事情:
把上一層傳下來的資料和自己這一層的資料打包,再發給下一層。而上一層傳下來的東西,就是這一層需要負責傳遞的東西,就稱之為 payload,而這一層的資訊,就稱之為 header,而這樣子打包完的東西,再往下傳(然後會成為下一層的 payload,下一層又會有自己的 header,再打包,再往下傳)。
最終,就成為了我們看到的樣子。
此時,我們有能力更細的看一下每一層傳遞了什麼,稍微了解一下即可:
-
傳輸層:
這是 TCP 的 Header,我們先只看 2 個欄位: Source Port 和 Destination Port,顧名思義,從這台電腦的某個 Port 想要往目標電腦的某個目標 Port。
而 Sequence Number、ACK Number、Checksum 是為了確保資料的完整性,而 Window 是做壅塞控制(Congestion Control),防止一下子傳送一大堆東西把網路塞爆。
-
網路層:
這邊我們看最重要的兩個,分別是 Source Address 和 Dest Address,代表你的電腦 IP 以及目標電腦 IP。
-
連結層:
這邊也只看最重要的 dest mac-addr 和 src mac-addr,代表當前封包要從哪一台電腦傳遞到哪一台電腦(每傳過一台設備這個就會變的不一樣)。
這樣子,我們應該已經能大致上明白個層在做哪一個步驟的事了,接下來我們就來進入今天的主題,傳輸層與應用層。
-
傳輸層
傳輸層最重要的兩個協定,分別是 TCP 和 UDP。
TCP 會建立一個可靠的通道,然後資料在這個通道當作以 stream 的方式來傳遞(你傳遞 "abcdefg",他可能會先傳遞 "ab" 再傳 "cdefg";也有可能先傳 "abcd",再傳 "efg";他並不太在意這些),然後還要很重要的 Congestion Control 和 Flow Control,粗淺理解前者是不把網路塞爆,後者是不把對方電腦塞爆。
UDP 會把資料發出去,發出去了就好,他不會做其他任何事。
這兩種傳遞資料的方式各有利弊,即有不同應用:TCP 適合用在對錯誤的容忍度很低的時候,比如聊天軟體、電子郵件;UDP 適合用在對錯誤不敏感,但對時間敏感的時候,例如實況、遊戲、通話。
而雖然說比起 TCP 這種「可靠」傳輸,UDP 是「不可靠」的,但你仍然可以在應用層做一些防護措施,甚至你可以在應用層做一套完整的錯誤偵測、流量監測⋯⋯,來做到幾乎不亞於 TCP 的可靠度(那你為何不直接用 TCP?)。
-
應用層常見的服務
-
網頁服務
我們有許多應用,例如你在訪問網站的時候,用的是 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:
-
網域系統(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),有數種類別,這邊只介紹兩個:
- A:讓這個網域指向到某個 IP,例如 google.com 指向到 172.217.24.14。
- 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。
-
Secure Shell(SSH)
SSH 可在不安全的網路中為網路服務提供安全的傳輸環境,其實原理和 HTTPS 一樣,都是經由加密傳輸內容。SSH 絕大多數的用途都是幫助我們遠端登入一台伺服器,然後可以在這台伺服器上面作業(要知道很多時候伺服器不會接螢幕,所以要連上去工作也是用 SSH 比較方便)。
在沒有 SSH 以前,人們會用 telnet 來連到遠端伺服器,但是 telnet 本身不會進行加密,所以不安全。
而 SSH 伺服器的慣用 port 是 22。
在 Linux 系統當中,SSH 的指令是這樣的:
$ ssh userName@hostName
而在 Windows 中,SSH 指令是這樣的:
$ ssh -l userName hostName
-
其他
像是早期很常被使用的 ftp(現在用 sftp 更方便),或是像是 NFS,都是很常拿來架 NAS 的服務。
還有例如 SMTP、LMAP 是拿來架設 Mail 服務的,但這邊就不多做介紹了。
-
-
網路小工具
Linux 為例:
-
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)。
-
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
-
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
-
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
-
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 所讀取的。 -
netcat
你可以用 netcat 來建立一個網路連線,例如我用 netcat 來監聽 5000 port:
然後我用 curl 去建立連線,curl 就會發送一個 HTTP Request,netcat 在與 curl 建立連線後,我便看得到來自於 curl 的 http request header。
-
telnet
telnet 也是很常見的工具,可以與別人建立連線,例如我用 netcat 和 telnet 來建立一個兩人聊天室:
有時候例如測試 Mail Server 或是測試什麼服務,都還算方便,另外,你還可以用 telnet 去連 ptt:
而可以看到他說:「注意,您使用的連線方式並不安全!」就是指 telnet 未經過加密。
-
