Path: blob/main/contrib/bsnmp/snmp_mibII/mibII_tcp.c
39478 views
/*1* Copyright (c) 2001-20032* Fraunhofer Institute for Open Communication Systems (FhG Fokus).3* All rights reserved.4*5* Author: Harti Brandt <[email protected]>6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*28* $Begemot: bsnmp/snmp_mibII/mibII_tcp.c,v 1.7 2005/05/23 09:03:42 brandt_h Exp $29*30* tcp31*/32#include "mibII.h"33#include "mibII_oid.h"34#include <sys/socketvar.h>35#include <netinet/in_pcb.h>36#include <netinet/tcp.h>37#include <netinet/tcp_var.h>38#include <netinet/tcp_fsm.h>3940struct tcp_index {41struct asn_oid index;42struct xtcpcb *tp;43};4445static uint64_t tcp_tick;46static uint64_t tcp_stats_tick;47static struct tcpstat tcpstat;48static uint64_t tcps_states[TCP_NSTATES];49static struct xinpgen *xinpgen;50static size_t xinpgen_len;51static u_int tcp_total;52static int tcp_rexmit_min;53static int tcp_rexmit_max;54static u_int oidnum;55static struct tcp_index *tcpoids;5657static int58tcp_compare(const void *p1, const void *p2)59{60const struct tcp_index *t1 = p1;61const struct tcp_index *t2 = p2;6263return (asn_compare_oid(&t1->index, &t2->index));64}6566static int67fetch_tcp_stats(void)68{69size_t len;7071len = sizeof(tcpstat);72if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, NULL, 0) == -1) {73syslog(LOG_ERR, "net.inet.tcp.stats: %m");74return (-1);75}76if (len != sizeof(tcpstat)) {77syslog(LOG_ERR, "net.inet.tcp.stats: wrong size");78return (-1);79}8081len = sizeof(tcps_states);82if (sysctlbyname("net.inet.tcp.states", &tcps_states, &len, NULL,830) == -1) {84syslog(LOG_ERR, "net.inet.tcp.states: %m");85return (-1);86}87if (len != sizeof(tcps_states)) {88syslog(LOG_ERR, "net.inet.tcp.states: wrong size");89return (-1);90}9192len = sizeof(tcp_rexmit_min);93if (sysctlbyname("net.inet.tcp.rexmit_min", &tcp_rexmit_min, &len,94NULL, 0) == -1) {95syslog(LOG_ERR, "net.inet.tcp.rexmit_min: %m");96return (-1);97}98if (len != sizeof(tcp_rexmit_min)) {99syslog(LOG_ERR, "net.inet.tcp.rexmit_min: wrong size");100return (-1);101}102103len = sizeof(tcp_rexmit_max);104if (sysctlbyname("net.inet.tcp.rexmit_max", &tcp_rexmit_max, &len,105NULL, 0) == -1) {106syslog(LOG_ERR, "net.inet.tcp.rexmit_max: %m");107return (-1);108}109if (len != sizeof(tcp_rexmit_max)) {110syslog(LOG_ERR, "net.inet.tcp.rexmit_max: wrong size");111return (-1);112}113114tcp_stats_tick = get_ticks();115116return (0);117}118119static int120fetch_tcp(void)121{122size_t len;123struct xinpgen *ptr;124struct xtcpcb *tp;125struct tcp_index *oid;126in_addr_t inaddr;127128len = 0;129if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) == -1) {130syslog(LOG_ERR, "net.inet.tcp.pcblist: %m");131return (-1);132}133if (len > xinpgen_len) {134if ((ptr = realloc(xinpgen, len)) == NULL) {135syslog(LOG_ERR, "%zu: %m", len);136return (-1);137}138xinpgen = ptr;139xinpgen_len = len;140}141if (sysctlbyname("net.inet.tcp.pcblist", xinpgen, &len, NULL, 0) == -1) {142syslog(LOG_ERR, "net.inet.tcp.pcblist: %m");143return (-1);144}145146tcp_tick = get_ticks();147148tcp_total = 0;149for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len);150ptr->xig_len > sizeof(struct xinpgen);151ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {152tp = (struct xtcpcb *)ptr;153if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen ||154(tp->xt_inp.inp_vflag & (INP_IPV4|INP_IPV6)) == 0)155continue;156157if (tp->xt_inp.inp_vflag & INP_IPV4)158tcp_total++;159}160161if (oidnum < tcp_total) {162oid = realloc(tcpoids, tcp_total * sizeof(tcpoids[0]));163if (oid == NULL) {164free(tcpoids);165oidnum = 0;166return (0);167}168tcpoids = oid;169oidnum = tcp_total;170}171172oid = tcpoids;173for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len);174ptr->xig_len > sizeof(struct xinpgen);175ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {176tp = (struct xtcpcb *)ptr;177if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen ||178(tp->xt_inp.inp_vflag & INP_IPV4) == 0)179continue;180oid->tp = tp;181oid->index.len = 10;182inaddr = ntohl(tp->xt_inp.inp_laddr.s_addr);183oid->index.subs[0] = (inaddr >> 24) & 0xff;184oid->index.subs[1] = (inaddr >> 16) & 0xff;185oid->index.subs[2] = (inaddr >> 8) & 0xff;186oid->index.subs[3] = (inaddr >> 0) & 0xff;187oid->index.subs[4] = ntohs(tp->xt_inp.inp_lport);188inaddr = ntohl(tp->xt_inp.inp_faddr.s_addr);189oid->index.subs[5] = (inaddr >> 24) & 0xff;190oid->index.subs[6] = (inaddr >> 16) & 0xff;191oid->index.subs[7] = (inaddr >> 8) & 0xff;192oid->index.subs[8] = (inaddr >> 0) & 0xff;193oid->index.subs[9] = ntohs(tp->xt_inp.inp_fport);194oid++;195}196197qsort(tcpoids, tcp_total, sizeof(tcpoids[0]), tcp_compare);198199return (0);200}201202/*203* Scalars204*/205int206op_tcp(struct snmp_context *ctx __unused, struct snmp_value *value,207u_int sub, u_int iidx __unused, enum snmp_op op)208{209switch (op) {210211case SNMP_OP_GETNEXT:212abort();213214case SNMP_OP_GET:215break;216217case SNMP_OP_SET:218return (SNMP_ERR_NOT_WRITEABLE);219220case SNMP_OP_ROLLBACK:221case SNMP_OP_COMMIT:222abort();223}224225if (tcp_stats_tick < this_tick)226if (fetch_tcp_stats() == -1)227return (SNMP_ERR_GENERR);228229switch (value->var.subs[sub - 1]) {230231case LEAF_tcpRtoAlgorithm:232value->v.integer = 4; /* Van Jacobson */233break;234235case LEAF_tcpRtoMin:236value->v.integer = tcp_rexmit_min;237break;238239case LEAF_tcpRtoMax:240value->v.integer = tcp_rexmit_max;241break;242243case LEAF_tcpMaxConn:244value->v.integer = -1;245break;246247case LEAF_tcpActiveOpens:248value->v.uint32 = tcpstat.tcps_connattempt;249break;250251case LEAF_tcpPassiveOpens:252value->v.uint32 = tcpstat.tcps_accepts;253break;254255case LEAF_tcpAttemptFails:256value->v.uint32 = tcpstat.tcps_conndrops;257break;258259case LEAF_tcpEstabResets:260value->v.uint32 = tcpstat.tcps_drops;261break;262263case LEAF_tcpCurrEstab:264value->v.uint32 = tcps_states[TCPS_ESTABLISHED] +265tcps_states[TCPS_CLOSE_WAIT];266break;267268case LEAF_tcpInSegs:269value->v.uint32 = tcpstat.tcps_rcvtotal;270break;271272case LEAF_tcpOutSegs:273value->v.uint32 = tcpstat.tcps_sndtotal -274tcpstat.tcps_sndrexmitpack;275break;276277case LEAF_tcpRetransSegs:278value->v.uint32 = tcpstat.tcps_sndrexmitpack;279break;280281case LEAF_tcpInErrs:282value->v.uint32 = tcpstat.tcps_rcvbadsum +283tcpstat.tcps_rcvbadoff +284tcpstat.tcps_rcvshort;285break;286}287return (SNMP_ERR_NOERROR);288}289290int291op_tcpconn(struct snmp_context *ctx __unused, struct snmp_value *value,292u_int sub, u_int iidx __unused, enum snmp_op op)293{294u_int i;295296if (tcp_tick < this_tick)297if (fetch_tcp() == -1)298return (SNMP_ERR_GENERR);299300switch (op) {301302case SNMP_OP_GETNEXT:303for (i = 0; i < tcp_total; i++)304if (index_compare(&value->var, sub, &tcpoids[i].index) < 0)305break;306if (i == tcp_total)307return (SNMP_ERR_NOSUCHNAME);308index_append(&value->var, sub, &tcpoids[i].index);309break;310311case SNMP_OP_GET:312for (i = 0; i < tcp_total; i++)313if (index_compare(&value->var, sub, &tcpoids[i].index) == 0)314break;315if (i == tcp_total)316return (SNMP_ERR_NOSUCHNAME);317break;318319case SNMP_OP_SET:320return (SNMP_ERR_NOT_WRITEABLE);321322case SNMP_OP_ROLLBACK:323case SNMP_OP_COMMIT:324default:325abort();326}327328switch (value->var.subs[sub - 1]) {329330case LEAF_tcpConnState:331switch (tcpoids[i].tp->t_state) {332333case TCPS_CLOSED:334value->v.integer = 1;335break;336case TCPS_LISTEN:337value->v.integer = 2;338break;339case TCPS_SYN_SENT:340value->v.integer = 3;341break;342case TCPS_SYN_RECEIVED:343value->v.integer = 4;344break;345case TCPS_ESTABLISHED:346value->v.integer = 5;347break;348case TCPS_CLOSE_WAIT:349value->v.integer = 8;350break;351case TCPS_FIN_WAIT_1:352value->v.integer = 6;353break;354case TCPS_CLOSING:355value->v.integer = 10;356break;357case TCPS_LAST_ACK:358value->v.integer = 9;359break;360case TCPS_FIN_WAIT_2:361value->v.integer = 7;362break;363case TCPS_TIME_WAIT:364value->v.integer = 11;365break;366default:367value->v.integer = 0;368break;369}370break;371372case LEAF_tcpConnLocalAddress:373value->v.ipaddress[0] = tcpoids[i].index.subs[0];374value->v.ipaddress[1] = tcpoids[i].index.subs[1];375value->v.ipaddress[2] = tcpoids[i].index.subs[2];376value->v.ipaddress[3] = tcpoids[i].index.subs[3];377break;378379case LEAF_tcpConnLocalPort:380value->v.integer = tcpoids[i].index.subs[4];381break;382383case LEAF_tcpConnRemAddress:384value->v.ipaddress[0] = tcpoids[i].index.subs[5];385value->v.ipaddress[1] = tcpoids[i].index.subs[6];386value->v.ipaddress[2] = tcpoids[i].index.subs[7];387value->v.ipaddress[3] = tcpoids[i].index.subs[8];388break;389390case LEAF_tcpConnRemPort:391value->v.integer = tcpoids[i].index.subs[9];392break;393}394return (SNMP_ERR_NOERROR);395}396397398