remote.เอกสารหน้าหลัก

ภาพรวมทางเทคนิค

เอกสารนี้อธิบายกลไกหลักในโค้ดปัจจุบัน ช่องข้อความ รูปแบบเฟรม และลำดับการจับมือที่สมบูรณ์อยู่ใน Wire protocol

ผู้ปฏิบัติงานและอุปกรณ์ต่างเชื่อมต่อขาออกกับ exchange

อุปกรณ์ภายในบ้านและสำนักงานสาขามักจะอยู่หลัง NAT ดังนั้น exchange จึงไม่สามารถโทรเข้าไปได้ ทั้งสองฝ่ายเริ่มต้นการเชื่อมต่อ WebSocket กับ exchange:

  • อุปกรณ์เชื่อมต่อกับ wss://<主机>/ws/device (ws:// สำหรับการดีบักข้อความธรรมดา) โดยลงทะเบียนกับโทเค็นอุปกรณ์ในเฟรมแรก
  • ตัวดำเนินการเชื่อมต่อกับ wss://<主机>/ws/operator โดยใช้โทเค็นตัวดำเนินการสำหรับการจับมือ

exchange จัดการการรับรองความถูกต้อง การกำหนดเส้นทาง และเส้นทางการตรวจสอบ --listen หรือ REMOTE_LISTEN กำหนดที่อยู่การฟัง พร็อกซีย้อนกลับที่อยู่ด้านหน้าจะยุติ TLS

ช่องว่าง ID เซสชันสองช่อง

ผู้ปฏิบัติงานและอุปกรณ์รักษา ID เซสชันที่เป็นอิสระ ผู้ดำเนินการสามารถรวม ID ของตนเองในคำขอโดยไม่ต้องรอการจัดสรรเซิร์ฟเวอร์ก่อนจึงจะส่งเฟรมตามมา ID ฝั่งอุปกรณ์จะได้รับการจัดสรรแยกกันสำหรับการเชื่อมต่ออุปกรณ์แต่ละเครื่องในปัจจุบัน โดยเพิ่มขึ้นจาก 1 แม้ว่าผู้ปฏิบัติงานสองคนจะใช้ ID ภายในเครื่อง 1 ทั้งคู่ก็จะได้รับ ID ที่แตกต่างกันบนอุปกรณ์

ID 0 ถูกสงวนไว้สำหรับข้อความระดับการเชื่อมต่อ การลงทะเบียนล้มเหลวโดยไม่ต้องใส่เส้นทางถ้า ID ฝั่งตัวดำเนินการเป็น 0 หรือใช้อยู่แล้วในการเชื่อมต่อของตัวดำเนินการนั้น

ตารางการแปลอยู่ใน crates/exchange/src/hub/session_table.rs hub.rs แนบคำแปลเข้ากับการเชื่อมต่อแต่ละรายการ: ID อุปกรณ์ → ID ผู้ปฏิบัติงานที่ฝั่งอุปกรณ์ และ ID ผู้ปฏิบัติงาน → (การเชื่อมต่ออุปกรณ์ ID อุปกรณ์) ที่ฝั่งผู้ปฏิบัติงาน

การส่งต่อจะเขียนใหม่เฉพาะรหัสเซสชันเท่านั้น

ไบต์ PTY และคำสั่ง stdout/stderr ใช้เฟรมไบนารี ส่วนหัวเก้าไบต์ประกอบด้วยประเภทสตรีมหนึ่งไบต์ session_id สี่ไบต์ และความยาวเพย์โหลดสี่ไบต์ ตามด้วยเพย์โหลดดิบ คำจำกัดความอยู่ใน crates/proto/src/frame.rs

exchange แทนที่เฉพาะ session_id เมื่อส่งต่อ:

  • ตัวดำเนินการไปยังอุปกรณ์: crates/exchange/src/ws/operator.rs ใช้ DataFrame::with_session_id เพื่อแทนที่ ID ฝั่งอุปกรณ์ จากนั้นวางไบต์ที่เข้ารหัสไว้ในคิวการส่งอุปกรณ์
  • อุปกรณ์ต่อผู้ปฏิบัติงาน: handle_data ใน crates/exchange/src/ws/device.rs จะแทนที่ ID ฝั่งอุปกรณ์ด้วย ID ดั้งเดิมของผู้ปฏิบัติงาน ความคิดเห็นแหล่งที่มาอธิบายการเขียนใหม่นี้

เพย์โหลดผ่านไปไม่เปลี่ยนแปลง การกำหนดเส้นทางไม่ได้ตรวจสอบการกดแป้น PTY หรือเอาต์พุตคำสั่ง เฟรมที่ไม่มีเซสชันที่ตรงกันจะถูกละทิ้ง ข้อความควบคุมคือกรอบข้อความ JSON การเปิดและปิดเซสชั่นจะแปล ID ลงในพื้นที่ ID ของผู้รับในขณะที่ยังคงรักษาสาขาธุรกิจไว้

การเชื่อมต่ออุปกรณ์ใหม่จะแทนที่การเชื่อมต่อเก่า

เมื่ออุปกรณ์เชื่อมต่อใหม่ การเชื่อมต่อใหม่จะเข้าสู่ตารางออนไลน์และแทนที่อันเก่าซึ่งผู้โทรจะปิดลง การปฏิเสธการเชื่อมต่อใหม่เนื่องจากซ้ำกันนั้นไม่เหมาะสม: การเชื่อมต่อเก่าที่เปิดไว้ครึ่งหนึ่งอาจยังคงลงทะเบียนอยู่ ทำให้อุปกรณ์ต้องรอจนหมดเวลา

การเชื่อมต่ออุปกรณ์แต่ละรายการมี epoch (UUID) ซึ่งสร้างขึ้นใน Hub::register_device ยกเลิกการเชื่อมต่อการล้างข้อมูลโดยใช้ Hub::unregister_device โดยถอดอุปกรณ์ออกและทำเครื่องหมายว่าออฟไลน์เฉพาะเมื่อยุคที่ลงทะเบียนตรงกับยุคการล้างข้อมูล ถ้าการล้างข้อมูลการเชื่อมต่อเก่ามาถึงหลังจากการลงทะเบียนการเชื่อมต่อใหม่ ยุคที่แตกต่างกัน ฟังก์ชันจะส่งกลับรายการว่าง และการเชื่อมต่อใหม่ยังคงลงทะเบียนอยู่

คิวการส่งมีขอบเขต คิวเต็มจะปิดการเชื่อมต่อ

WebSocket แต่ละตัวมีคิวความจุ 512 ซึ่งใช้งานโดย channel ใน crates/exchange/src/hub/outbound.rs การกำหนดเส้นทางจะเก็บการล็อกตารางการเชื่อมต่อ ดังนั้นการนำส่งจะใช้เฉพาะ Sender::try_send โดยไม่ต้องรอให้เพียร์อยู่ใต้การล็อก

คิวเต็มทำให้ try_send ส่งคืน SendError::Lagging และตั้งค่าสัญญาณปิด ข้อความควบคุม Close จะข้ามคิวและตั้งค่าสัญญาณเดียวกัน ดังนั้นแม้แต่คิวที่ถูกบล็อกก็สามารถขอปิดระบบได้ ทั้งอุปกรณ์และผู้ปฏิบัติงานรับลูปรอ sender.closed() ภายใน tokio::select! (crates/exchange/src/ws/device.rs, crates/exchange/src/ws/operator.rs) เมื่อได้รับสัญญาณแล้ว การส่งต่อจะสิ้นสุด จากนั้นยกเลิกการลงทะเบียนอุปกรณ์ตามยุคหรือล้างเซสชันของผู้ปฏิบัติงาน เพียร์ที่ทิ้งเครื่องรับไปแล้วจะสร้าง SendError::Closed ซึ่งแตกต่างจากผู้บริโภคที่ไม่สามารถตามทันได้

โทเค็นประกอบด้วยคำนำหน้าและความลับ เก็บเฉพาะแฮช argon2 ของความลับเท่านั้น

โทเค็นข้อความธรรมดามีรูปแบบ <prefix>.<secret> split_token ใน crates/exchange/src/auth.rs แยกที่ . แรก โดยปฏิเสธคำนำหน้าว่างหรือข้อมูลลับว่ามีรูปแบบไม่ถูกต้อง

ในการออก คำนำหน้าคือไบต์สุ่มแปดไบต์ที่เข้ารหัสเป็นเลขฐานสิบหก และความลับคือ 32 ไบต์สุ่มที่เข้ารหัสเป็น base64url ฐานข้อมูลจัดเก็บเพียงสองคอลัมน์:

  • token_prefix: ข้อความธรรมดาที่มีดัชนีเฉพาะ ใช้สำหรับการค้นหาหนึ่งครั้งระหว่างการตรวจสอบ
  • token_hash: สตริง PHC argon2id ของความลับ สร้างโดย hash_secret

บัญชีอุปกรณ์และผู้ให้บริการใช้รูปแบบนี้ การยืนยันจะดึงข้อมูลแฮชตามคำนำหน้า จากนั้นเปรียบเทียบข้อมูลลับกับ verify_secret ข้อความธรรมดาจะถูกส่งกลับเมื่อมีการออกเท่านั้น และไม่สามารถกู้คืนจากฐานข้อมูลได้

argon2 ใช้หน่วยความจำ 8 MiB การวนซ้ำสองครั้ง และความขนาน 1 ซึ่งต่ำกว่าค่าเริ่มต้นของไลบรารี ข้อมูลลับคือค่าสุ่ม 256 บิต; การแฮชที่ช้าเพิ่มเติมไม่ได้เพิ่มการป้องกันแบบเดรัจฉานในทางปฏิบัติ แต่เพิ่มความหน่วงของการจับมือเมื่ออุปกรณ์เชื่อมต่ออีกครั้ง พารามิเตอร์เหล่านี้ใช้กับโทเค็นแบบสุ่มประเภทนี้เท่านั้น

เอกสารที่เกี่ยวข้อง