มาทำโปรเจกต์กันเถอะ!
เครื่องมือ Linux เช่น ps
, top
&netstat
ดีมาก
พวกเขาให้ข้อมูลมากมายเกี่ยวกับสิ่งที่เกิดขึ้นกับระบบของคุณ
- แต่มันทำงานอย่างไร
- พวกเขาได้ข้อมูลทั้งหมดมาจากไหน?
- เราจะใช้สิ่งนี้เพื่อสร้างเครื่องมือของเราเองได้อย่างไร
ในโพสต์นี้ เราจะสร้างเครื่องมือ Linux ยอดนิยมสามตัวด้วยกัน
คุณจะได้รับอาหาร 2x1 เรียนรู้เคล็ดลับของ Ruby และรับความรู้เกี่ยวกับ Linux ที่มีประโยชน์ไปพร้อม ๆ กัน! 🙂
การค้นหาข้อมูลสถานะ
ลองตอบคำถามว่าเครื่องมือเหล่านี้หาข้อมูลได้จากที่ใด
คำตอบอยู่ในระบบไฟล์ proc!
หากคุณดูภายใน /proc
ไดเร็กทอรี มันจะดูเหมือนกลุ่มของไดเร็กทอรีและไฟล์ เช่นเดียวกับไดเร็กทอรีอื่นๆ ในคอมพิวเตอร์ของคุณ
นี่ไม่ใช่ไฟล์จริง แต่เป็นเพียงวิธีที่เคอร์เนล Linux เปิดเผยข้อมูลแก่ผู้ใช้
สะดวกมากเพราะสามารถจัดการได้เหมือนไฟล์ทั่วไป ซึ่งหมายความว่าคุณสามารถอ่านได้โดยไม่ต้องใช้เครื่องมือพิเศษใดๆ
ในโลกของ Linux มีหลายสิ่งหลายอย่างที่ทำงานในลักษณะนี้
หากคุณต้องการดูตัวอย่างอื่นให้ดูที่ /dev
ไดเรกทอรี
ตอนนี้เราเข้าใจสิ่งที่เรากำลังเผชิญอยู่แล้ว มาดูเนื้อหาของ /proc
ไดเรกทอรี…
110104105111101511469114741155211655
นี่เป็นเพียงตัวอย่างเล็กๆ แต่คุณสามารถสังเกตเห็นรูปแบบได้อย่างรวดเร็ว
ตัวเลขทั้งหมดนั้นคืออะไร
ปรากฎว่านี่คือ PID (รหัสกระบวนการ)
ทุกรายการมีข้อมูลเกี่ยวกับกระบวนการเฉพาะ
หากคุณเรียกใช้ ps
คุณสามารถดูได้ว่าทุกกระบวนการมี PID เกี่ยวข้องอย่างไร:
PID TTY TIME CMD15952 pts/5 00:00:00 ps22698 pts/5 00:00:01 ทุบตี
จากนี้เราสามารถสรุปได้ว่าสิ่งที่ ps ทำนั้นเป็นเพียงการวนซ้ำ /proc
ไดเร็กทอรี &พิมพ์ข้อมูลที่พบ
มาดูกันว่ามีอะไรอยู่ในไดเร็กทอรีที่มีลำดับเลขตัวใดตัวหนึ่ง:
attrautogroupauxvcgroupclear_refscmdlinecommcpusetcwdenvironexefd
นั่นเป็นเพียงตัวอย่างเพื่อประหยัดพื้นที่ แต่เราขอแนะนำให้คุณดูรายการทั้งหมด
นี่คือรายการที่น่าสนใจบางส่วน :
รายการ | คำอธิบาย |
---|---|
comm | ชื่อโปรแกรม |
cmdline | คำสั่งที่ใช้เปิดกระบวนการนี้ |
สิ่งแวดล้อม | ตัวแปรสภาพแวดล้อมที่กระบวนการนี้เริ่มต้นด้วย |
สถานะ | สถานะกระบวนการ (กำลังทำงาน กำลังสลีป…) &การใช้หน่วยความจำ |
fd | ไดเร็กทอรีที่มี file descriptor (เปิดไฟล์, sockets…) |
เมื่อรู้อย่างนี้แล้ว เราก็เริ่มเขียนเครื่องมือได้เลย!
วิธีการแสดงรายการโปรแกรมที่ทำงานอยู่
เริ่มจากการรับรายการไดเร็กทอรีทั้งหมดภายใต้ /proc
.
เราสามารถทำได้โดยใช้ Dir
ชั้นเรียน
ตัวอย่าง :
Dir.glob("/proc/[0-9]*")
สังเกตว่าฉันใช้ช่วงตัวเลขอย่างไร เหตุผลก็คือมีไฟล์อื่นภายใต้ /proc
ที่เราไม่สนใจในตอนนี้ เราต้องการแค่ไดเร็กทอรีที่มีหมายเลขเท่านั้น
ตอนนี้ เราสามารถวนซ้ำรายการนี้และพิมพ์สองคอลัมน์ คอลัมน์แรกมี PID และอีกคอลัมน์หนึ่งมีชื่อโปรแกรม
ตัวอย่าง :
pids =Dir.glob("/proc/[0-9]*")ใส่ "PID\tCMD" ใส่ "-" * 15pids.each ทำ |pid| cmd =File.read(pid + "/comm") pid =pid.scan(/\d+/).first ใส่ "#{pid}\t#{cmd}"end
และนี่คือผลลัพธ์ :
PID CMD ----------------1 systemd2 kthreadd3 ksoftirqd/05 kworker/07 การย้ายข้อมูล/08 rcu_preempt9 rcu_bh10 rcu_sched
เฮ้ ดูเหมือนว่าเราเพิ่งสร้าง ps
! ใช่ มันไม่รองรับตัวเลือกแฟนซีทั้งหมดจากต้นฉบับ แต่เราได้ทำบางสิ่งให้ได้ผล
ใครกำลังฟังอยู่
มาลองจำลอง netstat
. กัน ทีนี้ นี่คือผลลัพธ์ที่ออกมา (ด้วย -ant
เป็นธง)
การเชื่อมต่ออินเทอร์เน็ตที่ใช้งาน (เซิร์ฟเวอร์และที่จัดตั้งขึ้น)Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN tcp 0 0 192.168.1.82:39530 182.14.172.159:22 ก่อตั้ง
เราจะหาข้อมูลนี้ได้จากที่ไหน? ถ้าคุณพูดว่า “inside /proc
" คุณถูก! หากต้องการเจาะจงมากขึ้น คุณสามารถค้นหาได้ใน /proc/net/tcp
.
แต่มีปัญหานิดหน่อย ดูไม่เหมือน netstat
เอาท์พุต!
สิ่งนี้หมายความว่าเราต้องแยกวิเคราะห์ด้วยนิพจน์ทั่วไป ตอนนี้เรามากังวลเกี่ยวกับที่อยู่ในท้องถิ่นและสถานะกัน
นี่คือ regex ที่ฉันใช้ :
LINE_REGEX =/\s+\d+:(?\w+):(? \w+) \w+:\w+ (? \w+)/
นี่จะให้ค่าเลขฐานสิบหกที่เราจำเป็นต้องแปลงเป็นทศนิยม มาสร้างชั้นเรียนที่จะทำสิ่งนี้ให้เรากันเถอะ
คลาส TCPInfo def initialize(line) @data =parse(line) end def parse(line) line.match(LINE_REGEX) end def local_port @data["local_port"].to_i(16) end # แปลงฐานสิบหกเป็นค่าปกติ สัญลักษณ์ IP def local_addr decimal_to_ip(@data["local_addr"].to_i(16)) end STATUSES ={ "0A" => "LISTENING", "01" => "ESTABLISHED", "06" => "TIME_WAIT", "08" => "CLOSE_WAIT" } รหัสสถานะ def =@data["status"] STATUSES.fetch(code, "UNKNOWN") สิ้นสุด # อย่ากังวลเรื่องนี้มากเกินไป มันเป็นคณิตศาสตร์เลขฐานสอง def decimal_to_ip(ทศนิยม) ip =[] ip <<(ทศนิยม>> 24 &0xFF) ip <<(ทศนิยม>> 16 &0xFF) ip <<(ทศนิยม>> 8 &0xFF) ip <<(ทศนิยม &0xFF) ip.join(".") สิ้นสุด
เหลือเพียงพิมพ์ผลลัพธ์ในรูปแบบตารางที่สวยงาม
ต้องการการเชื่อมต่อ 'table_print'tp
ตัวอย่างผลลัพธ์ :
สถานะ | LOCAL_PORT | LOCAL_ADDR ------------|-----------|-------------- กำลังฟัง | 5432 | 127.0.0.1 ก่อตั้งแล้ว | 39530 | 192.168.88.46
ใช่ อัญมณีชิ้นนี้ยอดเยี่ยมมาก!
ฉันเพิ่งค้นพบและดูเหมือนว่าฉันจะไม่ต้องคลำหา ljust
/ rjust
อีกครั้ง 🙂
หยุดใช้พอร์ตของฉัน!
คุณเคยเห็นข้อความนี้ไหม
มีการใช้งานอยู่แล้ว - bind(2) สำหรับพอร์ต "localhost" 5000
อืม…
ฉันสงสัยว่าโปรแกรมใดใช้พอร์ตนั้นอยู่
มาหาคำตอบกัน :
fuser -n tcp -v 5000PORT USER PID ACCESS CMD5000/tcp rubyguides 30893 F.... nc
อา มีคนร้ายของเราแล้ว!
ตอนนี้ เราสามารถหยุดโปรแกรมนี้ได้ ถ้าเราไม่ต้องการให้มันทำงาน &นั่นจะทำให้พอร์ตของเราว่าง โปรแกรม "ฟิวเซอร์" รู้ได้อย่างไรว่าใครกำลังใช้พอร์ตนี้อยู่
คุณเดามัน!
/proc
ระบบไฟล์อีกครั้ง
อันที่จริง มันรวมสองสิ่งที่เราได้กล่าวถึงไปแล้ว:การเดินผ่านรายการกระบวนการ &อ่านการเชื่อมต่อที่ใช้งานอยู่จาก /proc/net/tcp
.
เราต้องการอีกหนึ่งขั้นตอน :
ค้นหาวิธีจับคู่ข้อมูลพอร์ตที่เปิดอยู่กับ PID
ถ้าเราดูข้อมูล TCP ที่เราได้จาก /proc/net/tcp
, ไม่มี PID แต่เราสามารถใช้เลขไอโหนดได้
“ไอโหนดคือโครงสร้างข้อมูลที่ใช้แทนออบเจกต์ระบบไฟล์” – วิกิพีเดีย
เราจะใช้ไอโหนดเพื่อค้นหากระบวนการจับคู่ได้อย่างไร ถ้าเราดูภายใต้ fd
ไดเร็กทอรีของกระบวนการที่เรารู้ว่ามีพอร์ตเปิดอยู่ เราจะพบบรรทัดดังนี้:
/proc/3295/fd/5 -> socket:[12345]
ตัวเลขระหว่างวงเล็บคือหมายเลขไอโหนด ตอนนี้ สิ่งที่เราต้องทำคือวนซ้ำไฟล์ทั้งหมด &เราจะพบกระบวนการจับคู่
นี่คือวิธีหนึ่งในการทำเช่นนั้น :
x =Dir.glob("/proc/[0-9]*/fd/*").find do |fd| ไฟล์.readlink(fd).include? "socket:[#{socket_inode}]" rescue nilendpid =x.scan(/\d+/).firstname =File.readlink("/proc/#{pid}/exe") วาง "พอร์ต #{hex_port.to_i() 16)} ถูกใช้โดย #{name} (#{pid})"
ตัวอย่างผลลัพธ์:
พอร์ต 5432 ที่ใช้งานโดย /usr/bin/postgres (474)
โปรดทราบว่าคุณจะต้องเรียกใช้โค้ดนี้ในฐานะรูทหรือในฐานะเจ้าของกระบวนการ
มิฉะนั้น คุณจะไม่สามารถอ่านรายละเอียดกระบวนการภายใน /proc
.
บทสรุป
ในโพสต์นี้ คุณได้เรียนรู้ว่า Linux เปิดเผยข้อมูลจำนวนมากผ่านเสมือน /proc
ระบบไฟล์ คุณยังได้เรียนรู้วิธีสร้างเครื่องมือ Linux ยอดนิยมเช่น ps, netstat &fuser โดยใช้ข้อมูลภายใต้ /proc
.
อย่าลืมสมัครรับจดหมายข่าวด้านล่างเพื่อไม่ให้พลาดโพสต์ต่อไป 🙂