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

1.31    ! canacar     1: /*     $OpenBSD: netstat.c,v 1.30 2007/02/25 18:21:24 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.
1.24      millert    16:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     34:  * netstat
                     35:  */
                     36: #include <sys/param.h>
                     37: #include <sys/socket.h>
                     38: #include <sys/socketvar.h>
                     39: #include <sys/mbuf.h>
                     40: #include <sys/protosw.h>
                     41:
                     42: #include <netinet/in.h>
                     43: #include <net/route.h>
                     44: #include <netinet/in_systm.h>
                     45: #include <netinet/ip.h>
                     46: #include <netinet/in_pcb.h>
                     47: #include <netinet/ip_icmp.h>
                     48: #include <netinet/icmp_var.h>
                     49: #include <netinet/ip_var.h>
                     50: #include <netinet/tcp.h>
                     51: #include <netinet/tcpip.h>
                     52: #include <netinet/tcp_seq.h>
                     53: #define TCPSTATES
                     54: #include <netinet/tcp_fsm.h>
                     55: #include <netinet/tcp_timer.h>
                     56: #include <netinet/tcp_var.h>
                     57: #include <netinet/tcp_debug.h>
                     58: #include <netinet/udp.h>
                     59: #include <netinet/udp_var.h>
1.7       millert    60: #include <arpa/inet.h>
1.1       deraadt    61:
                     62: #include <netdb.h>
                     63: #include <stdlib.h>
                     64: #include <string.h>
1.16      pvalchev   65: #include <err.h>
1.1       deraadt    66: #include <nlist.h>
                     67: #include <paths.h>
                     68: #include "systat.h"
1.31    ! canacar    69: #include "engine.h"
        !            70:
        !            71: struct netinfo {
        !            72:        union {
        !            73:                struct  in_addr nif_laddr;      /* local address */
        !            74:                struct  in6_addr nif_laddr6;    /* local address */
        !            75:        } l;
        !            76:        union {
        !            77:                struct  in_addr nif_faddr;      /* foreign address */
        !            78:                struct  in6_addr nif_faddr6;    /* foreign address */
        !            79:        } f;
        !            80:        char    *nif_proto;             /* protocol */
        !            81:        long    nif_rcvcc;              /* rcv buffer character count */
        !            82:        long    nif_sndcc;              /* snd buffer character count */
        !            83:        short   nif_lport;              /* local port */
        !            84:        short   nif_fport;              /* foreign port */
        !            85:        short   nif_state;              /* tcp state */
        !            86:        short   nif_family;
        !            87: };
        !            88:
        !            89: #define nif_laddr  l.nif_laddr
        !            90: #define nif_laddr6 l.nif_laddr6
        !            91: #define nif_faddr  f.nif_faddr
        !            92: #define nif_faddr6 f.nif_faddr6
1.1       deraadt    93:
1.21      millert    94: static void enter(struct inpcb *, struct socket *, int, char *);
                     95: static const char *inetname(struct in_addr);
1.31    ! canacar    96: static void inetprint(struct in_addr *, int, char *, field_def *);
1.21      millert    97: static const char *inet6name(struct in6_addr *);
1.31    ! canacar    98: static void inet6print(struct in6_addr *, int, char *, field_def *);
        !            99: static void shownetstat(struct netinfo *p);
        !           100:
        !           101: void print_ns(void);
        !           102: int read_ns(void);
        !           103: int select_ns(void);
        !           104: int ns_keyboard_callback(int);
1.1       deraadt   105:
                    106: #define        streq(a,b)      (strcmp(a,b)==0)
                    107:
1.31    ! canacar   108: static int aflag = 0;
        !           109:
        !           110: static struct nlist namelist[] = {
        !           111: #define        X_TCBTABLE      0               /* no sysctl */
        !           112:        { "_tcbtable" },
        !           113: #define        X_UDBTABLE      1               /* no sysctl */
        !           114:        { "_udbtable" },
        !           115:        { "" },
        !           116: };
        !           117: #define ADD_ALLOC  1000
        !           118:
        !           119:
        !           120: int protos;
        !           121:
        !           122: struct netinfo *netinfos = NULL;
        !           123: size_t num_ns = 0;
        !           124: static size_t num_alloc = 0;
        !           125:
        !           126:
        !           127: field_def fields_ns[] = {
        !           128:        {"LOCAL ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
        !           129:        {"FOREIGN ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
        !           130:        {"PROTO", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
        !           131:        {"RECV-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
        !           132:        {"SEND-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
        !           133:        {"STATE", 5, 11, 6, FLD_ALIGN_LEFT, -1, 0, 0, 0},
        !           134: };
        !           135:
        !           136: #define FIELD_ADDR(x) (&fields_ns[x])
        !           137:
        !           138: #define FLD_NS_LOCAL   FIELD_ADDR(0)
        !           139: #define FLD_NS_FOREIGN FIELD_ADDR(1)
        !           140: #define FLD_NS_PROTO   FIELD_ADDR(2)
        !           141: #define FLD_NS_RECV_Q  FIELD_ADDR(3)
        !           142: #define FLD_NS_SEND_Q  FIELD_ADDR(4)
        !           143: #define FLD_NS_STATE   FIELD_ADDR(5)
        !           144:
        !           145: /* Define views */
        !           146: field_def *view_ns_0[] = {
        !           147:        FLD_NS_LOCAL, FLD_NS_FOREIGN, FLD_NS_PROTO,
        !           148:        FLD_NS_RECV_Q, FLD_NS_SEND_Q, FLD_NS_STATE, NULL
        !           149: };
        !           150:
        !           151: /* Define view managers */
        !           152: struct view_manager netstat_mgr = {
        !           153:        "Netstat", select_ns, read_ns, NULL, print_header,
        !           154:        print_ns, ns_keyboard_callback, NULL, NULL
        !           155: };
1.1       deraadt   156:
1.31    ! canacar   157: field_view views_ns[] = {
        !           158:        {view_ns_0, "netstat", '0', &netstat_mgr},
        !           159:        {NULL, NULL, 0, NULL}
1.1       deraadt   160: };
                    161:
                    162:
                    163:
1.31    ! canacar   164:
        !           165: struct netinfo *
        !           166: next_ns(void)
        !           167: {
        !           168:        if (num_alloc <= num_ns) {
        !           169:                struct netinfo *ni;
        !           170:                size_t a = num_alloc + ADD_ALLOC;
        !           171:                if (a < num_alloc)
        !           172:                        return NULL;
        !           173:                ni = realloc(netinfos, a * sizeof(*ni));
        !           174:                if (ni == NULL)
        !           175:                        return NULL;
        !           176:                netinfos = ni;
        !           177:                num_alloc = a;
        !           178:        }
        !           179:
        !           180:        return &netinfos[num_ns++];
        !           181: }
        !           182:
        !           183: static void
        !           184: enter(struct inpcb *inp, struct socket *so, int state, char *proto)
1.1       deraadt   185: {
1.17      mpech     186:        struct netinfo *p;
1.1       deraadt   187:
1.31    ! canacar   188:        p = next_ns();
        !           189:        if (p == NULL) {
        !           190:                error("Out of Memory!");
        !           191:                return;
1.1       deraadt   192:        }
1.31    ! canacar   193:
        !           194:        p->nif_lport = inp->inp_lport;
        !           195:        p->nif_fport = inp->inp_fport;
        !           196:        p->nif_proto = proto;
        !           197:
        !           198:        if (inp->inp_flags & INP_IPV6) {
        !           199:                p->nif_laddr6 = inp->inp_laddr6;
        !           200:                p->nif_faddr6 = inp->inp_faddr6;
        !           201:                p->nif_family = AF_INET6;
        !           202:        } else {
        !           203:                p->nif_laddr = inp->inp_laddr;
        !           204:                p->nif_faddr = inp->inp_faddr;
        !           205:                p->nif_family = AF_INET;
        !           206:        }
        !           207:
        !           208:        p->nif_rcvcc = so->so_rcv.sb_cc;
        !           209:        p->nif_sndcc = so->so_snd.sb_cc;
        !           210:        p->nif_state = state;
1.1       deraadt   211: }
                    212:
1.31    ! canacar   213:
        !           214: /* netstat callback functions */
1.1       deraadt   215:
                    216: int
1.31    ! canacar   217: select_ns(void)
1.1       deraadt   218: {
1.31    ! canacar   219:        static int init = 0;
        !           220:        if (kd == NULL) {
        !           221:                num_disp = 1;
        !           222:                return (0);
        !           223:        }
1.14      ericj     224:
1.31    ! canacar   225:        if (!init) {
        !           226:                sethostent(1);
        !           227:                setnetent(1);
        !           228:                init = 1;
1.1       deraadt   229:        }
1.31    ! canacar   230:
        !           231:        num_disp = num_ns;
        !           232:        return (0);
1.1       deraadt   233: }
                    234:
1.31    ! canacar   235: int
        !           236: read_ns(void)
1.1       deraadt   237: {
                    238:        struct inpcbtable pcbtable;
1.17      mpech     239:        struct inpcb *head, *prev, *next;
1.1       deraadt   240:        struct inpcb inpcb;
                    241:        struct socket sockb;
                    242:        struct tcpcb tcpcb;
                    243:        void *off;
                    244:        int istcp;
                    245:
1.31    ! canacar   246:        if (kd == NULL) {
        !           247:                return (0);
        !           248:        }
        !           249:
        !           250:        num_ns = 0;
        !           251:
1.1       deraadt   252:        if (namelist[X_TCBTABLE].n_value == 0)
1.31    ! canacar   253:                return 0;
        !           254:
        !           255:        if (protos & TCP) {
1.20      deraadt   256:                off = NPTR(X_TCBTABLE);
1.1       deraadt   257:                istcp = 1;
1.31    ! canacar   258:        } else if (protos & UDP) {
1.20      deraadt   259:                off = NPTR(X_UDBTABLE);
1.1       deraadt   260:                istcp = 0;
1.20      deraadt   261:        } else {
1.1       deraadt   262:                error("No protocols to display");
1.31    ! canacar   263:                return 0;
1.1       deraadt   264:        }
1.31    ! canacar   265:
1.1       deraadt   266: again:
                    267:        KREAD(off, &pcbtable, sizeof (struct inpcbtable));
1.31    ! canacar   268:
1.1       deraadt   269:        prev = head = (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue;
1.28      otto      270:        next = CIRCLEQ_FIRST(&pcbtable.inpt_queue);
1.31    ! canacar   271:
1.1       deraadt   272:        while (next != head) {
                    273:                KREAD(next, &inpcb, sizeof (inpcb));
1.28      otto      274:                if (CIRCLEQ_PREV(&inpcb, inp_queue) != prev) {
1.1       deraadt   275:                        error("Kernel state in transition");
1.31    ! canacar   276:                        return 0;
1.1       deraadt   277:                }
                    278:                prev = next;
1.28      otto      279:                next = CIRCLEQ_NEXT(&inpcb, inp_queue);
1.12      itojun    280:
                    281:                if (!aflag) {
1.20      deraadt   282:                        if (!(inpcb.inp_flags & INP_IPV6) &&
                    283:                            inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
1.12      itojun    284:                                continue;
1.20      deraadt   285:                        if ((inpcb.inp_flags & INP_IPV6) &&
                    286:                            IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_laddr6))
1.12      itojun    287:                                continue;
                    288:                }
1.1       deraadt   289:                KREAD(inpcb.inp_socket, &sockb, sizeof (sockb));
                    290:                if (istcp) {
                    291:                        KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
                    292:                        enter(&inpcb, &sockb, tcpcb.t_state, "tcp");
                    293:                } else
                    294:                        enter(&inpcb, &sockb, 0, "udp");
                    295:        }
1.31    ! canacar   296:        if (istcp && (protos & UDP)) {
1.1       deraadt   297:                istcp = 0;
                    298:                off = NPTR(X_UDBTABLE);
                    299:                goto again;
                    300:        }
1.31    ! canacar   301:
        !           302:        num_disp = num_ns;
        !           303:        return 0;
1.1       deraadt   304: }
                    305:
1.31    ! canacar   306: void
        !           307: print_ns(void)
1.1       deraadt   308: {
1.31    ! canacar   309:        int n, count = 0;
1.1       deraadt   310:
1.31    ! canacar   311:        if (kd == NULL) {
        !           312:                print_fld_str(FLD_NS_LOCAL, "Failed to initialize KVM!");
        !           313:                print_fld_str(FLD_NS_FOREIGN, "Failed to initialize KVM!");
        !           314:                end_line();
        !           315:                return;
1.1       deraadt   316:        }
1.31    ! canacar   317:
        !           318:        for (n = dispstart; n < num_disp; n++) {
        !           319:                shownetstat(netinfos + n);
        !           320:                count++;
        !           321:                if (maxprint > 0 && count >= maxprint)
        !           322:                        break;
1.11      angelos   323:        }
1.1       deraadt   324: }
                    325:
                    326:
1.31    ! canacar   327: int
        !           328: initnetstat(void)
        !           329: {
        !           330:        field_view *v;
        !           331:        int ret;
1.1       deraadt   332:
1.31    ! canacar   333:        if (kd) {
        !           334:                if ((ret = kvm_nlist(kd, namelist)) == -1)
        !           335:                        errx(1, "%s", kvm_geterr(kd));
        !           336:                else if (ret)
        !           337:                        nlisterr(namelist);
        !           338:
        !           339:                if (namelist[X_TCBTABLE].n_value == 0) {
        !           340:                        error("No symbols in namelist");
        !           341:                        return(0);
        !           342:                }
        !           343:        }
        !           344:        protos = TCP|UDP;
        !           345:
        !           346:        for (v = views_ns; v->name != NULL; v++)
        !           347:                add_view(v);
        !           348:
        !           349:        return(1);
1.1       deraadt   350: }
                    351:
1.31    ! canacar   352: static void
        !           353: shownetstat(struct netinfo *p)
1.1       deraadt   354: {
1.31    ! canacar   355:        switch (p->nif_family) {
        !           356:        case AF_INET:
        !           357:                inetprint(&p->nif_laddr, p->nif_lport,
        !           358:                          p->nif_proto, FLD_NS_LOCAL);
        !           359:                inetprint(&p->nif_faddr, p->nif_fport,
        !           360:                          p->nif_proto, FLD_NS_FOREIGN);
        !           361:                break;
        !           362:        case AF_INET6:
        !           363:                inet6print(&p->nif_laddr6, p->nif_lport,
        !           364:                           p->nif_proto, FLD_NS_LOCAL);
        !           365:                inet6print(&p->nif_faddr6, p->nif_fport,
        !           366:                           p->nif_proto, FLD_NS_FOREIGN);
        !           367:                break;
        !           368:        }
        !           369:
        !           370:        tb_start();
        !           371:        tbprintf("%s", p->nif_proto);
        !           372:        if (p->nif_family == AF_INET6)
        !           373:                tbprintf("6");
        !           374:
        !           375:        print_fld_tb(FLD_NS_PROTO);
        !           376:
        !           377:        print_fld_size(FLD_NS_RECV_Q, p->nif_rcvcc);
        !           378:        print_fld_size(FLD_NS_SEND_Q, p->nif_sndcc);
        !           379:
        !           380:        if (streq(p->nif_proto, "tcp")) {
        !           381:                if (p->nif_state < 0 || p->nif_state >= TCP_NSTATES)
        !           382:                        print_fld_uint(FLD_NS_STATE, p->nif_state);
        !           383:                else
        !           384:                        print_fld_str(FLD_NS_STATE, tcpstates[p->nif_state]);
1.1       deraadt   385:        }
1.31    ! canacar   386:        end_line();
1.1       deraadt   387: }
                    388:
                    389: /*
                    390:  * Pretty print an Internet address (net address + port).
                    391:  * If the nflag was specified, use numbers instead of names.
                    392:  */
                    393: static void
1.31    ! canacar   394: inetprint(struct in_addr *in, int port, char *proto, field_def *fld)
1.1       deraadt   395: {
                    396:        struct servent *sp = 0;
                    397:
1.31    ! canacar   398:        tb_start();
        !           399:        tbprintf("%s", inetname(*in));
        !           400:
1.1       deraadt   401:        if (!nflag && port)
                    402:                sp = getservbyport(port, proto);
                    403:        if (sp || port == 0)
1.31    ! canacar   404:                tbprintf(":%s", sp ? sp->s_name : "*");
1.1       deraadt   405:        else
1.31    ! canacar   406:                tbprintf(":%d", ntohs((u_short)port));
        !           407:
        !           408:        print_fld_tb(fld);
1.1       deraadt   409: }
                    410:
1.12      itojun    411: static void
1.31    ! canacar   412: inet6print(struct in6_addr *in6, int port, char *proto, field_def *fld)
1.12      itojun    413: {
                    414:        struct servent *sp = 0;
                    415:
1.31    ! canacar   416:        tb_start();
        !           417:
        !           418:        tbprintf("%s", inet6name(in6));
1.12      itojun    419:        if (!nflag && port)
                    420:                sp = getservbyport(port, proto);
                    421:        if (sp || port == 0)
1.31    ! canacar   422:                tbprintf(":%s", sp ? sp->s_name : "*");
1.12      itojun    423:        else
1.31    ! canacar   424:                tbprintf(":%d", ntohs((u_short)port));
1.12      itojun    425:
1.31    ! canacar   426:        print_fld_tb(fld);
1.1       deraadt   427: }
1.12      itojun    428:
                    429: static const char *
1.22      deraadt   430: inet6name(struct in6_addr *in6)
1.12      itojun    431: {
                    432:        static char line[NI_MAXHOST];
                    433:        struct sockaddr_in6 sin6;
                    434:        int flags;
                    435:
1.25      itojun    436:        flags = nflag ? NI_NUMERICHOST : 0;
1.12      itojun    437:        if (IN6_IS_ADDR_UNSPECIFIED(in6))
                    438:                return "*";
                    439:        memset(&sin6, 0, sizeof(sin6));
                    440:        sin6.sin6_family = AF_INET6;
                    441:        sin6.sin6_len = sizeof(struct sockaddr_in6);
                    442:        sin6.sin6_addr = *in6;
                    443:        if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
1.20      deraadt   444:            line, sizeof(line), NULL, 0, flags) == 0)
1.12      itojun    445:                return line;
                    446:        return "?";
                    447: }
1.1       deraadt   448:
1.31    ! canacar   449: static const char *
        !           450: inetname(struct in_addr in)
        !           451: {
        !           452:        static char line[NI_MAXHOST];
        !           453:        struct sockaddr_in sin;
        !           454:        int flags, e;
        !           455:
        !           456:        flags = nflag ? NI_NUMERICHOST : 0;
        !           457:        if (in.s_addr == INADDR_ANY)
        !           458:                return "*";
        !           459:
        !           460:        memset(&sin, 0, sizeof(sin));
        !           461:        sin.sin_family = AF_INET;
        !           462:        sin.sin_len = sizeof(struct sockaddr_in);
        !           463:        sin.sin_addr = in;
        !           464:
        !           465:        e = getnameinfo((struct sockaddr *)&sin, sin.sin_len,
        !           466:                        line, sizeof(line), NULL, 0, flags);
        !           467:
        !           468:        if (e == 0)
        !           469:                return line;
        !           470:
        !           471:        error("Lookup: %s", gai_strerror(e));
        !           472:
        !           473:        return "?";
        !           474: }
        !           475:
        !           476: int
        !           477: kvm_ckread(void *a, void *b, size_t l)
        !           478: {
        !           479:        if (kvm_read(kd, (u_long)a, b, l) != l) {
        !           480:                if (verbose)
        !           481:                        error("error reading kmem at %x\n", a);
        !           482:                return (0);
        !           483:        } else
        !           484:                return (1);
        !           485: }
        !           486:
        !           487:
1.1       deraadt   488: int
1.31    ! canacar   489: ns_keyboard_callback(int ch)
1.1       deraadt   490: {
1.31    ! canacar   491:        switch (ch) {
        !           492:        case 'n':
        !           493:                nflag = !nflag;
        !           494:                gotsig_alarm = 1;
        !           495:                break;
        !           496:        case 't':
        !           497:                protos ^= TCP;
        !           498:                gotsig_alarm = 1;
        !           499:                break;
        !           500:        case 'u':
        !           501:                protos ^= UDP;
        !           502:                gotsig_alarm = 1;
        !           503:                break;
        !           504:        default:
        !           505:                return keyboard_callback(ch);
        !           506:        };
1.1       deraadt   507:
1.31    ! canacar   508:        return 1;
1.1       deraadt   509: }
1.31    ! canacar   510: