在linux下面经常会需要“进程打开了哪些端口,某端口是哪个进程打开的”相关信息,下面来看下如何获取这些信息。

注:"进程打开了哪些端口"与“某个端口属于哪个进程/线程”信息收集过程相近,只看“某个端口属于哪个进程/线程”情况

 

1 netstat查看端口及进程
用以下命令(需要root权限)查看端口及对应的进程

[redhat@localhost ~]$ su
密码:
[root@localhost redhat]# netstat -npta | grep 22
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1962/sshd
tcp        0      0 :::22                       :::*                        LISTEN      1962/sshd

由于一些嵌入式平台的netstat并不支持-p选项:

# ls -l /bin/netstat
lrwxrwxrwx    1 0        0               7 Jul 25 17:35 /bin/netstat -> busybox
# netstat -p
netstat: invalid option -- p
BusyBox v1.10.1 (2011-03-30 16:10:40 CST) multi-call binary

Usage: netstat [-laentuwxrW]

Display networking information

Options:
        -l      Display listening server sockets
        -a      Display all sockets (default: connected)
        -e      Display other/more information
        -n      Don't resolve names
        -t      Tcp sockets
        -u      Udp sockets
        -w      Raw sockets
        -x      Unix sockets
        -r      Display routing table
        -W      Display with no column truncation


下面跟踪下netstat是如何收集这些信息的,以便不使用netstat命令的情况下,也能知道某端口所属进程/线程

 

2 strace netstat
用strace来跟踪netstat -ntpa都干了什么

[root@localhost redhat]# strace netstat -ntpa
execve("/bin/netstat", ["netstat", "-ntpa"], [/* 47 vars */]) = 0
brk(0)                                  = 0x9e2d000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78e6000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
...
open("/proc", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3
fcntl64(3, F_GETFD)                     = 0x1 (flags FD_CLOEXEC)
getdents(3, /* 264 entries */, 32768)   = 4456
open("/proc/1/fd", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 4
getdents(4, /* 11 entries */, 32768)    = 176
readlink("/proc/1/fd/0", "/dev/null"..., 29) = 9
readlink("/proc/1/fd/1", "/dev/null", 29) = 9
readlink("/proc/1/fd/2", "/dev/null", 29) = 9
readlink("/proc/1/fd/3", "pipe:[8927]"..., 29) = 11
readlink("/proc/1/fd/4", "pipe:[8927]", 29) = 11
readlink("/proc/1/fd/5", "inotify"..., 29) = 7
readlink("/proc/1/fd/6", "inotify", 29) = 7
readlink("/proc/1/fd/7", "socket:[8928]"..., 29) = 13
open("/proc/1/cmdline", O_RDONLY)       = 5
read(5, "/sbin/init\0", 511)            = 11
close(5)                                = 0
open("/proc/1/attr/current", O_RDONLY|O_LARGEFILE) = 5
read(5, "system_u:system_r:init_t:s0\0", 4095) = 28
close(5)                                = 0
open("/selinux/mls", O_RDONLY|O_LARGEFILE) = 5
read(5, "1", 19)                        = 1
close(5)                                = 0
socket(PF_FILE, SOCK_STREAM|SOCK_CLOEXEC, 0) = 5
connect(5, {sa_family=AF_FILE, path="/var/run/setrans/.setrans-unix"}, 110) = -1 ENOENT (No such file or directory)
close(5)                                = 0
readlink("/proc/1/fd/9", "socket:[12555]"..., 29) = 14
open("/proc/1/attr/current", O_RDONLY|O_LARGEFILE) = 5
read(5, "system_u:system_r:init_t:s0\0", 4095) = 28
close(5)                                = 0
getdents(4, /* 0 entries */, 32768)     = 0
close(4)                                = 0
open("/proc/2/fd", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 4
getdents(4, /* 2 entries */, 32768)     = 32
getdents(4, /* 0 entries */, 32768)     = 0
close(4)                                = 0
...
write(1, "Active Internet connections (ser"..., 54Active Internet connections (servers and established)
) = 54
write(1, "Proto Recv-Q Send-Q Local Addres"..., 108Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name   
) = 108
open("/proc/net/tcp", O_RDONLY)         = 3
fstat64(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7535000
read(3, "  sl  local_address rem_address "..., 1024) = 900
write(1, "tcp        0      0 0.0.0.0:22  "..., 109tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1962/sshd           
) = 109
write(1, "tcp        0      0 127.0.0.1:63"..., 109tcp        0      0 127.0.0.1:631               0.0.0.0:*                   LISTEN      1656/cupsd          
) = 109
write(1, "tcp        0      0 127.0.0.1:25"..., 109tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      2050/master         
) = 109
write(1, "tcp        0      0 0.0.0.0:5286"..., 109tcp        0      0 0.0.0.0:52867               0.0.0.0:*                   LISTEN      1692/rpc.statd      
) = 109
write(1, "tcp        0      0 0.0.0.0:111 "..., 109tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      1596/rpcbind        
) = 109
read(3, "", 1024)                       = 0
close(3)                                = 0
munmap(0xb7535000, 4096)                = 0
[root@localhost redhat]# 

由以上信息可以看出,netstat -anpt做了如下几件事:
a.shell创建进程,exec netstat,ld装载netstat用到的动态链接库
b.通过遍历proc文件系统,收集进程打开的socket文件信息;/proc/pid/fd/目录下面文件为实际文件的软链接,socket文件为socket:[inodeno]
c.从/proc/net/tcp中收集tcp信息
d.通过inode号,将进程与tcp关联起来,并将信息整理输出


3 模拟netstat -p功能
3.1 查找socket对应的inode

[root@localhost redhat]# head -n 1 /proc/net/tcp && cat /proc/net/tcp | grep :0016
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
   0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 13828 1 ecb02140 299 0 0 2 -1

在linux中socket也可以如文件一样操作(如read/write),而对应的文件系统就是socketfs(挂载到内核,用户空间无法看到)
/proc/pid/fd/下面的socket文件,通常是socket:[inode]的软链接

3.2  根据socket文件inode号关联进程与socket

for dir in `find /proc -name "fd"`
do
    ls -l $dir | grep "socket\:\[13828\]" && echo $dir
done

for dir in `find /proc/ -name "fd"`; do ls -l $dir | grep 'socket\:\[13828\]' && echo $dir;done

结果为

[root@localhost redhat]# for dir in `find /proc -name "fd"`
> do
>     ls -l $dir | grep "socket\:\[13828\]" && echo $dir
> done
lrwx------. 1 root root 64 11月 21 19:19 3 -> socket:[13828]
/proc/1962/task/1962/fd
lrwx------. 1 root root 64 11月 21 19:04 3 -> socket:[13828]
/proc/1962/fd
[root@localhost redhat]# head -n 1 /proc/1962/status
Name:	sshd
[root@localhost redhat]#

可以看到22端口是4162/sshd进程打开的

注:/proc/pid/task/下面是对应进程的线程(轻量级进程)信息

 

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐