
ps उपयोगिता, eBPF मोड़ और कंटेनर संदर्भ के साथ
psc (ps container) एक तेज़ प्रक्रिया स्कैनर है जो सिस्टम स्थिति को सटीकता और पूर्ण कंटेनर संदर्भ के साथ क्वेरी करने के लिए eBPF इटरेटर और Google CEL का उपयोग करता है।
psc कर्नेल डेटा संरचनाओं से सीधे प्रक्रिया और फ़ाइल डिस्क्रिप्टर जानकारी पढ़ने के लिए eBPF इटरेटर का उपयोग करता है। यह दृष्टिकोण है:
/proc के माध्यम से उजागर नहीं होती है। मैं उन्नत उपयोग के लिए मांग पर task_struct के कुछ फ़ील्ड्स तक पहुँचने का एक तरीका जोड़ने की भी योजना बना रहा हूँ, लेकिन यह केवल एक विचार है/proc फ़ाइल सिस्टम को पूरी तरह से बायपास करता है, जो ऐसी दृश्यता प्रदान करता है जिसे यूज़रलैंड रूटकिट या LD_PRELOAD ट्रिक्स द्वारा कमजोर नहीं किया जा सकतापारंपरिक लिनक्स उपकरण जैसे ps, lsof, और ss शक्तिशाली लेकिन अनम्य हैं। वे निश्चित प्रारूप आउटपुट करते हैं जिनके लिए grep, awk, और sed के माध्यम से व्यापक पाइपिंग की आवश्यकता होती है:
# पारंपरिक: nginx प्रक्रियाएँ ढूँढें जो root के स्वामित्व में हैं
ps aux | grep nginx | grep root | grep -v grep
# psc: वही व्यक्त करें जो आपका मतलब है
psc 'process.name == "nginx" && process.user == "root"'
# पारंपरिक: पोर्ट 443 पर स्थापित कनेक्शन वाली प्रक्रियाएँ ढूँढें
ss -tnp | grep ESTAB | grep :443 | awk '{print $6}' | cut -d'"' -f2
# psc: एक स्पष्ट अभिव्यक्ति
psc 'socket.state == established && socket.dstPort == 443'
psc प्रक्रियाओं को फ़िल्टर करने के लिए Common Expression Language (CEL) का उपयोग करता है। CEL अभिव्यक्तियाँ लगभग प्राकृतिक भाषा की तरह पढ़ी जाती हैं, जो आपकी स्क्रिप्ट को स्व-दस्तावेजीकरण और रखरखाव योग्य बनाती हैं। अब grep | awk | sed | xargs की जटिल पाइपलाइनों को डिकोड करने की आवश्यकता नहीं है।
-o फ़्लैग आपको वही फ़ील्ड्स आउटपुट करने देता है जिनकी आपको आवश्यकता है, जो पोस्ट-प्रोसेसिंग को पूरी तरह से समाप्त कर देता है:
psc 'socket.state == listen' -o process.name,socket.srcPort
सामान्य जानकारी को जल्दी से प्रिंट करने के लिए आउटपुट प्रीसेट भी उपलब्ध हैं:
psc 'socket.type == tcp && socket.dstPort == 443' -o sockets
पारंपरिक उपकरणों में कंटेनरों की कोई अवधारणा नहीं होती है। कंटेनर जानकारी प्राप्त करने के लिए cgroup पथों को पार्स करना, कंटेनर रनटाइम को क्वेरी करना, और PID को मैन्युअल रूप से सहसंबंधित करना आवश्यक होता है:
# पारंपरिक: कंटेनरीकृत प्रक्रियाएँ ढूँढें (नाजुक, अपूर्ण)
ps aux | xargs -I{} sh -c 'cat /proc/{}/cgroup 2>/dev/null | grep -q docker && echo {}'
# psc: मूल कंटेनर समर्थन
psc 'container.runtime == docker'
psc स्वचालित रूप से Docker, containerd, CRI-O, और Podman के लिए कंटेनर संदर्भ (ID, नाम, इमेज, रनटाइम, लेबल) निकालता है। किसी भी कंटेनर की प्रक्रियाओं, फ़ाइलों और नेटवर्क कनेक्शनों को सीधे होस्ट से डीबग करें:
# किसी विशिष्ट कंटेनर में सभी प्रक्रियाएँ दिखाएँ
psc 'container.name == "my-app"' --tree
# root के रूप में चलने वाले कंटेनर ढूँढें
psc 'container.runtime == docker && process.user == "root"'
# अपने इमेज के साथ कंटेनरों की सूची बनाएँ
psc 'container.id != ""' -o process.pid,process.name,container.name,container.image
Debian/Ubuntu पर:
sudo apt-get install clang llvm libbpf-dev linux-headers-$(uname -r) linux-tools-$(uname -r)
Fedora/RHEL पर:
sudo dnf install clang llvm libbpf-devel kernel-devel bpftool
# vmlinux.h उत्पन्न करें (प्रति कर्नेल संस्करण एक बार आवश्यक)
make vmlinux
# बाइनरी बनाएँ
make build
या मैन्युअल रूप से:
bpftool btf dump file /sys/kernel/btf/vmlinux format c > bpf/vmlinux.h
go generate ./...
go build -o psc
sudo make install
eBPF प्रोग्राम लोड करने के लिए psc को रूट विशेषाधिकार की आवश्यकता होती है।
# सभी प्रक्रियाओं की सूची बनाएँ
sudo psc
# सभी प्रक्रियाओं को एक पेड़ के रूप में सूचीबद्ध करें
sudo psc --tree
प्रक्रियाओं को फ़िल्टर करने के लिए पहले तर्क के रूप में एक CEL अभिव्यक्ति पास करें:
# प्रक्रिया नाम से फ़िल्टर करें
psc 'process.name == "nginx"'
# उपयोगकर्ता द्वारा फ़िल्टर करें
psc 'process.user == "root"'
# कमांड लाइन सामग्री द्वारा फ़िल्टर करें
psc 'process.cmdline.contains("--config")'
# PID रेंज द्वारा फ़िल्टर करें
psc 'process.pid > 1000 && process.pid < 2000'
# शर्तों को संयोजित करें
psc 'process.name == "bash" || process.name == "zsh"'
# केवल कंटेनरीकृत प्रक्रियाएँ दिखाएँ
psc 'container.id != ""'
# कंटेनर रनटाइम द्वारा फ़िल्टर करें (स्थिरांक: docker, containerd, crio, podman)
psc 'container.runtime == docker'
# कंटेनर नाम द्वारा फ़िल्टर करें
psc 'container.name == "nginx"'
# कंटेनर इमेज द्वारा फ़िल्टर करें
psc 'container.image.contains("nginx:latest")'
# कंटेनर प्रक्रिया पदानुक्रम देखने के लिए पेड़ के रूप में दिखाएँ
psc 'container.runtime == docker' --tree
यह समझना कि कोई प्रक्रिया क्यों मौजूद है, अक्सर उसके खुले फ़ाइल डिस्क्रिप्टर और नेटवर्क कनेक्शन को देखने की आवश्यकता होती है:
# सुनने वाले TCP सॉकेट वाली प्रक्रियाएँ ढूँढें
psc 'socket.type == tcp && socket.state == listen'
# स्थापित कनेक्शन वाली प्रक्रियाएँ ढूँढें
psc 'socket.state == established'
# किसी विशिष्ट पोर्ट से जुड़ी प्रक्रियाएँ ढूँढें
psc 'socket.dstPort == 443'
# Unix सॉकेट का उपयोग करने वाली प्रक्रियाएँ ढूँढें
psc 'socket.family == unix'
# /etc में खुली फ़ाइलों वाली प्रक्रियाएँ ढूँढें
psc 'file.path.startsWith("/etc")'
प्रक्रिया फ़ील्ड्स (process.X):
name - प्रक्रिया का नाम (स्ट्रिंग)pid - प्रक्रिया ID (int)ppid - मूल प्रक्रिया ID (int)tid - थ्रेड ID (int)euid - प्रभावी उपयोगकर्ता ID (int)ruid - वास्तविक उपयोगकर्ता ID (int)suid - सहेजा गया सेट-उपयोगकर्ता-ID (int)user - उपयोगकर्ता नाम (स्ट्रिंग)cmdline - पूर्ण कमांड लाइन (स्ट्रिंग)state - प्रक्रिया स्थिति (uint)क्षमता फ़ील्ड्स (process.capabilities.X):
effective - प्रभावी क्षमताएँ बिटमास्क (uint)permitted - अनुमत क्षमताएँ बिटमास्क (uint)inheritable - वंशानुगत क्षमताएँ बिटमास्क (uint)नेमस्पेस फ़ील्ड्स (process.namespaces.X):
net - नेटवर्क नेमस्पेस inode (int)pid - PID नेमस्पेस inode (int)mnt - माउंट नेमस्पेस inode (int)uts - UTS नेमस्पेस inode (int)ipc - IPC नेमस्पेस inode (int)cgroup - Cgroup नेमस्पेस inode (int)कंटेनर फ़ील्ड्स (container.X):
id - कंटेनर ID (स्ट्रिंग)name - कंटेनर नाम (स्ट्रिंग)image - कंटेनर इमेज (स्ट्रिंग)runtime - कंटेनर रनटाइम (स्ट्रिंग)labels - कंटेनर लेबल (मैप)फ़ाइल/सॉकेट फ़ील्ड्स (file.X या socket.X):
path - फ़ाइल पथ (स्ट्रिंग)fd - फ़ाइल डिस्क्रिप्टर नंबर (int)srcPort - स्रोत पोर्ट (int)dstPort - गंतव्य पोर्ट (int)type - सॉकेट प्रकार (tcp, udp)state - सॉकेट स्थिति (फ़िल्टरिंग के लिए, listen, established जैसे स्थिरांक का उपयोग करें)family - पता परिवार (unix, inet, inet6)unixPath - Unix सॉकेट पथ (स्ट्रिंग)fdType - FD प्रकार (file_type, socket_type)अभिव्यक्तियों में बिना उद्धरण के इनका उपयोग करें:
docker, containerd, crio, podmantcp, udpunix, inet, inet6established, listen, syn_sent, syn_recv, fin_wait1, fin_wait2, , , , , नोट: आउटपुट
ss-शैली के स्थिति नामों का उपयोग करता है:ESTAB,LISTEN,SYN-SENT, आदि। UDP सॉकेट के लिए, केवलUNCONN(असंबद्ध) याESTAB(संबद्ध) दिखाए जाते हैं क्योंकि UDP कनेक्शन रहित है।
CEL स्ट्रिंग हेरफेर फ़ंक्शन प्रदान करता है:
.contains("substr") - जाँचें कि स्ट्रिंग में सबस्ट्रिंग है या नहीं.startsWith("prefix") - जाँचें कि स्ट्रिंग उपसर्ग से शुरू होती है या नहीं.endsWith("suffix") - जाँचें कि स्ट्रिंग प्रत्यय के साथ समाप्त होती है या नहीं--tree, -t - प्रक्रियाओं को एक पेड़ के रूप में प्रदर्शित करें--no-color - रंगीन आउटपुट अक्षम करें-o, --output - कस्टम आउटपुट कॉलम (अल्पविराम-पृथक फ़ील्ड नाम या प्रीसेट)psc fields - सभी उपलब्ध CEL फ़ील्ड्स, स्थिरांक और आउटपुट प्रीसेट सूचीबद्ध करेंpsc version - संस्करण जानकारी दिखाएँ-o के साथ कस्टम आउटपुट-o फ़्लैग आपको यह निर्दिष्ट करने देता है कि कौन से फ़ील्ड प्रदर्शित करने हैं। आप सामान्य उपयोग के मामलों के लिए प्रीसेट का उपयोग कर सकते हैं या अलग-अलग फ़ील्ड निर्दिष्ट कर सकते हैं।
प्रीसेट:
sockets - प्रक्रिया जानकारी + पूर्ण सॉकेट विवरण (परिवार, प्रकार, स्थिति, पते, पोर्ट)files - प्रक्रिया जानकारी + फ़ाइल डिस्क्रिप्टर विवरण (fd, प्रकार, पथ)containers - प्रक्रिया जानकारी + कंटेनर विवरण (नाम, इमेज, रनटाइम)network - कॉम्पैक्ट नेटवर्क दृश्य (pid, नाम, प्रकार, स्थिति, पोर्ट)# प्रीसेट का उपयोग करें
psc 'socket.state == listen' -o sockets
psc 'container.id != ""' -o containers
# या अलग-अलग फ़ील्ड निर्दिष्ट करें
psc -o process.pid,process.name,process.user
psc 'socket.state == listen' -o process.pid,process.name,socket.srcPort,socket.state
जब आउटपुट में फ़ाइल/सॉकेट फ़ील्ड शामिल होते हैं और फ़िल्टर प्रति प्रक्रिया कई फ़ाइलों से मेल खाता है, तो प्रत्येक मिलान की अपनी पंक्ति होती है:
$ psc 'socket.state == listen' -o network
PID NAME TYPE STATE SRCPORT DSTPORT
1234 nginx tcp LISTEN 80 0
1234 nginx tcp LISTEN 443 0
5678 sshd tcp LISTEN 22 0
सभी वेब सर्वर ढूँढें:
psc 'process.name == "nginx" || process.name == "apache2" || process.name == "httpd"'
विशेषाधिकार प्राप्त पोर्ट पर सुनने वाली प्रक्रियाएँ ढूँढें:
psc 'socket.state == listen && socket.srcPort < 1024'
एक अलग नेटवर्क नेमस्पेस में प्रक्रियाएँ ढूँढें (कंटेनर/पॉड निरीक्षण के लिए उपयोगी):
psc 'process.namespaces.net != 4026531840' -o process.pid,process.name,process.namespaces.net
विशेषाधिकार प्राप्त प्रक्रियाओं के लिए क्षमताएँ दिखाएँ:
psc 'process.euid == 0' -o process.pid,process.name,process.capabilities.effective,process.capabilities.permitted
SUID बाइनरी के माध्यम से विशेषाधिकार बढ़ाने वाली प्रक्रियाएँ ढूँढें (वास्तविक UID प्रभावी UID से भिन्न है):
psc 'process.ruid != process.euid'
बाहरी सेवाओं से कनेक्शन वाली प्रक्रियाएँ ढूँढें:
psc 'socket.state == established && socket.dstPort == 443'
कस्टम कॉलम के साथ नेटवर्क कनेक्शन दिखाएँ:
psc 'socket.state == established' -o process.pid,process.name,socket.srcPort,socket.dstPort,socket.dstAddr
MIT
time_waitcloseclose_waitlast_ackclosingfile_type, socket_type