[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.11

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