📄 netstat.c
字号:
/* * netstat This file contains an implementation of the command * that helps in debugging the networking modules. * * NET-TOOLS A collection of programs that form the base set of the * NET-3 Networking Distribution for the LINUX operating * system. * * Version: $Id: netstat.c,v 1.27 1999/04/20 14:28:14 philip Exp $ * * Authors: Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de> * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> * Phil Packer, <pep@wicked.demon.co.uk> * Johannes Stille, <johannes@titan.os.open.de> * Bernd Eckenfels, <net-tools@lina.inka.de> * Phil Blundell <philb@gnu.org> * Tuan Hoang <tqhoang@bigfoot.com> * * Tuned for NET3 by: * Alan Cox, <A.Cox@swansea.ac.uk> * Copyright (c) 1993 Fred Baumgarten * * Modified: * *960116 {1.01} Bernd Eckenfels: verbose, cleanups *960204 {1.10} Bernd Eckenfels: aftrans, usage, new route_info, * DLFT_AF *960204 {1.11} Bernd Eckenfels: netlink support *960204 {1.12} Bernd Eckenfels: route_init() *960215 {1.13} Bernd Eckenfels: netlink_print honors HAVE_ *960217 {1.14} Bernd Eckenfels: masq_info from Jos Vos and * ax25_info from Jonathan Naylor. *960218 {1.15} Bernd Eckenfels: ipx_info rewritten, -e for tcp/ipx *960220 {1.16} Bernd Eckenfels: minor output reformats, -a for -x *960221 {1.17} Bernd Eckenfels: route_init->getroute_init *960426 {1.18} Bernd Eckenfels: new RTACTION, SYM/NUM, FIB/CACHE *960517 {1.19} Bernd Eckenfels: usage() spelling fix and --unix inode, * ':' is part of sock_addr for --inet *960822 {x.xx} Frank Strauss: INET6 support * *970406 {1.33} Philip Copeland Added snmp reporting support module -s * code provided by Andi Kleen * (relly needs to be kernel hooked but * this will do in the meantime) * minor header file misplacement tidy up. *980411 {1.34} Arnaldo Carvalho i18n: catgets -> gnu gettext, substitution * of sprintf for snprintf *10/1998 Andi Kleen Use new interface primitives. *990101 {1.36} Bernd Eckenfels usage updated to include -s and -C -F, * fixed netstat -rC output (lib/inet_gr.c) * removed broken NETLINK Support * fixed format for /proc/net/udp|tcp|raw * added -w,-t,-u TcpExt support to -s *990131 {1.37} Jan Kratochvil added -p for prg_cache() & friends * Flames to <short@ucw.cz>. * Tuan Hoang added IGMP support for IPv4 and IPv6 * *990420 {1.38} Tuan Hoang removed a useless assignment from igmp_do_one() * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * */#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <strings.h>#include <unistd.h>#include <ctype.h>#include <fcntl.h>#include <netdb.h>#include <paths.h>#include <pwd.h>#include <getopt.h>#include <sys/param.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/ioctl.h>#include <net/if.h>#include <dirent.h>#include "net-support.h"#include "pathnames.h"#include "version.h"#include "config.h"#include "intl.h"#include "sockets.h"#include "interface.h"#define PROGNAME_WIDTH 20#if !defined(s6_addr32) && defined(in6a_words)#define s6_addr32 in6a_words /* libinet6 */#endif/* prototypes for statistics.c */void parsesnmp(int, int, int);void inittab(void);typedef enum { SS_FREE = 0, /* not allocated */ SS_UNCONNECTED, /* unconnected to any socket */ SS_CONNECTING, /* in process of connecting */ SS_CONNECTED, /* connected to socket */ SS_DISCONNECTING /* in process of disconnecting */} socket_state;#define SO_ACCEPTCON (1<<16) /* performed a listen */#define SO_WAITDATA (1<<17) /* wait data to read */#define SO_NOSPACE (1<<18) /* no space to write */#define DFLT_AF "inet"#define FEATURE_NETSTAT#include "lib/net-features.h"char *Release = RELEASE, *Version = "netstat 1.38 (1999-04-20)", *Signature = "Fred Baumgarten, Alan Cox, Bernd Eckenfels, Phil Blundell, Tuan Hoang and others";#define E_READ -1#define E_IOCTL -3int flag_int = 0;int flag_rou = 0;int flag_mas = 0;int flag_sta = 0;int flag_all = 0;int flag_lst = 0;int flag_cnt = 0;int flag_deb = 0;int flag_not = 0;int flag_cf = 0;int flag_opt = 0;int flag_raw = 0;int flag_tcp = 0;int flag_udp = 0;int flag_igmp= 0;int flag_rom = 0;int flag_exp = 1;int flag_prg = 0;int flag_arg = 0;int flag_ver = 0;FILE *procinfo;#define INFO_GUTS1(file,name,proc) \ procinfo = fopen((file), "r"); \ if (procinfo == NULL) { \ if (errno != ENOENT) { \ perror((file)); \ return -1; \ } \ if (flag_arg || flag_ver) \ ESYSNOT("netstat", (name)); \ if (flag_arg) \ rc = 1; \ } else { \ do { \ if (fgets(buffer, sizeof(buffer), procinfo)) \ (proc)(lnr++, buffer); \ } while (!feof(procinfo)); \ fclose(procinfo); \ }#if HAVE_AFINET6#define INFO_GUTS2(file,proc) \ lnr = 0; \ procinfo = fopen((file), "r"); \ if (procinfo != NULL) { \ do { \ if (fgets(buffer, sizeof(buffer), procinfo)) \ (proc)(lnr++, buffer); \ } while (!feof(procinfo)); \ fclose(procinfo); \ }#else#define INFO_GUTS2(file,proc)#endif#define INFO_GUTS3 \ return rc;#define INFO_GUTS6(file,file6,name,proc) \ char buffer[8192]; \ int rc = 0; \ int lnr = 0; \ if (!flag_arg || flag_inet) { \ INFO_GUTS1(file,name,proc) \ } \ if (!flag_arg || flag_inet6) { \ INFO_GUTS2(file6,proc) \ } \ INFO_GUTS3#define INFO_GUTS(file,name,proc) \ char buffer[8192]; \ int rc = 0; \ int lnr = 0; \ INFO_GUTS1(file,name,proc) \ INFO_GUTS3#define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)#define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)#define PROGNAME_WIDTH2(s) #s#define PRG_HASH_SIZE 211static struct prg_node { struct prg_node *next; int inode; char name[PROGNAME_WIDTH];} *prg_hash[PRG_HASH_SIZE];static char prg_cache_loaded = 0;#define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE)#define PROGNAME_BANNER "PID/Program name"#define print_progname_banner() do { if (flag_prg) printf("%-" PROGNAME_WIDTHs "s"," " PROGNAME_BANNER); } while (0)#define PRG_LOCAL_ADDRESS "local_address"#define PRG_INODE "inode"#define PRG_SOCKET_PFX "socket:["#define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX))#ifndef LINE_MAX#define LINE_MAX 4096#endif#define PATH_PROC "/proc"#define PATH_FD_SUFF "fd"#define PATH_FD_SUFFl strlen(PATH_FD_SUFF)#define PATH_PROC_X_FD PATH_PROC "/%s/" PATH_FD_SUFF#define PATH_CMDLINE "cmdline"#define PATH_CMDLINEl strlen(PATH_CMDLINE)/* NOT working as of glibc-2.0.7: */#undef DIRENT_HAVE_D_TYPE_WORKSstatic void prg_cache_add(int inode, char *name){ unsigned hi = PRG_HASHIT(inode); struct prg_node **pnp,*pn; prg_cache_loaded=2; for (pnp=prg_hash+hi;(pn=*pnp);pnp=&pn->next) { if (pn->inode==inode) { /* Some warning should be appropriate here as we got multiple processes for one i-node */ return; } } if (!(*pnp=malloc(sizeof(**pnp)))) return; pn=*pnp; pn->next=NULL; pn->inode=inode; if (strlen(name)>sizeof(pn->name)-1) name[sizeof(pn->name)-1]='\0'; strcpy(pn->name,name);}static const char *prg_cache_get(int inode){ unsigned hi=PRG_HASHIT(inode); struct prg_node *pn; for (pn=prg_hash[hi];pn;pn=pn->next) if (pn->inode==inode) return(pn->name); return("-");}static void prg_cache_clear(void){ struct prg_node **pnp,*pn; if (prg_cache_loaded == 2) for (pnp=prg_hash;pnp<prg_hash+PRG_HASH_SIZE;pnp++) while ((pn=*pnp)) { *pnp=pn->next; free(pn); } prg_cache_loaded=0;}static void prg_cache_load(void){ char line[LINE_MAX],*serr,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)); if (lnamelen < strlen(PRG_SOCKET_PFX+2)) continue; if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl) || lname[lnamelen-1]!=']') continue; lname[lnamelen-1]='\0'; inode = strtol(lname+PRG_SOCKET_PFXl,&serr,0); if (!serr || *serr || inode < 0 || inode >= INT_MAX) 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); 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"));}#if HAVE_AFNETROMstatic const char *netrom_state[] ={ N_("LISTENING"), N_("CONN SENT"), N_("DISC SENT"), N_("ESTABLISHED")};static int netrom_info(void){ FILE *f; char buffer[256], dev[16]; int st, vs, vr, sendq, recvq, ret; f = fopen(_PATH_PROCNET_NR, "r"); if (f == NULL) { if (errno != ENOENT) { perror(_PATH_PROCNET_NR); return (-1); } if (flag_arg || flag_ver) ESYSNOT("netstat", "AF NETROM"); if (flag_arg) return (1); else return (0); } printf(_("Active NET/ROM sockets\n")); printf(_("User Dest Source Device State Vr/Vs Send-Q Recv-Q\n")); fgets(buffer, 256, f); while (fgets(buffer, 256, f)) { buffer[9] = 0; buffer[19] = 0; buffer[29] = 0; ret = sscanf(buffer + 30, "%s %*x/%*x %*x/%*x %d %d %d %*d %*d/%*d %*d/%*d %*d/%*d %*d/%*d %*d/%*d %*d %d %d %*d", dev, &st, &vs, &vr, &sendq, &recvq); if (ret != 6) { printf(_("Problem reading data from %s\n"), _PATH_PROCNET_NR); continue; } printf("%-9s %-9s %-9s %-6s %-11s %03d/%03d %-6d %-6d\n", buffer, buffer + 10, buffer + 20, dev, _(netrom_state[st]), vr, vs, sendq, recvq); } fclose(f); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -