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

1.44    ! deraadt     1: /*     $OpenBSD: netstat.c,v 1.43 2015/01/16 00:03:37 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:  */
1.43      deraadt    36:
                     37: #include <sys/signal.h>
1.1       deraadt    38: #include <sys/socket.h>
                     39: #include <sys/socketvar.h>
                     40: #include <sys/mbuf.h>
                     41: #include <sys/protosw.h>
                     42:
                     43: #include <netinet/in.h>
                     44: #include <net/route.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/tcp_seq.h>
                     52: #define TCPSTATES
                     53: #include <netinet/tcp_fsm.h>
                     54: #include <netinet/tcp_timer.h>
                     55: #include <netinet/tcp_var.h>
                     56: #include <netinet/udp.h>
                     57: #include <netinet/udp_var.h>
1.7       millert    58: #include <arpa/inet.h>
1.1       deraadt    59:
                     60: #include <netdb.h>
                     61: #include <stdlib.h>
                     62: #include <string.h>
1.16      pvalchev   63: #include <err.h>
1.1       deraadt    64: #include <nlist.h>
                     65: #include <paths.h>
                     66: #include "systat.h"
1.31      canacar    67: #include "engine.h"
                     68:
                     69: struct netinfo {
                     70:        union {
                     71:                struct  in_addr nif_laddr;      /* local address */
                     72:                struct  in6_addr nif_laddr6;    /* local address */
                     73:        } l;
                     74:        union {
                     75:                struct  in_addr nif_faddr;      /* foreign address */
                     76:                struct  in6_addr nif_faddr6;    /* foreign address */
                     77:        } f;
                     78:        char    *nif_proto;             /* protocol */
                     79:        long    nif_rcvcc;              /* rcv buffer character count */
                     80:        long    nif_sndcc;              /* snd buffer character count */
                     81:        short   nif_lport;              /* local port */
                     82:        short   nif_fport;              /* foreign port */
                     83:        short   nif_state;              /* tcp state */
                     84:        short   nif_family;
                     85: };
                     86:
                     87: #define nif_laddr  l.nif_laddr
                     88: #define nif_laddr6 l.nif_laddr6
                     89: #define nif_faddr  f.nif_faddr
                     90: #define nif_faddr6 f.nif_faddr6
1.1       deraadt    91:
1.21      millert    92: static void enter(struct inpcb *, struct socket *, int, char *);
1.31      canacar    93: static void inetprint(struct in_addr *, int, char *, field_def *);
                     94: static void inet6print(struct in6_addr *, int, char *, field_def *);
                     95: static void shownetstat(struct netinfo *p);
                     96:
                     97: void print_ns(void);
                     98: int read_ns(void);
                     99: int select_ns(void);
                    100: int ns_keyboard_callback(int);
1.1       deraadt   101:
                    102: #define        streq(a,b)      (strcmp(a,b)==0)
                    103:
1.31      canacar   104: static int aflag = 0;
                    105:
                    106: static struct nlist namelist[] = {
                    107: #define        X_TCBTABLE      0               /* no sysctl */
                    108:        { "_tcbtable" },
                    109: #define        X_UDBTABLE      1               /* no sysctl */
                    110:        { "_udbtable" },
                    111:        { "" },
                    112: };
                    113: #define ADD_ALLOC  1000
                    114:
                    115:
                    116: int protos;
                    117:
                    118: struct netinfo *netinfos = NULL;
                    119: size_t num_ns = 0;
                    120: static size_t num_alloc = 0;
                    121:
                    122:
                    123: field_def fields_ns[] = {
                    124:        {"LOCAL ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    125:        {"FOREIGN ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    126:        {"PROTO", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    127:        {"RECV-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    128:        {"SEND-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    129:        {"STATE", 5, 11, 6, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    130: };
                    131:
1.34      jasper    132: #define FLD_NS_LOCAL   FIELD_ADDR(fields_ns,0)
                    133: #define FLD_NS_FOREIGN FIELD_ADDR(fields_ns,1)
                    134: #define FLD_NS_PROTO   FIELD_ADDR(fields_ns,2)
                    135: #define FLD_NS_RECV_Q  FIELD_ADDR(fields_ns,3)
                    136: #define FLD_NS_SEND_Q  FIELD_ADDR(fields_ns,4)
                    137: #define FLD_NS_STATE   FIELD_ADDR(fields_ns,5)
1.31      canacar   138:
                    139: /* Define views */
                    140: field_def *view_ns_0[] = {
                    141:        FLD_NS_LOCAL, FLD_NS_FOREIGN, FLD_NS_PROTO,
                    142:        FLD_NS_RECV_Q, FLD_NS_SEND_Q, FLD_NS_STATE, NULL
                    143: };
                    144:
                    145: /* Define view managers */
                    146: struct view_manager netstat_mgr = {
                    147:        "Netstat", select_ns, read_ns, NULL, print_header,
                    148:        print_ns, ns_keyboard_callback, NULL, NULL
                    149: };
1.1       deraadt   150:
1.31      canacar   151: field_view views_ns[] = {
                    152:        {view_ns_0, "netstat", '0', &netstat_mgr},
                    153:        {NULL, NULL, 0, NULL}
1.1       deraadt   154: };
                    155:
                    156:
                    157:
1.31      canacar   158:
                    159: struct netinfo *
                    160: next_ns(void)
                    161: {
                    162:        if (num_alloc <= num_ns) {
                    163:                struct netinfo *ni;
                    164:                size_t a = num_alloc + ADD_ALLOC;
                    165:                if (a < num_alloc)
                    166:                        return NULL;
1.41      doug      167:                ni = reallocarray(netinfos, a, sizeof(*ni));
1.31      canacar   168:                if (ni == NULL)
                    169:                        return NULL;
                    170:                netinfos = ni;
                    171:                num_alloc = a;
                    172:        }
                    173:
                    174:        return &netinfos[num_ns++];
                    175: }
                    176:
                    177: static void
                    178: enter(struct inpcb *inp, struct socket *so, int state, char *proto)
1.1       deraadt   179: {
1.17      mpech     180:        struct netinfo *p;
1.1       deraadt   181:
1.31      canacar   182:        p = next_ns();
                    183:        if (p == NULL) {
                    184:                error("Out of Memory!");
                    185:                return;
1.1       deraadt   186:        }
1.31      canacar   187:
                    188:        p->nif_lport = inp->inp_lport;
                    189:        p->nif_fport = inp->inp_fport;
                    190:        p->nif_proto = proto;
                    191:
                    192:        if (inp->inp_flags & INP_IPV6) {
                    193:                p->nif_laddr6 = inp->inp_laddr6;
                    194:                p->nif_faddr6 = inp->inp_faddr6;
                    195:                p->nif_family = AF_INET6;
                    196:        } else {
                    197:                p->nif_laddr = inp->inp_laddr;
                    198:                p->nif_faddr = inp->inp_faddr;
                    199:                p->nif_family = AF_INET;
                    200:        }
                    201:
                    202:        p->nif_rcvcc = so->so_rcv.sb_cc;
                    203:        p->nif_sndcc = so->so_snd.sb_cc;
                    204:        p->nif_state = state;
1.1       deraadt   205: }
                    206:
1.31      canacar   207:
                    208: /* netstat callback functions */
1.1       deraadt   209:
                    210: int
1.31      canacar   211: select_ns(void)
1.1       deraadt   212: {
1.31      canacar   213:        if (kd == NULL) {
                    214:                num_disp = 1;
                    215:                return (0);
                    216:        }
                    217:        num_disp = num_ns;
                    218:        return (0);
1.1       deraadt   219: }
                    220:
1.31      canacar   221: int
                    222: read_ns(void)
1.1       deraadt   223: {
                    224:        struct inpcbtable pcbtable;
1.39      tedu      225:        struct inpcb *next, *prev;
                    226:        struct inpcb inpcb, prevpcb;
1.1       deraadt   227:        struct socket sockb;
                    228:        struct tcpcb tcpcb;
                    229:        void *off;
                    230:        int istcp;
                    231:
1.31      canacar   232:        if (kd == NULL) {
                    233:                return (0);
                    234:        }
                    235:
                    236:        num_ns = 0;
                    237:
1.1       deraadt   238:        if (namelist[X_TCBTABLE].n_value == 0)
1.31      canacar   239:                return 0;
                    240:
                    241:        if (protos & TCP) {
1.20      deraadt   242:                off = NPTR(X_TCBTABLE);
1.1       deraadt   243:                istcp = 1;
1.31      canacar   244:        } else if (protos & UDP) {
1.20      deraadt   245:                off = NPTR(X_UDBTABLE);
1.1       deraadt   246:                istcp = 0;
1.20      deraadt   247:        } else {
1.1       deraadt   248:                error("No protocols to display");
1.31      canacar   249:                return 0;
1.1       deraadt   250:        }
1.31      canacar   251:
1.1       deraadt   252: again:
                    253:        KREAD(off, &pcbtable, sizeof (struct inpcbtable));
1.31      canacar   254:
1.39      tedu      255:        prev = NULL;
1.37      krw       256:        next = TAILQ_FIRST(&pcbtable.inpt_queue);
1.31      canacar   257:
1.38      tedu      258:        while (next != NULL) {
1.1       deraadt   259:                KREAD(next, &inpcb, sizeof (inpcb));
1.39      tedu      260:                if (prev != NULL) {
                    261:                        KREAD(prev, &prevpcb, sizeof (prevpcb));
                    262:                        if (TAILQ_NEXT(&prevpcb, inp_queue) != next) {
                    263:                                error("Kernel state in transition");
                    264:                                return 0;
                    265:                        }
                    266:                }
                    267:                prev = next;
1.37      krw       268:                next = TAILQ_NEXT(&inpcb, inp_queue);
1.12      itojun    269:
                    270:                if (!aflag) {
1.20      deraadt   271:                        if (!(inpcb.inp_flags & INP_IPV6) &&
1.35      okan      272:                            inet_lnaof(inpcb.inp_faddr) == INADDR_ANY)
1.12      itojun    273:                                continue;
1.20      deraadt   274:                        if ((inpcb.inp_flags & INP_IPV6) &&
1.35      okan      275:                            IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_faddr6))
1.12      itojun    276:                                continue;
                    277:                }
1.1       deraadt   278:                KREAD(inpcb.inp_socket, &sockb, sizeof (sockb));
                    279:                if (istcp) {
                    280:                        KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
1.35      okan      281:                        if (!aflag && tcpcb.t_state <= TCPS_LISTEN)
                    282:                                continue;
1.1       deraadt   283:                        enter(&inpcb, &sockb, tcpcb.t_state, "tcp");
                    284:                } else
                    285:                        enter(&inpcb, &sockb, 0, "udp");
                    286:        }
1.31      canacar   287:        if (istcp && (protos & UDP)) {
1.1       deraadt   288:                istcp = 0;
                    289:                off = NPTR(X_UDBTABLE);
                    290:                goto again;
                    291:        }
1.31      canacar   292:
                    293:        num_disp = num_ns;
                    294:        return 0;
1.1       deraadt   295: }
                    296:
1.31      canacar   297: void
                    298: print_ns(void)
1.1       deraadt   299: {
1.31      canacar   300:        int n, count = 0;
1.1       deraadt   301:
1.31      canacar   302:        if (kd == NULL) {
                    303:                print_fld_str(FLD_NS_LOCAL, "Failed to initialize KVM!");
                    304:                print_fld_str(FLD_NS_FOREIGN, "Failed to initialize KVM!");
                    305:                end_line();
                    306:                return;
1.1       deraadt   307:        }
1.31      canacar   308:
                    309:        for (n = dispstart; n < num_disp; n++) {
                    310:                shownetstat(netinfos + n);
                    311:                count++;
                    312:                if (maxprint > 0 && count >= maxprint)
                    313:                        break;
1.11      angelos   314:        }
1.1       deraadt   315: }
                    316:
                    317:
1.31      canacar   318: int
                    319: initnetstat(void)
                    320: {
                    321:        field_view *v;
                    322:        int ret;
1.1       deraadt   323:
1.31      canacar   324:        if (kd) {
                    325:                if ((ret = kvm_nlist(kd, namelist)) == -1)
                    326:                        errx(1, "%s", kvm_geterr(kd));
                    327:                else if (ret)
                    328:                        nlisterr(namelist);
                    329:
                    330:                if (namelist[X_TCBTABLE].n_value == 0) {
                    331:                        error("No symbols in namelist");
                    332:                        return(0);
                    333:                }
                    334:        }
                    335:        protos = TCP|UDP;
                    336:
                    337:        for (v = views_ns; v->name != NULL; v++)
                    338:                add_view(v);
                    339:
                    340:        return(1);
1.1       deraadt   341: }
                    342:
1.31      canacar   343: static void
                    344: shownetstat(struct netinfo *p)
1.1       deraadt   345: {
1.31      canacar   346:        switch (p->nif_family) {
                    347:        case AF_INET:
                    348:                inetprint(&p->nif_laddr, p->nif_lport,
                    349:                          p->nif_proto, FLD_NS_LOCAL);
                    350:                inetprint(&p->nif_faddr, p->nif_fport,
                    351:                          p->nif_proto, FLD_NS_FOREIGN);
                    352:                break;
                    353:        case AF_INET6:
                    354:                inet6print(&p->nif_laddr6, p->nif_lport,
                    355:                           p->nif_proto, FLD_NS_LOCAL);
                    356:                inet6print(&p->nif_faddr6, p->nif_fport,
                    357:                           p->nif_proto, FLD_NS_FOREIGN);
                    358:                break;
                    359:        }
                    360:
                    361:        tb_start();
                    362:        tbprintf("%s", p->nif_proto);
                    363:        if (p->nif_family == AF_INET6)
                    364:                tbprintf("6");
                    365:
                    366:        print_fld_tb(FLD_NS_PROTO);
                    367:
                    368:        print_fld_size(FLD_NS_RECV_Q, p->nif_rcvcc);
                    369:        print_fld_size(FLD_NS_SEND_Q, p->nif_sndcc);
                    370:
                    371:        if (streq(p->nif_proto, "tcp")) {
                    372:                if (p->nif_state < 0 || p->nif_state >= TCP_NSTATES)
                    373:                        print_fld_uint(FLD_NS_STATE, p->nif_state);
                    374:                else
                    375:                        print_fld_str(FLD_NS_STATE, tcpstates[p->nif_state]);
1.1       deraadt   376:        }
1.31      canacar   377:        end_line();
1.1       deraadt   378: }
                    379:
                    380: /*
                    381:  * Pretty print an Internet address (net address + port).
                    382:  * If the nflag was specified, use numbers instead of names.
                    383:  */
                    384: static void
1.31      canacar   385: inetprint(struct in_addr *in, int port, char *proto, field_def *fld)
1.1       deraadt   386: {
                    387:        struct servent *sp = 0;
                    388:
1.31      canacar   389:        tb_start();
                    390:        tbprintf("%s", inetname(*in));
                    391:
1.1       deraadt   392:        if (!nflag && port)
                    393:                sp = getservbyport(port, proto);
                    394:        if (sp || port == 0)
1.31      canacar   395:                tbprintf(":%s", sp ? sp->s_name : "*");
1.1       deraadt   396:        else
1.31      canacar   397:                tbprintf(":%d", ntohs((u_short)port));
                    398:
                    399:        print_fld_tb(fld);
1.1       deraadt   400: }
                    401:
1.12      itojun    402: static void
1.31      canacar   403: inet6print(struct in6_addr *in6, int port, char *proto, field_def *fld)
1.12      itojun    404: {
                    405:        struct servent *sp = 0;
                    406:
1.31      canacar   407:        tb_start();
                    408:
                    409:        tbprintf("%s", inet6name(in6));
1.12      itojun    410:        if (!nflag && port)
                    411:                sp = getservbyport(port, proto);
                    412:        if (sp || port == 0)
1.31      canacar   413:                tbprintf(":%s", sp ? sp->s_name : "*");
1.12      itojun    414:        else
1.31      canacar   415:                tbprintf(":%d", ntohs((u_short)port));
1.12      itojun    416:
1.31      canacar   417:        print_fld_tb(fld);
                    418: }
                    419:
                    420: int
                    421: kvm_ckread(void *a, void *b, size_t l)
                    422: {
                    423:        if (kvm_read(kd, (u_long)a, b, l) != l) {
                    424:                if (verbose)
1.36      deraadt   425:                        error("error reading kmem\n");
1.31      canacar   426:                return (0);
                    427:        } else
                    428:                return (1);
                    429: }
                    430:
                    431:
1.1       deraadt   432: int
1.31      canacar   433: ns_keyboard_callback(int ch)
1.1       deraadt   434: {
1.31      canacar   435:        switch (ch) {
1.35      okan      436:        case 'a':
                    437:                aflag = !aflag;
                    438:                gotsig_alarm = 1;
                    439:                break;
1.31      canacar   440:        case 'n':
                    441:                nflag = !nflag;
1.35      okan      442:                gotsig_alarm = 1;
                    443:                break;
                    444:        case 'r':
                    445:                aflag = 0;
                    446:                nflag = 1;
                    447:                protos = TCP|UDP;
1.31      canacar   448:                gotsig_alarm = 1;
                    449:                break;
                    450:        case 't':
                    451:                protos ^= TCP;
                    452:                gotsig_alarm = 1;
                    453:                break;
                    454:        case 'u':
                    455:                protos ^= UDP;
                    456:                gotsig_alarm = 1;
                    457:                break;
                    458:        default:
                    459:                return keyboard_callback(ch);
                    460:        };
1.1       deraadt   461:
1.31      canacar   462:        return 1;
1.1       deraadt   463: }
1.31      canacar   464: