আমার ভাবা সেরা FreeBSD প্যাকেট ফিল্টার (pf.conf)
হ্যালো, আমি মুনো (Munou)।
এইবার আমি আমার সাম্প্রতিক ঘাটাঘাটি করা প্যাকেট ফিল্টারটি আপনাদের সাথে শেয়ার করতে চাই।
বর্তমান কনফিগারেশন
এটি এইরকম।
প্যাকেট ফিল্টারের (Packet Filter) ক্ষেত্রে
NAT, rdr ইত্যাদির মতো রূপান্তর নিয়মগুলোর (conversion rules) ক্ষেত্রে যেটি আগে ম্যাচ করে সেটি প্রয়োগ করা হয়।
pass, block ইত্যাদির মতো ফিল্টার নিয়মগুলোর ক্ষেত্রে যেটি শেষে ম্যাচ করে সেটি প্রয়োগ করা হয়।
এটিই এর বৈশিষ্ট্য।
এই ক্ষেত্রে, পড়ার সুবিধার জন্য আমি ফিল্টার নিয়মগুলোর ক্ষেত্রে সবগুলোতে quick ব্যবহার করেছি যাতে সেই মুহূর্তেই ম্যাচ করা নিয়মটি প্রয়োগ করা হয়।
তবে, আমি fail2ban-এর block নিয়মগুলো শেষে রেখেছি যাতে কোনো কিছু বাদ না দিয়ে বিস্তৃতভাবে লগিং করা যায়।
যেখানে সম্ভব সেখানে আমি মন্তব্য (comments) যোগ করে রাখছি।
set skip on lo
set block-policy drop
set optimization conservative
set state-policy if-bound
set ruleset-optimization basic
wanint="vtnet0"
# ওয়্যারগার্ড কনফিগারেশন (WireGuard Configuration)
wg_ifs = "{ wg0, wg1 }"
wg_net = "10.1.0.0/24"
wg_ports="{51820}"
table <wg_clients> const { 10.1.0.2, 10.1.0.4, 10.1.0.22 }
#### -- স্ক্রাব নিয়ম (Scrub Rules) -- ####
scrub in on $wanint all random-id max-mss 1360
scrub out on $wanint all random-id max-mss 1360
scrub in all
scrub out all
#### -- NAT নিয়ম (NAT Rules) -- ####
# ওয়্যারগার্ড ক্লায়েন্ট NAT (WireGuard Clients NAT)
nat on $wanint inet from <wg_clients> to any -> ($wanint)
block all
#### -- Fail2Ban নিয়ম (Fail2Ban Rules) -- ####
anchor "f2b/*"
pass out quick keep state
#### -- UDP নিয়ম (UDP Rules) -- ####
pass in quick on $wg_ifs from $wg_net to any keep state
pass in quick on $wanint proto udp from any to ($wanint) port $wg_ports keep state
# HTTP/3 প্রোটোকল
pass in quick on $wanint proto udp to ($wanint) port 443 keep state
#### -- TCP নিয়ম (TCP Rules) -- ####
# মেইল প্রোটোকল (Mail Protocols)
pass in quick proto tcp from any to ($wanint) port {25, 465, 993, 995} synproxy state
# HTTP
pass in quick on $wanint proto tcp to ($wanint) port {80, 443} modulate state
set block-policy drop
নিয়মের সাথে ম্যাচ না করা সব প্যাকেট drop করা হবে।
return-এর ক্ষেত্রে, TCP হলে এটি RST পাঠিয়ে অপর পক্ষকে জানিয়ে সংযোগ বিচ্ছিন্ন করে।
UDP-র ক্ষেত্রে যেহেতু কোনো TCP সংযোগ নেই, তাই এটি শুধুমাত্র ICMP port unreachable পাঠায়।
set optimization conservative
এটি একটি অপ্টিমাইজেশন নিয়ম যা ডকুমেন্টেশনে রক্ষণশীল (conservative) সেটিংস হিসেবে পরিচিত।
aggressive-এর ক্ষেত্রে সংযোগগুলো দ্রুত শেষ করে দেওয়া হয়, কিন্তু WireGuard-এর মতো পরিবেশে যেখানে সবসময় সংযোগ বজায় রাখতে হয়, সেখানে নতুন প্যাকেট না এলেই সংযোগ বিচ্ছিন্ন হয়ে যেতে পারে।
এছাড়াও satellite-এর মতো অপশনও আছে, যা বেশ আকর্ষণীয়।
high-latency A high-latency environment (such as a satellite connec- tion). satellite Alias for high-latency.
set state-policy if-bound
state বজায় রেখে এবং সেটি মনে রেখে প্যাকেট পাস করার মাধ্যমে অসঙ্গতি রোধ করা হয়।
pfctl -ss-এর ফলাফল হলো state, উদাহরণস্বরূপ নিচের কনফিগারেশনের ক্ষেত্রে:
ক্লায়েন্ট ←→ wg ←→ সার্ভার
state-এর সাথে "কোন ইন্টারফেস দিয়ে এটি তৈরি হয়েছে" সেই তথ্য যুক্ত থাকে, তাই একই ইন্টারফেস দিয়ে আসা যোগাযোগকে বৈধ ধরে অসঙ্গতি এড়ানো হয়।
সাধারণ floating-এর ক্ষেত্রে:
প্রবেশ: wg0
প্রস্থান: vtnet0
ফিরতি: vtnet0 বা wg0 যেকোনোটি হতে পারে
তবে, state-policy if-bound-এর ক্ষেত্রে:
প্রবেশ: wg0
প্রস্থান: vtnet0
ফিরতি: অবশ্যই wg0 হতে হবে, অন্যথায় হবে না (NG)
set ruleset-optimization basic
এটি নিয়মগুলোকে সুচারুভাবে অপ্টিমাইজ করে দেয়।
অফিসিয়াল ডকুমেন্টেশন থেকে:
remove duplicate rules
remove rules that are a subset of another rule
combine multiple rules into a table when advanta-geous
re-order the rules to improve evaluation perfor-mance
বাংলায় অনুবাদ করলে:
ডুপ্লিকেট নিয়মগুলো সরিয়ে ফেলা
অন্য নিয়মের অন্তর্ভুক্ত নিয়মগুলো সরিয়ে ফেলা
প্রয়োজন অনুযায়ী একাধিক নিয়মকে একটি টেবিলে একত্রিত করা
মূল্যায়নের পারফরম্যান্স উন্নত করতে নিয়মগুলোর ক্রম পরিবর্তন করা
অর্থাৎ, অগোছালোভাবে লেখা pf নিয়মগুলোকেও এটি সুন্দরভাবে গুছিয়ে দেয়। এটি চালু রাখলে আপনি আপনার মতো করে সহজবোধ্য নিয়ম লিখতে পারেন, আর এটি নিজে থেকেই সেগুলো গুছিয়ে নেবে—এটি সত্যিই একটি অসাধারণ ফিচার।
ভেরিয়েবল সংজ্ঞায়িত করা
WAN ইন্টারফেসের নাম নির্ধারণ
wanint="vtnet0"
বরাদ্দকৃত IPv4 অ্যাড্রেস এবং একটি নির্দিষ্ট আউটগোয়িং আইপি হিসেবে সংজ্ঞায়িত
exsrv1 = "163.44.113.145"
WireGuard-এর ভেরিয়েবল এবং টেবিল সংজ্ঞায়িত করা
wg_ifs = "{ wg0, wg1 }"
wg_net = "10.1.0.0/24"
wg_ports="{51820}"
table <wg_clients> const { 10.1.0.2, 10.1.0.4, 10.1.0.22 }
Scrub Rules
এই ক্ষেত্রে, WAN থেকে আসা এবং যাওয়া উভয় প্যাকেটের জন্য MSS মান নির্ধারণ করা হয়েছে।all ramdom-id-এর ক্ষেত্রে মনে হচ্ছে এটি ওএস (OS) নিজেই প্যাকেট থেকে শনাক্ত হওয়া প্রতিরোধ করার জন্য, তবে sudo tcpdump -n -v -i $interface দিয়ে পরীক্ষা করে দেখা গেছে যে GNU/Linux-এর ক্ষেত্রে এটি ডিফল্টভাবে সক্রিয় থাকে।
04:15:18.538048 IP (tos 0x0, ttl 52, id 61686, offset 0, flags [DF], proto TCP (6), length 52)
04:15:18.538049 IP (tos 0x0, ttl 52, id 61687, offset 0, flags [DF], proto TCP (6), length 131)
04:15:18.538179 IP (tos 0x0, ttl 64, id 65430, offset 0, flags [DF], proto TCP (6), length 52)
04:15:18.538223 IP (tos 0x0, ttl 52, id 61688, offset 0, flags [DF], proto TCP (6), length 131)
এছাড়াও, WAN ইন্টারফেস ছাড়াও অন্যান্য ইন্টারফেস scrub করার জন্য in all এবং out all সেট করা হয়েছে।
scrub in on $wanint all random-id max-mss 1360
scrub out on $wanint all random-id max-mss 1360
scrub in all
scrub out all
NAT Rules
নির্দিষ্ট WireGuard ক্লায়েন্ট সাইড WireGuard সার্ভার সাইডের WAN ইন্টারফেসের NAT-এর মাধ্যমে বাইরে যায়।
তবে, এই ক্ষেত্রে এটি শুধুমাত্র IPv4 দিয়ে বের হয়। কারণ WireGuard সার্ভার সাইডে কোনো IPv6 অ্যাড্রেস প্রদান করা হচ্ছে না, তাই শুধুমাত্র inet from ব্যবহার করা হয়েছে।
nat on $wanint inet from <wg_clients> to any -> ($wanint)
Fail2Ban Rules
Fail2Ban-এর মাধ্যমে আক্রমণকারীর IP-কে pf টেবিলে যুক্ত করে ব্লক করার নিয়ম। এটি শেষে রাখা হয়েছে যাতে কোনো নিয়মের সাথে না মেলা প্যাকেটগুলো anchor "f2b/*"-এর মাধ্যমে pf টেবিলে যুক্ত IP থেকে আসা প্যাকেটগুলোকে Fail2Ban নিয়মে পাঠানো হয়।
এটি উপরে রাখা হয়েছে কারণ quick সেট করা ফিল্টার নিয়মের আগে এটি ম্যাচ হওয়া প্রয়োজন।
এর ঠিক আগেই ডিফল্ট নিয়ম block all থাকায়, এখানে ম্যাচ না হওয়া সমস্ত প্যাকেট block হয়ে যাবে।
/usr/local/etc/fail2ban/action.d/pf.conf:
# Option: block
#
# The action you want pf to take.
# Probably, you want "block quick", but adjust as needed.
# If you want to log all blocked use "blog log quick"
block = block quick
এই সেটিংস থেকে block quick-এর Fail2ban নিয়ম যুক্ত হয়, তাই এটি উপরের দিকে রাখা হয়েছে।
অর্থাৎ প্রথমে anchor "f2b/*" দিয়ে pf টেবিলে যুক্ত IP থেকে আসা প্যাকেটগুলোকে Fail2Ban নিয়মে পাঠানো হয়, এবং তারপর:
anchor "f2b/*"
ফিল্টার নিয়ম হিসেবে সবার আগে বাইরে যাওয়া প্যাকেট অনুমোদনের নিয়মটি রাখা হয়েছে।
pass out quick keep state
UDP Rules
WireGuard সার্ভারের জন্য অনুমোদনের নিয়ম।
51820/udp অনুমোদন করে $wg_ifs-এর WireGuard-এর সমস্ত ভার্চুয়াল NIC অনুমোদন করা হয়েছে।
জরুরি অবস্থার কথা চিন্তা করে এই অংশটি আরও কঠোর করা উচিত কি?
pass in quick on $wg_ifs from $wg_net to any keep state
pass in quick on $wanint proto udp from any to ($wanint) port $wg_ports keep state
এই ক্ষেত্রে, যেহেতু ইতিমধ্যে state বজায় রাখা হয়েছে, তাই WireGuard টানেলের মাধ্যমে আসা সমস্ত প্যাকেট অনুমোদিত হবে। যদি এই ক্রমটি উল্টো হয়, তবে pass in quick on $wg_ifs from $wg_net to any keep state নিয়মটি কাজ করবে না কারণ এটি WireGuard টানেল হওয়ার ওপর নির্ভরশীল।
HTTP/3 সক্রিয় করার জন্য 443/udp অনুমোদন করা হয়েছে।
# HTTP/3 Protocol
pass in quick on $wanint proto udp to ($wanint) port 443 keep state
TCP Rules
যারা nmap ব্যবহার করেছেন তারা জানেন যে, TCP-র ক্ষেত্রে পোর্ট স্ক্যানিং খুব দ্রুত হয়, তাই শুধু পোর্ট পরিবর্তন করলেই আক্রমণকারীরা তা সহজে খুঁজে পায়। UDP পোর্টের ক্ষেত্রে nmap স্ক্যান করতে অনেক সময় লাগে, তাই আরও নিরাপদ করতে শুধুমাত্র WireGuard টানেলের মাধ্যমে SSH অ্যাক্সেস করার ব্যবস্থা করা হয়েছে। অর্থাৎ, কার্যত TCP-কে UDP দিয়ে র্যাপ (wrap) করার মতো কনফিগারেশনই সবচেয়ে নিরাপদ হবে।
Fail2ban চালু থাকায়, SSH আক্রমণ হলে আক্রমণকারীর IP-কে pf টেবিলে যুক্ত করে ব্লক করা হয়। এটি কার্যত একটি হানিপট (honeypot)-এর মতো কাজ করে।
মেইল প্রোটোকলের ক্ষেত্রে SYN Flood আক্রমণ প্রতিরোধ করতে synproxy সক্রিয় করা হয়েছে।
এই ক্ষেত্রে HTTP-র জন্য ($wanint) দিয়ে গন্তব্য IP নির্দিষ্ট করার কারণ হলো WAN ইন্টারফেসে বরাদ্দকৃত IP অ্যাড্রেসের সাথে এটি যেন ডাইনামিকভাবে ম্যাচ করে। স্পষ্টভাবে inet উল্লেখ না করার কারণ হলো IPv4 এবং IPv6 উভয়কেই অনুমতি দেওয়া।
IPv6-এর মাধ্যমে আসা প্যাকেটগুলো ($wanint) দিয়ে গন্তব্য IP নির্দিষ্ট করার কারণে WAN ইন্টারফেসে বরাদ্দকৃত IPv6 অ্যাড্রেসের সাথে ডাইনামিকভাবে ম্যাচ করবে।
# Mail Protocols
pass in quick proto tcp from any to ($wanint) port {25, 465, 993, 995} synproxy state
# HTTP
pass in quick on $wanint proto tcp to ($wanint) port {80, 443} modulate state
যাই হোক, অনেক দীর্ঘ হয়ে গেল...।