radkesvat / ReverseTlsTunnel

Reverse Tcp Tunnel with custom sni handshake, mux support and more...
MIT License
473 stars 98 forks source link

راه حل موقت برای رفع مشکل کندی و پر شدن رم و سی پی یو #173

Open AkramiPro opened 9 months ago

AkramiPro commented 9 months ago

سلام دوستان کسانی که تعداد کاربر خیلی بالایی دارن احتمالا به مشکل بخورن توی هندل کردن درخواست ها البته طبق تست هایی که داشتم این داستان زیاد ربطی به RTT نداره . هرچند شاید بشه تا بهینه کردن کد ها و اضافه شدن Multithreading به RTT این مشکل رو حل کرد ولی بازم من مطمئن هستم که به مشکل میخوره بزارید کامل براتون توضیح بدم که متوجه بشید چرا بازم به مشکل میخوره


با توجه به اینکه بنده دانش فنی و تسلط کافی در بحث لینوکس و شبکه رو ندارم ممکن هست بعضی از گفته های بنده اشتباه باشه که پیشاپیش از شما معذرت میخوام و از اساتید محترم میخوام که بنده رو اصلاح کنن و مشکلات رو بگید که ویرایش کنم


اگر حوصله ندارید و کلا براتون مهم نیست که درک کنید مشکل چیه و چطوری حل میشه مقدمه رو نخونید .مستقیم برید راه حل رو بخونید


تمامی کد های زیر رو باید در سرور ایران اجرا کنید . البته بخش بهینه سازی رو میتونید در سرور خارج هم اجرا کنید


مقدمه و درک مشکل

من خودم از sing-box استفاده میکنم . حالت Multithreading همین الان هم داخل ساین باکس هست یعنی شما 1 بار ساین باکس رو اجرا میکنی ولی اون خودش میاد چندین پراسس دیگه که میشه child process رو اجرا میکنه چرا این کار رو میکنه ؟ برای اینکه بتونه بهتر مدیریت کنه درخواست ها رو و درخواست های ورودی رو بین چندین پراسس پخش میکنه تا هندل بشن و مثلا اگر شما 2 تا هسته داری از توان هر 2 هسته cpu شما استفاده بشه حالا چرا برنامه ها از حالت Multithreading پشتیبانی نمیکنن ؟ چون پیاده سازی همچین چیزی به این راحتی ها نیست و مدیریت کردن انجام شدن درخواست ها به صورت موازی یکم پیچیده هست که از دانش من هم خارج هست صرفا طبق چیز هایی که مطالعه کردم میدونم که سخت هست خب گفتیم که ساین باکس برای هندل کردن درخواست ها از چندین ترد که ایجاد کرده استفاده میکنه ولی بازم وقتی تعداد درخواست بالا میره به مشکل میخوره ساین باکس و نمیتونه مدیریت کنه اینکه چرا اینطوری میشه رو من دقیق نمیدونم شاید به خاطر این باشه که سیستم عامل بهش اجازه نمیده و یا محدودیت های نرم افزاری باشه یا چیز های دیگه در هر صورت من این راه حل به ذهنم رسید که بیام و به جای 1 ساین باکس چندین ساین باکس اجرا کنم و درخواست ها رو بین اینا پخش کنم حالا شما فرض کن خود ساین باکس هم ترد داره و اینطوری شما یه لود بالانس دستی درست کردی که یه تعداد زیادی ترد اماده هستن به درخواست های شما جواب بدن :) اینم بگم که این روش به این خاطر به ذهن من رسید که دیدم درصد استفاده از منابع سرور اصلا بالا نرفتن ولی وقتی درخواست ها زیاد میشه ساین باکس دیگه جواب نمیده . اینجا خب فکر کردم شاید محدودیت نرم افزاری باشه و اگر چند تا ساین باکس اجرا کنیم مشکل حل بشه که همین طور هم شد سرور من 8 گیگ رم و 2 تا هسته فرکانس 5.7 داره که به این راحتی پر نمیشه ولی جالب بود که با این همه منابع بازم ساین باکس به مشکل میخورد این نشون میده که کد هاش یا بهینه نیست یا درست نمیتونه از منابع سیستم استفاده کنه حالا شاید بگید چطوری فهمیدم که مشکل از RTT نیست و از ساین باکس هست ؟ من اومدم یک socks داخل ساین باکس تعریف کردم روی پورت مثلا 1080 روی 127 تا تست کنم اصلا ساین باکس میتونه به درخواست های داخلی جواب بده یا نه . چ برسه به درخواست هایی که از سرور ایران براش میاد

image بعدش کد زیر رو برای تست اجرا کردم

curl --socks5-hostname 127.0.0.1:1080 http://ip-api.com/

که خب تایم اوت میخورد این یعنی ساین باکس اصلا توان هندل یه درخواست داخلی هم نداشت و مشکل از RTT نیست پس بهترین کار این هست که چند تا ساین باکس اجرا کنیم و یه طوری حل کنیم این مشکل رو حالا این راه حل رو میشه برای بقیه برنامه ها هم زد . مثل RTT یا هر چیز دیگه

image

برای درک بهتر به عکس بالا دقت کنید که . بخش سفید رنگ ساین باکس هست که ران شده و اون سبز ها ترد هاش هستن حالا عکس زیر رو دقت کنید

image

این عکس هم مربوط به RTT هست که همین طور که مشاهده میکنید چون هنوز از ترد پشتیبانی نمیکنه هیچ تردی نداره و خودش همه درخواست ها رو با استفاده از 1 هسته cpu هندل میکنه . یعنی ممکن هست شما 4 تا هسته داشته باشی ولی RTT فقط از 1 هسته cpu شما استفاده میکنه اینطوری همه فشار روی 1 هسته هست و از تمام توان cpu شما استفاده نمیشه حالا فرض کنیم که RTT اپدیت بده و مثل ساین باکس ترد بهش اضافه بشه . به احتمال زیاد مشکل به صورت موقت حل میشه ولی امکان داره اون مشکل که برای ساین باکس گفتم برای RTT هم پیش بیاد یعنی حتی با وجود ترد امکان داره که درخواست ها بازم در ابعاد بالا به مشکل بخورن پس این راه حل که میگم میتونه یه راه حل خوبی باشه که شما بتونی تعداد کاربر بالا رو با این روش هندل کنید و کاربران هم به مشکل نخورن


راه حل

خب بریم سراغ راه حل . چیزی که من به ذهنم اومد این بود که RTT رو چندین بار اجرا کنیم تا اینطوری خودمون دستی حالت ترد رو پیاده سازی کرده باشیم ولی خب یه مشکلی که پیش میاد این هست که چندین برنامه نمیتونن به صورت هم زمان از یک پورت مثلا 443 استفاده کنن یعنی فرض کن شما توی سرور ایران به RTT گفتی که به 443 لسن کنه وقتی بخوای 4 تا RTT اجرا کنی دیگه نمیشه هر 4 تا از 443 لسن کنن و هر RTT باید از یک پورت جدا لسن کنه که اینجا برای حل این مشکل از haprpxy استفاده میکنیم . این haproxy یه برنامه قوی برای درست کردن لود بالانس هست . حالا این یعنی چی ؟ شما فرض کن من میخوام RTT رو 4 بار اجرا کنم . میام این 4 تا رو روی پورت های مختلف اجرا میکنم . مثلا پورت های زیر : 1010 2020 3030 4040 بعدش به haproxy میگم تو روی 443 لسن کن و هر درخواستی که به 443 اومده بین این 4 تا RTT پخش کن . به همین سادگی ! خب شاید بگید که الان مشکل RTT و ساین باکس برای haproxy چرا پیش نمیاد ؟ یعنی ممکن هست این وسط haproxy هم هنگ کنه و نتونه درخواست ها رو هندل کنه ولی خب اینطوری نیست چون haproxy یه برنامه قدیمی هست که اصلا کارش مدیریت کردن تعداد درخواست بالا هست و ساخته شده برای اینکار و طوری طراحی شده که کم نمیاره


بهینه سازی سرور

قبل از اینکه شروع کنیم چند تا کد زیر رو اجرا کنید که بتونید از تمامی توان نرم افزاری و سخت افزاری سرور استفاده کنید چون پیشفرض خیلی از چیز ها محدود هست . اگر نیاز بود بگید توضیح بدم که کد های زیر دقیقا چیکار میکنن ولی یه توضیح کوچیک زیر هر کدوم میدم .

این کد برای این هست که به سیستم بگیم اگر حجم log ها بیشتر از 10 مگ شد لاگ ها رو پاک کنه . اینطوری دیگه فضای سرور اگر مشکلی پیش بیاد پر نمیشه به خاطر لاگ

sudo sed -i 's/#SystemMaxUse=/SystemMaxUse=10M/' /etc/systemd/journald.conf && sudo systemctl restart systemd-journald

این کد هم برای بهینه کردن شبکه TCP هست . دقت کنید که من در 2 خط اخر ipv6 رو کلا غیر فعال کردم اگر به ipv6 نیاز دارید 2 خط اخر رو حذف کنید

sudo echo '
fs.file-max = 1048576
fs.inotify.max_user_instances = 1048576
net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.core.netdev_max_backlog=2000
net.ipv4.tcp_rmem = 8192 262144 536870912
net.ipv4.tcp_wmem = 4096 16384 536870912
net.ipv4.tcp_adv_win_scale = -2
net.ipv4.tcp_collapse_max_bytes = 6291456
# forward ipv4
net.ipv4.ip_forward = 1
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_keepalive_time = 90
net.ipv4.tcp_congestion_control=bbr
net.core.default_qdisc=cake
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
' > /etc/sysctl.conf

اینجا به سرور میگیم که کلا هیچ محدودیت برای nofile و nproc قرار نده و از حداکثر توان سرور استفاده کنه

sudo mkdir /etc/systemd/system.conf.d
sudo echo '[Manager]
DefaultLimitNOFILE=infinity' > /etc/systemd/system.conf.d/99-unlimited.conf
sudo echo 'session required pam_limits.so' >> /etc/pam.d/common-session
sudo echo 'session required pam_limits.so' >> /etc/pam.d/common-session-noninteractive
sudo echo '*       hard    nofile  unlimited
*       soft    nofile  unlimited
*       hard    nproc   unlimited
*       soft    nproc   unlimited
root       hard    nofile  unlimited
root       soft    nofile  unlimited
root       hard    nproc   unlimited
root       soft    nproc   unlimited' > /etc/security/limits.conf
sudo echo '*       hard    nofile  unlimited
*       soft    nofile  unlimited
*       hard    nproc   unlimited
*       soft    nproc   unlimited
root       hard    nofile  unlimited
root       soft    nofile  unlimited
root       hard    nproc   unlimited
root       soft    nproc   unlimited' > /etc/security/limits.d/99-unlimited.conf

برای اینکه کد های بالا اعمال بشن باید یه بار سیستم رو ریبوت کنید

reboot

بعد از اینکه سیستم ریبوت شد اگر درست انجام داده باشید با زدن دستور زیر باید یه عدد بزرگ مثل 1048576 رو نشون بده . اگر 1024 نشون داد یعنی یه جا اشتباه کردید و از اول انجام بدید دوباره .

ulimit -n

پیاده سازی haproxy

دستور نصب haproxy

sudo apt install --no-install-recommends software-properties-common -y
sudo add-apt-repository ppa:vbernat/haproxy-2.8 -y
sudo apt update
sudo apt install haproxy -y

اینم کانفیگ haproxy هست که بهش گفتیم به 443 گوش بده و درخواست ها رو بین 4 تا RTT که روی پورت های 1010 تا 4040 تنظیم شدن تقسیم کن . در ادامه بیشتر توضیح میدم

echo '
global
    nbthread    2
    cpu-map     1-2 0-1
    maxconn     500000
    tune.bufsize 49152
    daemon

defaults
    mode    http
    option  tcp-check
    option  redispatch
    option  dontlognull
    option  abortonclose
    option  http-keep-alive
    option  http-pretend-keepalive
    timeout connect 5000
    timeout client  50000
    timeout server  50000

    retry-on all-retryable-errors

listen RTT-Threads
    bind 0.0.0.0:443
    balance   static-rr
    server    s1 127.0.0.1:1010 check inter 2s
    server    s2 127.0.0.1:2020 check inter 2s
    server    s3 127.0.0.1:3030 check inter 2s
    server    s4 127.0.0.1:4040 check inter 2s
' > /etc/haproxy/haproxy.cfg

اینجا هم سروسی haproxy رو ران میکنیم و تنظیم میکنیم که با ری استارت شدن سرور خودکار اجرا میشه

systemctl enable haproxy
systemctl restart haproxy

کد بالا چند تا پارامتر مهم داره .

پارامتر nbthread تعداد ترد هایی هست که haproxy ایجاد میکنه تا بتونه درخواست ها رو جواب بده . بهتر هست مقدارش با تعداد هسته cpu هایی که دارید یکسان باشه . مثلا اگر 2 هسته دارید این هم 2 قرار بدید

پارامتر cpu-map هم مشخص میکنه هر ترد به کدوم هسته از cpu متصل بشه در پارامتر قبلی چون 2 تا ترد تنظیم کردیم پس 2 تا مپ هم میکنیم یعنی میگیم ترد 1 رو به هسته 0 متصل کن و ترد 2 رو به هسته 1 . سیستم عامل هسته ها رو از 0 شروع میکنه

پارامتر maxconn خیلی مهم هست . این رو بر اساس توان شبکه و سرور خودتون کم و زیاد کنید . من قرار دادم که به 500 هزار درخواست بتونه جواب بده . که تعداد خیلی بالایی هست. شما میتونید این مقدار رو کم یا زیاد کنید ولی پیشنهاد میکنیم همون 500 بزارید باشه . شاید بگید اگر از 500 هزار تا بیشتر شد چیکار میکنه ؟ سادش میشه اینکه میاد درخواست ها رو داخل pool قرار میده یعنی یه delay ایجاد میشه تا وقتی که درخواست های قبلی انجام بشن و فضا برای انجام درخواست های جدید باز بشه . یه حالت صف تشکیل میده

یه بخش bind هم داره که گفیتم به پورت 443 گوش بده و در خط های بعدی هم اومدیم RTT ها رو اضافه کردیم که من 4 تا اضافه کردم شما میتونید بیشتر اضافه کنید

نکته جالب اینکه میتونید بهش بگید درخواست ها رو فقط به RTT هایی ارسال کنه که up هستن یعنی اگر یک RTT به هر دلیلی براش مشکل پیش بیاد درخواست رو به RTT های دیگه ارسال میکنه . دقت کنید یه 2s زدم یعنی هر 2 ثانیه چک کنید این RTT کار میکنه یا نه اگر کار نکنه برای یه مدت از لیست حذفش میکنه و درخواست رو به RTT های دیگه ارسال میکنه خوبی این مورد برای وقتی هست که شما RTT ها رو ری استارت کردید و برای چند لحظه کوچیک درخواست ها drop میشن و کاربر لگ میخوره ولی با این قابلیت تا حد زیادی این لگ رفع میشه به این نکته هم دقت کنید که در ادامه ما تنظیم میکنیم که سرویس RTT هر یه مدت ری استارت بشه تا مشکل رم که پرم میشه حل بشه حالا اینجا یه مشکل پیش میاد . اگر ما هر 4 تا RTT رو هم زمان ری استارت کنیم پس 4 تا RTT که تنظیم کردیم down میشن و درخواست ها drop میشن برای چند لحظه پس باید هر RTT رو با یک فاصله زمانی متفاوت ری استارت کنید تا همیشه حداقل یک RTT وجود داشته باشه که به درخواست ها جواب بده اگر یک RTT ری استارت بشه خود haproxy میاد کاربران قدیمی رو به RTT بعدی منتقل میکنه . خیلی زیباست مگه نه ؟


تنظیم RTT ها

خب الان وقت این هست که RTT ها رو هم تنظیم کنیم که مثلا 4 تا RTT اجرا کنیم روی پورت های مختلف . برای اینکار اول از همه برید اگر از قبل RTT رو به صورت سرویس اجرا کردید خاموش کنید و سرویس رو disable کنید تا تداخل ایجاد نشه و پورت 443 رو اشغال نکنه حالا کد زیر رو که مخصوص اجرای 4 تا RTT هست اجرا کنید . متناسب با نیاز خودتون میتونید تعداد بیشتری از RTT اجرا کنید کافی هست پورت رو تغییر بدید و RTT جدید رو هم به haproxy اضافه کنید

یادتون نره که مقدار sni , password رو متناسب با نیاز خودتون تغییر بدید !

در کد های زیر در داخل سرویس من از پارامتر RuntimeMaxSec برای ری استارت خودکار RTT استفاده کردم که باید به ثانیه بهش مقدار بدید و مشخص میکنه سرویس بعد از چند ثانیه ری استارت بشه . و من 3600 رو دادم یعنی 1 ساعت ولی برای سرویس بعدی 100 ثانیه بهش اضافه کردم همون طور که توضیح دادم باید برای ری استارت یه فاصله ایجاد کنید که همه RTT ها با هم ری استارت نشن پس من هر سرویس رو تنظیم کردم که با فاصله 100 ثانیه ری استارت بشه .

RTT 1

echo '[Unit]
Description=RTT 1 Service
After=network.target
Wants=network.target

[Service]
Type=simple
ExecStart=/root/RTT --iran --keep-ufw --keep-os-limit --log:0 --listen:127.0.0.1 --lport:1010 --mux-width:1 --sni:github.com --password:1234
Restart=always
RestartSec=3s
RuntimeMaxSec=3600
LimitNOFILE=infinity
StandardOutput=null
StandardError=null

[Install]
WantedBy=multi-user.target' > /etc/systemd/system/rtt.1.service

RTT 2

echo '[Unit]
Description=RTT 2 Service
After=network.target
Wants=network.target

[Service]
Type=simple
ExecStart=/root/RTT --iran --keep-ufw --keep-os-limit --log:0 --listen:127.0.0.1 --lport:2020 --mux-width:1 --sni:github.com --password:1234
Restart=always
RestartSec=3s
RuntimeMaxSec=3700
LimitNOFILE=infinity
StandardOutput=null
StandardError=null

[Install]
WantedBy=multi-user.target' > /etc/systemd/system/rtt.2.service

RTT 3

echo '[Unit]
Description=RTT 3 Service
After=network.target
Wants=network.target

[Service]
Type=simple
ExecStart=/root/RTT --iran --keep-ufw --keep-os-limit --log:0 --listen:127.0.0.1 --lport:3030 --mux-width:1 --sni:github.com --password:1234
Restart=always
RestartSec=3s
RuntimeMaxSec=3800
LimitNOFILE=infinity
StandardOutput=null
StandardError=null

[Install]
WantedBy=multi-user.target' > /etc/systemd/system/rtt.3.service

RTT 4

echo '[Unit]
Description=RTT 4 Service
After=network.target
Wants=network.target

[Service]
Type=simple
ExecStart=/root/RTT --iran --keep-ufw --keep-os-limit --log:0 --listen:127.0.0.1 --lport:4040 --mux-width:1 --sni:github.com --password:1234
Restart=always
RestartSec=3s
RuntimeMaxSec=3900
LimitNOFILE=infinity
StandardOutput=null
StandardError=null

[Install]
WantedBy=multi-user.target' > /etc/systemd/system/rtt.4.service

حالا که سرویس رو تعریف کردیم باید همه RTT ها رو اجرا کنیم

sudo systemctl daemon-reload

sudo systemctl restart rtt.1.service
sudo systemctl restart rtt.2.service
sudo systemctl restart rtt.3.service
sudo systemctl restart rtt.4.service

sudo systemctl enable rtt.1.service
sudo systemctl enable rtt.2.service
sudo systemctl enable rtt.3.service
sudo systemctl enable rtt.4.service

خب الان باید همه چیز بدون مشکل کار کنه . اگر مشکلی بود حتما بگید . اگر راه حل دیگه ای هم سراغ دارید حتما بگید


نکته مهم

یه نکته بگم و تاکید کنم باز که من اصلا با RTT مشکل رم و سی پی یو ندارم و این مشکل روفقط با هسته های xray و sing-box داشتم و این راه حل رو روی اونا پیاده کرده بودم و جواب گرفتم . ولی چون یه تعداد گفتن که RTT رم رو اشغال میکنه راه حل رو برای RTT در کد های بالا قرار دادم ولی شما میتونید همین راه حل رو برای هسته هایی مثل ساین باکس هم پیاده سازی کنید که خیلی تاثیر داره

sajadshadmn commented 7 months ago

سلام خسته نباشید داستان هاپروکسی به کجا رسید لطفا ایا در ابدیت های اخیر تغیی خاصی صورت گرفته و نیاز به هاپروکسی نیست؟

hatinati2 commented 6 months ago

سلام وقت بخیر من تست نکردم ولی تعداد زیادی از دوستان که تست کردن می گن اگر کانفیگ از vless به vmess تغییر بدید مشکل دیلی و قطعی ای و وصلی حل میشه

masih1998 commented 2 months ago

سلام مهدی جان خوبی؟ میشه ازت بخوام تلگرام آنلاین بشی؟ یک کار خیلی واجب باهات دارم چند بار پیام‌ دادم فکر کنم متوجه نشدی @AkramiPro