Tailcat: شبکهی Tailscale بدون حساب Tailscale
خلاصهٔ کاملتر
تیم Tailscale یه پروژهی متنباز به اسم Tailcat منتشر کرده که شعارش «Tailscale بدون Tailscale» هست. این ابزار از data plane خود Tailscale (یعنی بخشی که خود ترافیک رو جابهجا میکنه و اسم داخلیش magicsock هست) استفاده میکنه، ولی control plane (سرویس مرکزی که ماشینها رو معرفی و مدیریت میکنه) رو کنار میذاره. اطلاعات اتصال رو هر جوری خودت بخوای جابهجا میکنی. هم CLI داره و هم یه کتابخونهی Go با مسیر github.com/tailscale/tailcat.
روال کار سادهست: یه طرف سرور راه میندازه و یه «آدرس tailcat» با پیشوند tc میگیره، طرف دیگه همین آدرس رو به کلاینت میده. همهی ترافیک end-to-end با WireGuard رمزنگاری میشه. اتصال اول از طریق یه سرور DERP (رلهای که هم برای عبور از NAT کمک میکنه و هم مسیر آخره) برقرار میشه و بعد magicsock سعی میکنه به اتصال مستقیم UDP برسه. به routing table یا DNS سیستم دست نمیزنه، پس root لازم نیست.
کاربردش فقط رد کردن stdin و stdout نیست. با tailcat serve میشه پورتهای TCP محلی رو در دسترس گذاشت و با forward اونا رو روی پورت محلی طرف مقابل آورد، یا با browse مستقیم مرورگر رو باز کرد. سرور SSH با authorized_keys یا کلیدهای عمومی حساب GitHub، سرویس exec شبیه inetd، ارسال و دریافت فایل روی SFTP، پراکسی SOCKS5 و حالت exit node هم داره. یه دموی آزمایشی WebAssembly تو مرورگر هم هست که فعلاً فقط از مسیر DERP کار میکنه.
آدرس tailcat شامل کلید عمومی WireGuard سرور و یه pre-shared key جداست، پس دونستن آدرس یعنی اجازهی اتصال. کلیدها پیشفرض ephemeral هستن، یعنی هر اجرا آدرس تازه میسازه و با بسته شدن پروسه آدرس برای همیشه از کار میافته. tailcat genkey کلید رو ذخیره میکنه تا آدرس ثابت بمونه، ولی هر کسی که قبلاً آدرس رو گرفته همیشه میتونه وصل بشه، مگه اینکه با --allow کلاینتها رو محدود کنی. خاموش کردن PSK با --psk=false حفاظت post-quantum رو هم از بین میبره.
مستندات روی امنیت خیلی تأکید داره. تو حالت no-auth-ssh خود آدرس حکم رمز رو داره و هر کی داشته باشه یه shell روی ماشین میگیره. آدرس رو میشه تو رکورد DNS TXT هم گذاشت تا با اسم دامنه وصل بشی، ولی چون این رکورد عمومیه، سرور باید با --allow یا --ssh-authorized-keys کلاینت رو احراز هویت کنه. برای اطمینان، tailcat ssh قبل از وصل شدن به مقصد DNS یه بار مثل یه غریبه امتحان میکنه و اگه موفق بشه، اتصال رو رد میکنه.
بهعنوان کتابخونه هم کار باهاش سادهست. مقدار صفر tailcat.Server برای کلید، رله و لاگ پیشفرض داره، با Start() شروع میشه و TailcatAddr() آدرس رو برمیگردونه. این سرور نمونهی مستندات به هر پورت TCP جواب میده:
s := &tailcat.Server{
OnTCP: func(port uint16) func(net.Conn) {
return func(c net.Conn) {
fmt.Fprintf(c, "hello from port %v\n", port)
c.Close()
}
},
}نکات کلیدی:
- بدون حساب Tailscale و بدون دسترسی root کار میکنه و به routing table و DNS دست نمیزنه.
- ترافیک end-to-end با WireGuard رمزنگاری میشه و هر وقت بشه به اتصال مستقیم UDP میرسه.
- کلیدها پیشفرض ephemeral هستن و tailcat genkey آدرس ثابت میسازه.
- رلههای DERP رایگان محدودیت نرخ دارن، ولی میشه سرور DERP شخصی راه انداخت.
- tailcat.MaxUDPPayload برابر 1232 بایته و فلوهای UDP بیکار بعد از دو دقیقه بسته میشن.
- آدرس سرور no-auth-ssh رو هیچوقت نباید تو DNS منتشر کرد.




