আপনি কেন পোর্ট স্ক্যানার লিখতে চাবেন?
পোর্ট স্ক্যানার লিখা TCP প্রোটোকলের বেসিক শিখতে একটি চমৎকার উপায়, যা অধিকাংশ ইন্টারনেট প্রোটোকলের (HTTP ও SSH সহ) ট্রান্সপোর্ট লেয়ার।
এছাড়া এটি রুবি নেটওয়ার্ক প্রোগ্রামিং কীভাবে কাজ করে সে সম্পর্কে আরও জানার জন্য একটি ভালো এক্সারসাইজ।
চলুন পোর্ট নিয়ে কথা বলা শুরু করি!
পোর্ট কী?
পোর্ট নিয়ে কথা বলার সময় আমরা আসলে কী নিয়ে কথা বলি? অপারেটিং সিস্টেম লেভেলে একটি পোর্ট শুধু একটি প্রসেসের সাথে যুক্ত একটি "ফাইল ডেসক্রিপ্টর"।
একটি ফাইল ডেসক্রিপ্টর শুধু একটি নম্বর যা একটি খোলা I/O চ্যানেল রেফারেন্স করতে ব্যবহৃত হয়, যেমন stdout (স্ট্যান্ডার্ড আউটপুট), একটি নেটওয়ার্ক সকেট বা একটি ফাইল।
যখন OS একটি TCP/IP প্যাকেট পায়, এটি ডেস্টিনেশন পোর্টে তাকিয়ে এবং এই পোর্টে লিসেন কর रहे কোনো প্রসেস খুঁজে বের করার চেষ্টা করে।
তারপর যদি কোনো লিসেনিং প্রসেস থাকে, প্যাকেটটি সেটি ডেলিভার করা হয়।
পোর্ট রেঞ্জ
মোট ৬৫,৫৩৫টি পোর্ট উপলব্ধ, কিন্তু প্র্যাক্টিসে সবগুলো রেগুলারলি ব্যবহৃত হয় না।
পোর্টগুলো ৩টি গ্রুপে ভাগ করা যায়:
| রেঞ্জ | নাম | উদাহরণ |
|---|---|---|
1-1023 |
ওয়েল-নোণ পোর্টস | 22 (SSH), 80 (HTTP), 443 (HTTPS) |
1024-49151 |
রেজিস্টার্ড পোর্টস | 3306 (MySQL), 5432 (PostgreSQL) |
49152-65535 |
এফিমারাল পোর্টস | Chrome, Firefox |
দ্বিতীয় রেঞ্জের পোর্টগুলো IANA (ইন্টারনেট অ্যাসাইনড নাম্বারস অথরিটি) দিয়ে অ্যাসাইন করা হয়।
এবং তৃতীয় রেঞ্জটি "ডাইনামিক" বা "এফিমারাল" পোর্টের জন্য ব্যবহৃত হয়, এগুলো কনেকশনের ক্লায়েন্ট সাইড যা সার্ভার থেকে ডেটা গ্রহণ করতে ব্যবহৃত হয়।
TCP কমিউনিকেশনের বেসিক
এখন আপনি পোর্ট নিয়ে আরও পরিচিত, কিন্তু আমরা এখনও পোর্ট স্ক্যানার লিখতে প্রস্তুত নই।
প্রথমে, আমাদের আলোচনা করতে হবে একটি পোর্ট খোলা থাকতে কী বোঝায়। তারপর আমরা নেটওয়ার্ক লেভেলে একটি ওপেন পোর্ট ও একটি ক্লোজড পোর্টের আচরণ পরীক্ষা করব যাতে আমরা সেগুলো আলাদা করতে পারি।
আপনি কীভাবে জানবেন একটি পোর্ট খোলা কিনা?
একটি ওপেন পোর্ট মানে শুধু যে অন্য দিকে একটি অ্যাপ্লিকেশন লিসেন করছে এবং আমাদের সেটি অ্যাক্সেসible (ফায়ারউয়াল দ্বারা ব্লক করা নয়)।
চলুন দেখি কীভাবে একটি নতুন TCP কানেকশন শুরু হয়।

একটি নতুন TCP কানেকশন একটি SYN প্যাকেট দিয়ে শুরু হয়। এই প্যাকেটটি একটি নতুন কানেকশনের শুরু বোঝায়।
তিনটি সম্ভাব্য ফলাফল আছে:
- সার্ভার
SYN/ACKদিয়ে উত্তর দেয় — এর মানে সেটি কানেকশন স্থাপনের জন্য রেডি - সার্ভার
RSTপ্যাকেট দিয়ে উত্তর দেয় — এর মানে কানেকশনটি রিজেক্ট করা হয়েছে - সার্ভার যেকোনো উত্তর দেয় না (কিছু ফায়ারউয়াল এটিকে DROP পলিসি হিসেবে ইমপ্লিমেন্ট করে)
যদি ক্লায়েন্ট SYN/ACK প্যাকেট পায়, তবে এটি ACK প্যাকেট পাঠিয়ে কানেকশন স্থাপন সম্পন্ন করতে পারে।
একে "থ্রি-ওয়ে হ্যান্ডশейক" বলা হয়।
নোট: এটি ঘটতে দেখার একটি চমৎকার উপায় হলো tcpdump বা wireshark এর মতো নেটওয়ার্কিং টুল ব্যবহার করা। এই টুলগুলো আপনাকে আপনার সিস্টেমে আসা ও যাওয়া প্রতিটি প্যাকেট দেখতে দেয়।
tshark (ওয়ায়ারশার্কের কমান্ড-লাইন ইন্টারফেস) থেকে একটি উদাহরণ কানেকশন:

এখন যেহেতু আপনার TCP কানেকশন কীভাবে স্থাপিত হয় সে সম্পর্কে বেসিক ধারণা আছে, আমরা একটি সিম্পল পোর্ট স্ক্যানার লিখতে পারি।
চলুন একটি পোর্ট স্ক্যানার লিখি!
আমাদের স্ক্যানার লিখতে সবচেয়ে সহজ উপায় হলো TCPSocket ব্যবহার করে একটি নতুন TCP কানেকশন খোলা এবং তারপর এই ফ্যাক্টের ওপর নির্ভর করা যে একটি রিজেক্টেড কানেকশন Errno::ECONNREFUSED এক্সসেপশন রেইজ করবে।
কোডটি এখানে:
require 'socket'
PORT = ARGV[0] || 22
HOST = ARGV[1] || 'localhost'
begin
socket = TCPSocket.new(HOST, PORT)
status = "open"
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT
status = "closed"
end
puts "Port #{PORT} is #{status}."
এই কোডের কিছু সীমাবদ্ধতা আছে:
আমরা একবারে শুধু একটি পোর্ট স্ক্যান করতে পারি। প্রায়শই আপনি পোর্টের একটি রেঞ্জ স্ক্যান করতে চান যাতে একটি নির্দিষ্ট হোস্টে কোন সার্ভিসেস এক্সপোজড আছে সেটি সম্পর্কে ভালো ধারণা পাওয়া যায়।
এই কোডের আরেকটি সীমাবদ্ধতা হলো নন-রেসপন্ডিং পোর্ট (আমি যা তৃতীয় ফলাফল বলেছিলাম) আপনাকে প্রায় ২০ সেকেন্ড অপেক্ষা করাতে পারে যতক্ষণ না কানেকশন টাইমআউট হয়।
এটি সমাধান করা যায় connect_nonblock, IO.select ও Socket ( TCPSocket এর পরিবর্তে, যা অবজেক্ট তৈরি হওয়ার সাথে সাথে কানেকশন শুরু করে) এর কম্বিনেশন দিয়ে।
উদাহরণ:
require 'socket'
TIMEOUT = 2
def scan_port(port)
socket = Socket.new(:INET, :STREAM)
remote_addr = Socket.sockaddr_in(port, 'www.example.com')
begin
socket.connect_nonblock(remote_addr)
rescue Errno::EINPROGRESS
end
_, sockets, _ = IO.select(nil, [socket], nil, TIMEOUT)
if sockets
p "Port #{port} is open"
else
# পোর্ট বন্ধ
end
end
PORT_LIST = [21,22,23,25,53,80,443,3306,8080]
threads = []
PORT_LIST.each { |i| threads << Thread.new { scan_port(i) } }
threads.each(&:join)
IO.select কলটি অপেক্ষা করবে যতক্ষণ না সকেট ডেটা রিসিভ করার জন্য রেডি হয় (যা মানে এটি খোলা) বা TIMEOUT সময় কাটে না যায়, এরপর আমরা অনুমান করতে পারি পোর্টটি হয় বন্ধ আছে অথবা কানেকশন রিকোয়েস্ট ইগনোর করছে।
তাহলে, লার্নিং এক্সারসাইজ হিসেবে এটি সব ঠিক আছে, কিন্তু আপনার যদি একটি প্রপার পোর্ট স্ক্যানার দরকার হয় তবে nmap এর মতো কিছু ব্যবহার করা উচিত।
Nmap ওপেন সোর্স এবং ১৫ বছরের বেশি ধরে এক্টিভ ডেভেলপমেন্টের অধীন।
Nmap আউটপুট এরকম দেখায়:

এটা অনেক ইনফো, তাই আপনাকে মনে রাখতে সাহায্য করতে এই পোস্ট থেকে শিখা ২টি নতুন জিনিস কমেন্টে লিখুন 🙂
সারসংক্ষেপ
এই পোস্টে আপনি শিখেছেন পোর্ট কী, বিভিন্ন পোর্ট রেঞ্জ, TCP কানেকশন কীভাবে শুরু হয় (থ্রি-ওয়ে হ্যান্ডশейক) এবং রুবি ব্যবহার করে একটি বেসিক পোর্ট স্ক্যানার কীভাবে লিখতে হয়।
যদি এই পোস্ট আপনার ভালো লাগে তবে এটি শেয়ার করুন যাতে আরও অনেক মানুষ এর উপভোগ করতে পারে 🙂