ฉันต้องการแยกวิเคราะห์/proc/net/tcp/
แต่ปลอดภัยหรือไม่
ฉันจะเปิดและอ่านไฟล์จาก/proc/
และไม่ต้องกลัวว่ากระบวนการอื่น ๆ (หรือระบบปฏิบัติการของตัวเอง) จะเปลี่ยนแปลงในเวลาเดียวกันได้อย่างไร
sysctl
ช่วยฉันแยกวิเคราะห์/proc/net/tcp/
ไฟล์ได้อย่างไร?
ฉันต้องการแยกวิเคราะห์/proc/net/tcp/
แต่ปลอดภัยหรือไม่
ฉันจะเปิดและอ่านไฟล์จาก/proc/
และไม่ต้องกลัวว่ากระบวนการอื่น ๆ (หรือระบบปฏิบัติการของตัวเอง) จะเปลี่ยนแปลงในเวลาเดียวกันได้อย่างไร
sysctl
ช่วยฉันแยกวิเคราะห์/proc/net/tcp/
ไฟล์ได้อย่างไร?
คำตอบ:
โดยทั่วไปไม่มี (ดังนั้นคำตอบส่วนใหญ่ที่นี่ผิด) มันอาจปลอดภัยขึ้นอยู่กับว่าคุณต้องการบ้านแบบใด แต่มันง่ายที่จะจบลงด้วยข้อบกพร่องในรหัสของคุณถ้าคุณถือว่ามากเกินไปเกี่ยวกับความสอดคล้องของไฟล์/proc
มา ตัวอย่างเช่นดูข้อผิดพลาดนี้ซึ่งมาจากสมมติว่า/proc/mounts
เป็นภาพที่สอดคล้องกัน
ตัวอย่างเช่น:
/proc/uptime
เป็นอะตอมโดยสิ้นเชิงอย่างที่ใครบางคนพูดถึงคำตอบอื่น - แต่เฉพาะตั้งแต่ Linux 2.6.30ซึ่งมีอายุน้อยกว่าสองปี ดังนั้นแม้แต่ไฟล์เล็ก ๆ น้อย ๆ นี้ก็ยังขึ้นอยู่กับสภาพการแข่งขันจนกระทั่งถึงตอนนั้นและยังคงอยู่ในเมล็ดส่วนใหญ่ขององค์กร ดูfs/proc/uptime.c
สำหรับแหล่งปัจจุบันหรือกระทำที่ทำให้มันอะตอม บนเคอร์เนลก่อน 2.6.30 คุณสามารถopen
ไฟล์read
บิตของมันแล้วถ้าคุณกลับมาในภายหลังและread
อีกครั้งชิ้นที่คุณได้รับจะไม่สอดคล้องกับชิ้นแรก (ฉันเพิ่งสาธิตเรื่องนี้ - ลองด้วยตัวเองเพื่อความสนุก)
/proc/mounts
เป็นatomic ภายในการread
เรียกใช้ระบบเดียว ดังนั้นหากคุณread
รวมไฟล์ทั้งหมดพร้อมกันคุณจะได้รับสแนปช็อตที่สอดคล้องกันของจุดเชื่อมต่อในระบบ อย่างไรก็ตามหากคุณใช้การread
เรียกของระบบหลายครั้ง- และถ้าไฟล์มีขนาดใหญ่สิ่งนี้จะเกิดอะไรขึ้นถ้าคุณใช้ไลบรารี I / O ปกติและไม่สนใจเรื่องนี้เป็นพิเศษ - คุณจะต้องถูกแย่งชิง เงื่อนไข. ไม่เพียง แต่คุณจะไม่ได้รับสแนปชอตที่สอดคล้องกัน แต่จุดเชื่อมต่อที่มีอยู่ก่อนที่คุณจะเริ่มต้นและไม่เคยหยุดนิ่งอยู่อาจหายไปในสิ่งที่คุณเห็น หากต้องการดูว่ามันเป็นอะตอมหนึ่งread()
, ดูที่m_start()
ในfs/namespace.c
และเห็นมันคว้าสัญญาณที่ยามรายการ mountpoints ซึ่งจะช่วยให้จนกว่าm_stop()
ซึ่งเรียกว่าเมื่อread()
เสร็จแล้ว หากต้องการดูสิ่งที่ผิดพลาดโปรดดูข้อผิดพลาดนี้จากปีที่แล้ว (อันเดียวกับที่ฉันลิงค์ด้านบน) ในซอฟต์แวร์คุณภาพสูงที่อ่าน/proc/mounts
ได้
/proc/net/tcp
ซึ่งเป็นสิ่งที่คุณถามจริง ๆ ก็มีความสอดคล้องน้อยกว่านั้น มันเป็นอะตอมเฉพาะภายในแถวของตารางแต่ละ ดูนี่ดูที่listening_get_next()
ในnet/ipv4/tcp_ipv4.c
และestablished_get_next()
ด้านล่างในไฟล์เดียวกันและดูล็อคที่พวกเขาจะออกในแต่ละรายการในทางกลับกัน ฉันไม่มีโค้ดการทำซ้ำที่สะดวกในการสาธิตการขาดความสอดคล้องจากแถวหนึ่งไปอีกแถวหนึ่ง แต่ไม่มีการล็อกที่นั่น (หรือสิ่งอื่นใด) ที่จะทำให้มันสอดคล้องกัน ซึ่งเหมาะสมถ้าคุณคิดเกี่ยวกับมัน - เครือข่ายมักเป็นส่วนที่ยุ่งสุดของระบบดังนั้นจึงไม่คุ้มค่าที่จะนำเสนอมุมมองที่สอดคล้องกันในเครื่องมือวิเคราะห์นี้
ชิ้นอื่น ๆ ที่ช่วยให้/proc/net/tcp
อะตอมในแต่ละแถวเป็นบัฟเฟอร์ในseq_read()
ซึ่งคุณสามารถอ่านใน fs/seq_file.c
สิ่งนี้ทำให้มั่นใจได้ว่าเมื่อคุณread()
เป็นส่วนหนึ่งของแถวข้อความของทั้งแถวจะถูกเก็บไว้ในบัฟเฟอร์เพื่อให้แถวถัดไปread()
จะได้รับส่วนที่เหลือของแถวนั้นก่อนที่จะเริ่มแถวใหม่ มีการใช้กลไกเดียวกันนี้/proc/mounts
เพื่อเก็บอะตอมมิกของแถวแต่ละแถวแม้ว่าคุณจะread()
โทรหลายครั้งและก็เป็นกลไกที่/proc/uptime
ในเมล็ดที่ใหม่กว่านั้นก็ยังคงใช้งานได้เหมือนเดิม กลไกนั้นไม่ได้บัฟเฟอร์ไฟล์ทั้งหมดเนื่องจากเคอร์เนลระมัดระวังเกี่ยวกับการใช้หน่วยความจำ
ไฟล์ส่วนใหญ่/proc
จะมีความสอดคล้องอย่างน้อย/proc/net/tcp
กับแต่ละแถวจะมีรูปภาพที่สอดคล้องกันของหนึ่งรายการในข้อมูลใดก็ตามที่พวกเขากำลังให้เพราะส่วนใหญ่จะใช้seq_file
สิ่งที่เป็นนามธรรมเดียวกัน ตาม/proc/uptime
ตัวอย่างแสดงให้เห็นว่าบางไฟล์ยังคงถูกย้ายไปใช้seq_file
เมื่อเร็ว ๆ นี้ในปี 2009 ฉันพนันได้ว่ายังมีบางอย่างที่ใช้กลไกที่เก่ากว่าและไม่มีแม้แต่ระดับอะตอมมิก คำเตือนเหล่านี้ไม่ค่อยมีการบันทึกไว้ สำหรับไฟล์ที่กำหนดการรับประกันเพียงอย่างเดียวของคุณคือการอ่านต้นฉบับ
ในกรณีของ/proc/net/tcp
คุณสามารถอ่านและแยกแต่ละบรรทัดโดยไม่ต้องกลัว แต่ถ้าคุณพยายามที่จะดึงข้อสรุปใด ๆ จากหลายบรรทัดพร้อมกัน - ระวังกระบวนการอื่น ๆ และเคอร์เนลจะเปลี่ยนมันในขณะที่คุณอ่านมันและคุณอาจจะสร้างข้อบกพร่อง
clock_gettime(2)
กับCLOCK_MONOTONIC
(แม้ว่าอาจจะมีเทคนิคที่ฉันไม่รู้จักที่นี่ sysinfo(2)
สำหรับลินุกซ์ที่คุณยังมีตัวเลือกของ
แม้ว่าแฟ้มใน/proc
ปรากฏเป็นไฟล์ปกติใน userspace พวกเขาไม่ได้จริงๆไฟล์ แต่หน่วยงานที่สนับสนุนการดำเนินงานไฟล์มาตรฐานจาก userspace ( open
, read
, close
) โปรดทราบว่านี่ค่อนข้างแตกต่างจากการมีไฟล์ธรรมดาบนดิสก์ที่เคอร์เนลเปลี่ยนไป
เคอร์เนลทั้งหมดจะพิมพ์สถานะภายในลงในหน่วยความจำของตัวเองโดยใช้sprintf
ฟังก์ชัน -like และหน่วยความจำนั้นจะถูกคัดลอกลงใน userspace ทุกครั้งที่คุณread(2)
เรียกใช้ระบบ
เคอร์เนลจัดการกับการเรียกเหล่านี้ในวิธีที่แตกต่างอย่างสิ้นเชิงกว่าสำหรับไฟล์ปกติซึ่งอาจหมายความว่าสแน็ปช็อตทั้งหมดของข้อมูลที่คุณจะอ่านอาจจะพร้อมในเวลาที่คุณopen(2)
ในขณะที่เคอร์เนลทำให้แน่ใจว่าการโทรพร้อมกันนั้น ฉันไม่ได้อ่านมันเลย แต่มันก็ไม่สมเหตุสมผลเลย
คำแนะนำของฉันคือการดูการใช้งานไฟล์ proc ใน Unix รสของคุณโดยเฉพาะ นี่เป็นปัญหาการใช้งานจริง (ตามรูปแบบและเนื้อหาของเอาต์พุต) ที่ไม่ได้ควบคุมโดยมาตรฐาน
ตัวอย่างที่ง่ายที่สุดคือการใช้งานuptime
ไฟล์ proc ใน Linux สังเกตว่าการผลิตบัฟเฟอร์ทั้งหมดในฟังก์ชั่นการโทรกลับที่ให้single_open
ไว้
proc
ไฟล์นั้นเป็นไฟล์ธรรมดาที่เปิดเพื่อเขียนโดยเคอร์เนล
open()
ผิดสำหรับหลาย ๆ ไฟล์และโดยเฉพาะอย่างยิ่งสำหรับ/proc/net/tcp
OP ที่เกี่ยวข้อง วิธีนี้เหมาะสมถ้าคุณคิดค่าใช้จ่ายในการให้ความหมายเหล่านั้น - คุณต้องทำอะไรบางอย่างเช่นล็อคโครงสร้างข้อมูลภายในที่บันทึกการเชื่อมต่อ TCP ทั้งหมดซึ่งในระบบไม่ว่างเป็นหายนะแม้ว่าคุณจะค้างไว้นาน เพียงพอที่จะสแกนและจัดรูปแบบข้อมูลไปยังบัฟเฟอร์ ดูคำตอบของฉันสำหรับรายละเอียดเกี่ยวกับสิ่งที่เกิดขึ้นจริง
/ proc เป็นระบบไฟล์เสมือนจริง ๆ แล้วมันให้มุมมองที่สะดวกของเคอร์เนลภายใน แน่นอนว่ามันปลอดภัยที่จะอ่าน (นั่นคือเหตุผลที่อยู่ที่นี่) แต่มีความเสี่ยงในระยะยาวเนื่องจากภายในของไฟล์เสมือนเหล่านี้อาจมีการพัฒนาด้วยเคอร์เนลเวอร์ชันใหม่กว่า
แก้ไข
มีข้อมูลเพิ่มเติมในเอกสารประกอบ proc ใน Linux kernel docบทที่ 1.4 ระบบเครือข่ายฉันไม่สามารถค้นหาข้อมูลที่มีการเปลี่ยนแปลงตลอดเวลา ฉันคิดว่ามันค้างเมื่อเปิด แต่ไม่สามารถมีคำตอบที่ชัดเจน
EDIT2
จากข้อมูลของSco doc (ไม่ใช่ linux แต่ฉันค่อนข้างมั่นใจว่าทุกอย่างของ * nix นั้นเป็นแบบนั้น)
แม้ว่าสถานะกระบวนการและจากนั้นเนื้อหาของไฟล์ / proc สามารถเปลี่ยนจากทันทีเป็นทันที แต่การอ่าน (2) ของไฟล์ / proc นั้นรับประกันว่าจะส่งกลับสถานะการเป็นตัวแทนของ `` สติ '' นั่นคือการอ่านจะเป็น สแน็ปช็อตอะตอมมิกของสถานะของกระบวนการ ไม่มีการรับประกันดังกล่าวกับการอ่านต่อเนื่องที่นำไปใช้กับไฟล์ / proc สำหรับกระบวนการทำงาน นอกจากนี้อะตอมมิกซิตี้ไม่ได้รับประกันเป็นพิเศษสำหรับ I / O ใด ๆ ที่นำไปใช้กับไฟล์ as (address-space) เนื้อหาของพื้นที่ที่อยู่ของกระบวนการใด ๆ อาจมีการแก้ไขพร้อมกันโดย LWP ของกระบวนการนั้นหรือกระบวนการอื่น ๆ ในระบบ
proc
ราวกับว่ามันมีพฤติกรรมที่คล้ายกันระหว่างเมล็ดที่แตกต่างกัน ) จะพาคุณไปสู่โลกแห่งความเจ็บปวด
/proc/net/tcp
ซึ่งเป็นข้อกังวลหลักของ OP ค่อนข้างเฉพาะแต่ละแถวในผลลัพธ์คืออะตอม ดูคำตอบของฉันสำหรับรายละเอียด
procfs API ในเคอร์เนล Linux จัดเตรียมอินเตอร์เฟสเพื่อให้แน่ใจว่าการอ่านส่งคืนข้อมูลที่สอดคล้องกัน __proc_file_read
อ่านความคิดเห็นใน รายการ 1) ในบล็อกความคิดเห็นขนาดใหญ่จะอธิบายถึงอินเทอร์เฟซนี้
ที่ถูกกล่าวว่ามันเป็นของหลักสูตรถึงการใช้งานของไฟล์ proc ที่เฉพาะเจาะจงเพื่อใช้อินเตอร์เฟซนี้อย่างถูกต้องเพื่อให้แน่ใจว่าข้อมูลที่ส่งคืนมีความสอดคล้อง ดังนั้นเพื่อตอบคำถามของคุณ: ไม่เคอร์เนลไม่รับประกันความสอดคล้องของไฟล์ proc ระหว่างการอ่าน แต่ให้วิธีการใช้งานของไฟล์เหล่านั้นเพื่อให้สอดคล้อง
/proc
ไม่ได้มีความสอดคล้องกัน ดูคำตอบของฉันสำหรับรายละเอียด
__proc_file_read()
seq_file
ดูความคิดเห็นที่ค่อนข้างทำให้โกรธ (โดย Linus) เหนือความคิดเห็นบล็อกยาว
ฉันมีแหล่งที่มาสำหรับ Linux 2.6.27.8 ที่มีประโยชน์เนื่องจากฉันกำลังพัฒนาไดรเวอร์ในขณะนี้บนเป้าหมาย ARM ที่ฝังอยู่
linux-2.6.27.8-lpc32xx/net/ipv4/raw.c
ตัวอย่างเช่นไฟล์ ... ที่บรรทัด 934 มี
seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
i, src, srcp, dest, destp, sp->sk_state,
atomic_read(&sp->sk_wmem_alloc),
atomic_read(&sp->sk_rmem_alloc),
0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
ซึ่งผลลัพธ์
[wally@zenetfedora ~]$ cat /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 15160 1 f552de00 299
1: 00000000:C775 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 13237 1 f552ca00 299
...
in function raw_sock_seq_show()
ซึ่งเป็นส่วนหนึ่งของลำดับชั้นของฟังก์ชันการจัดการprocfs ข้อความไม่ได้ถูกสร้างขึ้นจนกว่าจะมีการread()
ร้องขอ/proc/net/tcp
ไฟล์ซึ่งเป็นกลไกที่เหมาะสมเนื่องจากการอ่านprocfsนั้นเป็นเรื่องปกติที่พบได้น้อยกว่าการอัพเดทข้อมูล
บางคนขับ (เช่นเหมือง) ใช้ฟังก์ชั่น proc_read sprintf()
ที่มีเพียงหนึ่งเดียว ความซับซ้อนพิเศษในการใช้งานไดรเวอร์หลักคือการจัดการเอาต์พุตที่มีความยาวมากซึ่งอาจไม่พอดีกับบัฟเฟอร์กลางและเคอร์เนลพื้นที่ระหว่างการอ่านครั้งเดียว
ฉันทดสอบว่าด้วยโปรแกรมที่ใช้บัฟเฟอร์การอ่าน 64K แต่มันส่งผลให้บัฟเฟอร์พื้นที่เคอร์เนลของ 3072 ไบต์ในระบบของฉันสำหรับ proc_read เพื่อส่งคืนข้อมูล จำเป็นต้องโทรหลายครั้งด้วยตัวชี้ที่ก้าวหน้าเพื่อให้ได้รับมากกว่าข้อความที่ส่งคืน ฉันไม่ทราบว่าวิธีที่ถูกต้องในการทำให้ข้อมูลที่ส่งคืนสอดคล้องกันเมื่อต้องการมากกว่าหนึ่ง i / o แน่นอนว่าแต่ละรายการ/proc/net/tcp
มีความสอดคล้องกันในตัวเอง มีความเป็นไปได้บางอย่างที่เส้นข้างกันเป็นภาพรวมในเวลาที่ต่างกัน
ifstream
มันจะไม่ปลอดภัย แต่ถ้าฉันใช้read
มันจะปลอดภัยหรือไม่ หรือifstream
ใช้ภายในread
? แล้วคุณแนะนำอะไร?
/proc/net/tcp
ถูกจัดรูปแบบอย่างไรและไม่เกี่ยวข้องกับวิธีการอ่านข้อมูลของทุกคน
/proc/net/tcp
) ไม่ได้มาจากสแนปชอตเดียวกัน ดูคำตอบของฉันสำหรับคำอธิบาย
ไม่มีข้อบกพร่องที่ไม่ทราบสาเหตุมีเงื่อนไขการแข่งขัน/proc
ที่จะนำไปสู่การอ่านข้อมูลที่เสียหายหรือข้อมูลเก่าและใหม่ ในแง่นี้มันปลอดภัย อย่างไรก็ตามยังคงมีสภาพการแข่งขันที่ข้อมูลส่วนใหญ่ที่คุณอ่าน/proc
นั้นอาจล้าสมัยทันทีที่มีการสร้างและแม้กระทั่งช่วงเวลาที่คุณอ่าน / ประมวลผล สำหรับกระบวนการอินสแตนซ์สามารถตายได้ตลอดเวลาและกระบวนการใหม่สามารถกำหนด pid เดียวกัน; รหัสกระบวนการเดียวที่คุณสามารถใช้ได้โดยไม่มีเงื่อนไขการแข่งขันคือกระบวนการลูกของคุณเอง กันไปสำหรับข้อมูลเครือข่าย (เปิดพอร์ต ฯลฯ ) และส่วนใหญ่ของข้อมูล/proc
มา ฉันคิดว่ามันเป็นการปฏิบัติที่ไม่ดีและอันตรายที่ต้องพึ่งพาข้อมูลใด ๆ/proc
มีความถูกต้องยกเว้นข้อมูลเกี่ยวกับกระบวนการของคุณและกระบวนการลูก แน่นอนว่ามันอาจจะมีประโยชน์ในการนำเสนอข้อมูลอื่น ๆ จาก/proc
ผู้ใช้ / ผู้ดูแลระบบสำหรับข้อมูล / การบันทึก / ฯลฯ วัตถุประสงค์
getpid()
) ดังนั้นจะต้องปลอดภัย
/proc
อินเทอร์เฟซเกี่ยวข้องพวกเขาทั้งหมดมีจุดอ่อนและจุดแข็งเหมือนกัน อย่างไรก็ตาม OP จะถามเกี่ยวกับข้อมูลเกี่ยวกับไดรเวอร์อุปกรณ์ไม่ใช่กระบวนการ
N
เป็นกระบวนการลูกของคุณคุณสามารถมั่นใจได้ว่า pid N
ยังคงอ้างถึงกระบวนการเดียวกัน (อาจถูกยกเลิก) จนกว่าคุณจะเรียกใช้wait
ฟังก์ชัน -family สิ่งนี้ทำให้มั่นใจได้ว่าจะไม่มีการแข่งขัน
เมื่อคุณอ่านจากไฟล์ / proc เคอร์เนลกำลังเรียกใช้ฟังก์ชั่นที่ได้ลงทะเบียนล่วงหน้าเพื่อให้เป็นฟังก์ชั่น "อ่าน" สำหรับไฟล์ proc นั้น ดู__proc_file_read
ฟังก์ชั่นใน fs / proc / generic.c
ดังนั้นความปลอดภัยของ proc read จึงปลอดภัยเท่ากับฟังก์ชันที่เคอร์เนลเรียกใช้เพื่อตอบสนองการร้องขอการอ่าน หากฟังก์ชั่นนั้นล็อคข้อมูลทั้งหมดที่ถูกสัมผัสและกลับมาหาคุณในบัฟเฟอร์อย่างปลอดภัยแสดงว่าการอ่านโดยใช้ฟังก์ชันนั้นปลอดภัยอย่างสมบูรณ์ เนื่องจากไฟล์ proc เช่นไฟล์ที่ใช้สำหรับการตอบสนองการร้องขอการอ่านไปยัง / proc / net / tcp ได้รับการรอสักครู่และได้รับการตรวจสอบอย่างละเอียดพวกเขามีความปลอดภัยมากที่สุดเท่าที่จะทำได้ ที่จริงแล้วยูทิลิตี้ลีนุกซ์ทั่วไปจำนวนมากนั้นพึ่งพาการอ่านจากระบบไฟล์ proc และการจัดรูปแบบเอาต์พุตในวิธีที่แตกต่างกัน (นอกหัวฉันคิดว่า 'ps' และ 'netstat' ทำสิ่งนี้)
เช่นเคยคุณไม่ต้องใช้คำพูดของฉันมัน คุณสามารถดูแหล่งที่มาเพื่อสงบความกลัวของคุณ เอกสารต่อไปนี้จาก proc_net_tcp.txt บอกคุณว่าฟังก์ชัน "อ่าน" สำหรับ / proc / net / tcp live ดังนั้นคุณสามารถดูรหัสจริงที่ทำงานเมื่อคุณอ่านจากไฟล์ proc นั้นและตรวจสอบด้วยตัวคุณเองว่าไม่มี อันตรายจากการล็อค
เอกสารนี้อธิบายถึงอินเตอร์เฟส / proc / net / tcp และ / proc / net / tcp6
โปรดทราบว่าอินเทอร์เฟซเหล่านี้ถูกคัดค้าน tcp_diag อินเตอร์เฟส / proc เหล่านี้จัดเตรียมข้อมูลเกี่ยวกับการเชื่อมต่อ TCP ที่แอ็คทีฟในปัจจุบันและถูกนำไปใช้โดย tcp4_seq_show () ใน net / ipv4 / tcp_ipv4.c และ tcp6_seq_show () ใน net / ipv6 / tcp_ipv6.c ตามลำดับ