Bài viết này hướng dẫn dùng lệnh lsof cơ bản trên hệ điều hành Linux.
1. Giới thiệu lsof
Lệnh lsof
(list open files) là lệnh được sử dụng để liệt kê thông tin về các tệp được mở bởi các quy trình khác nhau. Trong hệ điều hành Linux, mọi thứ là một tập tin(ví dụ như: pipes, sockets, directories, devices,...). Lệnh lsof
được phát triển và hỗ trợ bởi Victor A. Abell. Chương trình sẽ liệt kê những tệp đang mở và tiến trình nào đang sử dụng chúng.
2. Cài đặt lsof
Lệnh lsof
có sẵn trên hầu hết các bản phân phối Linux. Nếu không được cài đặt sẳn chúng ta thực hiện như sau:
Đối với bản phân phối Debian/Ubuntu:
apt-get install lsof
Đối với với bản phân phối RHEL/CentOS:
yum install lsof
3. Sử dụng lsof
3.1. Lệnh lsof với tập tin
👉 Ví dụ 1: Liệt kê tất cả các tệp đang mở
Lệnh lsof
sẽ cung cấp danh sách tất cả các tệp đang mở thuộc về tất cả các quy trình đang hoạt động.
[root@test1 ~]# lsof
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
lsof 28207 root 0u CHR 136,0 0t0 3 /dev/pts/0
lsof 28207 root 1u CHR 136,0 0t0 3 /dev/pts/0
lsof 28207 root 2u CHR 136,0 0t0 3 /dev/pts/0
lsof 28207 root 3r DIR 0,3 0 1 /proc
lsof 28207 root 4r DIR 0,3 0 231727 /proc/28207/fd
lsof 28207 root 5w FIFO 0,9 0t0 231732 pipe
lsof 28207 root 6r FIFO 0,9 0t0 231733 pipe
lsof 28208 root cwd DIR 8,2 4096 2097217 /root
lsof 28208 root rtd DIR 8,2 263 64 /
lsof 28208 root txt REG 8,2 154184 6505411 /usr/sbin/lsof
...
Theo mặc định một tệp được hiển thị trên mỗi dòng. Chúng ta sẽ tìm hiểu ý nghĩa của cột FD và TYPE:
Cột FD đại diện cho bộ mô tả tập tin. Một số giá trị thường gặp của FD là:
- cwd: Thư mục làm việc hiện tại
- txt: Tập tin văn bản
- mem: Tập tin ánh xạ bộ nhớ
- mmap: Thiết bị ánh xạ bộ nhớ
- Number: Mô tả tập tin thực tế. Ký tự sau số biểu thị chế độ sau r để đọc, w để viết, u để đọc và viết.
Cột TYPE chỉ định loại tệp. Một số giá trị thường gặp của TYPE là:
- REG: Tệp thông thường
- DIR: Thư mục
- FIFO: First In First Out
- CHR: Tập tin character đặc biệt
Để tìm hiểu danh sách đầy đủ về FD và TYPE chúng ta chạy lệnh sau: man lsof
.
👉 Ví dụ 2: Liệt kê các tệp đã mở trong một thư mục
Để liệt kê các tệp đã mở trong một thư mục chúng ta sử dụng tùy chọn +D
như bên dưới:
[root@test1 ~]# lsof +D /var/log/
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
rsyslogd 13071 root 5w REG 8,2 11406 2103130 /var/log/messages
rsyslogd 13071 root 6w REG 8,2 4692 2103128 /var/log/cron
rsyslogd 13071 root 7w REG 8,2 678 2103131 /var/log/secure
auditd 13099 root 5w REG 8,2 1249123 2419921 /var/log/audit/audit.log
tuned 13234 root 3w REG 8,2 43507 6789997 /var/log/tuned/tuned.log
👉 Ví dụ 3: Liệt kê các tệp đã mở dựa vào tên tiến trình
Chúng ta có thể liệt kê các tệp được mở bằng tên tiến trình, sử dụng tùy chọn -c
. Chúng ta thực hiện như bên dưới:
[root@test1 ~]# lsof -c ssh
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 8352 root cwd DIR 8,2 263 64 /
sshd 8352 root rtd DIR 8,2 263 64 /
sshd 8352 root txt REG 8,2 853040 6439738 /usr/sbin/sshd
sshd 8352 root DEL REG 8,2 6292703 /usr/lib64/libnss_files-2.17.so;5c94fef7
sshd 8352 root mem REG 8,2 68192 6382963 /usr/lib64/libbz2.so.1.0.6
sshd 8352 root DEL REG 8,2 6357643 /usr/lib64/libelf-0.170.so
...
👉 Ví dụ 4: Liệt kê các tệp được mở bởi một người dùng cụ thể
Để tìm danh sách các tệp được mở bởi một người dùng cụ thể sử dụng tùy chọn '-u'. Cú pháp như sau:
lsof -u user
Khi chúng ta muốn liệt kê các tệp được mở bởi các người dùng nhưng loại trừ 1 người dùng chúng ta sử dụng tùy chọn sau -u ^
thực hiện như bên dưới:
[root@test1 ~]# lsof -u ^dang
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
tuned 13234 13268 root 8u a_inode 0,10 0 5074 [eventfd]
tuned 13234 13268 root 9r FIFO 0,9 0t0 48048 pipe
tuned 13234 13268 root 10w FIFO 0,9 0t0 48048 pipe
tuned 13234 13268 root 11w CHR 10,61 0t0 6812 /dev/cpu_dma_latency
tuned 13234 13268 root 18u a_inode 0,10 0 5074 [eventpoll]
udisksd 16939 root cwd DIR 8,2 263 64 /
udisksd 16939 root rtd DIR 8,2 263 64 /
udisksd 16939 root txt REG 8,2 434880 73402403 /usr/libexec/udisks2/udisksd
...
👉 Ví dụ 5: Liệt kê tất cả các tệp đang mở theo một tiến trình
Bạn có thể liệt kê tất cả các tệp được mở bởi một tiến trình cụ thể bằng tùy chọn -p
.
[root@test1 ~]# lsof -p 8352
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 8352 root cwd DIR 8,2 263 64 /
sshd 8352 root rtd DIR 8,2 263 64 /
sshd 8352 root txt REG 8,2 853040 6439738 /usr/sbin/sshd
sshd 8352 root DEL REG 8,2 6292703 /usr/lib64/libnss_files-2.17.so;5c94fef7
sshd 8352 root mem REG 8,2 68192 6382963 /usr/lib64/libbz2.so.1.0.6
sshd 8352 root DEL REG 8,2 6357643 /usr/lib64/libelf-0.170.so
sshd 8352 root mem REG 8,2 19896 6383002 /usr/lib64/libattr.so.1.1.0
sshd 8352 root mem REG 8,2 15688 6383311 /usr/lib64/libkeyutils.so.1.5
sshd 8352 root DEL REG 8,2 6383629 /usr/lib64/libkrb5support.so.0.1;5c94fef7
sshd 8352 root mem REG 8,2 11448 6292340 /usr/lib64/libfreebl3.so
sshd 8352 root mem REG 8,2 251832 6357565 /usr/lib64/libnspr4.so
sshd 8352 root mem REG 8,2 20096 6357566 /usr/lib64/libplc4.so
👉 Ví dụ 7: Thực thi lsof trong chế độ lặp lại
Lệnh lsof
có chế độ Lặp lại. Chế độ lặp lại có thể được bật bằng cách sử dụng tuỳ chọn -r
hoặc +r
. Nếu +r
được sử dụng thì chế độ lặp lại sẽ kết thúc khi không tìm thấy tệp đang mở còn tùu chọn -r
sẽ tiếp tục liệt kê, trì hoãn, liệt kê cho đến khi đưa ra bất kể các tệp có được mở hay không.
Các chu kỳ sẽ được phân tách bằng cách sử dụng '======='. Bạn cũng chỉ định thời gian trễ là '-r' | '+ r'.
[root@test1 ~]# lsof -c ssh -r5
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 8352 root cwd DIR 8,2 263 64 /
sshd 8352 root rtd DIR 8,2 263 64 /
sshd 8352 root txt REG 8,2 853040 6439738 /usr/sbin/sshd
sshd 8352 root DEL REG 8,2 6292703 /usr/lib64/libnss_files-2.17.so;5c94fef7
sshd 8352 root mem REG 8,2 68192 6382963 /usr/lib64/libbz2.so.1.0.6
sshd 8352 root DEL REG 8,2 6357643 /usr/lib64/libelf-0.170.so
...
=======
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 8352 root cwd DIR 8,2 263 64 /
sshd 8352 root rtd DIR 8,2 263 64 /
sshd 8352 root txt REG 8,2 853040 6439738 /usr/sbin/sshd
sshd 8352 root DEL REG 8,2 6292703 /usr/lib64/libnss_files-2.17.so;5c94fef7
sshd 8352 root mem REG 8,2 68192 6382963 /usr/lib64/libbz2.so.1.0.6
3.2. Lệnh lsof với tìm kiếm kết nối mạng
Kết nối mạng cũng là tập tin. Vì vậy, chúng tôi có thể tìm thấy thông tin họ bằng cách sử dụng lệnh lsof
.
👉 Ví dụ 1: Hiển thị tất cả các kết nối mạng
Chúng ta có thể liệt kê tất cả các kết nối mạng được mở bằng cách sử dụng tùy chọn -i
.
[root@test1 ~]# lsof -n -i
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
chronyd 489 chrony 1u IPv4 13504 0t0 UDP 127.0.0.1:323
chronyd 489 chrony 2u IPv6 13505 0t0 UDP [::1]:323
dhclient 578 root 6u IPv4 15376 0t0 UDP *:bootpc
dhclient 579 root 6u IPv4 15365 0t0 UDP *:bootpc
sshd 8352 root 3u IPv4 28174 0t0 TCP *:terminaldb (LISTEN)
sshd 8352 root 4u IPv6 28176 0t0 TCP *:terminaldb (LISTEN)
master 13050 root 13u IPv4 46933 0t0 TCP 127.0.0.1:smtp (LISTEN)
master 13050 root 14u IPv6 46934 0t0 TCP [::1]:smtp (LISTEN)
sshd 29521 root 3u IPv4 244046 0t0 TCP 102.96.126.130:terminaldb->26.79.26.92:50152 (ESTABLISHED)
Để nhận lưu lượng IPv6 với sử dụng tuỳ chọn -i 6
. Cú pháp như bên dưới:
[root@localhost ~]# lsof -i 6 -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
chronyd 3024 chrony 2u IPv6 13942 0t0 UDP [::1]:323
nginx 3259 root 28u IPv6 185119976 0t0 TCP *:http (LISTEN)
nginx 3259 root 30u IPv6 185119978 0t0 TCP *:https (LISTEN)
nginx 3261 nobody 28u IPv6 185119976 0t0 TCP *:http (LISTEN)
nginx 3261 nobody 30u IPv6 185119978 0t0 TCP *:https (LISTEN)
python 12539 bot 4u IPv6 192427365 0t0 TCP [2400:8901::f03c:91ff:fefb:dba1]:46710->[2001:67c:4e8:f004::9]:https (ESTABLISHED)
sshd 26892 root 4u IPv6 612238 0t0 TCP *:ssh (LISTEN)
👉 Ví dụ 2: Hiển thị các kết nối TCP hoặc UDP
Khi chúng ta muốn hiển thị các kết nối TCP hoặc UDP bằng cách cung cấp giao thức ngay sau tuỳ chọn -i
.
[root@test1 ~]# lsof -n -iUDP
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
chronyd 489 chrony 1u IPv4 13504 0t0 UDP 127.0.0.1:323
chronyd 489 chrony 2u IPv6 13505 0t0 UDP [::1]:323
dhclient 578 root 6u IPv4 15376 0t0 UDP *:bootpc
dhclient 579 root 6u IPv4 15365 0t0 UDP *:bootpc
[root@test1 ~]# lsof -n -iTCP
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 8352 root 3u IPv4 28174 0t0 TCP *:terminaldb (LISTEN)
sshd 8352 root 4u IPv6 28176 0t0 TCP *:terminaldb (LISTEN)
master 13050 root 13u IPv4 46933 0t0 TCP 127.0.0.1:smtp (LISTEN)
master 13050 root 14u IPv6 46934 0t0 TCP [::1]:smtp (LISTEN)
sshd 29521 root 3u IPv4 244046 0t0 TCP 102.96.126.130:terminaldb->26.79.26.92:50152 (ESTABLISHED)
👉 Ví dụ 3: Hiển thị mạng liên quan đến một cổng nhất định
Bằng cách sử dụng tuỳ chọn -i :port
bạn có thể hiển thị các kết nối mạng qua một cổng nhất định.
[root@test1 ~]# lsof -i :25
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
master 13050 root 13u IPv4 46933 0t0 TCP localhost:smtp (LISTEN)
master 13050 root 14u IPv6 46934 0t0 TCP localhost:smtp (LISTEN)
👉 Ví dụ 4: Hiển thị kết nối đến một máy chủ cụ thể
Bằng cách sử dụng tuỳ chọn -i@host
chúng ta có thể hiển thị kết nối đến một máy chủ cụ thể. Thực hiện như sau:
[root@test1 ~]# lsof -n -i@102.96.126.130
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 29521 root 3u IPv4 244046 0t0 TCP 102.96.126.130:terminaldb->26.79.26.92:50152 (ESTABLISHED)
👉 Ví dụ 5: Tìm các tiến trình có trạng thái TCP là LISTEN
Để tìm các cổng đang chờ kết nối. Cú pháp như sau:
lsof -i -sTCP:LISTEN
Bạn cũng có thể thực hiện bằng cách dùng lệnh grep cho LISTEN.
[root@test1 ~]# lsof -n -i -sTCP:LISTEN
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 8352 root 3u IPv4 28174 0t0 TCP *:terminaldb (LISTEN)
sshd 8352 root 4u IPv6 28176 0t0 TCP *:terminaldb (LISTEN)
master 13050 root 13u IPv4 46933 0t0 TCP 127.0.0.1:smtp (LISTEN)
master 13050 root 14u IPv6 46934 0t0 TCP [::1]:smtp (LISTEN)
👉 Ví dụ 6: Tìm tiến trình có trạng thái TCP là sTCP:ESTABLISHED
Bạn có thể hiển thị bất kỳ kết nối nào đã được thiết lập. Cú pháp như sau:
lsof -i -sTCP:ESTABLISHED
Bạn cũng có thể thực hiện bằng cách dùng lệnh grep cho ESTABLISHED.
[root@test1 ~]# lsof -n -i -sTCP:ESTABLISHED
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 29521 root 3u IPv4 244046 0t0 TCP 102.96.126.130:terminaldb->26.79.26.92:50152 (ESTABLISHED)
👉 Ví dụ 7: Chỉ ra các kết nối mà một user đang kết nối tới một host
Chúng ta có thể liệt kê các kết nối mà một user đang kết nối tới một host. Trong ví dụ naà thì user dang kết nối với 102.96.126.130 như bên dưới:
[root@test1 ~]# lsof -n -u dang -i @102.96.126.130
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 30071 root 3u IPv4 250523 0t0 TCP 102.96.126.130:terminaldb->26.79.26.92:50152 (ESTABLISHED)
Sử dụng các tùy chọn -t
và -c
để xử lý HUP cú pháp như sau:
kill -HUP `lsof -t -c sshd`
Trong đó ý nghĩa các lệnh như sau:
-HUP
: Để khởi động lại một tiến trình.-t
: Đầu ra ngắn gọn bằng ID của tiến trình-c
: Liệt kê các tệp đã mở dựa vào tên tiến trình
Cú pháp trên dùng để khởi động lại một tiến trình sshd.
👉 Ví dụ 9: Hiển thị các kết nối với một port trong phạm vi
Chúng ta có thể hiển thị các kết nối với một port trong phạm vi cú pháp như sau:
lsof -i @fw.google.com:2050=2580
5. Lời kết
Qua bài trên, cho chúng ta biết cách dùng lệnh lsof
để liệt kê thông tin về các tệp được, kết nối mạng được mở bởi các tiến trình khác nhau trên hệ điều hành Linux.