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 "../common/common.h"
23 #include "zbxjson.h"
24 #include "log.h"
25 
26 static struct ifmibdata	ifmd;
27 
get_ifmib_general(const char * if_name,char ** error)28 static int	get_ifmib_general(const char *if_name, char **error)
29 {
30 	int	mib[6], ifcount;
31 	size_t	len;
32 
33 	if (NULL == if_name || '\0' == *if_name)
34 	{
35 		*error = zbx_strdup(NULL, "Network interface name cannot be empty.");
36 		return FAIL;
37 	}
38 
39 	mib[0] = CTL_NET;
40 	mib[1] = PF_LINK;
41 	mib[2] = NETLINK_GENERIC;
42 	mib[3] = IFMIB_SYSTEM;
43 	mib[4] = IFMIB_IFCOUNT;
44 
45 	len = sizeof(ifcount);
46 
47 	if (-1 == sysctl(mib, 5, &ifcount, &len, NULL, 0))
48 	{
49 		*error = zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno));
50 		return FAIL;
51 	}
52 
53 	mib[3] = IFMIB_IFDATA;
54 	mib[5] = IFDATA_GENERAL;
55 
56 	len = sizeof(ifmd);
57 
58 	for (mib[4] = 1; mib[4] <= ifcount; mib[4]++)
59 	{
60 		if (-1 == sysctl(mib, 6, &ifmd, &len, NULL, 0))
61 		{
62 			if (ENOENT == errno)
63 				continue;
64 
65 			break;
66 		}
67 
68 		if (0 == strcmp(ifmd.ifmd_name, if_name))
69 			return SUCCEED;
70 	}
71 
72 	*error = zbx_strdup(NULL, "Cannot find information for this network interface.");
73 
74 	return FAIL;
75 }
76 
NET_IF_IN(AGENT_REQUEST * request,AGENT_RESULT * result)77 int	NET_IF_IN(AGENT_REQUEST *request, AGENT_RESULT *result)
78 {
79 	char	*if_name, *mode, *error;
80 
81 	if (2 < request->nparam)
82 	{
83 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
84 		return SYSINFO_RET_FAIL;
85 	}
86 
87 	if_name = get_rparam(request, 0);
88 	mode = get_rparam(request, 1);
89 
90 	if (FAIL == get_ifmib_general(if_name,&error))
91 	{
92 		SET_MSG_RESULT(result, error);
93 		return SYSINFO_RET_FAIL;
94 	}
95 
96 	if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))	/* default parameter */
97 		SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_ibytes);
98 	else if (0 == strcmp(mode, "packets"))
99 		SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_ipackets);
100 	else if (0 == strcmp(mode, "errors"))
101 		SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_ierrors);
102 	else if (0 == strcmp(mode, "dropped"))
103 		SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_iqdrops);
104 	else
105 	{
106 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
107 		return SYSINFO_RET_FAIL;
108 	}
109 
110 	return SYSINFO_RET_OK;
111 }
112 
NET_IF_OUT(AGENT_REQUEST * request,AGENT_RESULT * result)113 int	NET_IF_OUT(AGENT_REQUEST *request, AGENT_RESULT *result)
114 {
115 	char	*if_name, *mode, *error;
116 
117 	if (2 < request->nparam)
118 	{
119 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
120 		return SYSINFO_RET_FAIL;
121 	}
122 
123 	if_name = get_rparam(request, 0);
124 	mode = get_rparam(request, 1);
125 
126 	if (FAIL == get_ifmib_general(if_name, &error))
127 	{
128 		SET_MSG_RESULT(result, error);
129 		return SYSINFO_RET_FAIL;
130 	}
131 
132 	if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))	/* default parameter */
133 		SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_obytes);
134 	else if (0 == strcmp(mode, "packets"))
135 		SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_opackets);
136 	else if (0 == strcmp(mode, "errors"))
137 		SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_oerrors);
138 	else
139 	{
140 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
141 		return SYSINFO_RET_FAIL;
142 	}
143 
144 	return SYSINFO_RET_OK;
145 }
146 
NET_IF_TOTAL(AGENT_REQUEST * request,AGENT_RESULT * result)147 int	NET_IF_TOTAL(AGENT_REQUEST *request, AGENT_RESULT *result)
148 {
149 	char	*if_name, *mode, *error;
150 
151 	if (2 < request->nparam)
152 	{
153 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
154 		return SYSINFO_RET_FAIL;
155 	}
156 
157 	if_name = get_rparam(request, 0);
158 	mode = get_rparam(request, 1);
159 
160 	if (FAIL == get_ifmib_general(if_name, &error))
161 	{
162 		SET_MSG_RESULT(result, error);
163 		return SYSINFO_RET_FAIL;
164 	}
165 
166 	if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))	/* default parameter */
167 		SET_UI64_RESULT(result, (zbx_uint64_t)ifmd.ifmd_data.ifi_ibytes + ifmd.ifmd_data.ifi_obytes);
168 	else if (0 == strcmp(mode, "packets"))
169 		SET_UI64_RESULT(result, (zbx_uint64_t)ifmd.ifmd_data.ifi_ipackets + ifmd.ifmd_data.ifi_opackets);
170 	else if (0 == strcmp(mode, "errors"))
171 		SET_UI64_RESULT(result, (zbx_uint64_t)ifmd.ifmd_data.ifi_ierrors + ifmd.ifmd_data.ifi_oerrors);
172 	else
173 	{
174 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
175 		return SYSINFO_RET_FAIL;
176 	}
177 
178 	return SYSINFO_RET_OK;
179 }
180 
NET_TCP_LISTEN(AGENT_REQUEST * request,AGENT_RESULT * result)181 int     NET_TCP_LISTEN(AGENT_REQUEST *request, AGENT_RESULT *result)
182 {
183 	char		*port_str, command[64];
184 	unsigned short	port;
185 	int		res;
186 
187 	if (1 < request->nparam)
188 	{
189 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
190 		return SYSINFO_RET_FAIL;
191 	}
192 
193 	port_str = get_rparam(request, 0);
194 
195 	if (NULL == port_str || SUCCEED != is_ushort(port_str, &port))
196 	{
197 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
198 		return SYSINFO_RET_FAIL;
199 	}
200 
201 	zbx_snprintf(command, sizeof(command), "netstat -an | grep '^tcp.*\\.%hu[^.].*LISTEN' | wc -l", port);
202 
203 	if (SYSINFO_RET_FAIL == (res = EXECUTE_INT(command, result)))
204 		return res;
205 
206 	if (1 < result->ui64)
207 		result->ui64 = 1;
208 
209 	return res;
210 }
211 
NET_UDP_LISTEN(AGENT_REQUEST * request,AGENT_RESULT * result)212 int     NET_UDP_LISTEN(AGENT_REQUEST *request, AGENT_RESULT *result)
213 {
214 	char		*port_str, command[64];
215 	unsigned short	port;
216 	int		res;
217 
218 	if (1 < request->nparam)
219 	{
220 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
221 		return SYSINFO_RET_FAIL;
222 	}
223 
224 	port_str = get_rparam(request, 0);
225 
226 	if (NULL == port_str || SUCCEED != is_ushort(port_str, &port))
227 	{
228 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
229 		return SYSINFO_RET_FAIL;
230 	}
231 
232 	zbx_snprintf(command, sizeof(command), "netstat -an | grep '^udp.*\\.%hu[^.].*\\*\\.\\*' | wc -l", port);
233 
234 	if (SYSINFO_RET_FAIL == (res = EXECUTE_INT(command, result)))
235 		return res;
236 
237 	if (1 < result->ui64)
238 		result->ui64 = 1;
239 
240 	return res;
241 }
242 
NET_IF_COLLISIONS(AGENT_REQUEST * request,AGENT_RESULT * result)243 int     NET_IF_COLLISIONS(AGENT_REQUEST *request, AGENT_RESULT *result)
244 {
245 	char	*if_name, *error;
246 
247 	if (1 < request->nparam)
248 	{
249 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
250 		return SYSINFO_RET_FAIL;
251 	}
252 
253 	if_name = get_rparam(request, 0);
254 
255 	if (FAIL == get_ifmib_general(if_name, &error))
256 	{
257 		SET_MSG_RESULT(result, error);
258 		return SYSINFO_RET_FAIL;
259 	}
260 
261 	SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_collisions);
262 
263 	return SYSINFO_RET_OK;
264 }
265 
NET_IF_DISCOVERY(AGENT_REQUEST * request,AGENT_RESULT * result)266 int	NET_IF_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
267 {
268 	int			i;
269 	struct zbx_json		j;
270 	struct if_nameindex	*interfaces;
271 
272 	if (NULL == (interfaces = if_nameindex()))
273 	{
274 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
275 		return SYSINFO_RET_FAIL;
276 	}
277 
278 	zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
279 
280 	for (i = 0; 0 != interfaces[i].if_index; i++)
281 	{
282 		zbx_json_addobject(&j, NULL);
283 		zbx_json_addstring(&j, "{#IFNAME}", interfaces[i].if_name, ZBX_JSON_TYPE_STRING);
284 		zbx_json_close(&j);
285 	}
286 
287 	zbx_json_close(&j);
288 
289 	SET_STR_RESULT(result, strdup(j.buffer));
290 
291 	zbx_json_free(&j);
292 
293 	if_freenameindex(interfaces);
294 
295 	return SYSINFO_RET_OK;
296 }
297