سانسورشکن net.censor
ابزارهایی برای شبکههایی که در ترافیک دخالت میکنند: شناسایی پروتکل و خواندن نام سرور TLS، تکهتکه کردن ClientHello، لایهگذاری، مجموعههای قاعدهی دامنه با فهرستهای ایران، نگهبان کاوش و حافظهی تکرار.
واردسازی شبکه.سانسورشکن
نام آرگومانها شناسهی خود کد است و معادل فارسی ندارد؛ گونهها، کلیدواژهها و نام بستهها با معادل فارسی نوشته میشوند.
بعضی شبکهها فقط ترافیک را نمیبرند، نگاهش هم میکنند: بایتهای نخست یک اتصال به فیلتر میگویند چه پروتکلی است و نام سرور در نخستین پیام TLS میگوید به کدام سایت میروید. این بسته مجموعهای از ابزارهای کوچک و مستقل از هم برای کار با همین چیزهاست. تشخیص پروتکل و تجزیه پیام آغازین آنچه فیلتر میخواند را میخوانند. تکهتکه کردن پیام آغازین و اندازه تکهها از روی نام سرور آن پیام نخست را تکهتکه میکنند تا فیلتری که فقط یک بسته را نگاه میکند هرگز کل نام را نبیند. مجموعه دامنه و دستهبند از روی قاعده تصمیم میگیرند کدام میزبانها مستقیم بروند، از پراکسی بروند یا هیچجا نروند. نگهبان کاوش، حافظه تکرار و پاسخ طعمه تکههای کارسازی هستند که خودش را به کسی که امتحانش میکند لو نمیدهد. برای دیدن اینکه تکهها در یک برنامه چگونه کنار هم مینشینند، ساختن برنامهای به سبک v2ray یا VPN را بخوانید.
هیچ اتصالی باز نمیکند و وضعیت خودش را ندارد. روی بایتها و متنی کار میکند که میدهید، پس جلوی هر کدام از بستههای پراکسی جا میشود: تونل، ساکس، پراکسی اچتیتیپی، تروجان. هیچکدامشان خودشان آن را صدا نمیزنند؛ هر جا لازم دارید خودتان وصلش کنید.
ایدههای اصلی:
تشخیص پروتکلفقط چند بایت نخست لازم دارد و میگویدنوع تی ال اس،نوع اچ تی تی پی،نوع اس اس اچ،نوع ساکس۵یانوع ساکس۴، یا وقتی هنوز نمیتواند تشخیص دهدنوع داده ناکافی.تجزیه پیام آغازینیک ClientHello از TLS را بدون کتابخانهی TLS میخواند: نام سرور، پروتکلهای پیشنهادی، و اینکه Encrypted Client Hello هست یا نه.- تکهتکه کردن یک نقشه بهعلاوهی یک برش است.
اندازه تکههایااندازه تکهها از روی نام سرورنقشه را میکشند (اندازههایی که جمعشان برابر کل است)،برشبایتها را به تکههای ساده میبرد وتکهتکه کردن رکوردهایک رکورد TLS را به چند رکورد.تکهتکه کردن پیام آغازینکل کار را برای یک ClientHello انجام میدهد. - لایهگذاری اندازهها را پنهان میکند:
پوشاندن رکوردوپوشاندن جریانلایهی تصادفی درون رکوردهایی اضافه میکنند که شبیه دادهی برنامهی TLS هستند وگشودن رکوردآن را برمیدارد. - یک
مجموعه دامنهقاعدههای دامنه نگه میدارد (example.com،full:name،keyword:word)؛ یکدستهبندسهتایش و یک پیشفرض دارد وتصمیم پراکسی،تصمیم مستقیمیاتصمیم مسدودپاسخ میدهد.
چیزهایی که آدم را گیر میاندازد:
- تکهتکه کردن رمزنگاری نیست و جادو هم نیست. در برابر فیلترهایی کمک میکند که فقط نخستین بسته یا نخستین رکورد را نگاه میکنند. فیلترها عوض میشوند و بسیاری از شبکهها دوباره سر هم میکنند. روی همان شبکهای که واقعا استفاده میکنید آزمایشش کنید و تنهایی به آن تکیه نکنید.
- لایهگذاری هم رمزنگاری نیست.
پوشاندن جریاناندازهی تکهها را پنهان میکند، نه آنچه درونشان است. آن را درون TLS یا کانال رمزشدهی دیگر به کار ببرید، هرگز به جای آن. رکوردهای لایهدار سرآیندهایی شبیه TLS دارند که ساختهی همین بسته است: برای ناظر دقیق TLS واقعی به حساب نمیآیند. - پیش از خروج TLS تکه کنید، فقط در آغاز. برش روی نخستین رکورد یک دستدهی میرود. اتصالی که از پیش در جریان است اثری نمیبیند.
- فهرستهای ایران نقطهی شروعاند.
فهرست مستقیم ایرانوفهرست فیلترشدهفهرستهای کوتاه و دستنوشتهای هستند که کهنه میشوند. آنها را مثالهایی برای ویرایش بدانید و فهرست خودتان را در یک پرونده برایافزودن قاعدههانگه دارید. نگهبان کاوشوحافظه تکرارقفل ندارند. دادهی سادهاند. وقتی چند نخ از یکی استفاده میکنند فراخوانیها را در قفل خودتان بپیچید. خودشان جلوی کاوش را نمیگیرند: از مسیر پذیرش کارسازتان صدایشان میزنید.باید جایگزین شودفقط یک مقایسه است. کارسازی که وبسایت واقعی برای نشان دادن دارد همان است که پنهان میکند؛ بستهی تروجان را ببینید.- تصادفی بودن امن است.
عدد تصادفیوبایتهای تصادفیاز منبع امن سیستم میگیرند.تقسیم تصادفیتنها استثناست: با دانه عمدا تکرارپذیر است، که برای آزمون خوب است و برای پنهان کردن الگو انتخاب بدی.
تکهتکه کردن پیام آغازین TLS
کارخواه نخستین پیام TLS خود را به شکل یک رکورد میفرستد. اندازه تکهها از روی نام سرور نام سرور را در آن پیدا میکند و برشی در میانهی نام برنامهریزی میکند؛ برش بایتها را میبرد و تکهها یکی پس از دیگری، هر کدام در بستهی خودشان، فرستاده میشوند. کارساز آنها را به شکل یک جریان میخواند و همان پیام را میبیند. نمونه یک ClientHello را در دو تکه روی loopback میفرستد و نشان میدهد سمت گیرنده چه میخواند.
// زبان: فارسی
واردسازی شبکه.سانسورشکن
واردسازی شبکه.تی سی پی
واردسازی همگام سازی
پایا HELLO := "160301008c010000880303000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f206465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283000613011302c02b0100003900000014001200000f7777772e6578616d706c652e636f6d000a00040002001d0010000e000c02683208687474702f312e31002b0003020304"
ناپایا port := 0
ناپایا seen := ""
ناپایا ready := همگام سازی.گروه انتظار جدید()
تابع server():
srv := تی سی پی.پیوند(0)
port = تی سی پی.درگاه(srv)
همگام سازی.اتمام(ready)
c := تی سی پی.پذیرش(srv)
تی سی پی.تنظیم مهلت خواندن(c، 1500)
تا درست:
data := تی سی پی.خواندن(c، 4096)
اگر data.طول() برابر 0:
بشکن
پایان
seen += data.طول() + " "
پایان
تی سی پی.بستن(c)
پایان
تابع ریشه:
همگام سازی.افزودن(ready، 1 برگردان صحیح۶۴)
t := نخساز(server)
همگام سازی.انتظار(ready)
hello := سانسورشکن.از هگز(HELLO)
sizes := سانسورشکن.اندازه تکهها از روی نام سرور(hello.داده، hello.طول، نادرست)
ناپایا pieces := سانسورشکن.برش(hello.داده، hello.طول، sizes)
سرچاپ "نام سرور از بایت"، سانسورشکن.تجزیه پیام آغازین(hello.داده، hello.طول).جایگاه نام سرور، "شروع میشود و پس از"، sizes.بگیر(0)، "بایت بریده میشود"
conn := تی سی پی.شماره گیری("127.0.0.1"، port)
تی سی پی.غیرفعالسازی نگل(conn، درست)
تکرار pieces.طول() در i:
piece := pieces.بگیر(i)
تی سی پی.نوشتن بایت(conn، piece.داده، piece.طول)
همگام سازی.خواب میلی ثانیه(60)
پایان
تی سی پی.بستن(conn)
نخپیوند(t)
سرچاپ "سرور خواند:"، seen
سرچاپ "تکههای فرستادهشده:"، pieces.طول()
سانسورشکن.آزاد کردن تکهها(pieces)
پایاناین بایتهای جریان را میبرد که هر کارساز TCP دوباره سر هم میکند. تکهتکه کردن پیام آغازین کار دیگری میکند: رکورد را به چند رکورد TLS میبرد، پس حتی فیلتری که بستهها را سر هم میکند نام سرور را میان رکوردها شکسته میبیند. کارسازی که TLS را دنبال کند هر دو را میپذیرد. تکهها را با مکثی کوتاه یا با گزینهی TCP no-delay بفرستید تا هر کدام در بستهی خودش برود.
قاعدههای دامنه و فهرستهای ایران
یک مجموعه دامنه قاعدهها را از متن میخواند، یکی در هر سطر: example.com با همان دامنه و هر چه زیرش است میخواند، full:name فقط همان نام، keyword:word هر میزبانِ شامل آن واژه. یک دستهبند یک مجموعهی مسدود، یک مجموعهی پراکسی و یک مجموعهی مستقیم دارد و به ترتیب ثابت پاسخ میدهد: مسدود، سپس پراکسی، سپس مستقیم (مجموعهی مستقیم یا هر نشانی خصوصی)، سپس پیشفرضش. پس قاعدهای در مجموعهی پراکسی بر مجموعهی مستقیم برتری دارد و نشانی خصوصی مستقیم است مگر اینکه چیز دیگری بگویید.
ناپایا classifier := سانسورشکن.دستهبند جدید(سانسورشکن.تصمیم پراکسی)
classifier.مستقیم = سانسورشکن.مجموعه مستقیم ایران()
سرچاپ سانسورشکن.دستهبندی(classifier، "www.digikala.com") // مستقیم
سرچاپ سانسورشکن.دستهبندی(classifier، "mail.sharif.ir") // مستقیم
سرچاپ سانسورشکن.دستهبندی(classifier، "youtube.com") // پراکسی (پیشفرض)
فهرست مستقیم ایران دامنههای .ir و چند سایت بزرگ داخلی را دارد؛ فهرست فیلترشده سایتهایی که معمولا فیلترند. هر دو کوتاهاند و کهنه میشوند: آنها را در یک پرونده کپی کنید، ویرایش کنید و مال خودتان را با افزودن قاعدهها بار کنید. برای مسیریابی که با برچسب کار میکند، تونل تونل.مسیریاب ایران و تونل.تجزیه قاعدهها را دارد.
پنهان کردن کارساز از کاوش
کارسازی که کاوش میشود اتصالهایی میبیند که احراز هویت نمیشوند. پاسخ امن این است که مثل یک وبسرور معمولی دیده شود: اتصال را به یک سایت واقعی بسپارید (باید جایگزین شود برای هر چه احراز نشده باشد بله میگوید)، یا دستکم یک ۴۰۴ ساده بفرستید (پاسخ طعمه). نگهبان کاوش حافظه اضافه میکند: پس از بیشینه شکست شکست از یک نشانی در بازه شمارش، اجازه نگهبان به مدت مدت مسدودی نه میگوید. حافظه تکرار بایتهای نخست احراز هویتها را به یاد میسپارد تا دستدهی ضبطشدهای که دوباره فرستاده شود دیده شود (تکراری است). یک انتظار تصادفی کوچک (تاخیر تصادفی) پیش از پاسخ به کارخواه ناموفق نمیگذارد زمان مسیر شکست آن را لو بدهد.
اگر وارونه سانسورشکن.اجازه نگهبان(guard، client_ip، now):
close(connection)
وگرنه اگر وارونه authenticated:
سانسورشکن.ثبت شکست(guard، client_ip، now)
hand_to_real_website(connection)
پایان
کارساز تروجان کارخواههای ناموفق را از پیش به یک وبسایت واقعی میسپارد. این ابزارها لایهی اضافه برای کارسازهایی هستند که خودتان میسازید.
چه باید دانست
- هر تابع روی بایتها و متنی که میدهید کار میکند. هیچ چیز اینجا سوکتی باز نمیکند یا وضعیت سراسری نگه نمیدارد.
- تکهتکه کردن و لایهگذاری تدبیرهای جزئیاند، نه رمزنگاری؛ درون کانال رمزشده به کار ببرید و روی شبکهی خودتان آزمایششان کنید.
- فهرستهای ایران کوتاهاند و زود کهنه میشوند. مال خودتان را نگه دارید.
نگهبان کاوشوحافظه تکراردادهی سادهی بدون قفلاند و باید آزاد شوند (آزاد کردن نگهبان،آزاد کردن حافظه تکرار)؛ مجموعهها، تکهها و بافرهایی که میسازید هم (آزاد کردن مجموعه دامنه،آزاد کردن تکهها).- نشانیها متن IPv4 یا متن IPv6 هستند؛ ابزارها نام را حل نمیکنند.
- هیچ گزارشی خودکار نوشته نمیشود.
گونهها
مجموعه دامنه DomainSet
ساختار مجموعه دامنهمجموعه دامنه جدید ساخته و با افزودن قاعده یا افزودن قاعدهها پر میشود.| نام | انگلیسی | گونه | توضیح |
|---|---|---|---|
| پسوندها | suffixes | نگاشت<رشته، منطقی> | دامنههایی که با خودشان و هر چه زیرشان است میخوانند. |
| دامنههای کامل | fulls | نگاشت<رشته، منطقی> | نامهایی که باید دقیقا بخوانند. |
| کلیدواژهها | keywords | وکتور<رشته> | واژههایی که با هر میزبانِ شامل آنها میخوانند. |
| شمار | count | صحیح = 0 | چند قاعده اضافه شده است. |
// زبان: فارسی
واردسازی شبکه.سانسورشکن
تابع ریشه:
ناپایا set := سانسورشکن.مجموعه دامنه جدید()
سرچاپ سانسورشکن.افزودن قاعده(set، "example.com")، سانسورشکن.افزودن قاعده(set، "full:only.test.org")، سانسورشکن.افزودن قاعده(set، "keyword:torrent")
سرچاپ سانسورشکن.افزودن قاعده(set، "domain:*.cdn.net")، سانسورشکن.افزودن قاعده(set، "regexp:a.*")، سانسورشکن.افزودن قاعده(set، " ")
سرچاپ سانسورشکن.افزودن قاعدهها(set، "# a comment\nblocked.io # trailing\n\nfoo.bar\n")، set.شمار
سرچاپ سانسورشکن.تطبیق دامنه(set، "example.com")، سانسورشکن.تطبیق دامنه(set، "WWW.Example.COM.")، سانسورشکن.تطبیق دامنه(set، "badexample.com")
سرچاپ سانسورشکن.تطبیق دامنه(set، "only.test.org")، سانسورشکن.تطبیق دامنه(set، "x.only.test.org")، سانسورشکن.تطبیق دامنه(set، "my-torrent-site.xyz")
سرچاپ سانسورشکن.تطبیق دامنه(set، "a.b.cdn.net")، سانسورشکن.تطبیق دامنه(set، "x.blocked.io")، سانسورشکن.تطبیق دامنه(set، "net")
سرچاپ set.پسوندها.اندازه()، set.دامنههای کامل.اندازه()، set.کلیدواژهها.طول()
سانسورشکن.آزاد کردن مجموعه دامنه(set)
سرچاپ سانسورشکن.میزبان خصوصی("192.168.1.5")، سانسورشکن.میزبان خصوصی("172.20.0.1")، سانسورشکن.میزبان خصوصی("172.40.0.1")، سانسورشکن.میزبان خصوصی("localhost")، سانسورشکن.میزبان خصوصی("::1")، سانسورشکن.میزبان خصوصی("example.com")
ناپایا classifier := سانسورشکن.دستهبند جدید(سانسورشکن.تصمیم پراکسی)
classifier.مستقیم = سانسورشکن.مجموعه مستقیم ایران()
classifier.مسدود = سانسورشکن.مجموعه دامنه جدید()
سانسورشکن.افزودن قاعده(classifier.مسدود، "ads.example.org")
هر host در ["www.digikala.com"، "mail.sharif.ir"، "youtube.com"، "ads.example.org"، "192.168.1.5"، "172.40.0.1"]:
سرچاپ host، سانسورشکن.دستهبندی(classifier، host)
پایان
سرچاپ سانسورشکن.تصمیم پراکسی، سانسورشکن.تصمیم مستقیم، سانسورشکن.تصمیم مسدود
filtered := سانسورشکن.مجموعه فیلترشده()
سرچاپ سانسورشکن.تطبیق دامنه(filtered، "m.youtube.com")، سانسورشکن.تطبیق دامنه(filtered، "digikala.com")
سرچاپ سانسورشکن.فهرست مستقیم ایران().شروع با("#")، سانسورشکن.فهرست فیلترشده().دربردارد("youtube.com")
پایاندستهبند Classifier
ساختار دستهبنددستهبندی به ترتیب از آنها میپرسد و یک تصمیم برمیگرداند. با دستهبند جدید ساخته میشود و مجموعهها را پر کنید.| نام | انگلیسی | گونه | توضیح |
|---|---|---|---|
| مسدود | block | مجموعه دامنه | میزبانهایی که باید رد شوند. نخست بررسی میشود. |
| مستقیم | direct | مجموعه دامنه | میزبانهایی که باید مستقیم به آنها رسید. |
| پراکسی | proxy | مجموعه دامنه | میزبانهایی که باید از پراکسی بروند. دوم بررسی میشود، پس بر مستقیم و بر نشانیهای خصوصی برتری دارد. |
| تصمیم پیشفرض | default_decision | صحیح = 0 | با میزبانی که هیچچیز با آن نخواند چه کنیم. |
نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
پیام آغازین کارخواه ClientHello
ساختار پیام آغازین کارخواهتجزیه پیام آغازین از نخستین پیام TLS که یک کارخواه میفرستد میخواند: نام سرور، پروتکلهای پیشنهادی و چند واقعیت دربارهاش.| نام | انگلیسی | گونه | توضیح |
|---|---|---|---|
| معتبر | ok | منطقی = نادرست | درست وقتی بایتها یک ClientHello معتبرند (احتمالا بریده، ناقص را ببینید). |
| ناقص | truncated | منطقی = نادرست | درست وقتی بایتها پیش از پایان کل پیام تمام شدند. فیلدهای خواندهشده تا اینجا همچنان پر میشوند. |
| نسخه رکورد | record_version | صحیح = 0 | شمارهی نسخه در سرآیند رکورد TLS. |
| نسخه پیام | hello_version | صحیح = 0 | شمارهی نسخه در خود ClientHello. |
| طول رکورد | record_len | صحیح = 0 | طولی که سرآیند رکورد اعلام میکند. |
| نام سرور | sni | رشته = "" | نام سرور از افزونهی Server Name Indication، با حروف کوچک، یا خالی اگر نباشد. |
| جایگاه نام سرور | sni_offset | صحیح = -1 | نام سرور از کجای بایتها شروع میشود، یا ۱-. فیلتر همینجا را نگاه میکند و اندازه تکهها از روی نام سرور همینجا میبرد. |
| طول نام سرور | sni_len | صحیح = 0 | طول نام سرور. |
| پروتکلهای برنامه | alpn | وکتور<رشته> | پروتکلهای برنامهای که کارخواه پیشنهاد میکند، مثل h2 و http/1.1. |
| شمار رمزها | cipher_count | صحیح = 0 | چند مجموعهی رمز پیشنهاد شده است. |
| شمار افزونهها | ext_count | صحیح = 0 | پیام چند افزونه دارد. |
| دارای تی ال اس سیزده | has_tls13 | منطقی = نادرست | درست وقتی TLS 1.3 در افزونهی نسخههای پشتیبانیشده پیشنهاد شده است. |
| دارای ای سی اچ | has_ech | منطقی = نادرست | درست وقتی پیام افزونهی Encrypted Client Hello دارد که نام واقعی سرور را پنهان میکند. |
| طول شناسه نشست | session_id_len | صحیح = 0 | طول شناسهی نشستی که کارخواه فرستاد. کارخواههای TLS 1.3 ۳۲ بایت از آن میفرستند. |
// زبان: فارسی
واردسازی شبکه.سانسورشکن
پایا HELLO := "160301008c010000880303000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f206465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283000613011302c02b0100003900000014001200000f7777772e6578616d706c652e636f6d000a00040002001d0010000e000c02683208687474702f312e31002b0003020304"
تابع ریشه:
hello := سانسورشکن.از هگز(HELLO)
سرچاپ "hello bytes:"، hello.طول، سانسورشکن.به هگز(hello).طول()
سرچاپ سانسورشکن.نام نوع(سانسورشکن.تشخیص پروتکل(hello.داده، hello.طول))
سرچاپ سانسورشکن.نام نوع(سانسورشکن.تشخیص پروتکل("GET / HTTP/1.1" برگردان تهی*، 14))
سرچاپ سانسورشکن.نام نوع(سانسورشکن.تشخیص پروتکل("SSH-2.0-OpenSSH_9.6" برگردان تهی*، 19))
سرچاپ سانسورشکن.نام نوع(سانسورشکن.تشخیص پروتکل(سانسورشکن.از هگز("050100").داده، 3))
سرچاپ سانسورشکن.نام نوع(سانسورشکن.تشخیص پروتکل(سانسورشکن.از هگز("0401005000000001").داده، 8))
سرچاپ سانسورشکن.نام نوع(سانسورشکن.تشخیص پروتکل("GE" برگردان تهی*، 2))
سرچاپ سانسورشکن.نام نوع(سانسورشکن.تشخیص پروتکل("zzzz" برگردان تهی*، 4))
سرچاپ سانسورشکن.تشخیص پروتکل(hello.داده، hello.طول) برابر سانسورشکن.نوع تی ال اس، سانسورشکن.نوع ناشناخته، سانسورشکن.نوع اچ تی تی پی، سانسورشکن.نوع اس اس اچ، سانسورشکن.نوع ساکس۵، سانسورشکن.نوع ساکس۴، سانسورشکن.نوع داده ناکافی
ch := سانسورشکن.تجزیه پیام آغازین(hello.داده، hello.طول)
سرچاپ ch.معتبر، ch.ناقص، ch.طول رکورد
سرچاپ ch.نام سرور، ch.جایگاه نام سرور، ch.طول نام سرور
سرچاپ ch.نسخه رکورد، ch.نسخه پیام، ch.طول شناسه نشست، ch.شمار رمزها، ch.شمار افزونهها
سرچاپ ch.دارای تی ال اس سیزده، ch.دارای ای سی اچ، ch.پروتکلهای برنامه.طول()، ch.پروتکلهای برنامه.بگیر(0)، ch.پروتکلهای برنامه.بگیر(1)
سرچاپ سانسورشکن.استخراج نام سرور(hello.داده، hello.طول)
cut := سانسورشکن.تجزیه پیام آغازین(hello.داده، 60)
سرچاپ "cut short:"، cut.معتبر، cut.ناقص، cut.نام سرور.طول()
سرچاپ "not tls:"، سانسورشکن.تجزیه پیام آغازین("GET / HTTP/1.1" برگردان تهی*، 14).معتبر
پایاننگهبان کاوش ProbeGuard
ساختار نگهبان کاوشنگهبان کاوش جدید ساخته میشود. دادهی ساده است و قفل ندارد، پس فقط زیر قفل خودتان بین نخها شریکش کنید.| نام | انگلیسی | گونه | توضیح |
|---|---|---|---|
| بیشینه شکست | max_fails | صحیح = 5 | چند شکست در بازه باعث مسدودی میشود. |
| بازه شمارش | window_ms | صحیح۶۴ = 60000 | طول بازهی شمارش، به میلیثانیه. |
| مدت مسدودی | ban_ms | صحیح۶۴ = 600000 | مسدودی چند میلیثانیه میماند. |
| شکستها | fails | نگاشت<رشته، صحیح> | شمار شکست هر نشانی. |
| آغاز بازه | first_ms | نگاشت<رشته، صحیح۶۴> | بازهی جاری هر نشانی کی شروع شد. |
| زمان رفع مسدودی | banned_until | نگاشت<رشته، صحیح۶۴> | هر نشانی مسدودشده تا کی مسدود است. |
// زبان: فارسی
واردسازی شبکه.سانسورشکن
تابع ریشه:
ناپایا guard := سانسورشکن.نگهبان کاوش جدید(3، 1000 برگردان صحیح۶۴، 5000 برگردان صحیح۶۴)
سرچاپ guard.بیشینه شکست، guard.بازه شمارش، guard.مدت مسدودی
سرچاپ سانسورشکن.اجازه نگهبان(guard، "1.2.3.4"، 0 برگردان صحیح۶۴)
سرچاپ سانسورشکن.ثبت شکست(guard، "1.2.3.4"، 100 برگردان صحیح۶۴)، سانسورشکن.ثبت شکست(guard، "1.2.3.4"، 200 برگردان صحیح۶۴)، سانسورشکن.ثبت شکست(guard، "1.2.3.4"، 300 برگردان صحیح۶۴)
سرچاپ سانسورشکن.اجازه نگهبان(guard، "1.2.3.4"، 400 برگردان صحیح۶۴)، سانسورشکن.اجازه نگهبان(guard، "5.6.7.8"، 400 برگردان صحیح۶۴)، سانسورشکن.اجازه نگهبان(guard، "1.2.3.4"، 5400 برگردان صحیح۶۴)
سرچاپ سانسورشکن.ثبت شکست(guard، "9.9.9.9"، 0 برگردان صحیح۶۴)، سانسورشکن.ثبت شکست(guard، "9.9.9.9"، 2000 برگردان صحیح۶۴)، سانسورشکن.ثبت شکست(guard، "9.9.9.9"، 2100 برگردان صحیح۶۴)
سانسورشکن.ثبت شکست(guard، "7.7.7.7"، 0 برگردان صحیح۶۴)
سانسورشکن.ثبت شکست(guard، "7.7.7.7"، 10 برگردان صحیح۶۴)
سانسورشکن.ثبت موفقیت(guard، "7.7.7.7")
سرچاپ سانسورشکن.ثبت شکست(guard، "7.7.7.7"، 20 برگردان صحیح۶۴)، guard.شکستها.بگیر("7.7.7.7")
سانسورشکن.آزاد کردن نگهبان(guard)
ناپایا cache := سانسورشکن.حافظه تکرار جدید(1000 برگردان صحیح۶۴، 4)
سرچاپ cache.ماندگاری، cache.بیشینه ورودی
سرچاپ سانسورشکن.تکراری است(cache، "a"، 0 برگردان صحیح۶۴)، سانسورشکن.تکراری است(cache، "a"، 500 برگردان صحیح۶۴)، سانسورشکن.تکراری است(cache، "a"، 1600 برگردان صحیح۶۴)
سرچاپ cache.دیدهشده.اندازه()
سانسورشکن.آزاد کردن حافظه تکرار(cache)
سرچاپ سانسورشکن.باید جایگزین شود(نادرست)، سانسورشکن.باید جایگزین شود(درست)
wait := سانسورشکن.تاخیر تصادفی(5، 20)
سرچاپ wait بزرگتربرابر 5، wait کوچکتربرابر 20
سرچاپ سانسورشکن.پاسخ طعمه().زیررشته(0، 22)
سرچاپ سانسورشکن.پاسخ طعمه().دربردارد("nginx")
پایانحافظه تکرار ReplayCache
ساختار حافظه تکرارحافظه تکرار جدید ساخته میشود. دادهی ساده است و قفل ندارد.| نام | انگلیسی | گونه | توضیح |
|---|---|---|---|
| ماندگاری | ttl_ms | صحیح۶۴ = 120000 | یک کلید چند میلیثانیه به یاد میماند. پیشفرض ۱۲۰۰۰۰. |
| بیشینه ورودی | max_entries | صحیح = 4096 | اندازهای که در آن کلیدهای منقضی پاک میشوند. پیشفرض ۴۰۹۶. |
| دیدهشده | seen | نگاشت<رشته، صحیح۶۴> | کلیدها و زمانی که هر یک آخرین بار دیده شد. |
نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam
پایاها و متغیرها
تصمیمها Decision…
دستهبندی برمیگرداند.| نام | انگلیسی | مقدار |
|---|---|---|
| تصمیم پراکسی | DecisionProxy | 0 |
| تصمیم مستقیم | DecisionDirect | 1 |
| تصمیم مسدود | DecisionBlock | 2 |
نوعهای پروتکل Kind…
تشخیص پروتکل برمیگرداند.| نام | انگلیسی | مقدار |
|---|---|---|
| نوع ناشناخته | KindUnknown | 0 |
| نوع تی ال اس | KindTLS | 1 |
| نوع اچ تی تی پی | KindHTTP | 2 |
| نوع اس اس اچ | KindSSH | 3 |
| نوع ساکس۵ | KindSOCKS5 | 4 |
| نوع ساکس۴ | KindSOCKS4 | 5 |
| نوع داده ناکافی | KindTooShort | 6 |
سیاستهای تقسیم Split…
اندازه تکهها.| نام | انگلیسی | مقدار |
|---|---|---|
| تقسیم مساوی | SplitEven | 0 |
| تقسیم تصادفی | SplitRandom | 1 |
| تقسیم پس از نخستین تکه | SplitFirst | 2 |
بیشینه داده رکورد MaxRecordPayload
پایا بیشینه داده رکورد: صحیح۳۲ = 16000پوشاندن جریان در یک رکورد میگذارد: ۱۶۰۰۰ بایت.// زبان: فارسی
واردسازی فشرده سازی
واردسازی شبکه.سانسورشکن
پایا HELLO := "160301008c010000880303000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f206465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283000613011302c02b0100003900000014001200000f7777772e6578616d706c652e636f6d000a00040002001d0010000e000c02683208687474702f312e31002b0003020304"
تابع total(v: وکتور<صحیح>): صحیح:
ناپایا sum := 0
تکرار v.طول() در i:
sum += v.بگیر(i)
پایان
برگشت sum
پایان
تابع ریشه:
hello := سانسورشکن.از هگز(HELLO)
even := سانسورشکن.اندازه تکهها(100، سانسورشکن.تقسیم مساوی، 3، 0، 1 برگردان صحیح۶۴)
سرچاپ even.بگیر(0)، even.بگیر(1)، even.بگیر(2)، total(even)
random := سانسورشکن.اندازه تکهها(1000، سانسورشکن.تقسیم تصادفی، 5، 0، 42 برگردان صحیح۶۴)
again := سانسورشکن.اندازه تکهها(1000، سانسورشکن.تقسیم تصادفی، 5، 0، 42 برگردان صحیح۶۴)
سرچاپ random.طول()، total(random)، random.بگیر(0) برابر again.بگیر(0)، random.بگیر(4) برابر again.بگیر(4)
first := سانسورشکن.اندازه تکهها(517، سانسورشکن.تقسیم پس از نخستین تکه، 2، 5، 0 برگردان صحیح۶۴)
سرچاپ first.بگیر(0)، first.بگیر(1)
سرچاپ سانسورشکن.اندازه تکهها(3، سانسورشکن.تقسیم مساوی، 10، 0، 0 برگردان صحیح۶۴).طول()
cuts := سانسورشکن.اندازه تکهها از روی نام سرور(hello.داده، hello.طول، نادرست)
سرچاپ cuts.بگیر(0)، cuts.بگیر(1)، total(cuts)
lone := سانسورشکن.اندازه تکهها از روی نام سرور(hello.داده، hello.طول، درست)
سرچاپ lone.طول()، lone.بگیر(0)، lone.بگیر(1)، total(lone)
ناپایا pieces := سانسورشکن.برش(hello.داده، hello.طول، cuts)
سرچاپ pieces.طول()، فشرده سازی.برابری بافر(سانسورشکن.پیوست(pieces)، hello)
سانسورشکن.آزاد کردن تکهها(pieces)
ناپایا records := سانسورشکن.تکهتکه کردن پیام آغازین(hello.داده، hello.طول، 4، سانسورشکن.تقسیم مساوی، 0 برگردان صحیح۶۴)
سرچاپ records.طول()
head := records.بگیر(0)
سرچاپ head.طول، فشرده سازی.دریافت بایت(head، 0)، فشرده سازی.دریافت بایت(head، 1)، فشرده سازی.دریافت بایت(head، 2)
all := سانسورشکن.پیوست(records)
سرچاپ all.طول، all.طول برابر hello.طول + 15
سرچاپ سانسورشکن.تجزیه پیام آغازین(all.داده، all.طول).معتبر، سانسورشکن.تجزیه پیام آغازین(head.داده، head.طول).ناقص
سانسورشکن.آزاد کردن تکهها(records)
ناپایا by_hand := سانسورشکن.تکهتکه کردن رکوردها(hello.داده، hello.طول، cuts)
سرچاپ by_hand.طول()، by_hand.بگیر(0).طول، by_hand.بگیر(1).طول
سانسورشکن.آزاد کردن تکهها(by_hand)
سرچاپ "not a handshake:"، سانسورشکن.تکهتکه کردن پیام آغازین("GET / HTTP/1.1" برگردان تهی*، 14، 3، سانسورشکن.تقسیم مساوی، 0 برگردان صحیح۶۴).طول()
سرچاپ سانسورشکن.بیشینه داده رکورد
پایانتابعها
مجموعه دامنه جدید NewDomainSet
تابع مجموعه دامنه جدید(): مجموعه دامنهنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
افزودن قاعده AddRule
تابع افزودن قاعده(s &: مجموعه دامنه، rule: رشته): منطقیexample.com یا domain:example.com (آن دامنه و همهی زیرش)، full:name (دقیقا همان نام) یا keyword:word. *. در ابتدا مجاز است. برای سطر خالی یا نوعی که پشتیبانی نمیشود، مثل regexp:، نادرست.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
افزودن قاعدهها AddRules
تابع افزودن قاعدهها(s &: مجموعه دامنه، text: رشته): صحیح#، حتی پس از یک قاعده، رد میشوند. برمیگرداند چند قاعده اضافه شد.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
تطبیق دامنه MatchDomain
تابع تطبیق دامنه(s: مجموعه دامنه، host: رشته): منطقیbadexample.com با قاعدهی example.com نمیخواند.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
آزاد کردن مجموعه دامنه FreeDomainSet
تابع آزاد کردن مجموعه دامنه(s &: مجموعه دامنه)نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
میزبان خصوصی IsPrivateHost
تابع میزبان خصوصی(host: رشته): منطقیlocalhost و نشانیهای خصوصی، loopback و پیوند محلی: 127/8، 10/8، 172.16/12، 192.168/16، 169.254/16، ::1 و بازههای خصوصی و پیوند محلی IPv6.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
دستهبند جدید NewClassifier
تابع دستهبند جدید(default_decision: صحیح): دستهبندنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
دستهبندی Classify
تابع دستهبندی(c: دستهبند، host: رشته): صحیحنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
فهرست مستقیم ایران IranDirectList
تابع فهرست مستقیم ایران(): رشته.ir و چند سرویس شناختهشده. نقطهی شروع است و باید ویرایش شود.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
فهرست فیلترشده FilteredList
تابع فهرست فیلترشده(): رشتهنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
مجموعه مستقیم ایران IranDirectSet
تابع مجموعه مستقیم ایران(): مجموعه دامنهفهرست مستقیم ایران که در یک مجموعه دامنه بار شده است.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
مجموعه فیلترشده FilteredSet
تابع مجموعه فیلترشده(): مجموعه دامنهفهرست فیلترشده که در یک مجموعه دامنه بار شده است.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Domains.salam
تشخیص پروتکل Sniff
تابع تشخیص پروتکل(p: تهی*، n: صحیح): صحیحKind. فقط چند بایت لازم دارد و وقتی کافی نیستند نوع داده ناکافی میگوید.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Sniff.salam
نام نوع KindName
تابع نام نوع(k: صحیح): رشتهKind برمیگرداند: tls، http، ssh، socks5، socks4، short یا unknown.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Sniff.salam
تجزیه پیام آغازین ParseClientHello
تابع تجزیه پیام آغازین(p: تهی*، n: صحیح): پیام آغازین کارخواهناقص میدهند؛ هر چه ClientHello نباشد معتبر را نادرست میکند.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Sniff.salam
استخراج نام سرور ExtractSNI
تابع استخراج نام سرور(p: تهی*، n: صحیح): رشتهنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Sniff.salam
از هگز FromHex
تابع از هگز(text: رشته): فشرده سازی.بافر بایتنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Sniff.salam
به هگز ToHex
تابع به هگز(b: فشرده سازی.بافر بایت): رشتهنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Sniff.salam
عدد تصادفی RandomInt
تابع عدد تصادفی(lo: صحیح، hi: صحیح): صحیح// زبان: فارسی
واردسازی فشرده سازی
واردسازی شبکه.سانسورشکن
تابع ریشه:
body := "secret payload"
wrapped := سانسورشکن.پوشاندن رکورد(body برگردان تهی*، body.طول()، 20)
سرچاپ wrapped.طول، فشرده سازی.دریافت بایت(wrapped، 0)، فشرده سازی.دریافت بایت(wrapped، 1)، فشرده سازی.دریافت بایت(wrapped، 2)
ناپایا got := فشرده سازی.بافر بایت جدید()
سرچاپ سانسورشکن.گشودن رکورد(wrapped.داده، wrapped.طول، got)، got.طول
سرچاپ "needs more:"، سانسورشکن.گشودن رکورد(wrapped.داده، wrapped.طول - 1، got)
سرچاپ "not a record:"، سانسورشکن.گشودن رکورد("GET / HTTP/1.1" برگردان تهی*، 14، got)
سرچاپ "too big:"، سانسورشکن.پوشاندن رکورد(body برگردان تهی*، 20000، 0).طول
ناپایا big := فشرده سازی.بافر بایت جدید()
تکرار 40000 در i:
فشرده سازی.افزودن بایت(big، i % 251)
پایان
stream := سانسورشکن.پوشاندن جریان(big.داده، big.طول، 5، 50)
ناپایا back := فشرده سازی.بافر بایت جدید()
ناپایا offset := 0
ناپایا records := 0
تا offset کوچکتر stream.طول:
used := سانسورشکن.گشودن رکورد(((stream.داده برگردان صحیح۶۴) + (offset برگردان صحیح۶۴)) برگردان تهی*، stream.طول - offset، back)
اگر used کوچکتربرابر 0:
بشکن
پایان
offset += used
records++
پایان
سرچاپ records، فشرده سازی.برابری بافر(back، big)، offset برابر stream.طول
سرچاپ سانسورشکن.طول لایه(100، 10، 10، 64)
سرچاپ سانسورشکن.طول لایه(100، 0، 0، 1)
سرچاپ سانسورشکن.بایتهای تصادفی(32).طول، سانسورشکن.عدد تصادفی(5، 5)
r := سانسورشکن.عدد تصادفی(10، 20)
سرچاپ r بزرگتربرابر 10، r کوچکتربرابر 20
پایانبایتهای تصادفی RandomBytes
تابع بایتهای تصادفی(n: صحیح): فشرده سازی.بافر بایتنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Padding.salam
طول لایه PadLength
تابع طول لایه(payload_len: صحیح، min_pad: صحیح، max_pad: صحیح، block: صحیح): صحیحنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Padding.salam
پوشاندن رکورد WrapRecord
تابع پوشاندن رکورد(p: تهی*، n: صحیح، pad: صحیح): فشرده سازی.بافر بایتنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Padding.salam
گشودن رکورد UnwrapRecord
تابع گشودن رکورد(p: تهی*، n: صحیح، payload &: فشرده سازی.بافر بایت): صحیحپوشاندن رکورد را میخواند: بایتهای واقعیاش را در یک بافر میگذارد و برمیگرداند رکورد چند بایت گرفت، ۰ وقتی بایت بیشتری لازم است و ۱- وقتی رکورد معتبر نیست.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Padding.salam
پوشاندن جریان WrapStream
تابع پوشاندن جریان(p: تهی*، n: صحیح، min_pad: صحیح، max_pad: صحیح): فشرده سازی.بافر بایتپوشاندن رکورد تا بیشینه داده رکورد بایت میپیچد که هر یک لایهی تصادفی بین دو حد دارد. اندازهها را پنهان میکند، نه محتوا را: رمزنگاری نیست.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Padding.salam
اندازه تکهها SplitSizes
تابع اندازه تکهها(total: صحیح، policy: صحیح، pieces: صحیح، param: صحیح، seed: صحیح۶۴): وکتور<صحیح>تقسیم مساوی، تقسیم تصادفی یا تقسیم پس از نخستین تکه است؛ pieces شمار تکهها، param اندازهی تکهی نخست برای تقسیم پس از نخستین تکه و seed سیاست تصادفی را تکرارپذیر میکند. اندازهها همیشه جمعشان برابر کل است.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Fragment.salam
اندازه تکهها از روی نام سرور SNISplitSizes
تابع اندازه تکهها از روی نام سرور(p: تهی*، n: صحیح، head_first: منطقی): وکتور<صحیح>نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Fragment.salam
برش Slice
تابع برش(p: تهی*، n: صحیح، sizes: وکتور<صحیح>): وکتور<فشرده سازی.بافر بایت>نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Fragment.salam
تکهتکه کردن رکوردها FragmentRecords
تابع تکهتکه کردن رکوردها(p: تهی*، n: صحیح، sizes: وکتور<صحیح>): وکتور<فشرده سازی.بافر بایت>نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Fragment.salam
تکهتکه کردن پیام آغازین FragmentClientHello
تابع تکهتکه کردن پیام آغازین(p: تهی*، n: صحیح، pieces: صحیح، policy: صحیح، seed: صحیح۶۴): وکتور<فشرده سازی.بافر بایت>نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Fragment.salam
پیوست Concat
تابع پیوست(pieces: وکتور<فشرده سازی.بافر بایت>): فشرده سازی.بافر بایتنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Fragment.salam
آزاد کردن تکهها FreePieces
تابع آزاد کردن تکهها(pieces &: وکتور<فشرده سازی.بافر بایت>)نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Fragment.salam
نگهبان کاوش جدید NewProbeGuard
تابع نگهبان کاوش جدید(max_fails: صحیح، window_ms: صحیح۶۴، ban_ms: صحیح۶۴): نگهبان کاوشنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam
اجازه نگهبان GuardAllowed
تابع اجازه نگهبان(g: نگهبان کاوش، ip: رشته، now_ms: صحیح۶۴): منطقینمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam
ثبت شکست GuardRecordFail
تابع ثبت شکست(g &: نگهبان کاوش، ip: رشته، now_ms: صحیح۶۴): منطقینمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam
ثبت موفقیت GuardRecordOK
تابع ثبت موفقیت(g &: نگهبان کاوش، ip: رشته)نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam
آزاد کردن نگهبان FreeProbeGuard
تابع آزاد کردن نگهبان(g &: نگهبان کاوش)نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam
حافظه تکرار جدید NewReplayCache
تابع حافظه تکرار جدید(ttl_ms: صحیح۶۴، max_entries: صحیح): حافظه تکرارنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam
تکراری است ReplaySeen
تابع تکراری است(c &: حافظه تکرار، key: رشته، now_ms: صحیح۶۴): منطقینمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam
آزاد کردن حافظه تکرار FreeReplayCache
تابع آزاد کردن حافظه تکرار(c &: حافظه تکرار)نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam
باید جایگزین شود ShouldFallback
تابع باید جایگزین شود(authenticated: منطقی): منطقینمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam
تاخیر تصادفی DelayMs
تابع تاخیر تصادفی(min_ms: صحیح، max_ms: صحیح): صحیحنمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam
پاسخ طعمه DecoyResponse
تابع پاسخ طعمه(): رشته404 Not Found یک وبسرور رایج است، برای کارسازی که سایت واقعی برای نشان دادن ندارد.نمونهی این مورد همراه با موارد بالاتر آمده است: net-censor-Probe.salam