کتابخانه‌ی استاندارد · شبکه

انتقال شبکه net.transport

جریان بایتی زیر پروتکل‌های وی‌پی‌ان: اتصال TCP، TLS، وب‌سوکت و ارتقای HTTP با نام سرور، ALPN و تکه‌تکه کردن ClientHello، همراه با بافر بایت و نشانی.

واردسازی شبکه.انتقال شبکه

نام آرگومان‌ها شناسه‌ی خود کد است و معادل فارسی ندارد؛ گونه‌ها، کلیدواژه‌ها و نام بسته‌ها با معادل فارسی نوشته می‌شوند.

پروتکل پراکسی مثل وی لس یا وی مس می‌گوید بایت‌های اول یک اتصال چه معنایی دارند. اینکه خود اتصال چطور ساخته می‌شود را نمی‌گوید، و فیلتر دقیقاً به همین بخش نگاه می‌کند: TCP ساده است، TLS است و به کدام نام، وب‌سوکت است و روی کدام مسیر و با کدام سربرگ میزبان. این بسته همان لایه است. «به این میزبان و درگاه با این تنظیمات وصل شو» را به یک اتصال تبدیل می‌کند که هر چه زیرش باشد به یک شکل خوانده و نوشته می‌شود.

بسته چهار کار دارد:

  • حامل‌ها. شماره گیری و شنود روی TCP ساده، TLS، وب‌سوکت (تنها یا داخل TLS) و یک ارتقای ساده‌ی HTTP کار می‌کنند. از جریان و به عنوان جریان اجازه می‌دهند هر جریان تونل هم حامل یک پروتکل باشد، پس یک پروتکل می‌تواند داخل پروتکل دیگری اجرا شود.
  • شبیه چیز دیگری بودن. نام سرور TLS (نام سرور) و سرآیند Host دو تنظیم جدا هستند، پس کارخواه می‌تواند به نام جلویی یک CDN وصل شود و سایت دیگری را بخواهد. مسیر وب‌سوکت مثل یک رمز مشترک کار می‌کند: درخواست برای هر مسیر دیگر یک صفحه‌ی جعلی ۴۰۴ شبیه nginx می‌گیرد.
  • تکه‌تکه کردن ClientHello. تکه تکه کردن بایت‌های اول دست‌دهی TLS را در تکه‌های کوچک و با مکث بین آن‌ها می‌فرستد، که فیلترهایی را که نام سرور را از بسته‌ی اول می‌خوانند گیج می‌کند.
  • زیرساخت مشترک. بایت‌ها بافر رشدکننده‌ای است که بسته‌های پروتکل سرآیندشان را در آن می‌سازند و نشانی نشانی مقصد است که شکل روی سیم خودش را می‌داند.

هر مقدار تنظیمات کدام حامل را انتخاب می‌کند

هر فراخوانی شماره‌گیری و شنود یک مقدار تنظیمات می‌گیرد. مقدار صفر آن TCP ساده است.

تنظیماتحامل
شبکه = "tcp" (پیش‌فرض)جریان خام، و وقتی تی ال اس = درست باشد TLS روی آن.
شبکه = "ws"یک درخواست HTTP/1.1 که به وب‌سوکت ارتقا می‌یابد و بعد قاب‌های دودویی. قاب‌های کارخواه طبق استاندارد نقاب‌دارند. با تی ال اس = درست همان wss است.
شبکه = "httpupgrade"همان درخواست ارتقا بدون قاب‌بندی وب‌سوکت: بعد از پاسخ 101 بایت‌ها خام جریان می‌یابند. از ws سبک‌تر است و برای پراکسی‌ای که فقط درخواست اول را می‌خواند همان شکل را دارد.
تی ال اس = درستکارخواه گواهی سرور را با ریشه‌های سیستم یا پرونده گواهی ریشه می‌سنجد و نام را از نام سرور (یا میزبانِ شماره‌گیری‌شده وقتی خالی است) می‌گیرد. سرور به پرونده گواهی و پرونده کلید نیاز دارد.

هر متن دیگری برای شبکه اینجا رد نمی‌شود: اتصال همان ساده می‌ماند. تجزیه‌گر پیوند بسته‌های پروتکل نوع‌های پشتیبانی‌نشده را قبل از رسیدن به اینجا رد می‌کنند.

چیزهایی که گیر می‌اندازند

  • پذیرش هر اتصال تازه را به یک کارگر می‌سپارد. TLS و ارتقای وب‌سوکت در یک کارگر با سقف زمان (مهلت دست دادن، ۱۰ ثانیه) اجرا می‌شوند و حداکثر بیشینه دست دادن (۱۲۸) هم‌زمان؛ کارخواه گیرکرده رها می‌شود و اتصال بیش از سقف بلافاصله بسته می‌شود. پذیرش اتصال تمام‌شده‌ی بعدی را برمی‌گرداند، یا اتصال بسته‌ای که خطایش می‌گوید دست‌دهی چرا شکست خورد. پذیرش خام و ارتقا برای حلقه‌ی خودتان هنوز هستند.
  • نام سرور با سربرگ میزبان یکی نیست. نام سرور نام داخل دست‌دهی TLS است و گواهی با آن سنجیده می‌شود؛ سربرگ میزبان سرآیند Host داخل درخواست ارتقا است. پشت CDN معمولاً این دو فرق دارند.
  • تنظیم ALPN یک رشته است. "h2" یا "http/1.1" بدهید، نه فهرست. روی وب‌سوکت "http/1.1" بگذارید، چون ارتقا ویژگی HTTP/1.1 است.
  • اثر انگشت چیزی را عوض نمی‌کند. فیلد فقط نگه داشته می‌شود تا پیوندهایی که fp=chrome دارند رفت و برگشت شوند، اما دست‌دهی TLS مال خود این کتابخانه است و کپی مرورگر نیست. فیلتری که شکل دست‌دهی را تشخیص دهد فریب نمی‌خورد.
  • مهلت میلی ثانیه فقط اتصال را محدود می‌کند. برای اتصال برقرار مهلت بی کاری خواندن و مهلت بی کاری نوشتن را بگذارید: خواندن یا نوشتنی که این‌قدر منتظر بماند با ۰ یا کمتر تمام می‌شود. این‌ها سقف بی‌کاری‌اند، پس برای تونلی که ممکن است ساکت بماند ۰ بگذارید.
  • بافرها دستی‌اند. بایت‌های جدید حافظه می‌گیرد و آزادسازی بایت‌ها آزاد می‌کند؛ چیزی خودکار جمعشان نمی‌کند.
  • XHTTP، کوییک و انتقال HTTP/2 ساده نیست. gRPC (شبکه = "grpc")، ریالیتی (امنیت = "reality") و Mux.Cool هست؛ بخش‌های پایین را ببینید.

بافرها و نشانی‌ها

یک مقدار بایت‌ها یک اشاره‌گر، یک طول و یک ظرفیت است. توابع نوشتن (نوشتن بایت و هم‌خانواده‌ها) اضافه می‌کنند و در صورت نیاز بافر را بزرگ می‌کنند، بایت در و خواندن شانزده بیت می‌خوانند و به هگزا محتوا را نشان می‌دهد. نشانی مقصد یک نشانی است: نشانی جدید متن را می‌بیند و بین IP نسخه ۴، IP نسخه ۶ و نام دامنه تصمیم می‌گیرد و نوشتن نشانی آن را به ترتیبی می‌نویسد که سرآیند وی‌لس و وی‌مس می‌خواهند (درگاه، نوع، نشانی). تجزیه یو یو آی دی متن ۳۶ نویسه‌ای معمول را به ۱۶ بایتی که شناسه‌ی کاربر روی سیم است تبدیل می‌کند و اگر متن UUID نباشد خراب را درست می‌گذارد.

net-transport-guide-bytes.salam
// زبان: فارسی
واردسازی شبکه.انتقال شبکه

تابع ریشه:
    ناپایا b := انتقال شبکه.بایت‌های جدید(16)
    انتقال شبکه.نوشتن بایت(b، 0x7f)
    انتقال شبکه.نوشتن شانزده بیت(b، 443)
    انتقال شبکه.نوشتن رشته(b، "hi")
    سرچاپ انتقال شبکه.به هگزا(b)، b.طول
    سرچاپ انتقال شبکه.خواندن شانزده بیت(b، 1)، انتقال شبکه.بایت در(b، 3) برگردان صحیح
    انتقال شبکه.آزادسازی بایت‌ها(b)

    a := انتقال شبکه.نشانی جدید("example.com"، 443)
    سرچاپ a.میزبان، a.درگاه، a.نوع برابر انتقال شبکه.نشانی دامنه
    سرچاپ انتقال شبکه.نشانی جدید("192.168.1.9"، 80).نوع برابر انتقال شبکه.نشانی آی پی چهار
    سرچاپ انتقال شبکه.نشانی جدید("2001:db8::1"، 8080).نوع برابر انتقال شبکه.نشانی آی پی شش

    ناپایا wire := انتقال شبکه.بایت‌های جدید(32)
    انتقال شبکه.نوشتن نشانی(wire، a)
    سرچاپ انتقال شبکه.به هگزا(wire)
    ناپایا back := انتقال شبکه.نشانی {}
    used := انتقال شبکه.خواندن نشانی(wire، 0، back)
    سرچاپ used، back.میزبان، back.درگاه
    انتقال شبکه.آزادسازی بایت‌ها(wire)

    id := انتقال شبکه.تجزیه یو یو آی دی("b831381d-6324-4d53-ad4f-8cda48b30811")
    سرچاپ id.خراب، id.طول، انتقال شبکه.قالب یو یو آی دی(id)
    سرچاپ انتقال شبکه.تجزیه یو یو آی دی("not a uuid").خراب
پایان
خروجی7f01bb6869 5 443 104 example.com 443 true true true 01bb020b6578616d706c652e636f6d 15 example.com 443 false 16 b831381d-6324-4d53-ad4f-8cda48b30811 true

شروع سریع: یک کارخواه و یک سرور

شنود درگاهی را می‌گیرد (۰ یعنی درگاه آزاد و درگاه شنونده می‌گوید کدام)، پذیرش منتظر کارخواه می‌ماند و خواندن و نوشتن بایت جابه‌جا می‌کنند. وقتی طرف مقابل بسته باشد خواندن ۰ یا کمتر برمی‌گرداند. بعد از شماره‌گیری معتبر را بررسی کنید و اگر نادرست بود خطا را بخوانید. این برنامه سرور را در یک نخ اجرا می‌کند و از راه نشانی حلقه‌ی محلی با آن حرف می‌زند.

net-transport-guide-echo.salam
// زبان: فارسی
واردسازی حافظه
واردسازی همگام سازی
واردسازی شبکه.انتقال شبکه

ناپایا port := 0
ناپایا ready := همگام سازی.گروه انتظار جدید()

تابع echo_once():
    settings := انتقال شبکه.تنظیمات {}
    l := انتقال شبکه.شنود(0، settings)
    port = انتقال شبکه.درگاه شنونده(l)
    همگام سازی.اتمام(ready)
    ناپایا c := انتقال شبکه.پذیرش(l)
    buf := حافظه.تخصیص(4096 برگردان طبیعی۶۴)
    n := انتقال شبکه.خواندن(c، buf، 4096)
    اگر n بزرگتر 0:
        انتقال شبکه.نوشتن(c، buf، n)
    پایان
    حافظه.آزادسازی(buf)
    انتقال شبکه.بستن(c)
    انتقال شبکه.بستن شنونده(l)
پایان

تابع ریشه:
    همگام سازی.افزودن(ready، 1 برگردان صحیح۶۴)
    t := نخ‌ساز(echo_once)
    همگام سازی.انتظار(ready)

    ناپایا c := انتقال شبکه.شماره گیری("127.0.0.1"، port، انتقال شبکه.تنظیمات {})
    اگر وارونه انتقال شبکه.معتبر(c):
        سرچاپ "شماره‌گیری شکست خورد:"، c.خطا
        برگشت
    پایان
    ناپایا msg := انتقال شبکه.از رشته("hello transport")
    انتقال شبکه.ارسال بایت ها(c، msg)
    buf := حافظه.تخصیص(4096 برگردان طبیعی۶۴)
    n := انتقال شبکه.خواندن(c، buf، 4096)
    سرچاپ "پژواک"، n، "بایت:"، (buf برگردان رشته).زیررشته(0، n)
    حافظه.آزادسازی(buf)
    انتقال شبکه.آزادسازی بایت‌ها(msg)
    انتقال شبکه.بستن(c)
    نخ‌پیوند(t)
پایان
خروجیپژواک 15 بایت: hello transport

وب‌سوکت و اینکه چرا پذیرش کافی نیست

در دو طرف شبکه = "ws"، یک مسیر و اگر خواستید یک سربرگ میزبان بگذارید. کارخواه یک GET عادی با User-Agent مرورگر می‌فرستد. سرور مسیر را و، اگر سربرگ میزبان گذاشته باشید، سرآیند Host را می‌سنجد؛ ناهمخوانی با یک صفحه‌ی 404 Not Found به سبک nginx پاسخ داده می‌شود و اتصال بسته می‌شود، پس کاوشگری که مسیر دیگری را امتحان کند یک وب‌سرور معمولی می‌بیند.

برنامه‌ی زیر سمت سرور را محتاطانه انجام می‌دهد: پذیرش خام فقط اتصال TCP (و وقتی تی ال اس روشن است دست‌دهی TLS) را می‌گیرد و ارتقا بعد درخواست را می‌خواند. در سرور واقعی فراخوانی ارتقا و هر چه بعدش می‌آید برای هر اتصال در یک نخ کارگر قرار می‌گیرد تا کارخواهی که گیر کرده جلوی بقیه را نگیرد. نیمه‌ی دوم رد شدن یک مسیر اشتباه را نشان می‌دهد.

net-transport-guide-ws.salam
// زبان: فارسی
واردسازی حافظه
واردسازی همگام سازی
واردسازی شبکه.انتقال شبکه

ناپایا port := 0
ناپایا ready := همگام سازی.گروه انتظار جدید()
ناپایا seen_path := ""
ناپایا seen_host := ""

تابع settings(): انتقال شبکه.تنظیمات:
    ناپایا s := انتقال شبکه.تنظیمات {}
    s.شبکه = "ws"
    s.مسیر = "/tunnel"
    s.سربرگ میزبان = "cdn.example.com"
    برگشت s
پایان

تابع worker():
    s := settings()
    l := انتقال شبکه.شنود(0، s)
    port = انتقال شبکه.درگاه شنونده(l)
    همگام سازی.اتمام(ready)
    ناپایا c := انتقال شبکه.پذیرش خام(l)
    اگر انتقال شبکه.ارتقا(c، s):
        seen_path = c.مسیر درخواست
        seen_host = c.میزبان درخواست
        buf := حافظه.تخصیص(4096 برگردان طبیعی۶۴)
        n := انتقال شبکه.خواندن(c، buf، 4096)
        انتقال شبکه.نوشتن(c، buf، n)
        حافظه.آزادسازی(buf)
    پایان
    انتقال شبکه.بستن(c)
    انتقال شبکه.بستن شنونده(l)
پایان

تابع ریشه:
    همگام سازی.افزودن(ready، 1 برگردان صحیح۶۴)
    t := نخ‌ساز(worker)
    همگام سازی.انتظار(ready)

    ناپایا c := انتقال شبکه.شماره گیری("127.0.0.1"، port، settings())
    ناپایا msg := انتقال شبکه.از رشته("inside a websocket")
    انتقال شبکه.ارسال بایت ها(c، msg)
    buf := حافظه.تخصیص(4096 برگردان طبیعی۶۴)
    n := انتقال شبکه.خواندن(c، buf، 4096)
    سرچاپ (buf برگردان رشته).زیررشته(0، n)
    حافظه.آزادسازی(buf)
    انتقال شبکه.آزادسازی بایت‌ها(msg)
    انتقال شبکه.بستن(c)
    نخ‌پیوند(t)
    سرچاپ "سرور مسیر را دید"، seen_path، "و میزبان"، seen_host

    ناپایا wrong := settings()
    wrong.مسیر = "/other"
    همگام سازی.افزودن(ready، 1 برگردان صحیح۶۴)
    t2 := نخ‌ساز(worker)
    همگام سازی.انتظار(ready)
    bad := انتقال شبکه.شماره گیری("127.0.0.1"، port، wrong)
    سرچاپ "مسیر اشتباه پذیرفته شد:"، انتقال شبکه.معتبر(bad)
    سرچاپ bad.خطا
    نخ‌پیوند(t2)
پایان
خروجیinside a websocket سرور مسیر را دید /tunnel و میزبان cdn.example.com مسیر اشتباه پذیرفته شد: false upgrade refused: HTTP/1.1 404 Not Fou

داده زودهنگام همان ترفند «صفر رفت‌وبرگشت» به سبک Xray است: بایت‌های اول بار در سرآیند Sec-WebSocket-Protocol درخواست ارتقا می‌روند. آن‌ها را به شماره گیری با داده زودهنگام بدهید و داده زودهنگام را روی بزرگ‌ترین اندازه‌ای که در دو طرف اجازه می‌دهید بگذارید. سرور این بایت‌ها را در اولین خواندن پس می‌دهد.

وی‌لس یا وی‌مس روی وب‌سوکت و TLS پشت CDN

این راه معمول اجرای پراکسی‌ای است که باید زنده بماند: سرور واقعی پشت یک CDN پنهان است، اتصال به CDN HTTPS معمولی است و CDN درخواست‌های وب‌سوکت برای یک مسیر محرمانه را به سرور می‌رساند.

  1. یک دامنه را روی CDN بگذارید و به سرور اشاره دهید. پراکسی (ابر نارنجی) را روشن کنید و وب‌سوکت را فعال کنید. درگاهی را بگیرید که CDN برای HTTPS می‌پذیرد، مثل ۴۴۳، ۲۰۵۳، ۲۰۸۳، ۲۰۸۷ یا ۲۰۹۶.
  2. بگذارید CDN TLS را تمام کند. حالت «Full» آن را با گواهی مبدأ انتخاب کنید، یا سرور را با تی ال اس = درست و گواهی و کلید در پرونده گواهی و پرونده کلید اجرا کنید. اگر نمی‌خواهید مبدأ اصلاً TLS حرف بزند، با ws ساده روی یک درگاه محلی پشت پراکسی معکوس خودتان گوش دهید.
  3. در سرور با شبکه = "ws"، یک مسیر تصادفی بلند و سربرگ میزبان برابر دامنه‌ی خودتان شنود کنید. هر درخواست برای مسیر دیگر، ۴۰۴ شبیه nginx می‌گیرد.
  4. در کارخواه به نام جلویی (هر نامی که به CDN می‌رسد) با تی ال اس = درست، نام سرور برابر نام جلویی، سربرگ میزبان برابر دامنه‌ی خودتان و همان مسیر شماره‌گیری کنید. شبکه‌ی بین شما و CDN فقط TLS به نام جلویی را می‌بیند.
  5. الپن = "http/1.1" بگذارید. داده زودهنگام را فقط وقتی تنظیم کنید که CDN سرآیند Sec-WebSocket-Protocol را رد کند.
net-transport-guide-cdn.salam
// زبان: فارسی
واردسازی شبکه.انتقال شبکه

تابع client_settings(): انتقال شبکه.تنظیمات:
    ناپایا s := انتقال شبکه.تنظیمات {}
    s.شبکه = "ws"
    s.تی ال اس = درست
    s.نام سرور = "front.example.net"
    s.سربرگ میزبان = "vpn.example.org"
    s.مسیر = "/ws-8f3a"
    s.الپن = "http/1.1"
    s.داده زودهنگام = 2048
    s.مهلت میلی ثانیه = 8000
    برگشت s
پایان

تابع server_settings(): انتقال شبکه.تنظیمات:
    ناپایا s := انتقال شبکه.تنظیمات {}
    s.شبکه = "ws"
    s.مسیر = "/ws-8f3a"
    s.سربرگ میزبان = "vpn.example.org"
    برگشت s
پایان

تابع ریشه:
    c := انتقال شبکه.شماره گیری("front.example.net"، 443، client_settings())
    سرچاپ انتقال شبکه.معتبر(c)، c.خطا
    l := انتقال شبکه.شنود(10000، server_settings())
    سرچاپ انتقال شبکه.شنونده معتبر(l)
    انتقال شبکه.بستن شنونده(l)
پایان

سایت این برنامه را فقط وارسی می‌کند و اجرا نمی‌کند، چون به سرور شما نیاز دارد. همین چیدمان را روی یک پروتکل در صفحه‌های وی لس و وی مس ببینید و برای وصل کردنش به یک پراکسی محلی صفحه‌ی تونل را. CDN بین دو پای TLS خودش همه‌ی ترافیک شما را آشکار می‌بیند: TLS را برای شما تمام می‌کند و فقط پروتکل داخلی (وی‌مس) یا نبودنش (وی‌لس با encryption=none) باقی می‌ماند. اگر به CDN برای بار خود اعتماد ندارید، وی‌مس را با امنیت ای ای اس۱۲۸ جی سی ام یا امنیت چاچا۲۰ پلی۱۳۰۵ بگیرید.

تکه‌تکه کردن ClientHello در TLS

بعضی فیلترهای ملی، از جمله فیلتر ایران، نام سرور را از بسته‌ی اول اتصال TLS می‌خوانند و اگر نام در فهرست باشد اتصال را می‌برند. اغلب این کار را بدون سرهم‌کردن TCP یا رکوردهای TLS می‌کنند، پس ClientHello که تکه‌تکه برسد تطبیق نمی‌خورد. تکه تکه کردن = درست این کار را در لایه‌ی رکورد TLS سمت کارخواه انجام می‌دهد، بدون نخ یا سوکت کمکی. حالت تکه تکه کردن می‌گوید چه چیز شکسته شود:

  • "tcp" (پیش‌فرض): رکورد ClientHello در چند بسته‌ی TCP به اندازه‌ی تصادفی کمینه تکه تا بیشینه تکه با فاصله‌ی تاخیر تکه میلی ثانیه نوشته می‌شود.
  • "tls": خود رکورد ClientHello به چند رکورد TLS (هر کدام با سرآیند خودش) شکسته می‌شود که سرور دوباره سرهم می‌کند. رکوردها هر کدام در یک بسته می‌روند.
  • "both": رکورد شکسته می‌شود و نتیجه به بسته‌های TCP هم بریده می‌شود.

برش نام سرور = درست یک برش میان نام سرور می‌افزاید تا هیچ تکه و رکوردی آن را کامل نداشته باشد؛ اگر کمینه و بیشینه هر دو ۰ باشند تنها برش است. شمار نوشتن های تکه شده می‌گوید چند نوشتن اول دست‌دهی تکه شود (۱ همان ClientHello است). سرور در هر دو حالت همان بایت‌های دست‌دهی را می‌بیند؛ آزمون‌ها نشان می‌دهند سرور واقعی TLS دست‌دهی را کامل می‌کند و یک گیرنده رکوردها را به همان ClientHello یکسان سرهم می‌کند.

اندازه تکه ها تابعی است که اندازه‌ها را برمی‌گزیند. عمومی است تا ببینید یک تنظیم چه تولید می‌کند: همه‌ی تکه‌ها به‌جز آخری در بازه‌اند و مجموعشان برابر کل است.

net-transport-guide-fragment.salam
// زبان: فارسی
واردسازی شبکه.انتقال شبکه

تابع ریشه:
    sizes := انتقال شبکه.اندازه تکه ها(517، 5، 20)
    ناپایا total := 0
    ناپایا in_range := درست
    تکرار sizes.طول() در i:
        n := sizes.بگیر(i)
        total += n
        اگر i کوچکتر sizes.طول() - 1 و (n کوچکتر 5 یا n بزرگتر 20):
            in_range = نادرست
        پایان
    پایان
    سرچاپ "مجموع تکه‌ها برابر است با"، total
    سرچاپ "همه‌ی تکه‌ها جز آخری ۵ تا ۲۰ بایت‌اند:"، in_range
    سرچاپ "بیش از ۲۵ تکه:"، sizes.طول() بزرگتر 25
    سرچاپ "یک تکه وقتی کمینه و بیشینه کل پیام را می‌پوشانند:"، انتقال شبکه.اندازه تکه ها(10، 50، 60).طول()
پایان
خروجیمجموع تکه‌ها برابر است با 517 همه‌ی تکه‌ها جز آخری ۵ تا ۲۰ بایت‌اند: true بیش از ۲۵ تکه: true یک تکه وقتی کمینه و بیشینه کل پیام را می‌پوشانند: 1

برای روشن کردن آن در یک شماره‌گیری TLS:

net-transport-guide-fragment-tls.salam
// زبان: فارسی
واردسازی شبکه.انتقال شبکه

تابع ریشه:
    ناپایا s := انتقال شبکه.تنظیمات {}
    s.تی ال اس = درست
    s.نام سرور = "example.com"
    s.تکه تکه کردن = درست
    s.کمینه تکه = 3
    s.بیشینه تکه = 30
    s.تاخیر تکه میلی ثانیه = 5
    s.مهلت میلی ثانیه = 8000
    ناپایا c := انتقال شبکه.شماره گیری("example.com"، 443، s)
    سرچاپ انتقال شبکه.معتبر(c)، c.خطا
    انتقال شبکه.بستن(c)
پایان

با تکه‌های ۳ تا ۳۰ بایت و مکث ۵ تا ۱۰ میلی‌ثانیه شروع کنید. تکه‌ی کوچک‌تر و مکث بلندتر فیلترهای بیشتری را گیج می‌کند و دست‌دهی را کندتر؛ اگر اتصال شروع به شکست یا پایان مهلت کرد، تکه‌ها را بزرگ‌تر یا مکث را کوتاه‌تر کنید. تکه‌تکه کردن فقط در کارخواه و فقط با تی ال اس = درست کار می‌کند. باید همان‌جایی که هستید امتحانش کنید: فیلتری که جریان را بازسازی کند، یا فیلتری که روی نشانی IP یا چیزی جز نام سرور مسدود کند، تأثیر نمی‌پذیرد، و آنچه جواب می‌دهد با زمان عوض می‌شود. تکه‌تکه کردن نام را از فیلتر پنهان می‌کند؛ پنهان نمی‌کند که پراکسی به کار برده‌اید و شکل خود دست‌دهی را عوض نمی‌کند (بالا درباره‌ی اثر انگشت ببینید).

gRPC (gun و multi)

شبکه = "grpc" بایت‌ها را در یک جریان HTTP/2 از پیام‌های gRPC می‌برد، همان شکل «gun» V2Ray: کارخواه به /نام‌سرویس/Tun POST می‌کند و هر پیام یک فیلد پروتوبافر با داده دارد. حالت جی آر پی سی = "multi" از /نام‌سرویس/TunMulti استفاده می‌کند. با تی ال اس = درست ALPN به‌طور پیش‌فرض h2 است؛ بدون TLS HTTP/2 ساده است. نام سرویس را دو طرف بگذارید (پیوندها آن را serviceName می‌برند)؛ درخواست برای نام دیگر با خطای gRPC پاسخ داده می‌شود و اتصالی ساخته نمی‌شود. قاب‌بندی HTTP/2 در همین بسته با HPACK از net.http2 نوشته شده، چون اتصال باید هم‌زمان از دو نخ خوانده و نوشته شود. سرور چند جریان روی یک اتصال HTTP/2 را می‌پذیرد و هر کدام یک اتصال از پذیرش می‌شود. فقط با خودش آزموده شده و با هم‌تای واقعی gRPC Xray اجرا نشده است.

Mux.Cool

چندگانه ساز کارخواه جدید و چندگانه ساز کارساز جدید نشست‌ها را روی یک جریان چندپلکس می‌کنند، با قاب‌بندی V2Ray و Xray برای CmdMux: باز کردن نشست نشستی به یک مقصد باز می‌کند و جریانش را می‌دهد و پذیرش نشست در سمت دیگر هر نشست بازشده را با مقصدش برمی‌گرداند. MuxClient و MuxServer در بسته‌های وی‌لس و وی‌مس این را برای اتصالی که با CmdMux ساخته شده می‌پوشانند. مثل اصل، کنترل جریان میان نشست‌ها نیست و یک نشست گیرکرده می‌تواند بقیه را نگه دارد؛ افزونه‌های XUDP (شناسه‌ی سراسری، نشانی هر بسته) پیاده نشده است. نشست یو‌دی‌پی در هر نوشتن یک دیتاگرام می‌برد؛ ایکس‌ری اگر دیتاگرامی بزرگ‌تر از ۸۱۹۲ بایت برسد کل اتصال Mux را می‌بندد، پس بیشینه بسته چندگانه ساز اعمال می‌شود: نوشتن بزرگ‌تر رد می‌شود (۱- برمی‌گرداند) و نشست باز می‌ماند. با ایکس‌ری نشست یو‌دی‌پی تا ۸۱۹۲ بایت کار می‌کند و با سینگ‌باکس تا ۱۶۰۰۰ اندازه‌گیری شد.

ریالیتی

با امنیت = "reality" کارخواه دست‌دهی ریالیتی net.reality را به‌جای TLS اجرا می‌کند (ریلیتی را با کلید عمومی و شناسه‌ی کوتاه بگذارید) و شنونده سمت سرور را از ریلیتی کارساز انجام می‌دهد؛ اتصالی که احراز نشود به سایت پوشش رله می‌شود. بعد از دست‌دهی همه‌چیز مثل TLS است.

محدودیت‌ها و امنیت

  • گواهی‌ها به‌طور پیش‌فرض سنجیده می‌شوند. اجازه ناامن = درست سنجش را خاموش می‌کند و هر کسی روی مسیر می‌تواند اتصال را بخواند و تغییر دهد. فقط برای آزمایش با گواهی خودامضا از آن استفاده کنید، یا به‌جایش مرجع گواهی را به پرونده گواهی ریشه بدهید.
  • تکه‌تکه کردن فقط به نوشتن‌های اول دست می‌زند. رکوردهای بعدی مهر شده‌اند و هرگز شکسته نمی‌شوند؛ شمار نوشتن های تکه شده بیش از ۱ فقط برای دست‌دهی‌هایی که بیش از یک دسته پیام (flight) می‌فرستند اثر دارد.
  • ۴۰۴ جعلی تمام پوشش است. بازدیدکننده‌ای که مسیر درست را دارد ولی دست‌دهی وب‌سوکت ندارد، 400 Bad Request را به همان سبک nginx می‌گیرد. هیچ چیز دیگر سرور شبیه یک وب‌سایت ساخته نمی‌شود؛ اگر لازم دارید، یک پراکسی معکوس واقعی جلویش بگذارید.
  • شنونده به‌طور پیش‌فرض روی نشانی loopback می‌نشیند. شنود از نشانی شنود (127.0.0.1) استفاده می‌کند؛ برای پذیرش از ماشین‌های دیگر شنود همه یا شنود در نشانی با "0.0.0.0" را صدا بزنید. کارخواه‌های گیرکرده با سقف زمان دست‌دهی رها می‌شوند؛ برای بی‌کارها مهلت بی کاری خواندن بگذارید.
  • مقایسه‌ی زنده با Xray یا V2Ray انجام نشده. بسته با خودش و با بردارهای بایتی آزموده شده؛ اینکه یک CDN یا یک ساخت Xray درخواست‌هایش را بپذیرد باید در محیط خودتان امتحان شود.

گونه‌ها

تنظیمات Settings

ساختار تنظیمات
هر چه تعیین می‌کند اتصال چطور ساخته شود. مقدار صفرش TCP ساده است.
نامانگلیسیگونهتوضیح
شبکهnetworkرشته = "tcp""tcp"، "ws" یا "httpupgrade".
تی ال اسtlsمنطقی = نادرستاتصال را در TLS بپیچد. شنونده علاوه بر آن به پرونده گواهی و پرونده کلید نیاز دارد.
نام سرورsniرشته = ""نام سرور که در دست‌دهی TLS فرستاده می‌شود و گواهی با آن سنجیده می‌شود. خالی یعنی میزبان شماره‌گیری‌شده.
الپنalpnرشته = ""تنها پروتکل ALPN برای پیشنهاد، مثل "http/1.1". یک رشته است، نه فهرست.
اثر انگشتfingerprintرشته = ""نام یک مرورگر مثل "chrome". برای پیوندهایی که آن را دارند نگه داشته می‌شود؛ دست‌دهی را عوض نمی‌کند.
اجازه ناامنallow_insecureمنطقی = نادرستسنجش گواهی را رد می‌کند. روی شبکه‌ی واقعی ناامن است.
پرونده گواهی ریشهca_fileرشته = ""پرونده‌ی PEM مرجع‌های گواهی که به‌جای مرجع‌های سیستم باور می‌شوند.
مسیرpathرشته = "/"مسیر درخواست وب‌سوکت یا ارتقا. سرور هر مسیر دیگری را رد می‌کند.
سربرگ میزبانhostرشته = ""سرآیند Host درخواست ارتقا. سروری که این را گذاشته باشد نام‌های میزبان دیگر را رد می‌کند.
سربرگ هاheadersرشته = ""سرآیند‌های اضافه‌ی درخواست کارخواه، به صورت خط‌های Name: value که با \r\n جدا شده‌اند.
داده زودهنگامearly_dataصحیح = 0بیشترین تعداد بایت بار که در سرآیند Sec-WebSocket-Protocol فرستاده می‌شود. ۰ داده‌ی زودهنگام را خاموش می‌کند.
تکه تکه کردنfragmentمنطقی = نادرستبایت‌های اول دست‌دهی TLS را در تکه‌های کوچک می‌فرستد. سمت کارخواه و فقط با تی ال اس.
کمینه تکهfragment_minصحیح = 5کوچک‌ترین تکه به بایت.
بیشینه تکهfragment_maxصحیح = 20بزرگ‌ترین تکه به بایت.
تاخیر تکه میلی ثانیهfragment_delay_msصحیح = 10مکث بین دو تکه به میلی‌ثانیه.
پرونده گواهیcert_fileرشته = ""زنجیره‌ی گواهی سرور، به صورت پرونده‌ی PEM.
پرونده کلیدkey_fileرشته = ""کلید خصوصی سرور، به صورت پرونده‌ی PEM.
مهلت میلی ثانیهtimeout_msصحیح = 0اتصال TCP چقدر می‌تواند طول بکشد. ۰ یعنی پیش‌فرض سیستم. خواندن را محدود نمی‌کند.
مهلت بی کاری خواندنread_timeout_msصحیح = 0مهلت بی‌کاری خواندن یک اتصال برقرار به میلی‌ثانیه. ۰ یعنی همیشه منتظر ماندن.
مهلت بی کاری نوشتنwrite_timeout_msصحیح = 0مهلت بی‌کاری نوشتن یک اتصال برقرار به میلی‌ثانیه. ۰ یعنی همیشه منتظر ماندن.
حالت تکه تکه کردنfragment_modeرشته = "tcp"تکه تکه کردن چه چیزی را می‌شکند: "tcp" (پیش‌فرض) هلو را در چند بسته‌ی TCP می‌نویسد، "tls" رکورد ClientHello را به چند رکورد TLS می‌شکند و "both" هر دو را.
برش نام سرورfragment_sniمنطقی = نادرستدر میانه‌ی نام سرور هم برش می‌زند تا هیچ تکه‌ای نام کامل را نداشته باشد. اگر کمینه و بیشینه هر دو ۰ باشند این تنها برش است.
شمار نوشتن های تکه شدهfragment_writesصحیح = 1چند نوشتن اول دست‌دهی تکه می‌شود. پیش‌فرض ۱ همان ClientHello است.
نشانی شنودbindرشته = "127.0.0.1"نشانی‌ای که شنونده روی آن می‌نشیند. پیش‌فرض 127.0.0.1 است؛ برای همه‌ی رابط‌ها از شنود همه یا "0.0.0.0" استفاده کنید.
مهلت دست دادنhandshake_timeout_msصحیح = 10000سرور چقدر به یک اتصال تازه وقت می‌دهد دست‌دهی TLS و ارتقا را تمام کند، پیش از آنکه رهایش کند. پیش‌فرض ۱۰۰۰۰.
بیشینه دست دادن همزمانmax_handshakesصحیح = 128یک شنونده چند دست‌دهی را هم‌زمان پیش می‌برد. اتصال‌های بیشتر بلافاصله بسته می‌شوند. پیش‌فرض ۱۲۸.
بیشینه دست دادن مبداmax_per_sourceصحیح = 0یک نشانی مبدا چند دست‌دهی همزمان می‌تواند داشته باشد. اتصال‌های بیشتر از آن بی‌درنگ بسته می‌شوند. ۰ یعنی بدون سقف.
امنیتsecurityرشته = ""تهی برای انتخاب ساده یا tls، یا "reality" تا به‌جای TLS دست‌دهی ریالیتی اجرا شود.
ریلیتیrealityریالیتی.تنظیماتتنظیمات کارخواه ریالیتی (net.reality) وقتی security برابر "reality" است.
ریلیتی کارسازreality_serverریالیتی.تنظیمات سرورتنظیمات کارساز ریالیتی وقتی security برابر "reality" است.
نام سرویسservice_nameرشته = ""نام سرویس gRPC برای network = "grpc". مسیر درخواست /service/Tun است (در حالت multi: /service/TunMulti).
حالت جی آر پی سیgrpc_modeرشته = "gun""gun" (پیش‌فرض) یا "multi" برای network = "grpc".

اتصال Conn

ساختار اتصال
یک اتصال، هر چه حاملش باشد. با توابع این بسته بخوانید و بنویسید، نه از راه فیلدهایش.
نامانگلیسیگونهتوضیح
نوعkindصحیح = 0نوع تی سی پی، نوع تی ال اس یا نوع جریان.
تی سی پیtcpتی سی پی.اتصال شبکهسوکت TCP، اگر باشد.
تی ال اسtlsتی ال اس.اتصالنشست TLS، اگر باشد.
جریان زیرینupdyn تونل.جریانجریان زیر اتصال وقتی نوعش نوع جریان است.
وب سوکتwsمنطقی = نادرستبعد از ارتقای وب‌سوکت درست است: خواندن و نوشتن از آن به بعد با چارچوب است.
کارخواهclientمنطقی = نادرستدر طرفی که شماره‌گیری کرده درست است.
بازopenمنطقی = نادرستتا وقتی اتصال قابل استفاده است درست است. معتبر همین را برمی‌گرداند.
خطاerrرشته = ""دلیل شکست شماره‌گیری، پذیرش یا ارتقا، و در غیر این صورت خالی.
باقی چارچوبfr_leftصحیح = 0بایت‌های چارچوب وب‌سوکت جاری که هنوز خوانده نشده‌اند.
نقابدارfr_maskedمنطقی = نادرستچارچوب جاری نقاب‌دار است.
نقابfr_maskصحیح۶۴ = 0نقاب چارچوب جاری.
جایگاه چارچوبfr_posصحیح = 0جایگاه داخل قاب جاری، برای برداشتن نقاب.
پیش خواندهpreبایت‌هاداده‌ی زودهنگامی که با درخواست ارتقا رسیده. اولین خواندن‌ها آن را برمی‌گردانند.
مسیر درخواستrequest_pathرشته = ""در سرور بعد از ارتقا: مسیری که کارخواه خواسته.
میزبان درخواستrequest_hostرشته = ""در سرور بعد از ارتقا: سرآیند Host که کارخواه فرستاده.
بافر نوشتنwbufبایت‌هابافر قابل استفاده‌ی دوباره‌ای که قاب‌های وب‌سوکت پیش از یک نوشتن در آن ساخته می‌شوند.
مبداremoteرشته = ""نشانی همتا، یا تهی وقتی دانسته نیست.
بسته شدهclosedمنطقی = نادرستپس از اجرای Close درست است، پس بستن دوباره کاری نمی‌کند.

شنونده Listener

ساختار شنونده
سوکت شنونده با تنظیماتی که با آن ساخته شده.
نامانگلیسیگونهتوضیح
سرورserverتی سی پی.سرورسوکت سرور TCP.
تنظیماتsettingsتنظیماتتنظیماتی که به شنود داده شده.
پیکربندی تی ال اسtls_cfgتی ال اس.پیکربندی کارسازپیکربندی TLS سرور که از گواهی و کلید بارگیری شده.
آمادهreadyکانال.کانال<اتصال>صف اتصال‌هایی که دست‌دهی‌شان تمام شده و پذیرش از آن برمی‌دارد.
پرچم هاflagsصحیح۶۴*شمارنده‌های مشترک حلقه‌ی پذیرش: آغاز شده، متوقف شده.
جایگاه هاslotsهمگام سازی.نشانگرسقف دست‌دهی‌های هم‌زمان در حال انجام.
مبداهاsourcesتونل.جدول مبداهادست‌دهی‌های در جریان برای هر نشانی مبدا.

نشست پذیرفته MuxIncoming

ساختار نشست پذیرفته
نشستی که کارخواه باز کرده: جریان، مقصد و اینکه UDP است یا نه.
نامانگلیسیگونهتوضیح
جریانstreamdyn تونل.جریانجریان نشست. بستنش فقط نشست را پایان می‌دهد.
نشانیaddrنشانیمقصدی که کارخواه خواسته.
یو دی پیudpمنطقی = نادرستدرست وقتی هر نوشتن و خواندن جریان یک دیتاگرام است.

چندگانه ساز Mux

ساختار چندگانه ساز
یک چندگانه‌ساز Mux.Cool روی یک اتصال حامل: چند نشست که هر کدام یک جریان است.
نامانگلیسیگونهتوضیح
هستهcoreتهی*وضعیت مشترک چندگانه‌ساز.
معتبرokمنطقی = نادرستدرست وقتی چندگانه‌ساز ساخته شده باشد.

نشانی Addr

ساختار نشانی
نشانی مقصد: نوع، متن میزبان و درگاه.
نامانگلیسیگونهتوضیح
نوعkindصحیح = 2نشانی آی پی چهار، نشانی دامنه یا نشانی آی پی شش.
میزبانhostرشته = ""نشانی یا نام به صورت متن.
درگاهportصحیح = 0درگاه.

بایت‌ها Bytes

ساختار بایت‌ها
بافر بایتی رشدکننده. حافظه‌ی خودش را دارد: وقتی کارتان تمام شد با آزادسازی بایت‌ها آزادش کنید.
نامانگلیسیگونهتوضیح
نشانگرpتهی*آغاز حافظه.
طولlenصحیح = 0چند بایت در حال استفاده است.
ظرفیتcapصحیح = 0چند بایت جا دارد تا بافر بزرگ شود.
خرابbadمنطقی = نادرستوقتی بافر نتیجه‌ی یک تجزیه یا تبدیل ناموفق باشد، مثل هگزا یا UUID نامعتبر، درست است.

پایاها و متغیرها

نوع اتصال Kind…

مقدار فیلد نوع یک اتصال: نوع تی سی پی (۰) TCP ساده، نوع تی ال اس (۱) TLS، نوع جریان (۲) یک جریان net.tunnel.
نامانگلیسیمقدار
نوع تی سی پیKindTCP0
نوع تی ال اسKindTLS1
نوع جریانKindStream2

بیشینه بسته چندگانه ساز MuxMaxPacket

پایا بیشینه بسته چندگانه ساز: صحیح۳۲ = 8192
بزرگ‌ترین دیتاگرامی که نشست یو‌دی‌پی در یک نوشتن می‌پذیرد (۸۱۹۲، حد ایکس‌ری). نوشتن بزرگ‌تر ۱- برمی‌گرداند و چیزی نمی‌فرستد.

نشانی آی پی چهار AddrIPv4

پایا نشانی آی پی چهار: صحیح۳۲ = 1
شماره‌ی نوع نشانی برای IP نسخه ۴.

نشانی دامنه AddrDomain

پایا نشانی دامنه: صحیح۳۲ = 2
شماره‌ی نوع نشانی برای نام دامنه.

نشانی آی پی شش AddrIPv6

پایا نشانی آی پی شش: صحیح۳۲ = 3
شماره‌ی نوع نشانی برای IP نسخه ۶.

تابع‌ها

اندازه تکه ها FragmentSizes

تابع اندازه تکه ها(total: صحیح، min: صحیح، max: صحیح): وکتور<صحیح>
اندازه‌های تکه‌هایی که یک نوشتن تکه‌تکه‌ی total بایتی به کار می‌برد: هر تکه بین min و max بایت است، شاید به‌جز آخری، و مجموعشان total است. اندازه‌ها تصادفی‌اند.

معتبر Ok

تابع معتبر(c: اتصال): منطقی
وقتی اتصال باز است درست است.

خواندن Read

تابع خواندن(c &: اتصال، buf: تهی*، max: صحیح): صحیح
تا max بایت می‌خواند و می‌گوید چند بایت رسید. اتصال وب‌سوکت بار قاب‌های دودویی را برمی‌گرداند و پینگ را خودش پاسخ می‌دهد. ۰ یا کمتر یعنی اتصال تمام شد.

خواندن کامل ReadFull

تابع خواندن کامل(c &: اتصال، buf: تهی*، n: صحیح): منطقی
دقیقاً n بایت می‌خواند. اگر اتصال زودتر تمام شود نادرست است.

نوشتن Write

تابع نوشتن(c &: اتصال، p: تهی*، n: صحیح): منطقی
n بایت از یک اشاره‌گر می‌نویسد، در اتصال وب‌سوکت به صورت یک قاب. اگر شکست بخورد نادرست است.

ارسال بایت ها WriteBytes

تابع ارسال بایت ها(c &: اتصال، b: بایت‌ها): منطقی
یک بافر کامل را می‌نویسد.

تغییر به خواندن مستقیم SwitchDirect

تابع تغییر به خواندن مستقیم(c &: اتصال): منطقی
پس از آنکه همتای XTLS Vision فرمان مستقیم را فرستاد، خواندن‌های بعدی را مستقیم از سوکت TLS یا ریالیتی می‌کند. برای اتصالی که نمی‌تواند (وب‌سوکت یا TCP ساده) نادرست برمی‌گرداند.

مهلت خواندن SetReadTimeout

تابع مهلت خواندن(c &: اتصال، ms: صحیح)
خواندن را بعد از این‌همه میلی‌ثانیه رها می‌کند. ۰ تا ابد منتظر می‌ماند.

بستن Close

تابع بستن(c &: اتصال)
اتصال را می‌بندد؛ اتصال وب‌سوکت اول یک چارچوب بستن می‌فرستد.

شماره گیری با داده زودهنگام DialEarly

تابع شماره گیری با داده زودهنگام(host: رشته، port: صحیح، s: تنظیمات، early: بایت‌ها): اتصال
مثل شماره گیری وصل می‌شود و اگر تنظیمات داده‌ی زودهنگام را اجازه بدهند early را در درخواست ارتقا می‌فرستد.

شماره گیری Dial

تابع شماره گیری(host: رشته، port: صحیح، s: تنظیمات): اتصال
به یک میزبان و درگاه وصل می‌شود: TCP، بعد تکه‌تکه کردن ClientHello، TLS و درخواست ارتقا، هر چه تنظیمات بخواهند. معتبر را بررسی کنید و اگر نادرست بود خطا را بخوانید.

شنود در نشانی ListenAt

تابع شنود در نشانی(host: رشته، port: صحیح، s: تنظیمات): شنونده
روی یک نشانی IPv4 و درگاه مشخص شنود می‌کند. نشانی تهی یعنی loopback و "all" یا "0.0.0.0" یعنی همه‌ی رابط‌ها.

شنونده از سرور ListenerFrom

تابع شنونده از سرور(server: تی سی پی.سرور، s: تنظیمات): شنونده
یک شنونده از یک سرور TCP که از پیش بسته شده می‌سازد (مثلاً با rawsock.ListenOn)، با صف پذیرش، سقف دست‌دهی و TLS سرور آماده. net.vpn از آن استفاده می‌کند.

شنود Listen

تابع شنود(port: صحیح، s: تنظیمات): شنونده
روی یک درگاه گوش می‌دهد؛ ۰ درگاه آزاد برمی‌گزیند.

شنود همه ListenAll

تابع شنود همه(port: صحیح، s: تنظیمات): شنونده
مثل شنود اما روی همه‌ی رابط‌های شبکه. این همان پذیرش صریح است: خود شنود فقط روی نشانی loopback می‌نشیند.

شنونده معتبر ListenerOk

تابع شنونده معتبر(l: شنونده): منطقی
وقتی سوکت بسته شده و، با TLS، گواهی و کلید بارگیری شده باشند درست است.

درگاه شنونده ListenerPort

تابع درگاه شنونده(l: شنونده): صحیح
درگاهی که شنونده به آن بسته شده.

بستن شنونده CloseListener

تابع بستن شنونده(l: شنونده)
گوش دادن را متوقف می‌کند.

پذیرش خام AcceptRaw

تابع پذیرش خام(l: شنونده): اتصال
منتظر کارخواه می‌ماند و اتصال TCP و دست‌دهی TLS را تمام می‌کند، اما نه درخواست ارتقا را.

ارتقا Upgrade

تابع ارتقا(c &: اتصال، s: تنظیمات): منطقی
درخواست ارتقا را روی اتصالِ پذیرش خام می‌خواند، مسیر و میزبان را می‌سنجد، پاسخ می‌دهد و اتصال را به وب‌سوکت یا حالت خام می‌برد. برای tcp ساده کاری نمی‌کند. درخواست ردشده پاسخ می‌گیرد و اتصال بسته می‌شود.

خاموش کردن اتصال ShutdownConn

تابع خاموش کردن اتصال(c &: اتصال)
سوکت یک اتصال TCP یا TLS را بی‌آنکه آزادش کند در هر دو سو خاموش می‌کند، تا خواندنی که در نخ دیگری منتظر است ۰ یا کمتر برگرداند و طرف مقابل پایان را ببیند. پس از آن بستن را صدا بزنید. اتصالی که روی جریان net.tunnel است دست‌نخورده می‌ماند.
net-transport-CloseWriteConn.salam
// زبان: فارسی
واردسازی حافظه
واردسازی همگام سازی
واردسازی شبکه.انتقال شبکه

ناپایا port := 0
ناپایا ready := همگام سازی.گروه انتظار جدید()

تابع count_then_answer():
    l := انتقال شبکه.شنود(0، انتقال شبکه.تنظیمات {})
    port = انتقال شبکه.درگاه شنونده(l)
    همگام سازی.اتمام(ready)
    ناپایا c := انتقال شبکه.پذیرش(l)
    buf := حافظه.تخصیص(4096 برگردان طبیعی۶۴)
    ناپایا total := 0
    ناپایا n := انتقال شبکه.خواندن(c، buf، 4096)
    تا n بزرگتر 0:
        total += n
        n = انتقال شبکه.خواندن(c، buf، 4096)
    پایان
    حافظه.آزادسازی(buf)
    ناپایا reply := انتقال شبکه.از رشته("سرور " + total + " بایت خواند")
    انتقال شبکه.ارسال بایت ها(c، reply)
    انتقال شبکه.آزادسازی بایت‌ها(reply)
    انتقال شبکه.خاموش کردن اتصال(c)
    انتقال شبکه.بستن(c)
    انتقال شبکه.بستن شنونده(l)
پایان

تابع ریشه:
    همگام سازی.افزودن(ready، 1 برگردان صحیح۶۴)
    t := نخ‌ساز(count_then_answer)
    همگام سازی.انتظار(ready)

    ناپایا c := انتقال شبکه.شماره گیری("127.0.0.1"، port، انتقال شبکه.تنظیمات {})
    اگر وارونه انتقال شبکه.معتبر(c):
        سرچاپ "شماره‌گیری شکست خورد:"، c.خطا
        برگشت
    پایان
    ناپایا msg := انتقال شبکه.از رشته("first part, second part")
    انتقال شبکه.ارسال بایت ها(c، msg)
    انتقال شبکه.آزادسازی بایت‌ها(msg)
    انتقال شبکه.بستن نوشتن اتصال(c)
    buf := حافظه.تخصیص(4096 برگردان طبیعی۶۴)
    n := انتقال شبکه.خواندن(c، buf، 4096)
    سرچاپ (buf برگردان رشته).زیررشته(0، n)
    سرچاپ "بعد"، انتقال شبکه.خواندن(c، buf، 4096)
    حافظه.آزادسازی(buf)
    انتقال شبکه.بستن(c)
    نخ‌پیوند(t)
پایان
خروجیسرور 23 بایت خواند بعد 0

بستن نوشتن اتصال CloseWriteConn

تابع بستن نوشتن اتصال(c &: اتصال)
به طرف مقابل می‌گوید چیز دیگری فرستاده نمی‌شود، در حالی که شما پاسخش را همچنان می‌خوانید: TLS هشدار close_notify را می‌فرستد، TCP سوی نوشتن را خاموش می‌کند و جریان net.tunnel فراخوانی را به لایه‌ی زیرین می‌دهد. سپس خواندن طرف مقابل ۰ برمی‌گرداند.

نمونه‌ی این مورد همراه با موارد بالاتر آمده است: net-transport-CloseWriteConn.salam

پذیرش Accept

تابع پذیرش(l: شنونده): اتصال
پذیرش خام و بعد ارتقا، در نخ فراخواننده. کارخواه گیرکرده فراخواننده را نگه می‌دارد.

به عنوان جریان AsStream

تابع به عنوان جریان(c: اتصال): dyn تونل.جریان
اتصال را به صورت tunnel.Stream می‌پیچد تا کد تونل از آن استفاده کند.

از جریان FromStream

تابع از جریان(s: dyn تونل.جریان، client: منطقی): اتصال
یک tunnel.Stream را حامل یک اتصال می‌کند. با client بگویید کدام طرف است.

چندگانه ساز کارخواه جدید NewMuxClient

تابع چندگانه ساز کارخواه جدید(up: dyn تونل.جریان): چندگانه ساز
سمت کارخواه چندگانه‌ساز را روی یک جریان و با یک نخ خواننده راه می‌اندازد.

چندگانه ساز کارساز جدید NewMuxServer

تابع چندگانه ساز کارساز جدید(up: dyn تونل.جریان): چندگانه ساز
سمت کارساز چندگانه‌ساز را روی یک جریان و با یک نخ خواننده راه می‌اندازد.

باز کردن نشست MuxOpen

تابع باز کردن نشست(m: چندگانه ساز، addr: نشانی، udp: منطقی): dyn تونل.جریان
سمت کارخواه: نشستی به یک مقصد باز می‌کند و جریانش را برمی‌گرداند. اگر حامل رفته باشد جریان معتبر نیست.

پذیرش نشست MuxAccept

تابع پذیرش نشست(m: چندگانه ساز، out &: نشست پذیرفته): منطقی
سمت کارساز: منتظر می‌ماند کارخواه نشستی باز کند و جریان و مقصدش را در out می‌گذارد. نادرست وقتی حامل تمام شده باشد.

چندگانه ساز معتبر MuxOk

تابع چندگانه ساز معتبر(m: چندگانه ساز): منطقی
درست تا وقتی حامل زنده است.

بستن چندگانه ساز MuxClose

تابع بستن چندگانه ساز(m: چندگانه ساز)
حامل را می‌بندد و همه‌ی نشست‌ها پایان می‌یابند.

تشخیص نوع نشانی DetectKind

تابع تشخیص نوع نشانی(host: رشته): صحیح
تشخیص می‌دهد متن میزبان IP نسخه ۴ است، IP نسخه ۶ یا نام دامنه.

نشانی جدید NewAddr

تابع نشانی جدید(host: رشته، port: صحیح): نشانی
نشانی می‌سازد و نوعش را از روی متن می‌گذارد.

نوشتن نشانی PutAddr

تابع نوشتن نشانی(b &: بایت‌ها، a: نشانی): منطقی
شکل روی سیم را اضافه می‌کند: درگاه، بایت نوع و نشانی. پیش از دامنه طول آن می‌آید. اگر نشانی قابل نوشتن نباشد نادرست است، مثلاً نام خالی، نام بلندتر از ۲۵۵ بایت یا IP‌ای که تجزیه نمی‌شود.

قالب آی پی شش FormatIPv6

تابع قالب آی پی شش(p: طبیعی۸*): رشته
۱۶ بایت را به متن IP نسخه ۶ در می‌آورد.

خواندن نشانی ReadAddr

تابع خواندن نشانی(b: بایت‌ها، off: صحیح، a &: نشانی): صحیح
نشانی را از یک بافر و یک جایگاه می‌خواند و جایگاه درست بعد از نشانی را برمی‌گرداند، یا ۱- وقتی بایت‌ها نشانی معتبر نباشند.

تجزیه یو یو آی دی ParseUUID

تابع تجزیه یو یو آی دی(s: رشته): بایت‌ها
متن ۳۶ نویسه‌ای UUID را به ۱۶ بایت تبدیل می‌کند؛ برای هر متن دیگر خراب درست می‌شود.

قالب یو یو آی دی FormatUUID

تابع قالب یو یو آی دی(b: بایت‌ها): رشته
۱۶ بایت را به متن ۳۶ نویسه‌ای UUID تبدیل می‌کند.

بایت‌های جدید NewBytes

تابع بایت‌های جدید(cap0: صحیح): بایت‌ها
بافر خالی با جای دست‌کم cap0 بایت می‌گیرد.

آزادسازی بایت‌ها FreeBytes

تابع آزادسازی بایت‌ها(b &: بایت‌ها)
حافظه را آزاد می‌کند و بافر را بازنشانی می‌کند.

بازنشانی بایت‌ها ResetBytes

تابع بازنشانی بایت‌ها(b &: بایت‌ها)
بافر را خالی می‌کند و حافظه‌اش را نگه می‌دارد.

نشانگر بایت‌ها BytesPtr

تابع نشانگر بایت‌ها(b: بایت‌ها، off: صحیح): تهی*
اشاره‌گر به بایتِ جایگاه off، برای دادن به تابعی که حافظه را پر یا می‌خواند.

رزرو Reserve

تابع رزرو(b &: بایت‌ها، need: صحیح)
تضمین می‌کند need بایت دیگر بدون بزرگ شدن دوباره جا شود.

نوشتن بایت Put8

تابع نوشتن بایت(b &: بایت‌ها، v: صحیح)
یک بایت اضافه می‌کند.

نوشتن شانزده بیت Put16

تابع نوشتن شانزده بیت(b &: بایت‌ها، v: صحیح)
عدد ۱۶ بیتی را با بایت بالا در ابتدا اضافه می‌کند.

نوشتن سی‌ودو بیت Put32

تابع نوشتن سی‌ودو بیت(b &: بایت‌ها، v: صحیح۶۴)
عدد ۳۲ بیتی را با بایت بالا در ابتدا اضافه می‌کند.

نوشتن شصت‌وچهار بیت Put64

تابع نوشتن شصت‌وچهار بیت(b &: بایت‌ها، v: طبیعی۶۴)
عدد ۶۴ بیتی را با بایت بالا در ابتدا اضافه می‌کند.

نوشتن خام PutRaw

تابع نوشتن خام(b &: بایت‌ها، src: تهی*، n: صحیح)
n بایت از یک اشاره‌گر اضافه می‌کند.

نوشتن بایت‌ها PutBytes

تابع نوشتن بایت‌ها(b &: بایت‌ها، src: بایت‌ها)
بافر دیگری را اضافه می‌کند.

نوشتن رشته PutStr

تابع نوشتن رشته(b &: بایت‌ها، s: رشته)
بایت‌های یک متن را اضافه می‌کند.

نوشتن صفرها PutZeros

تابع نوشتن صفرها(b &: بایت‌ها، n: صحیح)
n بایت صفر اضافه می‌کند.

بایت در At

تابع بایت در(b: بایت‌ها، i: صحیح): صحیح
بایتِ جایگاه i به صورت عددی از ۰ تا ۲۵۵.

تنظیم بایت Set8

تابع تنظیم بایت(b &: بایت‌ها، i: صحیح، v: صحیح)
بایتِ جایگاه i را بازنویسی می‌کند.

خواندن شانزده بیت Peek16

تابع خواندن شانزده بیت(b: بایت‌ها، i: صحیح): صحیح
عدد ۱۶ بیتی را از یک جایگاه می‌خواند، بایت بالا در ابتدا.

خواندن سی‌ودو بیت Peek32

تابع خواندن سی‌ودو بیت(b: بایت‌ها، i: صحیح): صحیح۶۴
عدد ۳۲ بیتی را از یک جایگاه می‌خواند، بایت بالا در ابتدا.

مصرف Consume

تابع مصرف(b &: بایت‌ها، n: صحیح)
n بایت اول را دور می‌ریزد.

برابر Equal

تابع برابر(a: بایت‌ها، b: بایت‌ها): منطقی
درست است وقتی دو بافر بایت‌های یکسان داشته باشند. مقایسه در اولین تفاوت متوقف نمی‌شود.

به هگزا ToHex

تابع به هگزا(b: بایت‌ها): رشته
بافر را به صورت متن هگزای حروف کوچک برمی‌گرداند.

از هگزا FromHex

تابع از هگزا(h: رشته): بایت‌ها
متن هگزا را در بافر تازه می‌خواند؛ اگر متن هگزای معتبر نباشد خراب درست می‌شود.

از رشته FromStr

تابع از رشته(s: رشته): بایت‌ها
متنی را در بافر تازه کپی می‌کند.