چگونه یک زیرشبکه را از تونل VPN اندروید حذف کنیم
VpnService نمیتواند یک مسیر را حذف کند، بنابراین متمم را اضافه میکنید: هشت پیشوند تولیدشده برای /8، بههمراه بررسیهای IPv6، DNS و جستوجو که بقیه را میگیرند.
VpnService اندروید هیچ مسیر حذفی ندارد، و هیچ میزان خواندن API یکی تولید نمیکند. Builder.addRoute() همیشه فقط مقصدها را به تونل اضافه میکند، بنابراین نگهداشتن یک بخش LAN بهصورت محلی یعنی آن بخش هرگز به فهرست مسیرها وارد نمیشود. چیزی که در عوض اضافه میکنید متمم بخش است، بیانشده با پیشوندهای معمولی. کار حسابی است، و در چند جای قابل پیشبینی شکست میخورد.
بررسیهای زیر را به ترتیب انجام دهید. هر کدام فرض میکند قبلی برقرار بوده، بنابراین در نخستین شکست متوقف شوید، نه اینکه علائم پایینتر را وصله کنید.
از آنچه تونل ادعا میکند شروع کنید
دادن 0.0.0.0/0 به addRoute() به اندروید میگوید که هر مقصد IPv4 به تونل تعلق دارد. به همین دلیل بسیاری از کلاینتها در تونلسازی تقسیمی ناتوان به نظر میرسند: کل فضای نشانی را ادعا میکنند و سپس میکوشند از آن کم کنند. هیچ چیز در سازنده کم نمیکند. مسیر مشخصتر برای شبکهای که میخواستید محلی بماند، برخلاف انتظار عمل میکند، زیرا طولانیترین پیشوند منطبق برنده میشود و آن شبکه داخل تونل میافتد.
فهرست مسیرها تمام سیاست است. هیچ وتوی مقصدی در پشت آن نیست، و مرجع Builder هیچ روشی را که چنین چیزی بدهد فهرست نمیکند.
متمم را از حساب پیشوندها تولید کنید
متمم یک پیشوند حذفشده مجموعه همنیاهای آن در مسیر تا ریشه درخت نشانیها است. برای هر طول از 1 تا طول حذفشده، بلوک همان طول را که پیشوند شما را دربر دارد بردارید، بیت درست زیر پیشوند را برگردانید و نتیجه را بیرون بدهید. تا وقتی اجرایش نکنید انتزاعی به نظر میرسد.
حذف 10.0.0.0/8 هشت مسیر میدهد: 128.0.0.0/1، 64.0.0.0/2، 32.0.0.0/3، 16.0.0.0/4، 0.0.0.0/5، 12.0.0.0/6، 8.0.0.0/7، 11.0.0.0/8. هیچکدام 10.0.0.0/8 را دربر ندارد، و با هم بقیه را پوشش میدهند.
هشت خط آن فهرست را برای هر پیشوندی تولید میکند:
import ipaddress
def complement(addr, length):
base = int(ipaddress.IPv4Address(addr))
out = []
for k in range(1, length + 1):
block = base & (0xFFFFFFFF << (32 - k))
sibling = block ^ (1 << (32 - k))
out.append(f"{ipaddress.IPv4Address(sibling)}/{k}")
return out
print(complement("10.0.0.0", 8))
شمار مسیرها برابر طول پیشوند است، و همان عددی است که باید پیگیری شود. یک حذف /21 هزینه 21 مسیر دارد و خوانا میماند. ده حذف میتواند چند صد هزینه داشته باشد، که معمولاً یعنی طراحی شبکه باید تغییر کند نه مولد.
خانواده نشانی و دامنه تونل را بررسی کنید
مسیرهای IPv4 برای IPv6 کاری نمیکنند. اگر تونل نشانی IPv6 ادعا کند، پیشوند LAN از IPv6 به متمم خودش نیاز دارد، که با همان حساب روی 128 بیت تولید میشود. علت رایج اینکه حذف روی کاغذ کار میکند ولی دستگاه محلی دسترسناپذیر میماند این است: میزبان از طریق IPv6 رسیده شده بود، و فقط IPv4 بریده شده بود. پیش از نتیجهگیری که حساب غلط است، هر دو خانواده را بررسی کنید.
دامنه نیمه دیگر بررسی است. اندروید مسیریابی را بر پایه شبکه و برنامه ردیابی میکند، بنابراین همان پیشوند میتواند برای یک برنامه از تونل برود و برای برنامه دیگر مستقیم، بسته به اینکه VPN چگونه اعلام شده باشد.
قواعد DNS و هر برنامه را جای خودش بگذارید
حذفهای مسیر حلکننده را تغییر نمیدهند. یک نام میزبان محلی هنوز میتواند توسط سرور DNS تونل پاسخ داده شود در حالی که نشانیاش محلی مسیریابی میشود، و ناسازگاری بهصورت نامی ظاهر میشود که به چیزی حل میشود که LAN به آن نمیرسد. سیاست حلکننده را آگاهانه تنظیم کنید، با یک دامنه جستوجو یا قاعده DNS تقسیمشده. فرض نکنید مسیرها این را برای شما تصمیم گرفتهاند.
addDisallowedApplication() یک برنامه را بیرون تونل نگه میدارد؛ برای برنامههایی که داخل میمانند مقصدی را بیرون نگه نمیدارد. protect() اجازه میدهد سوکتی که باز میکنید تونل را دور بزند، و اینگونه تونل از گرفتن انتقال خودش پرهیز میکند. هیچکدام جای متمم را نمیگیرند.
با جستوجو بررسی کنید، نه با فهرست خودتان
وقتی تونل بالا آمد، از دستگاه بپرسید یک نشانی واقعاً کجا میرود، بهجای اینکه فهرستی که ساختهاید را دوباره بخوانید. روی بیلدی که iproute2 دارد، adb shell ip route get 10.1.2.3 رابطی را که هسته انتخاب کرده نام میبرد. همان دستور را برای یک نشانی عمومی اجرا کنید و تأیید کنید که تونل را نام میبرد.
دو بررسی دیگر حلقه را میبندند. نخست یک نام محلی را حل کنید، سپس adb shell ip route get را روی نشانی حلشده اجرا کنید و رابطی را بخواهید که تونل نیست، زیرا adb shell ping -c 1 host.lan موفق دسترسپذیری را ثابت میکند نه مسیر را. آزمون خانواده نشانی را روی IPv6 تکرار کنید اگر تونل یکی ادعا میکند. در سطح API که عرضه میکنید آزمون کنید، زیرا نحوه نمایش شبکههای VPN به جدول مسیریابی در نسخهها تغییر کرده است. فهرست مسیری که روی کاغذ درست به نظر میرسد و جستوجویی که رابط اشتباه را برمیگزیند دو اشکال متفاوتاند، و تنها دومی به کاربران میرسد.
اگر فهرست حذف همچنان رشد میکند، تولید مسیر را متوقف کنید و شبکه دور را دوباره شمارهگذاری کنید یا در عوض تونل را باریک کنید. مولد یک راهحل موقت برای API غایب است، نه ابزار طراحی.