1 /* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 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 * 17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Begemot: bsnmp/snmp_mibII/mibII_tcp.c,v 1.7 2005/05/23 09:03:42 brandt_h Exp $ 30 * 31 * tcp 32 */ 33 #include "mibII.h" 34 #include "mibII_oid.h" 35 #include <sys/socketvar.h> 36 #include <netinet/in_pcb.h> 37 #include <netinet/tcp.h> 38 #include <netinet/tcp_var.h> 39 #include <netinet/tcp_timer.h> 40 #include <netinet/tcp_fsm.h> 41 42 struct tcp_index { 43 struct asn_oid index; 44 struct xtcpcb *tp; 45 }; 46 47 static uint64_t tcp_tick; 48 static struct tcpstat tcpstat; 49 static struct xinpgen *xinpgen; 50 static size_t xinpgen_len; 51 static u_int tcp_count; 52 static u_int tcp_total; 53 54 static u_int oidnum; 55 static struct tcp_index *tcpoids; 56 57 static int 58 tcp_compare(const void *p1, const void *p2) 59 { 60 const struct tcp_index *t1 = p1; 61 const struct tcp_index *t2 = p2; 62 63 return (asn_compare_oid(&t1->index, &t2->index)); 64 } 65 66 static int 67 fetch_tcp(void) 68 { 69 size_t len; 70 struct xinpgen *ptr; 71 struct xtcpcb *tp; 72 struct tcp_index *oid; 73 in_addr_t inaddr; 74 75 len = sizeof(tcpstat); 76 if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, NULL, 0) == -1) { 77 syslog(LOG_ERR, "net.inet.tcp.stats: %m"); 78 return (-1); 79 } 80 if (len != sizeof(tcpstat)) { 81 syslog(LOG_ERR, "net.inet.tcp.stats: wrong size"); 82 return (-1); 83 } 84 85 len = 0; 86 if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) == -1) { 87 syslog(LOG_ERR, "net.inet.tcp.pcblist: %m"); 88 return (-1); 89 } 90 if (len > xinpgen_len) { 91 if ((ptr = realloc(xinpgen, len)) == NULL) { 92 syslog(LOG_ERR, "%zu: %m", len); 93 return (-1); 94 } 95 xinpgen = ptr; 96 xinpgen_len = len; 97 } 98 if (sysctlbyname("net.inet.tcp.pcblist", xinpgen, &len, NULL, 0) == -1) { 99 syslog(LOG_ERR, "net.inet.tcp.pcblist: %m"); 100 return (-1); 101 } 102 103 tcp_tick = get_ticks(); 104 105 tcp_count = 0; 106 tcp_total = 0; 107 for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); 108 ptr->xig_len > sizeof(struct xinpgen); 109 ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { 110 tp = (struct xtcpcb *)ptr; 111 if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen || 112 (tp->xt_inp.inp_vflag & (INP_IPV4|INP_IPV6)) == 0) 113 continue; 114 115 if (tp->xt_inp.inp_vflag & INP_IPV4) 116 tcp_total++; 117 118 if (tp->xt_tp.t_state == TCPS_ESTABLISHED || 119 tp->xt_tp.t_state == TCPS_CLOSE_WAIT) 120 tcp_count++; 121 } 122 123 if (oidnum < tcp_total) { 124 oid = realloc(tcpoids, tcp_total * sizeof(tcpoids[0])); 125 if (oid == NULL) { 126 free(tcpoids); 127 oidnum = 0; 128 return (0); 129 } 130 tcpoids = oid; 131 oidnum = tcp_total; 132 } 133 134 oid = tcpoids; 135 for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); 136 ptr->xig_len > sizeof(struct xinpgen); 137 ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { 138 tp = (struct xtcpcb *)ptr; 139 if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen || 140 (tp->xt_inp.inp_vflag & INP_IPV4) == 0) 141 continue; 142 oid->tp = tp; 143 oid->index.len = 10; 144 inaddr = ntohl(tp->xt_inp.inp_laddr.s_addr); 145 oid->index.subs[0] = (inaddr >> 24) & 0xff; 146 oid->index.subs[1] = (inaddr >> 16) & 0xff; 147 oid->index.subs[2] = (inaddr >> 8) & 0xff; 148 oid->index.subs[3] = (inaddr >> 0) & 0xff; 149 oid->index.subs[4] = ntohs(tp->xt_inp.inp_lport); 150 inaddr = ntohl(tp->xt_inp.inp_faddr.s_addr); 151 oid->index.subs[5] = (inaddr >> 24) & 0xff; 152 oid->index.subs[6] = (inaddr >> 16) & 0xff; 153 oid->index.subs[7] = (inaddr >> 8) & 0xff; 154 oid->index.subs[8] = (inaddr >> 0) & 0xff; 155 oid->index.subs[9] = ntohs(tp->xt_inp.inp_fport); 156 oid++; 157 } 158 159 qsort(tcpoids, tcp_total, sizeof(tcpoids[0]), tcp_compare); 160 161 return (0); 162 } 163 164 /* 165 * Scalars 166 */ 167 int 168 op_tcp(struct snmp_context *ctx __unused, struct snmp_value *value, 169 u_int sub, u_int iidx __unused, enum snmp_op op) 170 { 171 switch (op) { 172 173 case SNMP_OP_GETNEXT: 174 abort(); 175 176 case SNMP_OP_GET: 177 break; 178 179 case SNMP_OP_SET: 180 return (SNMP_ERR_NOT_WRITEABLE); 181 182 case SNMP_OP_ROLLBACK: 183 case SNMP_OP_COMMIT: 184 abort(); 185 } 186 187 if (tcp_tick < this_tick) 188 if (fetch_tcp() == -1) 189 return (SNMP_ERR_GENERR); 190 191 switch (value->var.subs[sub - 1]) { 192 193 case LEAF_tcpRtoAlgorithm: 194 value->v.integer = 4; /* Van Jacobson */ 195 break; 196 197 #define hz clockinfo.hz 198 199 case LEAF_tcpRtoMin: 200 value->v.integer = 1000 * TCPTV_MIN / hz; 201 break; 202 203 case LEAF_tcpRtoMax: 204 value->v.integer = 1000 * TCPTV_REXMTMAX / hz; 205 break; 206 #undef hz 207 208 case LEAF_tcpMaxConn: 209 value->v.integer = -1; 210 break; 211 212 case LEAF_tcpActiveOpens: 213 value->v.uint32 = tcpstat.tcps_connattempt; 214 break; 215 216 case LEAF_tcpPassiveOpens: 217 value->v.uint32 = tcpstat.tcps_accepts; 218 break; 219 220 case LEAF_tcpAttemptFails: 221 value->v.uint32 = tcpstat.tcps_conndrops; 222 break; 223 224 case LEAF_tcpEstabResets: 225 value->v.uint32 = tcpstat.tcps_drops; 226 break; 227 228 case LEAF_tcpCurrEstab: 229 value->v.uint32 = tcp_count; 230 break; 231 232 case LEAF_tcpInSegs: 233 value->v.uint32 = tcpstat.tcps_rcvtotal; 234 break; 235 236 case LEAF_tcpOutSegs: 237 value->v.uint32 = tcpstat.tcps_sndtotal - 238 tcpstat.tcps_sndrexmitpack; 239 break; 240 241 case LEAF_tcpRetransSegs: 242 value->v.uint32 = tcpstat.tcps_sndrexmitpack; 243 break; 244 245 case LEAF_tcpInErrs: 246 value->v.uint32 = tcpstat.tcps_rcvbadsum + 247 tcpstat.tcps_rcvbadoff + 248 tcpstat.tcps_rcvshort; 249 break; 250 } 251 return (SNMP_ERR_NOERROR); 252 } 253 254 int 255 op_tcpconn(struct snmp_context *ctx __unused, struct snmp_value *value, 256 u_int sub, u_int iidx __unused, enum snmp_op op) 257 { 258 u_int i; 259 260 if (tcp_tick < this_tick) 261 if (fetch_tcp() == -1) 262 return (SNMP_ERR_GENERR); 263 264 switch (op) { 265 266 case SNMP_OP_GETNEXT: 267 for (i = 0; i < tcp_total; i++) 268 if (index_compare(&value->var, sub, &tcpoids[i].index) < 0) 269 break; 270 if (i == tcp_total) 271 return (SNMP_ERR_NOSUCHNAME); 272 index_append(&value->var, sub, &tcpoids[i].index); 273 break; 274 275 case SNMP_OP_GET: 276 for (i = 0; i < tcp_total; i++) 277 if (index_compare(&value->var, sub, &tcpoids[i].index) == 0) 278 break; 279 if (i == tcp_total) 280 return (SNMP_ERR_NOSUCHNAME); 281 break; 282 283 case SNMP_OP_SET: 284 return (SNMP_ERR_NOT_WRITEABLE); 285 286 case SNMP_OP_ROLLBACK: 287 case SNMP_OP_COMMIT: 288 default: 289 abort(); 290 } 291 292 switch (value->var.subs[sub - 1]) { 293 294 case LEAF_tcpConnState: 295 switch (tcpoids[i].tp->xt_tp.t_state) { 296 297 case TCPS_CLOSED: 298 value->v.integer = 1; 299 break; 300 case TCPS_LISTEN: 301 value->v.integer = 2; 302 break; 303 case TCPS_SYN_SENT: 304 value->v.integer = 3; 305 break; 306 case TCPS_SYN_RECEIVED: 307 value->v.integer = 4; 308 break; 309 case TCPS_ESTABLISHED: 310 value->v.integer = 5; 311 break; 312 case TCPS_CLOSE_WAIT: 313 value->v.integer = 8; 314 break; 315 case TCPS_FIN_WAIT_1: 316 value->v.integer = 6; 317 break; 318 case TCPS_CLOSING: 319 value->v.integer = 10; 320 break; 321 case TCPS_LAST_ACK: 322 value->v.integer = 9; 323 break; 324 case TCPS_FIN_WAIT_2: 325 value->v.integer = 7; 326 break; 327 case TCPS_TIME_WAIT: 328 value->v.integer = 11; 329 break; 330 default: 331 value->v.integer = 0; 332 break; 333 } 334 break; 335 336 case LEAF_tcpConnLocalAddress: 337 value->v.ipaddress[0] = tcpoids[i].index.subs[0]; 338 value->v.ipaddress[1] = tcpoids[i].index.subs[1]; 339 value->v.ipaddress[2] = tcpoids[i].index.subs[2]; 340 value->v.ipaddress[3] = tcpoids[i].index.subs[3]; 341 break; 342 343 case LEAF_tcpConnLocalPort: 344 value->v.integer = tcpoids[i].index.subs[4]; 345 break; 346 347 case LEAF_tcpConnRemAddress: 348 value->v.ipaddress[0] = tcpoids[i].index.subs[5]; 349 value->v.ipaddress[1] = tcpoids[i].index.subs[6]; 350 value->v.ipaddress[2] = tcpoids[i].index.subs[7]; 351 value->v.ipaddress[3] = tcpoids[i].index.subs[8]; 352 break; 353 354 case LEAF_tcpConnRemPort: 355 value->v.integer = tcpoids[i].index.subs[9]; 356 break; 357 } 358 return (SNMP_ERR_NOERROR); 359 } 360