1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21 #include "sysinfo.h"
22 #include "zbxjson.h"
23 #include "log.h"
24
25 static struct nlist kernel_symbols[] =
26 {
27 {"_ifnet", N_UNDF, 0, 0, 0},
28 {"_tcbtable", N_UNDF, 0, 0, 0},
29 {NULL, 0, 0, 0, 0}
30 };
31
32 #define IFNET_ID 0
33
get_ifdata(const char * if_name,zbx_uint64_t * ibytes,zbx_uint64_t * ipackets,zbx_uint64_t * ierrors,zbx_uint64_t * idropped,zbx_uint64_t * obytes,zbx_uint64_t * opackets,zbx_uint64_t * oerrors,zbx_uint64_t * tbytes,zbx_uint64_t * tpackets,zbx_uint64_t * terrors,zbx_uint64_t * icollisions,char ** error)34 static int get_ifdata(const char *if_name,
35 zbx_uint64_t *ibytes, zbx_uint64_t *ipackets, zbx_uint64_t *ierrors, zbx_uint64_t *idropped,
36 zbx_uint64_t *obytes, zbx_uint64_t *opackets, zbx_uint64_t *oerrors,
37 zbx_uint64_t *tbytes, zbx_uint64_t *tpackets, zbx_uint64_t *terrors,
38 zbx_uint64_t *icollisions, char **error)
39 {
40 struct ifnet_head head;
41 struct ifnet *ifp;
42 struct ifnet v;
43
44 kvm_t *kp;
45 int len = 0;
46 int ret = SYSINFO_RET_FAIL;
47
48 if (NULL == if_name || '\0' == *if_name)
49 {
50 *error = zbx_strdup(NULL, "Network interface name cannot be empty.");
51 return FAIL;
52 }
53
54 if (NULL == (kp = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL))) /* requires root privileges */
55 {
56 *error = zbx_strdup(NULL, "Cannot obtain a descriptor to access kernel virtual memory.");
57 return FAIL;
58 }
59
60 if (N_UNDF == kernel_symbols[IFNET_ID].n_type)
61 if (0 != kvm_nlist(kp, &kernel_symbols[0]))
62 kernel_symbols[IFNET_ID].n_type = N_UNDF;
63
64 if (N_UNDF != kernel_symbols[IFNET_ID].n_type)
65 {
66 len = sizeof(struct ifnet_head);
67
68 if (kvm_read(kp, kernel_symbols[IFNET_ID].n_value, &head, len) >= len)
69 {
70 len = sizeof(struct ifnet);
71
72 /* if_ibytes; total number of octets received */
73 /* if_ipackets; packets received on interface */
74 /* if_ierrors; input errors on interface */
75 /* if_iqdrops; dropped on input, this interface */
76 /* if_obytes; total number of octets sent */
77 /* if_opackets; packets sent on interface */
78 /* if_oerrors; output errors on interface */
79 /* if_collisions; collisions on csma interfaces */
80
81 if (ibytes)
82 *ibytes = 0;
83 if (ipackets)
84 *ipackets = 0;
85 if (ierrors)
86 *ierrors = 0;
87 if (idropped)
88 *idropped = 0;
89 if (obytes)
90 *obytes = 0;
91 if (opackets)
92 *opackets = 0;
93 if (oerrors)
94 *oerrors = 0;
95 if (tbytes)
96 *tbytes = 0;
97 if (tpackets)
98 *tpackets = 0;
99 if (terrors)
100 *terrors = 0;
101 if (icollisions)
102 *icollisions = 0;
103
104 for (ifp = head.tqh_first; ifp; ifp = v.if_list.tqe_next)
105 {
106 if (kvm_read(kp, (u_long)ifp, &v, len) < len)
107 break;
108
109 if (0 == strcmp(if_name, v.if_xname))
110 {
111 if (ibytes)
112 *ibytes += v.if_ibytes;
113 if (ipackets)
114 *ipackets += v.if_ipackets;
115 if (ierrors)
116 *ierrors += v.if_ierrors;
117 if (idropped)
118 *idropped += v.if_iqdrops;
119 if (obytes)
120 *obytes += v.if_obytes;
121 if (opackets)
122 *opackets += v.if_opackets;
123 if (oerrors)
124 *oerrors += v.if_oerrors;
125 if (tbytes)
126 *tbytes += v.if_ibytes + v.if_obytes;
127 if (tpackets)
128 *tpackets += v.if_ipackets + v.if_opackets;
129 if (terrors)
130 *terrors += v.if_ierrors + v.if_oerrors;
131 if (icollisions)
132 *icollisions += v.if_collisions;
133 ret = SYSINFO_RET_OK;
134 }
135 }
136 }
137 }
138
139 kvm_close(kp);
140
141 if (SYSINFO_RET_FAIL == ret)
142 {
143 *error = zbx_strdup(NULL, "Cannot find information for this network interface.");
144 return SYSINFO_RET_FAIL;
145 }
146
147 return ret;
148 }
149
NET_IF_IN(AGENT_REQUEST * request,AGENT_RESULT * result)150 int NET_IF_IN(AGENT_REQUEST *request, AGENT_RESULT *result)
151 {
152 char *if_name, *mode, *error;
153 zbx_uint64_t ibytes, ipackets, ierrors, idropped;
154
155 if (2 < request->nparam)
156 {
157 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
158 return SYSINFO_RET_FAIL;
159 }
160
161 if_name = get_rparam(request, 0);
162 mode = get_rparam(request, 1);
163
164 if (SYSINFO_RET_OK != get_ifdata(if_name, &ibytes, &ipackets, &ierrors, &idropped, NULL, NULL, NULL, NULL, NULL,
165 NULL, NULL, &error))
166 {
167 SET_MSG_RESULT(result, error);
168 return SYSINFO_RET_FAIL;
169 }
170
171 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* default parameter */
172 SET_UI64_RESULT(result, ibytes);
173 else if (0 == strcmp(mode, "packets"))
174 SET_UI64_RESULT(result, ipackets);
175 else if (0 == strcmp(mode, "errors"))
176 SET_UI64_RESULT(result, ierrors);
177 else if (0 == strcmp(mode, "dropped"))
178 SET_UI64_RESULT(result, idropped);
179 else
180 {
181 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
182 return SYSINFO_RET_FAIL;
183 }
184
185 return SYSINFO_RET_OK;
186 }
187
NET_IF_OUT(AGENT_REQUEST * request,AGENT_RESULT * result)188 int NET_IF_OUT(AGENT_REQUEST *request, AGENT_RESULT *result)
189 {
190 char *if_name, *mode, *error;
191 zbx_uint64_t obytes, opackets, oerrors;
192
193 if (2 < request->nparam)
194 {
195 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
196 return SYSINFO_RET_FAIL;
197 }
198
199 if_name = get_rparam(request, 0);
200 mode = get_rparam(request, 1);
201
202 if (SYSINFO_RET_OK != get_ifdata(if_name, NULL, NULL, NULL, NULL, &obytes, &opackets, &oerrors, NULL, NULL,
203 NULL, NULL, &error))
204 {
205 SET_MSG_RESULT(result, error);
206 return SYSINFO_RET_FAIL;
207 }
208
209 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* default parameter */
210 SET_UI64_RESULT(result, obytes);
211 else if (0 == strcmp(mode, "packets"))
212 SET_UI64_RESULT(result, opackets);
213 else if (0 == strcmp(mode, "errors"))
214 SET_UI64_RESULT(result, oerrors);
215 else
216 {
217 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
218 return SYSINFO_RET_FAIL;
219 }
220
221 return SYSINFO_RET_OK;
222 }
223
NET_IF_TOTAL(AGENT_REQUEST * request,AGENT_RESULT * result)224 int NET_IF_TOTAL(AGENT_REQUEST *request, AGENT_RESULT *result)
225 {
226 char *if_name, *mode, *error;
227 zbx_uint64_t tbytes, tpackets, terrors;
228
229 if (2 < request->nparam)
230 {
231 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
232 return SYSINFO_RET_FAIL;
233 }
234
235 if_name = get_rparam(request, 0);
236 mode = get_rparam(request, 1);
237
238 if (SYSINFO_RET_OK != get_ifdata(if_name, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &tbytes, &tpackets,
239 &terrors, NULL, &error))
240 {
241 SET_MSG_RESULT(result, error);
242 return SYSINFO_RET_FAIL;
243 }
244
245 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* default parameter */
246 SET_UI64_RESULT(result, tbytes);
247 else if (0 == strcmp(mode, "packets"))
248 SET_UI64_RESULT(result, tpackets);
249 else if (0 == strcmp(mode, "errors"))
250 SET_UI64_RESULT(result, terrors);
251 else
252 {
253 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
254 return SYSINFO_RET_FAIL;
255 }
256
257 return SYSINFO_RET_OK;
258 }
259
NET_IF_COLLISIONS(AGENT_REQUEST * request,AGENT_RESULT * result)260 int NET_IF_COLLISIONS(AGENT_REQUEST *request, AGENT_RESULT *result)
261 {
262 char *if_name, *error;
263 zbx_uint64_t icollisions;
264
265 if (1 < request->nparam)
266 {
267 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
268 return SYSINFO_RET_FAIL;
269 }
270
271 if_name = get_rparam(request, 0);
272
273 if (SYSINFO_RET_OK != get_ifdata(if_name, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
274 NULL, &icollisions, &error))
275 {
276 SET_MSG_RESULT(result, error);
277 return SYSINFO_RET_FAIL;
278 }
279
280 SET_UI64_RESULT(result, icollisions);
281
282 return SYSINFO_RET_OK;
283 }
284
NET_IF_DISCOVERY(AGENT_REQUEST * request,AGENT_RESULT * result)285 int NET_IF_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
286 {
287 int i;
288 struct zbx_json j;
289 struct if_nameindex *interfaces;
290
291 if (NULL == (interfaces = if_nameindex()))
292 {
293 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
294 return SYSINFO_RET_FAIL;
295 }
296
297 zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
298
299 zbx_json_addarray(&j, ZBX_PROTO_TAG_DATA);
300
301 for (i = 0; 0 != interfaces[i].if_index; i++)
302 {
303 zbx_json_addobject(&j, NULL);
304 zbx_json_addstring(&j, "{#IFNAME}", interfaces[i].if_name, ZBX_JSON_TYPE_STRING);
305 zbx_json_close(&j);
306 }
307
308 zbx_json_close(&j);
309
310 SET_STR_RESULT(result, strdup(j.buffer));
311
312 zbx_json_free(&j);
313
314 if_freenameindex(interfaces);
315
316 return SYSINFO_RET_OK;
317 }
318