netstat查看进程时不显示进程名“-”

netstat查看进程时不显示进程名“-”

问题描述

netstat 看不了监听端口的进程与pid。
netstat检查端口、lsof -i:端口号 检查socket id

定位分析

为啥有的端口ok有的不能显示?是否是监听端口范围问题?
用python -m SimpleHTTPServer测试监听不同端口,netstat都不能查出进程名pid
说明这台机器有问题,strace跟踪比较6200、24849这2个进程pid有什么不同,netstat到底做了什么?

进程pid: 6200
在这里插入图片描述
进程pid:24849
在这里插入图片描述
对比发现,netstat在处理6200这个pid时,没有读取/proc/PID/cmdline。为啥没读取呢?估计得看netstat源码了。偷懒google了一把。发现之前有人遇到过这个问题,原因是:
netstat低版本有bug,当Socket id 大于 2^31 时,会造成无法显示进程信息。

源码解惑
有点奇怪为啥是大于2^31就不行,这个博客也没讲清楚。下载了当前系统netstat 1.6.0版源码, grep -r -i "cmdline"狂扫。在netstat.c文件找到处理cmdline的函数代码:

static void prg_cache_load(void)
{
char line[LINE_MAX],eacces=0;
int procfdlen,fd,cmdllen,lnamelen;
char lname[30],cmdlbuf[512],finbuf[PROGNAME_WIDTH];
long inode;
const char *cs,*cmdlp;
DIR *dirproc=NULL,*dirfd=NULL;
struct dirent *direproc,*direfd;

if (prg_cache_loaded || !flag_prg) return;
prg_cache_loaded=1;
cmdlbuf[sizeof(cmdlbuf)-1]='\0';
if (!(dirproc=opendir(PATH_PROC))) goto fail;
while (errno=0,direproc=readdir(dirproc)) {

#ifdef DIRENT_HAVE_D_TYPE_WORKS
if (direproc->d_type!=DT_DIR) continue;
#endif
for (cs=direproc->d_name;*cs;cs++)
if (!isdigit(*cs))
break;
if (*cs)
continue;
procfdlen=snprintf(line,sizeof(line),PATH_PROC_X_FD,direproc->d_name);
if (procfdlen<=0 || procfdlen>=sizeof(line)-5)
continue;
errno=0;
dirfd=opendir(line);
if (! dirfd) {
if (errno==EACCES)
eacces=1;
continue;
}
line[procfdlen] = ‘/’;
cmdlp = NULL;
while ((direfd = readdir(dirfd))) {
#ifdef DIRENT_HAVE_D_TYPE_WORKS
if (direfd->d_type!=DT_LNK)
continue;
#endif
if (procfdlen+1+strlen(direfd->d_name)+1>sizeof(line))
continue;
memcpy(line + procfdlen - PATH_FD_SUFFl, PATH_FD_SUFF “/”,
PATH_FD_SUFFl+1);
strcpy(line + procfdlen + 1, direfd->d_name);
lnamelen=readlink(line,lname,sizeof(lname)-1);
lname[lnamelen] = ‘\0’; /make it a null-terminated string/

        extract_type_1_socket_inode(lname, &inode);

        if (inode < 0) extract_type_2_socket_inode(lname, &inode);

        if (inode < 0) continue;

 if (!cmdlp) {
    if (procfdlen - PATH_FD_SUFFl + PATH_CMDLINEl >=
     sizeof(line) - 5)
     continue;
    strcpy(line + procfdlen-PATH_FD_SUFFl, PATH_CMDLINE);
    fd = open(line, O_RDONLY);
    if (fd < 0)
     continue;
    cmdllen = read(fd, cmdlbuf, sizeof(cmdlbuf) - 1);   #读取/proc/PID/cmdline
    if (close(fd))
     continue;
    if (cmdllen == -1)
     continue;
    if (cmdllen < sizeof(cmdlbuf) - 1)
     cmdlbuf[cmdllen]='\0';
    if ((cmdlp = strrchr(cmdlbuf, '/')))
     cmdlp++;
    else
     cmdlp = cmdlbuf;
 }

 snprintf(finbuf, sizeof(finbuf), "%s/%s", direproc->d_name, cmdlp);
 prg_cache_add(inode, finbuf);
}
closedir(dirfd);
dirfd = NULL;
}
if (dirproc)
closedir(dirproc);
if (dirfd)
closedir(dirfd);
if (!eacces)
return;
if (prg_cache_loaded == 1) {
fail:
fprintf(stderr,_("(No info could be read for \"-p\": geteuid()=%d but you should be root.)\n"),
    geteuid());
}
else
fprintf(stderr, _("(Not all processes could be identified, non-owned process info\n"
         " will not be shown, you would have to be root to see it all.)\n"));

}

prg_cache_load函数的第60行打开/proc/PID/cmdline, 63行读取/proc/PID/cmdline。现在需要找到这段代码没执行的原因。
回头看,如果inode<0会绕过这段代码。我们看相关的extract_type_1_socket_inode、extract_type_2_socket_inode函数。

static void extract_type_1_socket_inode(const char lname[], long * inode_p) {

/* If lname is of the form "socket:[12345]", extract the "12345"
   as *inode_p. Otherwise, return -1 as *inode_p.
   */

if (strlen(lname) < PRG_SOCKET_PFXl+3) *inode_p = -1;
else if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl)) *inode_p = -1;
else if (lname[strlen(lname)-1] != ']') *inode_p = -1;
else {
    char inode_str[strlen(lname + 1)]; /* e.g. "12345" */
    const int inode_str_len = strlen(lname) - PRG_SOCKET_PFXl - 1;
    char *serr;

    strncpy(inode_str, lname+PRG_SOCKET_PFXl, inode_str_len);
    inode_str[inode_str_len] = '\0';
    *inode_p = strtol(inode_str,&serr,0);
    if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX)
        *inode_p = -1;
}

}

注意到末尾,当inode_p >= INT_MAX时, *inode_p指针值为-1.检查机器的INT_MAX值: getconf INT_MAX 结果是2147483647,而pid为6200的进程socket inode号2413086211大于2147483647所以返回-1值。

static void extract_type_2_socket_inode(const char lname[], long * inode_p) {

/* If lname is of the form "[0000]:12345", extract the "12345"
   as *inode_p. Otherwise, return -1 as *inode_p.
   */

if (strlen(lname) < PRG_SOCKET_PFX2l+1) *inode_p = -1;
else if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l)) *inode_p = -1;
else {
    char *serr;

    *inode_p=strtol(lname + PRG_SOCKET_PFX2l,&serr,0);
    if (!serr || *serr || *inode_p < 0 || *inode_p >= INT_MAX)
        *inode_p = -1;
}

}

同样extract_type_2_socket_inode也返回-1值,导致prg_cache_load函数未读取/proc/PID/cmdline文件内容。
现在可以确认: 原因是socket inode超过INT_MAX,引起netstat不识别进程名pid.

文章引用:
http://blog.chinaunix.net/uid-28337979-id-4230505.html

仅做参考学习

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值