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

1.45    ! claudio     1: /*     $OpenBSD: netstat.c,v 1.44 2015/01/20 18:26:57 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:
1.45    ! claudio    37: #include <kvm.h>
        !            38: #include <sys/types.h>
        !            39: #include <sys/sysctl.h>
1.1       deraadt    40: #include <sys/socket.h>
1.45    ! claudio    41: #define _KERNEL
        !            42: #include <sys/file.h>
        !            43: #undef _KERNEL
1.1       deraadt    44:
                     45: #include <netinet/in.h>
                     46: #include <netinet/tcp.h>
                     47: #include <netinet/tcp_seq.h>
                     48: #define TCPSTATES
                     49: #include <netinet/tcp_fsm.h>
1.7       millert    50: #include <arpa/inet.h>
1.1       deraadt    51:
                     52: #include <netdb.h>
1.45    ! claudio    53: #include <signal.h>
1.1       deraadt    54: #include <stdlib.h>
                     55: #include <string.h>
1.16      pvalchev   56: #include <err.h>
1.1       deraadt    57: #include <nlist.h>
                     58: #include <paths.h>
                     59: #include "systat.h"
1.31      canacar    60: #include "engine.h"
                     61:
1.45    ! claudio    62: #define        TCP     0x1
        !            63: #define        UDP     0x2
        !            64: #define        OTHER   0x4
        !            65:
1.31      canacar    66: struct netinfo {
                     67:        union {
                     68:                struct  in_addr nif_laddr;      /* local address */
                     69:                struct  in6_addr nif_laddr6;    /* local address */
                     70:        } l;
                     71:        union {
                     72:                struct  in_addr nif_faddr;      /* foreign address */
                     73:                struct  in6_addr nif_faddr6;    /* foreign address */
                     74:        } f;
                     75:        long    nif_rcvcc;              /* rcv buffer character count */
                     76:        long    nif_sndcc;              /* snd buffer character count */
                     77:        short   nif_lport;              /* local port */
                     78:        short   nif_fport;              /* foreign port */
                     79:        short   nif_state;              /* tcp state */
                     80:        short   nif_family;
1.45    ! claudio    81:        short   nif_proto;              /* protocol */
        !            82:        short   nif_ipproto;
1.31      canacar    83: };
                     84:
                     85: #define nif_laddr  l.nif_laddr
                     86: #define nif_laddr6 l.nif_laddr6
                     87: #define nif_faddr  f.nif_faddr
                     88: #define nif_faddr6 f.nif_faddr6
1.1       deraadt    89:
1.45    ! claudio    90: static void enter(struct kinfo_file *);
        !            91: static int kf_comp(const void *, const void *);
1.31      canacar    92: static void inetprint(struct in_addr *, int, char *, field_def *);
                     93: static void inet6print(struct in6_addr *, int, char *, field_def *);
                     94: static void shownetstat(struct netinfo *p);
                     95:
                     96: void print_ns(void);
                     97: int read_ns(void);
                     98: int select_ns(void);
                     99: int ns_keyboard_callback(int);
1.1       deraadt   100:
                    101: #define        streq(a,b)      (strcmp(a,b)==0)
                    102:
1.31      canacar   103: static int aflag = 0;
                    104:
                    105: #define ADD_ALLOC  1000
                    106:
                    107: int protos;
                    108:
                    109: struct netinfo *netinfos = NULL;
                    110: size_t num_ns = 0;
                    111: static size_t num_alloc = 0;
                    112:
                    113:
                    114: field_def fields_ns[] = {
                    115:        {"LOCAL ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    116:        {"FOREIGN ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    117:        {"PROTO", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    118:        {"RECV-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    119:        {"SEND-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
                    120:        {"STATE", 5, 11, 6, FLD_ALIGN_LEFT, -1, 0, 0, 0},
                    121: };
                    122:
1.34      jasper    123: #define FLD_NS_LOCAL   FIELD_ADDR(fields_ns,0)
                    124: #define FLD_NS_FOREIGN FIELD_ADDR(fields_ns,1)
                    125: #define FLD_NS_PROTO   FIELD_ADDR(fields_ns,2)
                    126: #define FLD_NS_RECV_Q  FIELD_ADDR(fields_ns,3)
                    127: #define FLD_NS_SEND_Q  FIELD_ADDR(fields_ns,4)
                    128: #define FLD_NS_STATE   FIELD_ADDR(fields_ns,5)
1.31      canacar   129:
                    130: /* Define views */
                    131: field_def *view_ns_0[] = {
                    132:        FLD_NS_LOCAL, FLD_NS_FOREIGN, FLD_NS_PROTO,
                    133:        FLD_NS_RECV_Q, FLD_NS_SEND_Q, FLD_NS_STATE, NULL
                    134: };
                    135:
                    136: /* Define view managers */
                    137: struct view_manager netstat_mgr = {
                    138:        "Netstat", select_ns, read_ns, NULL, print_header,
                    139:        print_ns, ns_keyboard_callback, NULL, NULL
                    140: };
1.1       deraadt   141:
1.31      canacar   142: field_view views_ns[] = {
                    143:        {view_ns_0, "netstat", '0', &netstat_mgr},
                    144:        {NULL, NULL, 0, NULL}
1.1       deraadt   145: };
                    146:
                    147:
                    148:
1.31      canacar   149:
                    150: struct netinfo *
                    151: next_ns(void)
                    152: {
                    153:        if (num_alloc <= num_ns) {
                    154:                struct netinfo *ni;
                    155:                size_t a = num_alloc + ADD_ALLOC;
                    156:                if (a < num_alloc)
                    157:                        return NULL;
1.41      doug      158:                ni = reallocarray(netinfos, a, sizeof(*ni));
1.31      canacar   159:                if (ni == NULL)
                    160:                        return NULL;
                    161:                netinfos = ni;
                    162:                num_alloc = a;
                    163:        }
                    164:
                    165:        return &netinfos[num_ns++];
                    166: }
                    167:
                    168: static void
1.45    ! claudio   169: enter(struct kinfo_file *kf)
1.1       deraadt   170: {
1.45    ! claudio   171: #define s6_addr32 __u6_addr.__u6_addr32
1.17      mpech     172:        struct netinfo *p;
1.1       deraadt   173:
1.45    ! claudio   174:        /* first filter out unwanted sockets */
        !           175:        if (kf->so_family != AF_INET && kf->so_family != AF_INET6)
        !           176:                return;
        !           177:
        !           178:        switch (kf->so_protocol) {
        !           179:        case IPPROTO_TCP:
        !           180:                if ((protos & TCP) == 0)
        !           181:                        return;
        !           182:                break;
        !           183:        case IPPROTO_UDP:
        !           184:                if ((protos & UDP) == 0)
        !           185:                        return;
        !           186:                break;
        !           187:        default:
        !           188:                if ((protos & OTHER) == 0)
        !           189:                        return;
        !           190:                break;
        !           191:        }
        !           192:
        !           193:        if (!aflag) {
        !           194:                struct in6_addr faddr6;
        !           195:
        !           196:                switch (kf->so_family) {
        !           197:                case AF_INET:
        !           198:                        if (kf->inp_faddru[0] == INADDR_ANY)
        !           199:                                return;
        !           200:                        break;
        !           201:                case AF_INET6:
        !           202:                        faddr6.s6_addr32[0] = kf->inp_faddru[0];
        !           203:                        faddr6.s6_addr32[1] = kf->inp_faddru[1];
        !           204:                        faddr6.s6_addr32[2] = kf->inp_faddru[2];
        !           205:                        faddr6.s6_addr32[3] = kf->inp_faddru[3];
        !           206:                        if (IN6_IS_ADDR_UNSPECIFIED(&faddr6))
        !           207:                                return;
        !           208:                        break;
        !           209:                }
        !           210:        }
        !           211:
        !           212:        /* finally enter the socket to the table */
1.31      canacar   213:        p = next_ns();
                    214:        if (p == NULL) {
                    215:                error("Out of Memory!");
                    216:                return;
1.1       deraadt   217:        }
1.31      canacar   218:
1.45    ! claudio   219:        p->nif_lport = kf->inp_lport;
        !           220:        p->nif_fport = kf->inp_fport;
        !           221:        p->nif_proto = kf->so_protocol;
        !           222:        p->nif_ipproto = kf->inp_proto;
        !           223:
        !           224:        switch (kf->so_family) {
        !           225:        case AF_INET:
        !           226:                p->nif_family = AF_INET;
        !           227:                p->nif_laddr.s_addr = kf->inp_laddru[0];
        !           228:                p->nif_faddr.s_addr = kf->inp_faddru[0];
        !           229:                break;
        !           230:        case AF_INET6:
1.31      canacar   231:                p->nif_family = AF_INET6;
1.45    ! claudio   232:                p->nif_laddr6.s6_addr32[0] = kf->inp_laddru[0];
        !           233:                p->nif_laddr6.s6_addr32[1] = kf->inp_laddru[1];
        !           234:                p->nif_laddr6.s6_addr32[2] = kf->inp_laddru[2];
        !           235:                p->nif_laddr6.s6_addr32[3] = kf->inp_laddru[3];
        !           236:                p->nif_faddr6.s6_addr32[0] = kf->inp_faddru[0];
        !           237:                p->nif_faddr6.s6_addr32[1] = kf->inp_faddru[1];
        !           238:                p->nif_faddr6.s6_addr32[2] = kf->inp_faddru[2];
        !           239:                p->nif_faddr6.s6_addr32[3] = kf->inp_faddru[3];
        !           240:                break;
1.31      canacar   241:        }
                    242:
1.45    ! claudio   243:        p->nif_rcvcc = kf->so_rcv_cc;
        !           244:        p->nif_sndcc = kf->so_snd_cc;
        !           245:        p->nif_state = kf->t_state;
        !           246: #undef s6_addr32
1.1       deraadt   247: }
                    248:
1.31      canacar   249:
                    250: /* netstat callback functions */
1.1       deraadt   251:
                    252: int
1.31      canacar   253: select_ns(void)
1.1       deraadt   254: {
1.45    ! claudio   255:        num_disp = num_ns;
        !           256:        return (0);
        !           257: }
        !           258:
        !           259: static int type_map[] = { -1, 2, 3, 1, 4, 5 };
        !           260:
        !           261: static int
        !           262: kf_comp(const void *a, const void *b)
        !           263: {
        !           264:        const struct kinfo_file *ka = a, *kb = b;
        !           265:
        !           266:        if (ka->so_family != kb->so_family) {
        !           267:                /* AF_INET < AF_INET6 < AF_LOCAL */
        !           268:                if (ka->so_family == AF_INET)
        !           269:                        return (-1);
        !           270:                if (ka->so_family == AF_LOCAL)
        !           271:                        return (1);
        !           272:                if (kb->so_family == AF_LOCAL)
        !           273:                        return (-1);
        !           274:                return (1);
        !           275:        }
        !           276:        if (ka->so_family == AF_LOCAL) {
        !           277:                if (type_map[ka->so_type] < type_map[kb->so_type])
        !           278:                        return (-1);
        !           279:                if (type_map[ka->so_type] > type_map[kb->so_type])
        !           280:                        return (1);
        !           281:        } else if (ka->so_family == AF_INET || ka->so_family == AF_INET6) {
        !           282:                if (ka->so_protocol < kb->so_protocol)
        !           283:                        return (-1);
        !           284:                if (ka->so_protocol > kb->so_protocol)
        !           285:                        return (1);
        !           286:                if (ka->so_type == SOCK_DGRAM || ka->so_type == SOCK_STREAM) {
        !           287:                        /* order sockets by remote port desc */
        !           288:                        if (ka->inp_fport > kb->inp_fport)
        !           289:                                return (-1);
        !           290:                        if (ka->inp_fport < kb->inp_fport)
        !           291:                                return (1);
        !           292:                } else if (ka->so_type == SOCK_RAW) {
        !           293:                        if (ka->inp_proto > kb->inp_proto)
        !           294:                                return (-1);
        !           295:                        if (ka->inp_proto < kb->inp_proto)
        !           296:                                return (1);
        !           297:                }
1.31      canacar   298:        }
                    299:        return (0);
1.1       deraadt   300: }
                    301:
1.45    ! claudio   302:
1.31      canacar   303: int
                    304: read_ns(void)
1.1       deraadt   305: {
1.45    ! claudio   306:        struct kinfo_file *kf;
        !           307:        int i, fcnt;
1.1       deraadt   308:
1.31      canacar   309:        if (kd == NULL) {
1.45    ! claudio   310:                error("Failed to initialize KVM!");
1.31      canacar   311:                return (0);
                    312:        }
1.45    ! claudio   313:        kf = kvm_getfiles(kd, KERN_FILE_BYFILE, DTYPE_SOCKET,
        !           314:            sizeof(*kf), &fcnt);
        !           315:        if (kf == NULL) {
        !           316:                error("Out of Memory!");
        !           317:                return (0);
        !           318:        }
        !           319:
        !           320:        /* sort sockets by AF, proto and type */
        !           321:        qsort(kf, fcnt, sizeof(*kf), kf_comp);
1.31      canacar   322:
                    323:        num_ns = 0;
                    324:
1.45    ! claudio   325:        for (i = 0; i < fcnt; i++)
        !           326:                enter(&kf[i]);
1.31      canacar   327:
                    328:        num_disp = num_ns;
                    329:        return 0;
1.1       deraadt   330: }
                    331:
1.31      canacar   332: void
                    333: print_ns(void)
1.1       deraadt   334: {
1.31      canacar   335:        int n, count = 0;
1.1       deraadt   336:
1.31      canacar   337:        for (n = dispstart; n < num_disp; n++) {
                    338:                shownetstat(netinfos + n);
                    339:                count++;
                    340:                if (maxprint > 0 && count >= maxprint)
                    341:                        break;
1.11      angelos   342:        }
1.1       deraadt   343: }
                    344:
                    345:
1.31      canacar   346: int
                    347: initnetstat(void)
                    348: {
                    349:        field_view *v;
                    350:
1.45    ! claudio   351:        protos = TCP|UDP|OTHER;
1.31      canacar   352:        for (v = views_ns; v->name != NULL; v++)
                    353:                add_view(v);
                    354:
                    355:        return(1);
1.1       deraadt   356: }
                    357:
1.31      canacar   358: static void
                    359: shownetstat(struct netinfo *p)
1.1       deraadt   360: {
1.45    ! claudio   361:        char *proto = NULL;
        !           362:
        !           363:        switch (p->nif_proto) {
        !           364:        case IPPROTO_TCP:
        !           365:                proto = "tcp";
        !           366:                break;
        !           367:        case IPPROTO_UDP:
        !           368:                proto = "udp";
        !           369:                break;
        !           370:        }
        !           371:
1.31      canacar   372:        switch (p->nif_family) {
                    373:        case AF_INET:
                    374:                inetprint(&p->nif_laddr, p->nif_lport,
1.45    ! claudio   375:                          proto, FLD_NS_LOCAL);
1.31      canacar   376:                inetprint(&p->nif_faddr, p->nif_fport,
1.45    ! claudio   377:                          proto, FLD_NS_FOREIGN);
1.31      canacar   378:                break;
                    379:        case AF_INET6:
                    380:                inet6print(&p->nif_laddr6, p->nif_lport,
1.45    ! claudio   381:                           proto, FLD_NS_LOCAL);
1.31      canacar   382:                inet6print(&p->nif_faddr6, p->nif_fport,
1.45    ! claudio   383:                           proto, FLD_NS_FOREIGN);
1.31      canacar   384:                break;
                    385:        }
                    386:
                    387:        tb_start();
1.45    ! claudio   388:        switch (p->nif_proto) {
        !           389:        case IPPROTO_TCP:
        !           390:        case IPPROTO_UDP:
        !           391:                tbprintf(proto);
        !           392:                if (p->nif_family == AF_INET6)
        !           393:                        tbprintf("6");
        !           394:                break;
        !           395:        case IPPROTO_DIVERT:
        !           396:                tbprintf("divert");
        !           397:                if (p->nif_family == AF_INET6)
        !           398:                        tbprintf("6");
        !           399:                break;
        !           400:        default:
        !           401:                tbprintf("%d", p->nif_ipproto);
        !           402:                break;
        !           403:        }
1.31      canacar   404:
                    405:        print_fld_tb(FLD_NS_PROTO);
                    406:
                    407:        print_fld_size(FLD_NS_RECV_Q, p->nif_rcvcc);
                    408:        print_fld_size(FLD_NS_SEND_Q, p->nif_sndcc);
                    409:
1.45    ! claudio   410:        if (p->nif_proto == IPPROTO_TCP) {
1.31      canacar   411:                if (p->nif_state < 0 || p->nif_state >= TCP_NSTATES)
                    412:                        print_fld_uint(FLD_NS_STATE, p->nif_state);
                    413:                else
                    414:                        print_fld_str(FLD_NS_STATE, tcpstates[p->nif_state]);
1.1       deraadt   415:        }
1.31      canacar   416:        end_line();
1.1       deraadt   417: }
                    418:
                    419: /*
                    420:  * Pretty print an Internet address (net address + port).
                    421:  * If the nflag was specified, use numbers instead of names.
                    422:  */
                    423: static void
1.31      canacar   424: inetprint(struct in_addr *in, int port, char *proto, field_def *fld)
1.1       deraadt   425: {
                    426:        struct servent *sp = 0;
                    427:
1.31      canacar   428:        tb_start();
                    429:        tbprintf("%s", inetname(*in));
                    430:
1.1       deraadt   431:        if (!nflag && port)
                    432:                sp = getservbyport(port, proto);
                    433:        if (sp || port == 0)
1.31      canacar   434:                tbprintf(":%s", sp ? sp->s_name : "*");
1.1       deraadt   435:        else
1.31      canacar   436:                tbprintf(":%d", ntohs((u_short)port));
                    437:
                    438:        print_fld_tb(fld);
1.1       deraadt   439: }
                    440:
1.12      itojun    441: static void
1.31      canacar   442: inet6print(struct in6_addr *in6, int port, char *proto, field_def *fld)
1.12      itojun    443: {
                    444:        struct servent *sp = 0;
                    445:
1.31      canacar   446:        tb_start();
                    447:
                    448:        tbprintf("%s", inet6name(in6));
1.12      itojun    449:        if (!nflag && port)
                    450:                sp = getservbyport(port, proto);
                    451:        if (sp || port == 0)
1.31      canacar   452:                tbprintf(":%s", sp ? sp->s_name : "*");
1.12      itojun    453:        else
1.31      canacar   454:                tbprintf(":%d", ntohs((u_short)port));
1.12      itojun    455:
1.31      canacar   456:        print_fld_tb(fld);
                    457: }
                    458:
                    459: int
                    460: ns_keyboard_callback(int ch)
1.1       deraadt   461: {
1.31      canacar   462:        switch (ch) {
1.35      okan      463:        case 'a':
                    464:                aflag = !aflag;
                    465:                gotsig_alarm = 1;
                    466:                break;
1.31      canacar   467:        case 'n':
                    468:                nflag = !nflag;
1.45    ! claudio   469:                gotsig_alarm = 1;
        !           470:                break;
        !           471:        case 'o':
        !           472:                protos ^= OTHER;
1.35      okan      473:                gotsig_alarm = 1;
                    474:                break;
                    475:        case 'r':
                    476:                aflag = 0;
                    477:                nflag = 1;
                    478:                protos = TCP|UDP;
1.31      canacar   479:                gotsig_alarm = 1;
                    480:                break;
                    481:        case 't':
                    482:                protos ^= TCP;
                    483:                gotsig_alarm = 1;
                    484:                break;
                    485:        case 'u':
                    486:                protos ^= UDP;
                    487:                gotsig_alarm = 1;
                    488:                break;
                    489:        default:
                    490:                return keyboard_callback(ch);
                    491:        };
1.1       deraadt   492:
1.31      canacar   493:        return 1;
1.1       deraadt   494: }
1.31      canacar   495: