--- title: '傳輸層 - TCP / UDP' disqus: kyleAlien --- 傳輸層 - TCP / UDP === ## OverView of Content 如有引用參考請詳註出處,感謝 :smile: 傳輸層的協定能讓網路層(IP)的包、應用層的需求連接,其中最常見的就是 TCP、UDP 協議 [TOC] ## 傳輸層 概述 ### TCP 概述 * TCP 是傳輸層的一項協定,TCP 之所以流行是因為它對應用沒有太多要求,只須知道開啟、讀取、寫入、關閉... 等等行為即可(就跟處理檔案差不多) * TCP 的實現大多都包裹在系統核心之中,它幫我們處理了以下事項 1. 傳送時將數據切分打包 2. 接收時將數據拆分 3. 檢查錯誤、盡可能的修復 > 當然如果我們停留在應用層級是不需要知道這麽多資訊,大致如下圖 ``` mermaid graph TD; 客戶端發送-HelloWorld-->客戶端核心-拆數據-He_llo_Wor_ld; 客戶端核心-拆數據-He_llo_Wor_ld-->Internet; Internet-->遠端核心-解數據-He_llo_Wor_ld; 遠端核心-解數據-He_llo_Wor_ld-->遠端核心組裝&修復; 遠端核心組裝&修復-->遠端應用收到-HelloWorld; ``` ### UDP 概述 * UDP 單次傳輸就可以構成完整的傳輸(不用糾正封包、不關心亂序),但 **UDP 仍有連接埠(Port)的概念** :::warning * 雖然 UDP 有連接埠的概念,不過它不用使用連接埠來進行連接!該連接埠只是用來發送資料,而遠端是否要回覆都可以 > 所以 UDP 的速度會比 TCP 快,但相對的不穩定 ::: ## 連接埠 Port 就算視同種類的服務,只要編號(連接埠 Port)不同,該服務就可被視為令一個連線 > 連接埠 Port 是一個數字 ### IP & Port 關係 * 簡單來說 **Mac、IP 是++唯一++的地址,就像大樓門牌號碼** >  * Port 是在同地址的下,不同的分配位子 >  ### TCP 連接埠、連接 - netstat * 使用 TCP 連線時,應用會在本地開啟一個連接埠(Port)與遠端主機的一個連接埠(Port)連接 ``` mermaid graph TD; 本機Port_12345-->遠端Port_443; ``` :::warning * 這種 Port 的連接是建立在 NetworkManager 連線之上 ::: 可以使用 `netstat` 觀察當前主機與哪些遠端的 Port 有連接關係 ```shell= # -n 不做 DNS 解析 # -t 只顯示 tcp netstat -n -t ``` >  ### 伺服器 & 常見 Port * 什麼是 Port 號 ? 是拿來幹嘛的 ? 就像是 **同大樓中共用地址 (可能地址都是 123),但有不同的樓層房號 (房號 1 ~ 50 號) 這就是 Port 號** :::success * Port 號有幾個呢 ? **一個 Port 規定為 16 位元,也就是 2^16^ 個不同端口** ::: * 一台伺服器通常會處理不只一種服務,有可能有網頁、郵件、檔案傳輸... 等等,如果要從另外一台裝置透過外部訪問(網路 IP),就需要指定 Port 號 > 不同 Port 代表不同服務 其中有包含 **特殊端口號** | 端口號 | 功能 | 補充 | | -------- | -------- | -------- | | 0 ~ 1023(2^10^) | 系統端口號(標準、知名埠) | 不可隨意使用,`Http:80`、`FTP:21`、`TELNET:23` | | 1024 ~ 49151 | 登記端口號 | 讓第三方有登記的應用使用,透過 IANA 登記 | | 49152 ~ 65535 | 暫時端口號 | 可以自由使用,通常由系統隨機挑選使用(以保證不會發生衝突) | * 透過通訊埠編號(Port)識別時,我們有幾個常見的公認通訊 Port(Well-Known),**範圍為 ++0 ~ 1023++**,**在這個範圍內的 Port 請不要隨意佔用** | 常見 Port 號 | 用途 | | -------- | -------- | | 20 | FTP 傳送資料 | | 21 | FTP 控制 | | 22 | SSH (Secure Shell) | | 23 | Telnet 傳送 **未加密** 內容的文字傳輸協定 | | 25 | SMTP 接收、發送郵件 | | 80 | HTTP 網頁伺服器 | | 110 | POP3 接收郵件 | | 123 | NTP NetWork Time Protocol | | 443 | Https 在 Http 基礎加上 SSH 加密傳輸內容 | :::info - 在由瀏覽器上基本是不需要指定 Port 號 ```shell= www.google.com:443 ``` ::: 另外我們可以查看 `/etc/services` 文件看看有哪些公認的連接埠 ```shell= cat /etc/services ``` >  ### 路由器的 Port * 在路由器內也有使用通訊埠編號 (Port),內部大部份是內建了 1. NAT (`Network Address Translation`):將全球 IP 位址轉為私人 IP 位址 > 這樣就換變成 1 個 全球 IP 位址對應 多個私人位置 ``` mermaid graph TD; 全球_IP-117.122.1.32-->路由器_NAT; 路由器_NAT-->裝置A_B_C-117.122.1.32; ``` 2. NAPT (`Network Address Port Translation`):在 NAT 的機制下加上 Port 號,讓每個私人 IP 都有 Port 號 ``` mermaid graph TD; 全球_IP_117.122.1.32-->路由器_NAPT; 路由器_NAPT-->裝置A_117.122.1.32:80001; 路由器_NAPT-->裝置B_117.122.1.32:80002; 路由器_NAPT-->裝置C_117.122.1.32:80003; ``` ### Port 建立 TCP 連接 * 要建立傳輸層連接,應用會先發送一系列特別的封包,先初始化一個本機連接埠(Port)到選端的連接埠 * **客戶端**:通常發起連接端稱之為客戶端 > 客戶端 Port 通常是隨意挑選一個未使用的 Port,這種 Port 又稱為 **動態連接埠** * **伺服器**:接收(監聽)資料端稱為 伺服器 > 伺服器端的 Port 則是固定公認的 可以使用 `netstat` 查看本地正在監聽的 Port ```shell= # -l 監聽中 netstat -n -t -l ``` > 下圖中可以看到某些服務正監聽本地(127.0.0.1)的 25, 631, 5939 連接埠 > >  :::info * 可以使用 `lsof` 搭配 `grep` 命令查看是哪個應用正在監聽該連接埠 ::: ## TCP & UDP * TCP / UDP 為++全雙工++;並且該協議是 **==傳輸層== 控制協定,TCP 又稱為++可靠協議++,UDP 又稱為++不可靠協議++**,以下會詳細介紹 TCP 的握手協定 :::info * 那是否每個通訊方式都需要經過 OSI 協定的傳輸層呢? 不用,並非每個傳輸協定都要經過傳輸層;像是 **Ping 傳輸命令就不需要經過傳輸層**(它基於網路層協定運作) ::: > 網路層: ICMP 控制報文協議、IGMP internet 管理協議 > > 鏈路層: ARP 地址解析、RARP 地址加密協定 >  :::info Android 最底層的是使用工具 **`tcpdump`** (指令式)、上層使用 `fiddle`、`charls`,並使用 `waveshark` 分析 ::: ### TCP 數據包結構 * 每一次都會傳輸都會發送這種格式的數據,**在三次握手 \ 四次揮手時會操作到一系列的 Flag (紅色框)** >  ### 三次握手 * 小寫代表序列號,大寫代表數據包中的 Flag 狀態,**注意流程** 1. **第一次 (Client to Server) :** `SYN = 1`、**`seq = J` ++系統隨機生成、不可固定++ (因為數據如果斷線後重連,同序列號會導致無法確認是否是同一資料)** 2. **第二次 (Server to Client) :** `SYN = 1`、`ACK = 1`、**`ack = J + 1` (才能確認是否有收到),seq = K 改為 established 建立連接狀態** 3. **第三次 (Client to Server) :** `ACK = 1`、`ack = K + 1` * 交換完初始序號後,就可以開始傳送數據了,**如果連上後不發送數據會自動斷開 (超時機制)** >  :::warning * **為何是三次握手、不是四次、五次 ?** > **主要是為了 TCP 的考靠性,該可靠性是在確認序列號 (比對序列號)**,**==主要是為了++交換 TCP 的初始序列號 ISN++==**,這樣才能確認是否是相同連線,3 次以上握手是多餘的 ::: ### TCP 握手漏洞 - STN Flood * **SYN 攻擊,大量發送偽造園地址的攻擊報文,發送到服務端,造成服務端上的==半開連結隊列溢出==,阻止其他用戶訪問** > 原理 : > > Client 偽造 IP 地指向 Server 端發出請求 (一次握手),而服務端自然響應 (二次握手) 但無法發送到指定 IP,所以**服務端會一直等待第三次握手,而處於半開連結狀態 (等待第三次握手)**,這會導致資源耗損 :::success **解決方案: 無效連接監控釋放、防火牆** ::: ### 四次揮手 * 斷開一個 TCP 連接時,需要客戶端共發起 4 次確認訊息,C/S 都可以發出揮手,以下以客戶端主動斷開 1. **Client :** `FIN = 1` **(發起斷線),Client 狀態轉為 FIN_WAIT_1** 2. **Server :** `ACK = 1` **(同意斷線),Client 狀態轉為 FIN_WAIT_2,轉為半連接狀態** 3. **Server :** `FIN = 1` **(確定斷線請求)** 4. **Client :** `ACK = 1` **(發送確定斷線請求),Client 狀態轉為 TIME_WAIT,並==等待 2MSL 的時間,超過後就默認真正斷開==** * **MSL : Maxnum Segment Lifetime**,2MSL 是數據包來回時間 >  :::warning * **為何是四次揮手 ? 三次可以嗎 ?** > 因為是 **++全雙工++ 的原因**,導致雙方都要確認斷線需要四次,但是**要三次也是可以 (Server、Client 端的 FIN 同時發送)** * 為何需要 `TIME_WAIT` ? 1. 保證 Server 端真的接收到 Client 端斷線訊息,這樣 Server 端才可以正確的關閉連線 2. 保證 Client 端可以收到 Server 端回覆的訊息,這樣 Client 端才可以正確地關閉連線 3. 意外連線關閉 * 如果超過 `TIME_WAIT`,雙方也會進行 Port 關閉 ::: ## TCP 通訊原理 ### Socket * TCP 用主機的 `IP 地址` + `Port 號` 作為 TCP 連接的端點,這種端點稱為 Socket * TCP 的 Socket 的**內核中都有一個發送緩衝區和一個接收緩衝區** ### 可靠性 * 除了透過之前說過的三次握手++交換序列號++,還有一個 **==確認號==,確認每次數據的傳輸,如下圖** >  * 當數據接收失敗 or 遺失,**過一段++特定時間間格++就會在傳輸一次** >  * 因為 TCP / IP是全雙工,不會有一傳一收的問題,也就**沒有先發先到的問題** :::success * 如何知道數據發送完畢 ? > 收到確認性信號,就可以保證傳完,而傳到哪裡為止是由上層應用層決定 ::: ### 窗口機制 * 滑動窗口機制,這個窗口就包含在 TCP 的數據包中,而**確切的窗口大小是由 ==接收端決定==,因為接收端可以調整其數據接收的大小** (能力強就可調高) 1. 保證數據不會因為緩衝不足而丟失,當傳超出緩存時就會要求重新傳 2. 可調整傳輸速度 >  ## 傳輸層 - 工具 ### 連線工具 `netcat`、`telnet` * 我們可以透過 `telnet`、`netcat` 指令來連接傳輸層 * 使用 `telnet` 連接 google ```shell= telnet www.google.com 80 ``` >  * 使用 `netcat` 連接 google ```shell= netcat www.google.com 80 ``` >  ### `nmap` - 查看主機 Port * `nmap` 指令可以查看目標主機有開放哪些 Port 可以給我們使用 :::success * 最好使用兩個角度(本機、另一個網域的裝置)來查看 `nmap` 指令,因為該指令獲取到的資訊可能不是第一手(**有可能已經被防火牆過濾完**) ::: ```shell= # 查看 google 主機的 ip 位置 host www.google.com # 查看 google 網域開放了哪些可訪問的 port nmap 142.251.43.4 ``` >  ## Appendix & FAQ :::info ::: ###### tags: `網路基礎`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up