JordyMalone
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 研讀 kecho contributed by < `Jordymalone` > :::info 好多東西都沒看過,~~看的頭好痛...~~,缺什麼補什麼 ::: ## 解釋 drop-tcp-socket 核心模組運作原理 用 `insmod drop-tcp-socket.ko` 把核心模組載入之後,kernel 會呼叫 `drop_tcp_init` -> `register_pernet_subsys(&droptcp_pernet_ops);` 模組初始化並設定: ```c static int drop_tcp_init(void) { int res = register_pernet_subsys(&droptcp_pernet_ops); if (res) return res; return 0; } ``` - [ ] [register_pernet_subsys](https://github.com/torvalds/linux/blob/ebd297a2affadb6f6f4d2e5d975c1eda18ac762d/net/core/net_namespace.c#L1387) 是什麼? > `int register_pernet_subsys(struct pernet_operations *ops)` - register a network namespace subsystem > @ops: pernet operations structure for the subsystem 這邊的 ops 也就是 `&droptcp_pernet_ops`,這個參數指向一組 callback 函式與必要欄位 (如 `.init`,`.exit`,`.id`,`.size`) > callback 函式指的就是由呼叫端在未來某個時機回頭呼叫由你自己實作並註冊給他的函式。 當 `register_pernet_subsys()` 執行時,底層的 `register_pernet_operations()` 會呼叫一系列管理 per-net 資料結構的函式,最終透過 `ops->id` 和 `ida_alloc_min()` 把新分配的索引寫進你的 `droptcp_pernet_id` 變數 (也就是 `.id = &droptcp_pernet_id`),讓之後呼叫 `net_generic(net, droptcp_pernet_id)` 時能正確地定位到對應 namespace 的私有資料區。 在載入並初始化模組後,會為每個現有的 namespace 和未來新增的 namespace 執行一次 `droptcp_pernet_init`,並做以下這些事: ```c struct droptcp_pernet *dt = net_generic(net, droptcp_pernet_id); dt->net = net; dt->pde = proc_create_data(DROPTCP_PDE_NAME, 0600, net->proc_net, &droptcp_proc_fops, dt); ``` :::info 何謂 network namespace? > 參考 [計算機網路 - Network Namespace](https://hackmd.io/@0xff07/SJzOwViYF#%E7%B0%A1%E4%BB%8B) Network namespace 在本質上是 kernel 裡用來隔離網路堆疊的資料結構。它不是一個實體裝置,而是描述「這個行程所能看到哪些網路資源」的上下文。我們常說它「就像一台獨立的機器」,是為了幫助理解,因為它真的讓一個 process 感覺自己擁有一套獨立的 IP、介面和路由,但這一切其實是透過 kernel 的 namespace 機制動態切換出來的。 Process 與 netns 的對應: 一個 process 在任何時刻只屬於一個 netns。它的網路行為(能看到哪些介面、socket、IP、路由)都會被這個 netns 決定。雖然 process 無法同時存在於多個 netns,但可以透過 setns() 切換 netns,或用 veth 等機制讓不同 netns 互通。 雖然每個 process 在任何時刻只屬於一個 netns,但 `/proc/net/drop_tcp_socker` 是以 netns 為單位建立的介面。也就是說屬於同個 netns 中的 process 們會共用這個介面。而不是每個 process 都有一份自己的。 * Docker 使用 Network Namespace 來實現容器的網路隔離。 ::: 透過 `net_generic` 取得此 namespace 對應的私有結構 `struct droptcp_pernet *`,`net` 這個參數是目標的 `struct net *`,代表某個 network namespace,`droptcp_pernet_id` 則是先前由 `register_pernet_subsys` 分配並寫入的索引值。 `dt->net` 的用意則是在後續的 TCP drop 操作中 (`droptcp_drop()`、`droptcp_process()`),都需要知道要在哪個 namespace 的 hash table 中尋找 socket。把 net 存在 `dt` 中,除了方便函式內使用,也讓各 namespace 的上下文清晰且不易搞錯。 `dt->pde = proc_create_data` 則是在各 namespace 的 `/proc/net` 下建立介面,主要是提供使用者一個介面,可以對其輸入字串,就能在該 namespace 執行特定的 TCP 連線 drop 所以可以知道 `droptcp_pernet_init()` 的用途就是核心在每個 namespace (已存在與新建) 呼叫,用來配置 namespace 專屬的 `/proc/net/drop_tcp_sock` 介面,以及設置私有狀態。 接著,進到下一步,對 `/proc/net/drop_tcp_socket` 做操作,先介紹以下結構: ```c // 用於 /proc 介面讀寫時的暫存 buffer struct droptcp_data { uint32_t len; // 已寫入長度 uint32_t avail; // buffer 總大小 char data[0]; // 變動大小陣列(flexible array) }; ``` 只會在你對 `/proc/net/drop_tcp_sock` 這個檔案進行寫入操作時用到,它的用途是在核心模組的 procfs 介面中,累積並暫存使用者傳來的命令字串,讓後續一次性地解析與處理。具體流程如下: 當你在 shell 裡寫 `> /proc/net/drop_tcp_sock` 時,shell 先 在執行 `echo` 這個 builtin 之前,就呼叫 `open("/proc/net/drop_tcp_sock", O_WRONLY|O_TRUNC)` 來把標準輸出 (fd 1) 指向這個檔案。這個 `open` 系統呼叫,則是對應到 `droptcp_proc_open(struct inode *inode, struct file *file)` :::info 目前還不清楚 VFS 有關這種對應的概念 ::: * `droptcp_proc_open` 開啟檔案時分配緩衝區 當使用者第一次 open `/proc/net/drop_tcp_sock`,核心執行 `droptcp_proc_open()`,裡面呼叫 ```c struct droptcp_data *d = kzalloc(PAGE_SIZE, GFP_KERNEL); d->avail = PAGE_SIZE - (sizeof(*d) + 1); file->private_data = d; ``` 這時就會建立一個大小為一頁 (PAGE_SIZE) 的 `droptcp_data` 結構,用以儲存後續所有的 write 內容,avail 則是記錄最大可用空間 同時把新分配的 `droptcp_data` 結構指標存在 `file->private_data`。 `struct file` 代表一個開啟中的檔案或設備,每次 `open()` 呼叫都會分配並初始化一個新的 `struct file`。 接著 shell 執行 `echo`,把它要輸出的字串透過 `write(fd=1, buf, len)` 寫入。 對應到的即是 `droptcp_proc_write(file, buf, size, pos)` 這個操作, * `droptcp_proc_write` 每次寫入時把資料 append 到 `data[]` 若原本的緩衝不足,會用 `krealloc()` 自動擴大,再用 `copy_from_user()` 把新進的字串拷貝到 `d->data + d->len`,並更新 `d->len` 在尾端加上 `'\0'` 做字串結尾。 這樣就能把所有使用者輸入的命令行都累積在同一個連續的 buffer 裡 drop-tcp-socket。 最後,當 echo 完成後,shell 關掉標準輸出 fd,就觸發 `release()`。對應到 `droptcp_proc_release(struct inode *inode, struct file *file)`, * `droptcp_proc_release` 關閉檔案時一次性的解析與釋放 ```c droptcp_process(PDE_DATA(file_inode(file)), d); kfree(d), file->private_data = NULL; ``` 核心會呼叫 `droptcp_process()` 解析 `d->data` 中的每一對「來源→目的」字串,並依序呼叫 `droptcp_drop()` 丟棄對應的 TCP 連線或 TIME-WAIT 物件;最後釋放整塊 buffer > 「來源 → 目的」指的就是 TCP 連線的兩端端點 (endpoint),也就是一組「來源 IP:來源埠號」對應「目的 IP:目的埠號」。模組透過這組四元組來唯一定位要丟棄的那條 TCP 連線 (或 TIME-WAIT 控制塊)。使用 `droptcp_process` 這個函式來解析來源和目的。 當你在使用者空間對 `/proc/net/drop_tcp_sock` 做操作時,底層走的就是一般的 VFS 機制,映射到你在 core 裡面註冊的 procfs callback。 :::info 所以為什麼要這樣做? 為甚麼不能直接使用 kernel 提供的 syscall? ::: ## TIME-WAIT sockets 又是什麼? > - [ ] 參閱 [TCP連線階段與TIME_WAIT意義](https://claire-chang.com/2020/03/01/tcp%E9%80%A3%E7%B7%9A%E9%9A%8E%E6%AE%B5%E8%88%87time_wait%E6%84%8F%E7%BE%A9/),[TCP TIME_WAIT的釋義](https://low-understated.blogspot.com/2009/03/tcp-timewait.html),[谈谈 TCP 的 TIME_WAIT](https://zhenbianshu.github.io/2018/12/talk_about_tcp_timewait.html) > TIME-WAIT sockets 是指處於 TCP 連接終止過程中特定狀態的 socket。在 TCP 四次揮手關閉連接的過程中,主動關閉連接的一方發送最後一個 ACK 後會進入 TIME_WAIT 狀態。TIME_WAIT 狀態將持續 2 個 MSL (Max Segment Lifetime),以 Linux 來說為 60s。 主動關閉端為了 最後 ACK 安全 + 舊封包隔離 而暫留約 1 分鐘的遺體。 可以把他想成是緩衝期,**等 1 分鐘,確保沒人再叫我,也確保舊資料消散,再徹底放手。** ```c if (sk->sk_state == TCP_TIME_WAIT) { inet_twsk_deschedule_put(inet_twsk(sk)); } else { tcp_done(sk); sock_put(sk); } ``` 若已在 TIME_WAIT,呼叫 `inet_twsk_deschedule_put()` 強制將其從 TIME-WAIT hash 表中移除,並釋放。 在高頻的短連線情況下會大量堆積,因此 drop‑tcp‑socket 模組允許你用文字命令即時拔掉這些 TIME‑WAIT,快速回收核心網路資源而不破壞其他 namespace。 可以使用以下命令來確認 TIME_WAIT 會持續多久 ```bash $ sysctl net.ipv4.tcp_fin_timeout -----預期輸出----- net.ipv4.tcp_fin_timeout = 60 ``` 若想修改時間可用以下命令: ```bash $ sudo sysctl -w net.ipv4.tcp_fin_timeout=30 ``` ## 待辦 - [ ] [Create Your Own Network Namespace](https://itnext.io/create-your-own-network-namespace-90aaebc745d) - [ ] [TIME_WAIT and its design implications for protocols and scalable client server systems](https://serverframework.com/asynchronousevents/2011/01/time-wait-and-its-design-implications-for-protocols-and-scalable-servers.html) - [ ] [What is a TCP Reset (RST)?](https://www.pico.net/kb/what-is-a-tcp-reset-rst/)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    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

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully