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 typedef struct
26 {
27 	zbx_uint64_t ibytes;
28 	zbx_uint64_t ipackets;
29 	zbx_uint64_t ierr;
30 	zbx_uint64_t obytes;
31 	zbx_uint64_t opackets;
32 	zbx_uint64_t oerr;
33 	zbx_uint64_t colls;
34 }
35 net_stat_t;
36 
get_net_stat(const char * if_name,net_stat_t * ns,char ** error)37 static int	get_net_stat(const char *if_name, net_stat_t *ns, char **error)
38 {
39 #if defined(HAVE_LIBPERFSTAT)
40 	perfstat_id_t		ps_id;
41 	perfstat_netinterface_t	ps_netif;
42 
43 	if (NULL == if_name || '\0' == *if_name)
44 	{
45 		*error = zbx_strdup(NULL, "Network interface name cannot be empty.");
46 		return SYSINFO_RET_FAIL;
47 	}
48 
49 	strscpy(ps_id.name, if_name);
50 
51 	if (-1 == perfstat_netinterface(&ps_id, &ps_netif, sizeof(ps_netif), 1))
52 	{
53 		*error = zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno));
54 		return SYSINFO_RET_FAIL;
55 	}
56 
57 	ns->ibytes = (zbx_uint64_t)ps_netif.ibytes;
58 	ns->ipackets = (zbx_uint64_t)ps_netif.ipackets;
59 	ns->ierr = (zbx_uint64_t)ps_netif.ierrors;
60 
61 	ns->obytes = (zbx_uint64_t)ps_netif.obytes;
62 	ns->opackets = (zbx_uint64_t)ps_netif.opackets;
63 	ns->oerr = (zbx_uint64_t)ps_netif.oerrors;
64 
65 	ns->colls = (zbx_uint64_t)ps_netif.collisions;
66 
67 	return SYSINFO_RET_OK;
68 #else
69 	SET_MSG_RESULT(result, zbx_strdup(NULL, "Agent was compiled without support for Perfstat API."));
70 	return SYSINFO_RET_FAIL;
71 #endif
72 }
73 
NET_IF_IN(AGENT_REQUEST * request,AGENT_RESULT * result)74 int	NET_IF_IN(AGENT_REQUEST *request, AGENT_RESULT *result)
75 {
76 	char		*if_name, *mode, *error;
77 	net_stat_t	ns;
78 
79 	if (2 < request->nparam)
80 	{
81 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
82 		return SYSINFO_RET_FAIL;
83 	}
84 
85 	if_name = get_rparam(request, 0);
86 	mode = get_rparam(request, 1);
87 
88 	if (SYSINFO_RET_FAIL == get_net_stat(if_name, &ns, &error))
89 	{
90 		SET_MSG_RESULT(result, error);
91 		return SYSINFO_RET_FAIL;
92 	}
93 
94 	if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))
95 		SET_UI64_RESULT(result, ns.ibytes);
96 	else if (0 == strcmp(mode, "packets"))
97 		SET_UI64_RESULT(result, ns.ipackets);
98 	else if (0 == strcmp(mode, "errors"))
99 		SET_UI64_RESULT(result, ns.ierr);
100 	else
101 	{
102 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
103 		return SYSINFO_RET_FAIL;
104 	}
105 
106 	return SYSINFO_RET_OK;
107 }
108 
NET_IF_OUT(AGENT_REQUEST * request,AGENT_RESULT * result)109 int	NET_IF_OUT(AGENT_REQUEST *request, AGENT_RESULT *result)
110 {
111 	char		*if_name, *mode, *error;
112 	net_stat_t	ns;
113 
114 	if (2 < request->nparam)
115 	{
116 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
117 		return SYSINFO_RET_FAIL;
118 	}
119 
120 	if_name = get_rparam(request, 0);
121 	mode = get_rparam(request, 1);
122 
123 	if (SYSINFO_RET_FAIL == get_net_stat(if_name, &ns, &error))
124 	{
125 		SET_MSG_RESULT(result, error);
126 		return SYSINFO_RET_FAIL;
127 	}
128 
129 	if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))
130 		SET_UI64_RESULT(result, ns.obytes);
131 	else if (0 == strcmp(mode, "packets"))
132 		SET_UI64_RESULT(result, ns.opackets);
133 	else if (0 == strcmp(mode, "errors"))
134 		SET_UI64_RESULT(result, ns.oerr);
135 	else
136 	{
137 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
138 		return SYSINFO_RET_FAIL;
139 	}
140 
141 	return SYSINFO_RET_OK;
142 }
143 
NET_IF_TOTAL(AGENT_REQUEST * request,AGENT_RESULT * result)144 int	NET_IF_TOTAL(AGENT_REQUEST *request, AGENT_RESULT *result)
145 {
146 	char		*if_name, *mode, *error;
147 	net_stat_t	ns;
148 
149 	if (2 < request->nparam)
150 	{
151 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
152 		return SYSINFO_RET_FAIL;
153 	}
154 
155 	if_name = get_rparam(request, 0);
156 	mode = get_rparam(request, 1);
157 
158 	if (SYSINFO_RET_FAIL == get_net_stat(if_name, &ns, &error))
159 	{
160 		SET_MSG_RESULT(result, error);
161 		return SYSINFO_RET_FAIL;
162 	}
163 
164 	if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))
165 		SET_UI64_RESULT(result, ns.ibytes + ns.obytes);
166 	else if (0 == strcmp(mode, "packets"))
167 		SET_UI64_RESULT(result, ns.ipackets + ns.opackets);
168 	else if (0 == strcmp(mode, "errors"))
169 		SET_UI64_RESULT(result, ns.ierr + ns.oerr);
170 	else
171 	{
172 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
173 		return SYSINFO_RET_FAIL;
174 	}
175 
176 	return SYSINFO_RET_OK;
177 }
178 
NET_IF_COLLISIONS(AGENT_REQUEST * request,AGENT_RESULT * result)179 int	NET_IF_COLLISIONS(AGENT_REQUEST *request, AGENT_RESULT *result)
180 {
181 	char		*if_name, *error;
182 	net_stat_t	ns;
183 
184 	if (1 < request->nparam)
185 	{
186 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
187 		return SYSINFO_RET_FAIL;
188 	}
189 
190 	if_name = get_rparam(request, 0);
191 
192 	if (SYSINFO_RET_FAIL == get_net_stat(if_name, &ns, &error))
193 	{
194 		SET_MSG_RESULT(result, error);
195 		return SYSINFO_RET_FAIL;
196 	}
197 
198 	SET_UI64_RESULT(result, ns.colls);
199 
200 	return SYSINFO_RET_OK;
201 }
202 
NET_IF_DISCOVERY(AGENT_REQUEST * request,AGENT_RESULT * result)203 int	NET_IF_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
204 {
205 #if defined(HAVE_LIBPERFSTAT)
206 	int			rc, i, ret = SYSINFO_RET_FAIL;
207 	perfstat_id_t		ps_id;
208 	perfstat_netinterface_t	*ps_netif = NULL;
209 	struct zbx_json		j;
210 
211 	/* check how many perfstat_netinterface_t structures are available */
212 	if (-1 == (rc = perfstat_netinterface(NULL, NULL, sizeof(perfstat_netinterface_t), 0)))
213 	{
214 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
215 		return SYSINFO_RET_FAIL;
216 	}
217 
218 	zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
219 
220 	if (0 == rc)	/* no network interfaces found */
221 	{
222 		ret = SYSINFO_RET_OK;
223 		goto end;
224 	}
225 
226 	ps_netif = zbx_malloc(ps_netif, rc * sizeof(perfstat_netinterface_t));
227 
228 	/* set name to first interface */
229 	strscpy(ps_id.name, FIRST_NETINTERFACE);	/* pseudo-name for the first network interface */
230 
231 	/* ask to get all the structures available in one call */
232 	/* return code is number of structures returned */
233 	if (-1 != (rc = perfstat_netinterface(&ps_id, ps_netif, sizeof(perfstat_netinterface_t), rc)))
234 		ret = SYSINFO_RET_OK;
235 
236 	/* collecting of the information for each of the interfaces */
237 	for (i = 0; i < rc; i++)
238 	{
239 		zbx_json_addobject(&j, NULL);
240 		zbx_json_addstring(&j, "{#IFNAME}", ps_netif[i].name, ZBX_JSON_TYPE_STRING);
241 		zbx_json_close(&j);
242 	}
243 
244 	zbx_free(ps_netif);
245 end:
246 	zbx_json_close(&j);
247 
248 	SET_STR_RESULT(result, strdup(j.buffer));
249 
250 	zbx_json_free(&j);
251 
252 	return ret;
253 #else
254 	SET_MSG_RESULT(result, zbx_strdup(NULL, "Agent was compiled without support for Perfstat API."));
255 	return SYSINFO_RET_FAIL;
256 #endif
257 }
258