1 /*
2  * Copyright (c) 2016 Intel Corporation
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(net_shell);
10 
11 #include <stdlib.h>
12 
13 #include "net_shell_private.h"
14 
15 #include <zephyr/net/capture.h>
16 
17 #if defined(CONFIG_NET_CAPTURE)
18 #define DEFAULT_DEV_NAME "NET_CAPTURE0"
19 static const struct device *capture_dev;
20 
get_address_str(const struct sockaddr * addr,char * str,int str_len)21 static void get_address_str(const struct sockaddr *addr,
22 			    char *str, int str_len)
23 {
24 	if (IS_ENABLED(CONFIG_NET_IPV6) && addr->sa_family == AF_INET6) {
25 		snprintk(str, str_len, "[%s]:%u",
26 			 net_sprint_ipv6_addr(&net_sin6(addr)->sin6_addr),
27 			 ntohs(net_sin6(addr)->sin6_port));
28 
29 	} else if (IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET) {
30 		snprintk(str, str_len, "%s:%d",
31 			 net_sprint_ipv4_addr(&net_sin(addr)->sin_addr),
32 			 ntohs(net_sin(addr)->sin_port));
33 
34 	} else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
35 		   addr->sa_family == AF_PACKET) {
36 		snprintk(str, str_len, "AF_PACKET");
37 	} else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) &&
38 		   addr->sa_family == AF_CAN) {
39 		snprintk(str, str_len, "AF_CAN");
40 	} else if (addr->sa_family == AF_UNSPEC) {
41 		snprintk(str, str_len, "AF_UNSPEC");
42 	} else {
43 		snprintk(str, str_len, "AF_UNK(%d)", addr->sa_family);
44 	}
45 }
46 
capture_cb(struct net_capture_info * info,void * user_data)47 static void capture_cb(struct net_capture_info *info, void *user_data)
48 {
49 	struct net_shell_user_data *data = user_data;
50 	const struct shell *sh = data->sh;
51 	int *count = data->user_data;
52 	char addr_local[ADDR_LEN + 7];
53 	char addr_peer[ADDR_LEN + 7];
54 
55 	if (*count == 0) {
56 		PR("      \t\tCapture  Tunnel\n");
57 		PR("Device\t\tiface    iface   Local\t\t\tPeer\n");
58 	}
59 
60 	get_address_str(info->local, addr_local, sizeof(addr_local));
61 	get_address_str(info->peer, addr_peer, sizeof(addr_peer));
62 
63 	PR("%s\t%c        %d      %s\t%s\n", info->capture_dev->name,
64 	   info->is_enabled ?
65 	   (net_if_get_by_iface(info->capture_iface) + '0') : '-',
66 	   net_if_get_by_iface(info->tunnel_iface),
67 	   addr_local, addr_peer);
68 
69 	(*count)++;
70 }
71 #endif
72 
cmd_net_capture(const struct shell * sh,size_t argc,char * argv[])73 static int cmd_net_capture(const struct shell *sh, size_t argc, char *argv[])
74 {
75 #if defined(CONFIG_NET_CAPTURE)
76 	bool ret;
77 
78 	if (capture_dev == NULL) {
79 		capture_dev = device_get_binding(DEFAULT_DEV_NAME);
80 	}
81 
82 	if (capture_dev == NULL) {
83 		PR_INFO("Network packet capture %s\n", "not configured");
84 	} else {
85 		struct net_shell_user_data user_data;
86 		int count = 0;
87 
88 		ret = net_capture_is_enabled(capture_dev);
89 		PR_INFO("Network packet capture %s\n",
90 			ret ? "enabled" : "disabled");
91 
92 		user_data.sh = sh;
93 		user_data.user_data = &count;
94 
95 		net_capture_foreach(capture_cb, &user_data);
96 	}
97 #else
98 	ARG_UNUSED(argc);
99 	ARG_UNUSED(argv);
100 
101 	PR_INFO("Set %s to enable %s support.\n",
102 		"CONFIG_NET_CAPTURE", "network packet capture");
103 #endif
104 	return 0;
105 }
106 
cmd_net_capture_setup(const struct shell * sh,size_t argc,char * argv[])107 static int cmd_net_capture_setup(const struct shell *sh, size_t argc, char *argv[])
108 {
109 #if defined(CONFIG_NET_CAPTURE)
110 	int ret, arg = 1;
111 	const char *remote, *local, *peer;
112 
113 	remote = argv[arg++];
114 	if (!remote) {
115 		PR_WARNING("Remote IP address not specified.\n");
116 		return -ENOEXEC;
117 	}
118 
119 	local = argv[arg++];
120 	if (!local) {
121 		PR_WARNING("Local IP address not specified.\n");
122 		return -ENOEXEC;
123 	}
124 
125 	peer = argv[arg];
126 	if (!peer) {
127 		PR_WARNING("Peer IP address not specified.\n");
128 		return -ENOEXEC;
129 	}
130 
131 	if (capture_dev != NULL) {
132 		PR_INFO("Capture already setup, cleaning up settings.\n");
133 		net_capture_cleanup(capture_dev);
134 		capture_dev = NULL;
135 	}
136 
137 	ret = net_capture_setup(remote, local, peer, &capture_dev);
138 	if (ret < 0) {
139 		PR_WARNING("Capture cannot be setup (%d)\n", ret);
140 		return -ENOEXEC;
141 	}
142 
143 	PR_INFO("Capture setup done, next enable it by "
144 		"\"net capture enable <idx>\"\n");
145 #else
146 	ARG_UNUSED(argc);
147 	ARG_UNUSED(argv);
148 
149 	PR_INFO("Set %s to enable %s support.\n",
150 		"CONFIG_NET_CAPTURE", "network packet capture");
151 #endif
152 
153 	return 0;
154 }
155 
cmd_net_capture_cleanup(const struct shell * sh,size_t argc,char * argv[])156 static int cmd_net_capture_cleanup(const struct shell *sh, size_t argc, char *argv[])
157 {
158 	ARG_UNUSED(argc);
159 	ARG_UNUSED(argv);
160 
161 #if defined(CONFIG_NET_CAPTURE)
162 	int ret;
163 
164 	if (capture_dev == NULL) {
165 		return 0;
166 	}
167 
168 	ret = net_capture_cleanup(capture_dev);
169 	if (ret < 0) {
170 		PR_WARNING("Capture %s failed (%d)\n", "cleanup", ret);
171 		return -ENOEXEC;
172 	}
173 
174 	capture_dev = NULL;
175 #else
176 	PR_INFO("Set %s to enable %s support.\n",
177 		"CONFIG_NET_CAPTURE", "network packet capture");
178 #endif
179 
180 	return 0;
181 }
182 
cmd_net_capture_enable(const struct shell * sh,size_t argc,char * argv[])183 static int cmd_net_capture_enable(const struct shell *sh, size_t argc, char *argv[])
184 {
185 	ARG_UNUSED(argc);
186 	ARG_UNUSED(argv);
187 
188 #if defined(CONFIG_NET_CAPTURE)
189 	int ret, arg = 1, if_index;
190 	struct net_if *iface;
191 
192 	if (capture_dev == NULL) {
193 		return 0;
194 	}
195 
196 	if (argv[arg] == NULL) {
197 		PR_WARNING("Interface index is missing. Please give interface "
198 			   "what you want to monitor\n");
199 		return -ENOEXEC;
200 	}
201 
202 	if_index = atoi(argv[arg++]);
203 	if (if_index == 0) {
204 		PR_WARNING("Interface index %d is invalid.\n", if_index);
205 		return -ENOEXEC;
206 	}
207 
208 	iface = net_if_get_by_index(if_index);
209 	if (iface == NULL) {
210 		PR_WARNING("No such interface with index %d\n", if_index);
211 		return -ENOEXEC;
212 	}
213 
214 	ret = net_capture_enable(capture_dev, iface);
215 	if (ret < 0) {
216 		PR_WARNING("Capture %s failed (%d)\n", "enable", ret);
217 		return -ENOEXEC;
218 	}
219 #else
220 	PR_INFO("Set %s to enable %s support.\n",
221 		"CONFIG_NET_CAPTURE", "network packet capture");
222 #endif
223 
224 	return 0;
225 }
226 
cmd_net_capture_disable(const struct shell * sh,size_t argc,char * argv[])227 static int cmd_net_capture_disable(const struct shell *sh, size_t argc, char *argv[])
228 {
229 	ARG_UNUSED(argc);
230 	ARG_UNUSED(argv);
231 
232 #if defined(CONFIG_NET_CAPTURE)
233 	int ret;
234 
235 	if (capture_dev == NULL) {
236 		return 0;
237 	}
238 
239 	ret = net_capture_disable(capture_dev);
240 	if (ret < 0) {
241 		PR_WARNING("Capture %s failed (%d)\n", "disable", ret);
242 		return -ENOEXEC;
243 	}
244 #else
245 	PR_INFO("Set %s to enable %s support.\n",
246 		"CONFIG_NET_CAPTURE", "network packet capture");
247 #endif
248 
249 	return 0;
250 }
251 
252 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_capture,
253 	SHELL_CMD(setup, NULL, "Setup network packet capture.\n"
254 		  "'net capture setup <remote-ip-addr> <local-addr> <peer-addr>'\n"
255 		  "<remote> is the (outer) endpoint IP address,\n"
256 		  "<local> is the (inner) local IP address,\n"
257 		  "<peer> is the (inner) peer IP address\n"
258 		  "Local and Peer addresses can have UDP port number in them (optional)\n"
259 		  "like 198.0.51.2:9000 or [2001:db8:100::2]:4242",
260 		  cmd_net_capture_setup),
261 	SHELL_CMD(cleanup, NULL, "Cleanup network packet capture.",
262 		  cmd_net_capture_cleanup),
263 	SHELL_CMD(enable, NULL, "Enable network packet capture for a given "
264 		  "network interface.\n"
265 		  "'net capture enable <interface index>'",
266 		  cmd_net_capture_enable),
267 	SHELL_CMD(disable, NULL, "Disable network packet capture.",
268 		  cmd_net_capture_disable),
269 	SHELL_SUBCMD_SET_END
270 );
271 
272 SHELL_SUBCMD_ADD((net), capture, &net_cmd_capture,
273 		 "Configure network packet capture.", cmd_net_capture, 1, 0);
274