আপনি /etc/ppp/ip-up-এ একটি route কমান্ড রাখেন, অফিস টানেল আবার সংযুক্ত করেন, কিন্তু ফাইলটি কখনও চলে না। স্ক্রিপ্টে কোনো সমস্যা নেই: ওই সংযোগটি মোটেও PPP দিয়ে যায় না। অন্তর্নির্মিত Cisco IPSec ও IKEv2 ক্লায়েন্ট কখনও pppd চালু করে না, তাই হুক ডিরেক্টরি কখনও পড়া হয় না, অথচ PPTP এবং IPSec-এর উপর L2TP এখনও এর মধ্য দিয়ে যায়। আপনার কোন ক্ষেত্রটি তা নির্ধারণ করুন, তারপর launchd নজরদারি জব থেকে অ-PPP ক্ষেত্রটি চালু করুন।

যেকোনো হুক সম্পাদনার আগে ইন্টারফেস যাচাই করুন

দুটি কমান্ড ঠিক করে দেয় কোন প্রক্রিয়াটি কাজ করতে পারে। কনফিগার করা সেবাগুলো তালিকাভুক্ত করুন, তারপর টানেল চালু থাকাকালীন বিদ্যমান ইন্টারফেসগুলো তালিকাভুক্ত করুন। ইন্টারফেসের নামটাই প্রমাণ; সিস্টেম সেটিংসের লেবেল প্রমাণ নয়।

scutil --nc list
ifconfig -l | tr ' ' '\n' | grep -E '^(utun|ppp)[0-9]+$'

ppp0 তৈরি করে এমন সেবা PPP হুকগুলো চালায় এবং আপনার ফাইল নির্বাহ করবে। Cisco IPSec বা IKEv2 সেবা বরং একটি utun ডিভাইস তৈরি করে, PPP স্তরহীন একটি টানেল ইন্টারফেস, তাই /etc/ppp-এর ভিতরের কিছুই এটিতে পৌঁছাতে পারে না। দুই ধরনেরই দেখা গেলে যাচাই করুন আপনি কোন সেবায় সংযুক্ত হয়েছেন। মানুষ ক্লায়েন্টের নাম পড়ে ভুল হুকে একটি বিকেল নষ্ট করে।

PPP পথে ফাইলটির মালিক root হতে হবে এবং এটি নির্বাহযোগ্য হতে হবে, কারণ pppd কিছু চালানোর আগে দুটোই যাচাই করে। install মালিক ও মোড এক ধাপে সেট করে।

sudo install -o root -g wheel -m 0755 /dev/null /etc/ppp/ip-up
sudo ls -l /etc/ppp/ip-up

Finder বা গ্রাফিক্যাল এডিটর দিয়ে তৈরি ফাইল প্রায়ই আপনার অ্যাকাউন্টের মালিকানায় থাকে, অথবা নির্বাহ বিট ছাড়া থাকে, তারপর অনুপস্থিত হুকের মতোই নীরবে ব্যর্থ হয়। এখনই এর পাশে ip-down রাখুন। মালিক কলামে root ও wheel এবং মোড কলামে rwxr-xr-x—এটাই আপনি চান।

টানেল দেখা দিলে launchd-কে স্ক্রিপ্ট চালাতে দিন

যে ক্লায়েন্ট PPP স্পর্শ করে না, তাদের জন্য ট্রিগার অন্য জায়গা থেকে আসতে হবে, আর সিস্টেম কনফিগারেশন স্টোরই সৎ উৎস: macOS প্রতিটি টানেল পরিবর্তনে এটি পুনর্লিখন করে। ওই ডিরেক্টরি লক্ষ্য করা একটি launchd জব টানেল দেখা দিলে বা হারিয়ে গেলে ডাকা হয়।

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
  <key>WatchPaths</key>
  <array><string>/Library/Preferences/SystemConfiguration</string></array>
  <key>Label</key><string>net.example.tunnel-watch</string>
  <key>ProgramArguments</key>
  <array><string>/bin/sh</string><string>/usr/local/sbin/tunnel-hook</string></array>
  <key>RunAtLoad</key><true/>
  <key>ThrottleInterval</key><integer>20</integer>
</dict>
</plist>

এটি per-user এজেন্ট নয়, launch daemon হিসেবে ইনস্টল করুন, কারণ রুট মেরামত মেশিনের কাজ। bootstrap বর্তমান সংস্করণে পুরোনো load -w রূপটি প্রতিস্থাপন করে। RunAtLoad প্রথম নির্বাহকে পর্যবেক্ষণযোগ্য করে, আর ThrottleInterval Wi-Fi সংযোগের পরিবর্তনের ঢলকে স্ক্রিপ্ট বারবার চালু করা থেকে থামায়।

sudo install -o root -g wheel -m 0644 tunnel-watch.plist \
  /Library/LaunchDaemons/net.example.tunnel-watch.plist
sudo launchctl bootstrap system \
  /Library/LaunchDaemons/net.example.tunnel-watch.plist

ফাঁদটি হলো, লক্ষ্য করা ডিরেক্টরিটি আপনার VPN-এর সঙ্গে সম্পর্কহীন ঘটনাতেও বদলায়: Wi-Fi সংযোগ, DHCP নবায়ন, কেবল প্লাগ করা। নিচের প্রহরী কোলাহলপূর্ণ ট্রিগারকে ব্যবহারযোগ্য হুকে পরিণত করে, আর একটি লগ লাইন অদ্ভুত সময়ের রুট ব্যাখ্যা করে।

মালিকানা স্ক্রিপ্টের মতো plist-কেও অন্তর্ভুক্ত করে। যে ডেমন আপনার নিজের অ্যাকাউন্ট যেখানে লিখতে পারে এমন ডিরেক্টরির একটি ফাইল নির্বাহ করে, সে ওই অ্যাকাউন্টকে root দিয়ে দেয়।

স্ক্রিপ্ট পাহারা দিন যাতে দ্বিতীয় চালান কিছুই না বদলায়

স্ক্রিপ্ট প্রথমে ঠিক করে টানেল আছে কি না, না থাকলে নীরবে প্রস্থান করে। এর পরের সবকিছু পুনরাবৃত্তির জন্য নিরাপদ হতে হবে, কারণ ট্রিগার একটি সংযোগের চেয়ে অনেক বেশি বার চলে। পরের সংযোগে বদলে যাওয়া কোনো ইনডেক্স হার্ডকোড না করে রানটাইমে ইন্টারফেস নির্ধারণ করুন।

#!/bin/sh
set -u
TUN=$(ifconfig -l | tr ' ' '\n' | grep -m1 '^utun[0-9]' || true)
[ -n "$TUN" ] || exit 0
netstat -rn -f inet | grep -q '^10\.42' && exit 0
route -n add -net 10.42.0.0/16 -interface "$TUN"

route add রুট আগে থেকেই থাকলে অশূন্য স্ট্যাটাসে প্রস্থান করে, তাই প্রতিটি অশূন্য স্ট্যাটাসকে ব্যর্থতা ধরার স্ক্রিপ্ট সঠিক কাজ করলেও প্রতিবার ভাঙা হুক রিপোর্ট করে। উপরের netstat পরীক্ষা ওই অবস্থাকে স্পষ্ট নো-অপে পরিণত করে।

ইন্টারফেসের উপস্থিতি দেখতে যতটা শক্ত, ততটা নয়, কারণ অন্য VPN ক্লায়েন্ট এবং কিছু কনটেইনার রানটাইমও utun ডিভাইস তৈরি করে। scutil --nc status "Office VPN" দিয়ে সেবাটিকেই জিজ্ঞাসা করুন এবং রাউটিং স্পর্শ করার আগে সংযুক্ত অবস্থা দাবি করুন। উত্তরটি একটি লগ লাইনে রাখুন, কারণ এক সপ্তাহ পরে ওই রেকর্ডই আপনার একমাত্র ব্যাখ্যা হবে।

DNS না ভেঙে গেটওয়ে ফিরিয়ে আনুন

টানেল ডিফল্ট রুট দখল করলে সাধারণ ব্রাউজিং অফিস দিয়ে বেরিয়ে যায় এবং স্থানীয় ইন্টারনেট পথ কাজ করা বন্ধ করে। প্রথমে ফিজিক্যাল ইন্টারফেসের রাউটার ধরে নিন, তারপর ডিফল্ট আবার তার দিকে ঘুরিয়ে দিন। DHCP এমন একটি টেবিল পার্স করার চেয়ে ভালো যেখানে ইতিমধ্যেই টানেলের নিজের ডিফল্ট আছে।

PHYS=en0
GW=$(ipconfig getoption "$PHYS" router)
[ -n "$GW" ] && sudo route -n change default "$GW"

রিজলভার আলাদা যন্ত্রসহ আলাদা স্তর, আর রুট মেরামত তাদের মেরামত করে না। scutil --dns দিয়ে কী কার্যকর তা দেখুন, তারপর যা এটি তৈরি করে তা ঠিক করুন: সেবার ক্রম এবং ফিজিক্যাল সেবার DNS এন্ট্রি। ক্যাশে ফ্লাশ করা নেটওয়ার্ক বদলের পর আটকে থাকা লুকআপ নির্ণয় করে; এটি নির্ধারিত করার মতো কিছু নয়।

Wi-Fi পরিবর্তন সত্ত্বেও টিকে থাকা অথচ DNS আটকে যাওয়া টানেল তৃতীয় ত্রুটি: sudo killall -HUP mDNSResponder রিজলভারকে তার কনফিগারেশন আবার পড়তে বাধ্য করে। এটি একবার, হাতে ব্যবহার করুন।

প্রমাণ করুন কাজটি নিজে থেকেই চলে

নজরদারি পথে ভরসা করার আগে kickstart -k দিয়ে একবার চালান বাধ্য করুন, তারপর জবের রেকর্ড করা প্রস্থান স্ট্যাটাস পড়ুন। পরিষ্কার প্রস্থান প্রমাণ করে স্ক্রিপ্ট কাজ করে; এটি প্রমাণ করে না ট্রিগার কাজ করে। তারপর জব লোড থাকা অবস্থায় সংযোগ বিচ্ছিন্ন ও পুনঃসংযুক্ত করুন, এবং আপনি চাননি এমন একটি চালানের জন্য নজর রাখুন।

sudo launchctl kickstart -k system/net.example.tunnel-watch
sudo launchctl print system/net.example.tunnel-watch | grep -E 'last exit code|state ='

প্রতিটি প্রচেষ্টার আগে ও পরে scutil --nc status যাচাই করুন। টানেল বন্ধ থাকাকালীন চলা স্ক্রিপ্ট সংযোগ পথ সম্পর্কে কিছুই প্রমাণ করে না।

ভাঙার শাখাটিও সংযোগ শাখার মতোই একই আচরণ দাবি করে: রুটটি হাতে সরান, জব চলতে দিন, এবং তা ফিরে আসে কি না নিশ্চিত করুন। যে হুক রুট যোগ করে এবং কখনও সরায় না, সে এক সপ্তাহ পরে খারাপ আচরণ করা একটি মেশিন রেখে যায়, আর দুটি ঘটনাকে কিছুই যুক্ত করে না। উভয় আচরণ টিকলে sudo launchctl bootout system/net.example.tunnel-watch জবটিকে পরিষ্কারভাবে অবসরে পাঠায়। লোড করা অবস্থায় রাখা একটি নজরদারি ডেমনই এক-বারের মেরামতকে মাসখানেক পরে অব্যাখ্যাত রুটে পরিণত করে।

সম্পর্কিত নিবন্ধ