1 /*
2 * CDDL HEADER START
3 *
4 * This file and its contents are supplied under the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may only use this file in accordance with the terms of version
7 * 1.0 of the CDDL.
8 *
9 * A full copy of the text of the CDDL should have accompanied this
10 * source. A copy of the CDDL is also available via the Internet at
11 * http://www.illumos.org/license/CDDL.
12 *
13 * CDDL HEADER END
14 */
15 /*
16 * Copyright (c) 2015 by Delphix. All rights reserved.
17 */
18
19 #include <err.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <strings.h>
25 #include <unistd.h>
26 #include <stropts.h>
27 #include <sys/debug.h>
28 #include <sys/tihdr.h>
29 #include "connstat.h"
30
31 int
mibopen(const char * proto)32 mibopen(const char *proto)
33 {
34 int saved;
35 int fd;
36
37 fd = open("/dev/arp", O_RDWR);
38 if (fd == -1) {
39 return (-1);
40 }
41
42 if (ioctl(fd, I_PUSH, proto) == -1) {
43 saved = errno;
44 (void) close(fd);
45 errno = saved;
46 return (-1);
47 }
48
49 return (fd);
50 }
51
52 int
conn_walk(int fd,connstat_proto_t * proto,conn_walk_state_t * state)53 conn_walk(int fd, connstat_proto_t *proto, conn_walk_state_t *state)
54 {
55 struct strbuf cbuf, dbuf;
56 struct opthdr *hdr;
57 int flags, r, err = 0;
58 struct {
59 struct T_optmgmt_req req;
60 struct opthdr hdr;
61 } req;
62 union {
63 struct T_optmgmt_ack ack;
64 uint8_t space[sizeof (struct T_optmgmt_ack) +
65 sizeof (struct opthdr) * 2];
66 } ack;
67
68 bzero(&cbuf, sizeof (cbuf));
69 bzero(&dbuf, sizeof (dbuf));
70
71 req.req.PRIM_type = T_OPTMGMT_REQ;
72 req.req.OPT_offset = (caddr_t)&req.hdr - (caddr_t)&req;
73 req.req.OPT_length = sizeof (req.hdr);
74 req.req.MGMT_flags = T_CURRENT;
75
76 req.hdr.level = proto->csp_miblevel;
77 req.hdr.name = 0;
78 req.hdr.len = 0;
79
80 cbuf.buf = (caddr_t)&req;
81 cbuf.len = sizeof (req);
82
83 if (putmsg(fd, &cbuf, NULL, 0) == -1) {
84 warn("failed to request connection info: putmsg");
85 return (-1);
86 }
87
88 /*
89 * Each reply consists of a control part for one fixed structure or
90 * table, as defined in mib2.h. The format is a T_OPTMGMT_ACK
91 * containing an opthdr structure. The level and name identify the
92 * entry, and len is the size of the data part of the message.
93 */
94 for (;;) {
95 cbuf.buf = (caddr_t)&ack;
96 cbuf.maxlen = sizeof (ack);
97 flags = 0;
98
99 /*
100 * We first do a getmsg() for the control part so that we
101 * can allocate a properly sized buffer to read the data
102 * part.
103 */
104 do {
105 r = getmsg(fd, &cbuf, NULL, &flags);
106 } while (r < 0 && errno == EINTR);
107
108 if (r < 0) {
109 warn("failed to fetch further connection info");
110 err = -1;
111 break;
112 } else if ((r & MORECTL) != 0) {
113 warnx("failed to fetch full control message");
114 err = -1;
115 break;
116 }
117
118 if (cbuf.len < sizeof (struct T_optmgmt_ack) ||
119 ack.ack.PRIM_type != T_OPTMGMT_ACK ||
120 ack.ack.MGMT_flags != T_SUCCESS ||
121 ack.ack.OPT_length < sizeof (struct opthdr)) {
122 warnx("cannot process invalid message from getmsg()");
123 err = -1;
124 break;
125 }
126
127 /* LINTED E_BAD_PTR_CAST_ALIGN */
128 hdr = (struct opthdr *)((caddr_t)&ack + ack.ack.OPT_offset);
129 if (r == 0 && hdr->level == 0 && hdr->name == 0) {
130 /*
131 * snmpcom_req() has sent us the final End-Of-Data
132 * message, so there's nothing further to read.
133 */
134 break;
135 }
136
137 /* Only data should remain. */
138 VERIFY3S(r, ==, MOREDATA);
139
140 /* Allocate a buffer to hold the data portion of the message */
141 if ((dbuf.buf = realloc(dbuf.buf, hdr->len)) == NULL) {
142 warn("failed to realloc() buffer");
143 err = -1;
144 break;
145 }
146 dbuf.maxlen = hdr->len;
147 dbuf.len = 0;
148 flags = 0;
149
150 do {
151 r = getmsg(fd, NULL, &dbuf, &flags);
152 } while (r < 0 && errno == EINTR);
153
154 if (r < 0) {
155 warn("failed to fetch connection data: getmsg()");
156 err = -1;
157 break;
158 } else if (r != 0) {
159 warnx("failed to fetch all data: "
160 "getmsg() returned %d", r);
161 err = -1;
162 break;
163 }
164
165 if ((state->cws_flags & CS_IPV4) &&
166 hdr->name == proto->csp_mibv4name) {
167 proto->csp_v4walk(&dbuf, state);
168 } else if ((state->cws_flags & CS_IPV6) &&
169 hdr->name == proto->csp_mibv6name) {
170 proto->csp_v6walk(&dbuf, state);
171 }
172 }
173
174 free(dbuf.buf);
175
176 return (err);
177 }
178