সকেট, পোর্ট, আর কী listen করছে
প্রতিটা নেটওয়ার্ক সার্ভিস একটা সকেট। প্রতিটা খোলা পোর্ট এমন একটা সকেট যা কেউ bind করেছে। আপনার VPS ঠিক কী এক্সপোজ করছে তা বলে দেওয়া চারটা টুল।
বাস্তব জীবনের উপমা
সকেট আর পোর্ট অনেকটা নম্বর দেওয়া জানালাওয়ালা একটা পোস্ট অফিসের মতো — প্রতিটা সার্ভিস নিজের জানালা নম্বরে listen করে, আর OS আসা মেইল সঠিক জানালায় route করে।
গল্পে বুঝি
ফাতিমা আল-ফিহরির বিশাল অফিস বিল্ডিংয়ের সামনের দিকটায় সারি সারি নম্বর দেওয়া সার্ভিস জানালা। জানালা 80 হলো সাধারণ জিজ্ঞাসার জন্য, জানালা 443 গোপন-নিরাপদ লেনদেনের জন্য, আর জানালা 22 হলো কেয়ারটেকারের ঢোকার দরজা। যে জানালাগুলো খোলা, তার প্রতিটার পেছনে একজন কেরানি বসে আছে — কেউ এসে সামনে দাঁড়ালেই সে শুনতে (listen) প্রস্তুত। কেউ জানালা 80-এর সামনে গিয়ে দাঁড়ায়, কেরানির সঙ্গে একটা কথোপকথন শুরু করে, কাজ সেরে চলে যায়; পরের জন এসে দাঁড়ায় আবার নতুন করে।
বিল্ডিংয়ের সিকিউরিটি ম্যানেজার ইবনে সিনা কিছুক্ষণ পরপর সামনের সারি ধরে হেঁটে যান। তিনি ঠিক দেখে নেন কোন কোন নম্বরের জানালা এই মুহূর্তে খোলা আর সেখানে কে বসে আছে। জানালা 80, 443, 22 — এগুলো তো খোলা থাকারই কথা। কিন্তু হঠাৎ যদি চোখে পড়ে জানালা 5432 (যেটা ভেতরের হিসাব-নিকাশের জন্য, বাইরের কারো জন্য নয়) পাবলিকের দিকে খুলে বসে আছে, তিনি সঙ্গে সঙ্গে সেটা বন্ধ করিয়ে দেন। যে জানালা জনসাধারণের জন্য খোলা থাকার কথা না, সেটা এক মুহূর্তও খোলা থাকবে না।
এই গল্পটাই আসলে socket আর port। প্রতিটা নম্বর দেওয়া সার্ভিস জানালা হলো একটা port (80, 443, 22)। খোলা জানালার পেছনে বসে থাকা কেরানি হলো সেই port-এ listen করা একটা service। কেউ এসে জানালার সামনে দাঁড়িয়ে লেনদেন করা মানে একটা socket কানেকশন। আর ইবনে সিনার হেঁটে হেঁটে কোন জানালা খোলা তা যাচাই করে অপ্রত্যাশিতগুলো বন্ধ করাটাই হলো কী listen করছে তা অডিট করা — বাস্তবে ss -tlnp বা netstat -tlnp চালিয়ে দেখা কোন কোন port খোলা, আর অচেনা কিছু খোলা থাকলে সেটা বন্ধ করা। আপনার VPS-এ এই সিকিউরিটি ওয়াক-থ্রু নিয়মিত করাটাই আপনাকে বাঁচায় — না-জেনে খোলা থাকা একটা port-ই attacker-এর দরজা।
একটা সকেট হলো একটা ফাইল ডেসক্রিপ্টর যা নেটওয়ার্কের সঙ্গে কথা বলে
একটা প্রসেস যখন একটা নেটওয়ার্কের উপর ডেটা পাঠাতে বা পেতে চায়, এটা কার্নেলের কাছে একটা সকেট চায় — আর কার্নেল একটা ফাইল ডেসক্রিপ্টর ফেরত দেয়, ঠিক একটা ফাইল খোলার মতোই। সেখান থেকে, প্রসেস অন্য যেকোনো ফাইলের মতোই এটাতে read() আর write() করতে পারে। কার্নেল TCP, UDP, retransmit, congestion control, এসব সামলায়।
পৃথিবীর প্রতিটা নেটওয়ার্ক সার্ভিস এতেই নেমে আসে:
- প্রসেস
socket(AF_INET, SOCK_STREAM, 0)কল করে — “আমাকে একটা TCP/IP সকেট দাও।” - প্রসেস
bind(fd, "0.0.0.0:8080")কল করে — “আমি চাই এই সকেট পোর্ট 8080-এর মালিক হোক।” - প্রসেস
listen(fd, backlog)কল করে — “আমি কানেকশন accept করতে প্রস্তুত।” - লুপ:
accept(fd)— কেউ কানেক্ট না করা পর্যন্ত block করে, তারপর সেই কানেকশনের জন্য একটা নতুন সকেট রিটার্ন করে।
একটা “পোর্ট” হলো 1 থেকে 65535 পর্যন্ত একটা সংখ্যা। 1024-এর নিচের পোর্টগুলো privileged — শুধু root বা CAP_NET_BIND_SERVICE-ওয়ালা একটা প্রসেসই সেগুলো bind করতে পারে। এজন্যই root হিসেবে nginx পোর্ট 80-এ listen করতে পারে, কিন্তু আপনার unprivileged Go বাইনারি পারে না — যদি না আপনি এটাকে ক্যাপাবিলিটি দেন বা পোর্ট 8080-এ চালান আর সামনে nginx বসান।
আমার বক্সে এখন কী আছে?
এই চ্যাপ্টারের একক সবচেয়ে গুরুত্বপূর্ণ কমান্ড:
ss -tlnp এটা মুখস্থ করুন। এর মানে:
t— শুধু TCP (UDP-এর জন্য-uব্যবহার করুন)।l— শুধু listening সকেট (যেসব সকেট আসা কানেকশন accept করছে)।n— numeric অ্যাড্রেস আর পোর্ট দেখাও, DNS বা সার্ভিস নাম রিজলভ করার চেষ্টা কোরো না।p— কোন প্রসেস প্রতিটা সকেটের মালিক তা দেখাও (সবকিছুর জন্য root দরকার)।
আউটপুট:
$ sudo ss -tlnp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1234,fd=6))
LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=1234,fd=7))
LISTEN 0 128 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=987,fd=5))
LISTEN 0 4096 *:22 *:* users:(("sshd",pid=750,fd=3))
LISTEN 0 511 0.0.0.0:8080 0.0.0.0:* users:(("myapp",pid=1567,fd=4)) এটা এভাবে পড়ুন:
- nginx
0.0.0.0:80আর0.0.0.0:443-এ listen করছে — পাবলিক ইন্টারনেট সেগুলোতে পৌঁছাতে পারে। - postgres
127.0.0.1:5432-এ — শুধু এই মেশিনই কানেক্ট করতে পারে। ভালো। Postgres-কে কখনো ইন্টারনেটে এক্সপোজ করবেন না। - sshd
*:22-এ (IPv4 আর IPv6 দুটোই) — আপনার সদর দরজা। - myapp
0.0.0.0:8080-এ — পাবলিক।
0.0.0.0 বনাম 127.0.0.1 বনাম ::
একটা সকেট যে অ্যাড্রেসে bind করে তা ঠিক করে কে এতে পৌঁছাতে পারবে।
| Bind address | কে কানেক্ট করতে পারে |
|---|---|
127.0.0.1 (বা localhost) | শুধু এই মেশিন। নেটওয়ার্কের কিছুই এতে পৌঁছাতে পারে না। |
0.0.0.0 | যেকোনো ইন্টারফেসে যেকোনো IPv4 অ্যাড্রেস — পাবলিক ইন্টারনেটসহ। |
::1 | শুধু এই মেশিন, IPv6-এর উপর। |
:: | যেকোনো ইন্টারফেসে যেকোনো IPv6 অ্যাড্রেস। |
192.168.1.10 (একটা নির্দিষ্ট IP) | শুধু সেই সঠিক ইন্টারফেস/IP-তে আসা কানেকশন। |
একটা সাধারণ ভুল: একটা ডেটাবেস “ইন্টারনেটে এক্সপোজড” কারণ এটা 127.0.0.1:5432-এর বদলে 0.0.0.0:5432-এ bind করেছে। শক্তিশালী পাসওয়ার্ড থাকলেও, আপনি চান না র্যান্ডম স্ক্যানাররা হাজার হাজার অথেন্টিকেশন চেষ্টা চালাক। নেটওয়ার্কজুড়ে সত্যিই কিছুর পৌঁছানো দরকার না হলে localhost-এ bind করুন।
Established কানেকশন
এখন কে কানেক্টেড তা দেখতে -l বাদ দিন:
ss -tnp অথবা সেগুলো গুনুন:
ss -tn state established | wc -l পোর্ট দিয়ে ফিল্টার করুন:
ss -tn '( dport = :443 or sport = :443 )' peer অ্যাড্রেস দিয়ে:
ss -tn dst 1.2.3.4 ss যা করে, তা আপনি আগে netstat দিয়ে করতেন। netstat এখনো কাজ করে (netstat -tlnp) কিন্তু deprecated আর ব্যস্ত হোস্টে ধীর।
lsof — যখন ss যথেষ্ট নয়
lsof খোলা ফাইল লিস্ট করে, আর যেহেতু সকেট হলো ফাইল, এটা সকেটও লিস্ট করে। এটা verbose কিন্তু নমনীয়:
sudo lsof -i :8080 # who has port 8080 open?
sudo lsof -i TCP # all TCP sockets
sudo lsof -i 4 -P # IPv4 only, no name resolution
sudo lsof -p 1234 # all open files for PID 1234, including sockets
sudo lsof -u postgres # everything postgres user has open আপনি যখন “কে এই ফাইল/পোর্ট ধরে রেখেছে” ডিবাগ করছেন তখন lsof ব্যবহার করুন আর একটা দ্রুত listening ম্যাপ চাইলে ss।
netstat (legacy কিন্তু এখনো উপকারী)
netstat -tlnp # same idea as ss -tlnp
netstat -s # cumulative protocol stats
netstat -i # per-interface byte counters
netstat -rn # routing table netstat -s অদ্ভুত নেটওয়ার্ক সমস্যা নির্ণয়ে সত্যিকারভাবে উপকারী — retransmit, accept queue overflow, কার্নেল লেভেলে ড্রপ হওয়া কানেকশন — যা ss এত সুন্দরভাবে summarize করে না।
TCP স্টেট — এদের মানে কী
ss -tn State কলাম আপনাকে বলে প্রতিটা কানেকশন TCP-এর state machine-এর কোথায় আছে। যেগুলো গুরুত্বপূর্ণ:
| State | মানে |
|---|---|
LISTEN | সার্ভার সাইড, কানেকশনের জন্য অপেক্ষা করছে। |
SYN-SENT | ক্লায়েন্ট সাইড, SYN পাঠিয়েছে, SYN-ACK-এর অপেক্ষায়। |
SYN-RECV | সার্ভার, SYN পেয়েছে, SYN-ACK পাঠিয়েছে, ACK-এর অপেক্ষায়। |
ESTABLISHED | কানেকশন দুই দিকেই খোলা। আপনার বেশিরভাগ সকেট। |
FIN-WAIT-1 / FIN-WAIT-2 | লোকাল সাইড বন্ধ হচ্ছে। |
CLOSE-WAIT | রিমোট সাইড বন্ধ করেছে; আপনার অ্যাপ এখনো বন্ধ করেনি। বাগের ইঙ্গিত। |
TIME-WAIT | কানেকশন বন্ধ; কার্নেল দেরিতে আসা প্যাকেট সামলাতে সকেটটা সংক্ষিপ্তভাবে ধরে রাখে। |
একটা ব্যস্ত সার্ভারে কয়েকশো TIME-WAIT স্বাভাবিক। দশ লাখ CLOSE-WAIT মানে peer disconnect করার পর আপনার অ্যাপ সকেট বন্ধ করতে ব্যর্থ হচ্ছে — একটা ধীর ফাইল ডেসক্রিপ্টর লিক।
Listen backlog আর accept queue overflow
ss -tln-এ Send-Q কলাম খেয়াল করুন:
LISTEN 0 511 0.0.0.0:80 ওই 511 হলো listen backlog — যেসব কানেকশন TCP handshake সম্পন্ন করেছে কিন্তু আপনার অ্যাপ এখনো accept() করেনি তার সর্বোচ্চ সংখ্যা। আপনার অ্যাপ accept করতে বেশি ধীর হলে, queue ভরে যায় আর কার্নেল নতুন কানেকশন ড্রপ করা শুরু করে। আপনি এটা দেখবেন এভাবে:
netstat -s | grep -i listen
# 1234 SYNs to LISTEN sockets dropped load-এর সময় সেই সংখ্যা বাড়লে, আপনার অ্যাপ accept()-এর সঙ্গে তাল মেলাতে পারছে না — সাধারণত কারণ event-loop concurrency ব্লকড বা worker pool saturated।
একটা প্র্যাকটিক্যাল অডিট — কী এক্সপোজড?
একটা তরতাজা-অনুভূত VPS-এ এটা চালান:
sudo ss -tlnp | awk '$4 !~ /^127\.|^\[::1\]/ {print}' অনুবাদ: যেসব listening TCP সকেটের লোকাল অ্যাড্রেস localhost নয় সেগুলো লিস্ট করো। ওটাই আপনার পাবলিক অ্যাটাক সারফেস। প্রতিটা লাইন পড়ুন। কী listen করছে তা চিনতে না পারলে, ঘুমাতে যাওয়ার আগে খুঁজে বের করুন।
UDP ভুলবেন না
UDP সার্ভিস লুকিয়ে থাকে কারণ এদের কোনো LISTEN স্টেট নেই — UDP-তে কোনো কানেকশন নেই। এদের লিস্ট করুন এভাবে:
sudo ss -ulnp আপনি যা দেখতে পারেন:
*:53— DNS resolver (systemd-resolved বা unbound)।*:67/*:68— DHCP ক্লায়েন্ট।*:123— NTP।*:5353— mDNS (Avahi)।
Unix domain socket
সব সকেট নেটওয়ার্ক পার হয় না। Unix domain socket হলো লোকাল IPC-এর জন্য ব্যবহৃত ফাইল-সিস্টেম পাথ — দ্রুত, কোনো TCP overhead নেই। nginx PHP-FPM-এর সঙ্গে কথা বলা, আপনার অ্যাপ একটা sidecar-এর সঙ্গে কথা বলা, postgres একটা লোকাল সকেটে:
ss -xln আউটপুট এমন দেখায়:
u_str LISTEN 0 4096 /run/postgresql/.s.PGSQL.5432 ...
u_str LISTEN 0 128 /run/dbus/system_bus_socket ... এগুলো ফাইলসিস্টেমে ফাইল; সকেট ফাইলের পারমিশন নিয়ন্ত্রণ করে কে কানেক্ট করতে পারবে। Postgres-এর ডিফল্ট config OS ইউজারের সঙ্গে মেলানো ডেটাবেস ইউজার থেকে আসা লোকাল সকেট কানেকশন trust করে। এজন্যই postgres শেল ইউজার থেকে psql পাসওয়ার্ড ছাড়া কাজ করে কিন্তু একটা TCP কানেকশনের অথেন্টিকেশন দরকার।
একসঙ্গে জোড়া লাগানো — একটা ৩০-সেকেন্ডের পোর্ট অডিট
এই তিনটা কমান্ড আপনার মাসল মেমরিতে গেঁথে ফেলুন:
sudo ss -tlnp # what TCP services are listening?
sudo ss -ulnp # what UDP services are listening?
sudo ss -tn state established # who is currently connected? আপনি যদি যেকোনো অচেনা Linux বক্সে এই তিনটা চালিয়ে প্রতিটা লাইন ব্যাখ্যা করতে পারেন, আপনি এর নেটওয়ার্ক সারফেস বোঝেন।
রিক্যাপ
- একটা সকেট একটা ফাইল ডেসক্রিপ্টর। একটা listening সকেট হলো এমন একটা যা একটা পোর্টে bound আর অপেক্ষা করছে।
- লোকাল-অনলি সার্ভিসের জন্য
127.0.0.1-এ bind করুন। ডেটাবেস কখনো পাবলিকলি এক্সপোজ করবেন না। ss -tlnplistening TCP সকেট আর তাদের মালিক প্রসেস লিস্ট করে। এটা মুখস্থ করুন।- TCP স্টেট আপনাকে lifecycle বলে।
CLOSE-WAITজমতে থাকা মানে আপনার অ্যাপ লিক করছে। - accept queue সসীম — saturated অ্যাপ SYN ড্রপ করে, যা
netstat -sপ্রকাশ করে। - Unix domain socket আছে আর লোকাল IPC-এর জন্য দ্রুত। সকেট ফাইলের পারমিশন অ্যাক্সেস নিয়ন্ত্রণ করে।
পরের চ্যাপ্টার: এখন যেহেতু আপনি জানেন কী এক্সপোজড, তা লক ডাউন করার ফায়ারওয়াল।