[BACK]Return to netstat.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / systat

Annotation of src/usr.bin/systat/netstat.c, Revision 1.2

1.1       deraadt     1: /*     $NetBSD: netstat.c,v 1.3 1995/06/18 23:53:07 cgd Exp $  */
                      2:
                      3: /*-
                      4:  * Copyright (c) 1980, 1992, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by the University of
                     18:  *     California, Berkeley and its contributors.
                     19:  * 4. Neither the name of the University nor the names of its contributors
                     20:  *    may be used to endorse or promote products derived from this software
                     21:  *    without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  */
                     35:
                     36: #ifndef lint
                     37: #if 0
                     38: static char sccsid[] = "@(#)netstat.c  8.1 (Berkeley) 6/6/93";
                     39: #endif
                     40: static char rcsid[] = "$NetBSD: netstat.c,v 1.3 1995/06/18 23:53:07 cgd Exp $";
                     41: #endif /* not lint */
                     42:
                     43: /*
                     44:  * netstat
                     45:  */
                     46: #include <sys/param.h>
                     47: #include <sys/socket.h>
                     48: #include <sys/socketvar.h>
                     49: #include <sys/mbuf.h>
                     50: #include <sys/protosw.h>
                     51:
                     52: #include <netinet/in.h>
                     53: #include <net/route.h>
                     54: #include <netinet/in_systm.h>
                     55: #include <netinet/ip.h>
                     56: #include <netinet/in_pcb.h>
                     57: #include <netinet/ip_icmp.h>
                     58: #include <netinet/icmp_var.h>
                     59: #include <netinet/ip_var.h>
                     60: #include <netinet/tcp.h>
                     61: #include <netinet/tcpip.h>
                     62: #include <netinet/tcp_seq.h>
                     63: #define TCPSTATES
                     64: #include <netinet/tcp_fsm.h>
                     65: #include <netinet/tcp_timer.h>
                     66: #include <netinet/tcp_var.h>
                     67: #include <netinet/tcp_debug.h>
                     68: #include <netinet/udp.h>
                     69: #include <netinet/udp_var.h>
                     70:
                     71: #include <netdb.h>
                     72: #include <stdlib.h>
                     73: #include <string.h>
                     74: #include <nlist.h>
                     75: #include <paths.h>
                     76: #include "systat.h"
                     77: #include "extern.h"
                     78:
                     79: static void enter __P((struct inpcb *, struct socket *, int, char *));
                     80: static char *inetname __P((struct in_addr));
                     81: static void inetprint __P((struct in_addr *, int, char *));
                     82:
                     83: #define        streq(a,b)      (strcmp(a,b)==0)
1.2     ! mickey     84: #define        YMAX(w)         ((w)->_maxy-1)
1.1       deraadt    85:
                     86: WINDOW *
                     87: opennetstat()
                     88: {
                     89:        sethostent(1);
                     90:        setnetent(1);
                     91:        return (subwin(stdscr, LINES-5-1, 0, 5, 0));
                     92: }
                     93:
                     94: struct netinfo {
                     95:        struct  netinfo *ni_forw, *ni_prev;
                     96:        short   ni_line;                /* line on screen */
                     97:        short   ni_seen;                /* 0 when not present in list */
                     98:        short   ni_flags;
                     99: #define        NIF_LACHG       0x1             /* local address changed */
                    100: #define        NIF_FACHG       0x2             /* foreign address changed */
                    101:        short   ni_state;               /* tcp state */
                    102:        char    *ni_proto;              /* protocol */
                    103:        struct  in_addr ni_laddr;       /* local address */
                    104:        long    ni_lport;               /* local port */
                    105:        struct  in_addr ni_faddr;       /* foreign address */
                    106:        long    ni_fport;               /* foreign port */
                    107:        long    ni_rcvcc;               /* rcv buffer character count */
                    108:        long    ni_sndcc;               /* snd buffer character count */
                    109: };
                    110:
                    111: static struct {
                    112:        struct  netinfo *ni_forw, *ni_prev;
                    113: } netcb;
                    114:
                    115: static int aflag = 0;
                    116: static int nflag = 0;
                    117: static int lastrow = 1;
                    118: static void enter(), inetprint();
                    119: static char *inetname();
                    120:
                    121: void
                    122: closenetstat(w)
                    123:         WINDOW *w;
                    124: {
                    125:        register struct netinfo *p;
                    126:
                    127:        endhostent();
                    128:        endnetent();
                    129:        p = (struct netinfo *)netcb.ni_forw;
                    130:        while (p != (struct netinfo *)&netcb) {
                    131:                if (p->ni_line != -1)
                    132:                        lastrow--;
                    133:                p->ni_line = -1;
                    134:                p = p->ni_forw;
                    135:        }
                    136:         if (w != NULL) {
                    137:                wclear(w);
                    138:                wrefresh(w);
                    139:                delwin(w);
                    140:        }
                    141: }
                    142:
                    143: static struct nlist namelist[] = {
                    144: #define        X_TCBTABLE      0
                    145:        { "_tcbtable" },
                    146: #define        X_UDBTABLE      1
                    147:        { "_udbtable" },
                    148:        { "" },
                    149: };
                    150:
                    151: int
                    152: initnetstat()
                    153: {
                    154:        if (kvm_nlist(kd, namelist)) {
                    155:                nlisterr(namelist);
                    156:                return(0);
                    157:        }
                    158:        if (namelist[X_TCBTABLE].n_value == 0) {
                    159:                error("No symbols in namelist");
                    160:                return(0);
                    161:        }
                    162:        netcb.ni_forw = netcb.ni_prev = (struct netinfo *)&netcb;
                    163:        protos = TCP|UDP;
                    164:        return(1);
                    165: }
                    166:
                    167: void
                    168: fetchnetstat()
                    169: {
                    170:        struct inpcbtable pcbtable;
                    171:        register struct inpcb *head, *prev, *next;
                    172:        register struct netinfo *p;
                    173:        struct inpcb inpcb;
                    174:        struct socket sockb;
                    175:        struct tcpcb tcpcb;
                    176:        void *off;
                    177:        int istcp;
                    178:
                    179:        if (namelist[X_TCBTABLE].n_value == 0)
                    180:                return;
                    181:        for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw)
                    182:                p->ni_seen = 0;
                    183:        if (protos&TCP) {
                    184:                off = NPTR(X_TCBTABLE);
                    185:                istcp = 1;
                    186:        }
                    187:        else if (protos&UDP) {
                    188:                off = NPTR(X_UDBTABLE);
                    189:                istcp = 0;
                    190:        }
                    191:        else {
                    192:                error("No protocols to display");
                    193:                return;
                    194:        }
                    195: again:
                    196:        KREAD(off, &pcbtable, sizeof (struct inpcbtable));
                    197:        prev = head = (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue;
                    198:        next = pcbtable.inpt_queue.cqh_first;
                    199:        while (next != head) {
                    200:                KREAD(next, &inpcb, sizeof (inpcb));
                    201:                if (inpcb.inp_queue.cqe_prev != prev) {
                    202: printf("prev = %x, head = %x, next = %x, inpcb...prev = %x\n", prev, head, next, inpcb.inp_queue.cqe_prev);
                    203:                        p = netcb.ni_forw;
                    204:                        for (; p != (struct netinfo *)&netcb; p = p->ni_forw)
                    205:                                p->ni_seen = 1;
                    206:                        error("Kernel state in transition");
                    207:                        return;
                    208:                }
                    209:                prev = next;
                    210:                next = inpcb.inp_queue.cqe_next;
                    211:
                    212:                if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
                    213:                        continue;
                    214:                if (nhosts && !checkhost(&inpcb))
                    215:                        continue;
                    216:                if (nports && !checkport(&inpcb))
                    217:                        continue;
                    218:                KREAD(inpcb.inp_socket, &sockb, sizeof (sockb));
                    219:                if (istcp) {
                    220:                        KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
                    221:                        enter(&inpcb, &sockb, tcpcb.t_state, "tcp");
                    222:                } else
                    223:                        enter(&inpcb, &sockb, 0, "udp");
                    224:        }
                    225:        if (istcp && (protos&UDP)) {
                    226:                istcp = 0;
                    227:                off = NPTR(X_UDBTABLE);
                    228:                goto again;
                    229:        }
                    230: }
                    231:
                    232: static void
                    233: enter(inp, so, state, proto)
                    234:        register struct inpcb *inp;
                    235:        register struct socket *so;
                    236:        int state;
                    237:        char *proto;
                    238: {
                    239:        register struct netinfo *p;
                    240:
                    241:        /*
                    242:         * Only take exact matches, any sockets with
                    243:         * previously unbound addresses will be deleted
                    244:         * below in the display routine because they
                    245:         * will appear as ``not seen'' in the kernel
                    246:         * data structures.
                    247:         */
                    248:        for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) {
                    249:                if (!streq(proto, p->ni_proto))
                    250:                        continue;
                    251:                if (p->ni_lport != inp->inp_lport ||
                    252:                    p->ni_laddr.s_addr != inp->inp_laddr.s_addr)
                    253:                        continue;
                    254:                if (p->ni_faddr.s_addr == inp->inp_faddr.s_addr &&
                    255:                    p->ni_fport == inp->inp_fport)
                    256:                        break;
                    257:        }
                    258:        if (p == (struct netinfo *)&netcb) {
                    259:                if ((p = malloc(sizeof(*p))) == NULL) {
                    260:                        error("Out of memory");
                    261:                        return;
                    262:                }
                    263:                p->ni_prev = (struct netinfo *)&netcb;
                    264:                p->ni_forw = netcb.ni_forw;
                    265:                netcb.ni_forw->ni_prev = p;
                    266:                netcb.ni_forw = p;
                    267:                p->ni_line = -1;
                    268:                p->ni_laddr = inp->inp_laddr;
                    269:                p->ni_lport = inp->inp_lport;
                    270:                p->ni_faddr = inp->inp_faddr;
                    271:                p->ni_fport = inp->inp_fport;
                    272:                p->ni_proto = proto;
                    273:                p->ni_flags = NIF_LACHG|NIF_FACHG;
                    274:        }
                    275:        p->ni_rcvcc = so->so_rcv.sb_cc;
                    276:        p->ni_sndcc = so->so_snd.sb_cc;
                    277:        p->ni_state = state;
                    278:        p->ni_seen = 1;
                    279: }
                    280:
                    281: /* column locations */
                    282: #define        LADDR   0
                    283: #define        FADDR   LADDR+23
                    284: #define        PROTO   FADDR+23
                    285: #define        RCVCC   PROTO+6
                    286: #define        SNDCC   RCVCC+7
                    287: #define        STATE   SNDCC+7
                    288:
                    289:
                    290: void
                    291: labelnetstat()
                    292: {
                    293:        if (namelist[X_TCBTABLE].n_type == 0)
                    294:                return;
                    295:        wmove(wnd, 0, 0); wclrtobot(wnd);
                    296:        mvwaddstr(wnd, 0, LADDR, "Local Address");
                    297:        mvwaddstr(wnd, 0, FADDR, "Foreign Address");
                    298:        mvwaddstr(wnd, 0, PROTO, "Proto");
                    299:        mvwaddstr(wnd, 0, RCVCC, "Recv-Q");
                    300:        mvwaddstr(wnd, 0, SNDCC, "Send-Q");
                    301:        mvwaddstr(wnd, 0, STATE, "(state)");
                    302: }
                    303:
                    304: void
                    305: shownetstat()
                    306: {
                    307:        register struct netinfo *p, *q;
                    308:
                    309:        /*
                    310:         * First, delete any connections that have gone
                    311:         * away and adjust the position of connections
                    312:         * below to reflect the deleted line.
                    313:         */
                    314:        p = netcb.ni_forw;
                    315:        while (p != (struct netinfo *)&netcb) {
                    316:                if (p->ni_line == -1 || p->ni_seen) {
                    317:                        p = p->ni_forw;
                    318:                        continue;
                    319:                }
                    320:                wmove(wnd, p->ni_line, 0); wdeleteln(wnd);
                    321:                q = netcb.ni_forw;
                    322:                for (; q != (struct netinfo *)&netcb; q = q->ni_forw)
                    323:                        if (q != p && q->ni_line > p->ni_line) {
                    324:                                q->ni_line--;
                    325:                                /* this shouldn't be necessary */
                    326:                                q->ni_flags |= NIF_LACHG|NIF_FACHG;
                    327:                        }
                    328:                lastrow--;
                    329:                q = p->ni_forw;
                    330:                p->ni_prev->ni_forw = p->ni_forw;
                    331:                p->ni_forw->ni_prev = p->ni_prev;
                    332:                free(p);
                    333:                p = q;
                    334:        }
                    335:        /*
                    336:         * Update existing connections and add new ones.
                    337:         */
                    338:        for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) {
                    339:                if (p->ni_line == -1) {
                    340:                        /*
                    341:                         * Add a new entry if possible.
                    342:                         */
                    343:                        if (lastrow > YMAX(wnd))
                    344:                                continue;
                    345:                        p->ni_line = lastrow++;
                    346:                        p->ni_flags |= NIF_LACHG|NIF_FACHG;
                    347:                }
                    348:                if (p->ni_flags & NIF_LACHG) {
                    349:                        wmove(wnd, p->ni_line, LADDR);
                    350:                        inetprint(&p->ni_laddr, p->ni_lport, p->ni_proto);
                    351:                        p->ni_flags &= ~NIF_LACHG;
                    352:                }
                    353:                if (p->ni_flags & NIF_FACHG) {
                    354:                        wmove(wnd, p->ni_line, FADDR);
                    355:                        inetprint(&p->ni_faddr, p->ni_fport, p->ni_proto);
                    356:                        p->ni_flags &= ~NIF_FACHG;
                    357:                }
                    358:                mvwaddstr(wnd, p->ni_line, PROTO, p->ni_proto);
                    359:                mvwprintw(wnd, p->ni_line, RCVCC, "%6d", p->ni_rcvcc);
                    360:                mvwprintw(wnd, p->ni_line, SNDCC, "%6d", p->ni_sndcc);
                    361:                if (streq(p->ni_proto, "tcp"))
                    362:                        if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES)
                    363:                                mvwprintw(wnd, p->ni_line, STATE, "%d",
                    364:                                    p->ni_state);
                    365:                        else
                    366:                                mvwaddstr(wnd, p->ni_line, STATE,
                    367:                                    tcpstates[p->ni_state]);
                    368:                wclrtoeol(wnd);
                    369:        }
                    370:        if (lastrow < YMAX(wnd)) {
                    371:                wmove(wnd, lastrow, 0); wclrtobot(wnd);
                    372:                wmove(wnd, YMAX(wnd), 0); wdeleteln(wnd);       /* XXX */
                    373:        }
                    374: }
                    375:
                    376: /*
                    377:  * Pretty print an Internet address (net address + port).
                    378:  * If the nflag was specified, use numbers instead of names.
                    379:  */
                    380: static void
                    381: inetprint(in, port, proto)
                    382:        register struct in_addr *in;
                    383:        int port;
                    384:        char *proto;
                    385: {
                    386:        struct servent *sp = 0;
                    387:        char line[80], *cp, *index();
                    388:
                    389:        sprintf(line, "%.*s.", 16, inetname(*in));
                    390:        cp = index(line, '\0');
                    391:        if (!nflag && port)
                    392:                sp = getservbyport(port, proto);
                    393:        if (sp || port == 0)
                    394:                sprintf(cp, "%.8s", sp ? sp->s_name : "*");
                    395:        else
                    396:                sprintf(cp, "%d", ntohs((u_short)port));
                    397:        /* pad to full column to clear any garbage */
                    398:        cp = index(line, '\0');
                    399:        while (cp - line < 22)
                    400:                *cp++ = ' ';
                    401:        *cp = '\0';
                    402:        waddstr(wnd, line);
                    403: }
                    404:
                    405: /*
                    406:  * Construct an Internet address representation.
                    407:  * If the nflag has been supplied, give
                    408:  * numeric value, otherwise try for symbolic name.
                    409:  */
                    410: static char *
                    411: inetname(in)
                    412:        struct in_addr in;
                    413: {
                    414:        char *cp = 0;
                    415:        static char line[50];
                    416:        struct hostent *hp;
                    417:        struct netent *np;
                    418:
                    419:        if (!nflag && in.s_addr != INADDR_ANY) {
                    420:                int net = inet_netof(in);
                    421:                int lna = inet_lnaof(in);
                    422:
                    423:                if (lna == INADDR_ANY) {
                    424:                        np = getnetbyaddr(net, AF_INET);
                    425:                        if (np)
                    426:                                cp = np->n_name;
                    427:                }
                    428:                if (cp == 0) {
                    429:                        hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
                    430:                        if (hp)
                    431:                                cp = hp->h_name;
                    432:                }
                    433:        }
                    434:        if (in.s_addr == INADDR_ANY)
                    435:                strcpy(line, "*");
                    436:        else if (cp)
                    437:                strcpy(line, cp);
                    438:        else {
                    439:                in.s_addr = ntohl(in.s_addr);
                    440: #define C(x)   ((x) & 0xff)
                    441:                sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
                    442:                        C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
                    443:        }
                    444:        return (line);
                    445: }
                    446:
                    447: int
                    448: cmdnetstat(cmd, args)
                    449:        char *cmd, *args;
                    450: {
                    451:        register struct netinfo *p;
                    452:
                    453:        if (prefix(cmd, "all")) {
                    454:                aflag = !aflag;
                    455:                goto fixup;
                    456:        }
                    457:        if  (prefix(cmd, "numbers") || prefix(cmd, "names")) {
                    458:                int new;
                    459:
                    460:                new = prefix(cmd, "numbers");
                    461:                if (new == nflag)
                    462:                        return (1);
                    463:                p = netcb.ni_forw;
                    464:                for (; p != (struct netinfo *)&netcb; p = p->ni_forw) {
                    465:                        if (p->ni_line == -1)
                    466:                                continue;
                    467:                        p->ni_flags |= NIF_LACHG|NIF_FACHG;
                    468:                }
                    469:                nflag = new;
                    470:                goto redisplay;
                    471:        }
                    472:        if (!netcmd(cmd, args))
                    473:                return (0);
                    474: fixup:
                    475:        fetchnetstat();
                    476: redisplay:
                    477:        shownetstat();
                    478:        refresh();
                    479:        return (1);
                    480: }