xref: /freebsd/tests/sys/net/routing/rtsock_print.h (revision a90b9d0159070121c221b966469c3e36d912bf82)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2019 Alexander V. Chernikov
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #ifndef _NET_ROUTING_RTSOCK_PRINT_H_
29 #define _NET_ROUTING_RTSOCK_PRINT_H_
30 
31 
32 #define	RLOG(_fmt, ...)	printf("%s: " _fmt "\n", __func__, ##__VA_ARGS__)
33 #define	RLOG_ERRNO(_fmt, ...)	do {			\
34 	printf("%s: " _fmt, __func__, ##__VA_ARGS__);	\
35 	printf(": %s\n", strerror(errno));		\
36 } while(0)
37 
38 #define	RTSOCK_ATF_REQUIRE_MSG(_rtm, _cond, _fmt, ...)	 do {	\
39 	if (!(_cond)) {						\
40 		printf("-- CONDITION FAILED, rtm dump  --\n\n");\
41 		rtsock_print_message(_rtm);			\
42 		rtsock_print_table(AF_INET);			\
43 		rtsock_print_table(AF_INET6);			\
44 		printf("===================================\n");\
45 	}							\
46 	ATF_REQUIRE_MSG(_cond, _fmt, ##__VA_ARGS__);		\
47 } while (0);
48 
49 #define	RTSOCKHD_ATF_REQUIRE_MSG(_rtm, _cond, _fmt, ...) do {	\
50 	if (!(_cond)) {						\
51 		printf("-- CONDITION FAILED, rtm hexdump--\n\n");\
52 		rtsock_print_message_hd(_rtm);				\
53 	}							\
54 	ATF_REQUIRE_MSG(_cond, _fmt, ##__VA_ARGS__);		\
55 } while (0);
56 
57 
58 /* from route.c */
59 static const char *const msgtypes[] = {
60 	"",
61 	"RTM_ADD",
62 	"RTM_DELETE",
63 	"RTM_CHANGE",
64 	"RTM_GET",
65 	"RTM_LOSING",
66 	"RTM_REDIRECT",
67 	"RTM_MISS",
68 	"RTM_LOCK",
69 	"RTM_OLDADD",
70 	"RTM_OLDDEL",
71 	"RTM_RESOLVE",
72 	"RTM_NEWADDR",
73 	"RTM_DELADDR",
74 	"RTM_IFINFO",
75 	"RTM_NEWMADDR",
76 	"RTM_DELMADDR",
77 	"RTM_IFANNOUNCE",
78 	"RTM_IEEE80211",
79 };
80 
81 static const char metricnames[] =
82     "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire"
83     "\1mtu";
84 static const char routeflags[] =
85     "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE"
86     "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
87     "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3"
88     "\024FIXEDMTU\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
89 static const char ifnetflags[] =
90     "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
91     "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
92     "\017LINK2\020MULTICAST";
93 static const char addrnames[] =
94     "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
95 
96 static int
97 _printb(char *buf, size_t bufsize, int b, const char *str)
98 {
99 	int i;
100 	int gotsome = 0;
101 
102 	char *pbuf = buf;
103 
104 	if (b == 0) {
105 		*pbuf = '\0';
106 		return (0);
107 	}
108 	while ((i = *str++) != 0) {
109 		if (b & (1 << (i-1))) {
110 			if (gotsome == 0)
111 				i = '<';
112 			else
113 				i = ',';
114 			*pbuf++ = i;
115 			gotsome = 1;
116 			for (; (i = *str) > 32; str++)
117 				*pbuf++ = i;
118 		} else
119 			while (*str > 32)
120 				str++;
121 	}
122 	if (gotsome)
123 		*pbuf++ = '>';
124 	*pbuf = '\0';
125 
126 	return (int)(pbuf - buf);
127 }
128 
129 const char *
130 rtsock_print_cmdtype(int cmd)
131 {
132 
133 	return (msgtypes[cmd]);
134 }
135 
136 char *
137 rtsock_print_rtm_flags(char *buf, int buflen, int rtm_flags)
138 {
139 
140 	_printb(buf, buflen, rtm_flags, routeflags);
141 	return (buf);
142 }
143 
144 
145 #define	_PRINTX(fmt, ...)	do {				\
146 	one_len = snprintf(ptr, rem_len, fmt, __VA_ARGS__);	\
147 	ptr += one_len;						\
148 	rem_len -= one_len;					\
149 } while(0)
150 
151 
152 void
153 sa_print_hd(char *buf, int buflen, const char *data, int len)
154 {
155 	char *ptr;
156 	int one_len, rem_len;
157 
158 	ptr = buf;
159 	rem_len = buflen;
160 
161 	const char *last_char = NULL;
162 	unsigned char v;
163 	int repeat_count = 0;
164 	for (int i = 0; i < len; i++) {
165 		if (last_char && *last_char == data[i] && data[i] == 0x00) {
166 			repeat_count++;
167 			continue;
168 		}
169 
170 		if (repeat_count > 1) {
171 			_PRINTX("{%d}", repeat_count);
172 			repeat_count = 0;
173 		}
174 
175 		v = ((const unsigned char *)data)[i];
176 		if (last_char == NULL)
177 			_PRINTX("x%02X", v);
178 		else
179 			_PRINTX(", x%02X", v);
180 
181 		last_char = &data[i];
182 		repeat_count = 1;
183 	}
184 
185 	if (repeat_count > 1)
186 		snprintf(ptr, rem_len, "{%d}", repeat_count);
187 }
188 
189 #undef _PRINTX
190 
191 void
192 sa_print(const struct sockaddr *sa, int include_hexdump)
193 {
194 	char hdbuf[512], abuf[64];
195 	char ifbuf[128];
196 	const struct sockaddr_dl *sdl;
197 	const struct sockaddr_in6 *sin6;
198 	const struct sockaddr_in *sin;
199 	int i;
200 
201 	switch (sa->sa_family) {
202 		case AF_INET:
203 			sin = (struct sockaddr_in *)sa;
204 			inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof(abuf));
205 			printf(" af=inet len=%d addr=%s", sa->sa_len, abuf);
206 			break;
207 		case AF_INET6:
208 			sin6 = (struct sockaddr_in6 *)sa;
209 			inet_ntop(AF_INET6, &sin6->sin6_addr, abuf, sizeof(abuf));
210 			int scope_id = sin6->sin6_scope_id;
211 			printf(" af=inet6 len=%d addr=%s", sa->sa_len, abuf);
212 			if (scope_id != 0) {
213 				memset(ifbuf, 0, sizeof(ifbuf));
214 				if_indextoname(scope_id, ifbuf);
215 				printf(" scope_id=%d if_name=%s", scope_id, ifbuf);
216 			}
217 			break;
218 		case AF_LINK:
219 			sdl = (const struct sockaddr_dl *)sa;
220 			int sdl_index = sdl->sdl_index;
221 			if (sdl_index != 0) {
222 				memset(ifbuf, 0, sizeof(ifbuf));
223 				if_indextoname(sdl_index, ifbuf);
224 				printf(" af=link len=%d sdl_index=%d if_name=%s", sdl->sdl_len, sdl_index, ifbuf);
225 			}
226 			if (sdl->sdl_nlen) {
227 				char _ifname[IFNAMSIZ];
228 				memcpy(_ifname, sdl->sdl_data, sdl->sdl_nlen);
229 				_ifname[sdl->sdl_nlen] = '\0';
230 				printf(" name=%s", _ifname);
231 			}
232 			if (sdl->sdl_alen) {
233 				printf(" addr=");
234 				const char *lladdr = LLADDR(sdl);
235 				for (int i = 0; i < sdl->sdl_alen; i++) {
236 					if (i + 1 < sdl->sdl_alen)
237 						printf("%02X:", ((const unsigned char *)lladdr)[i]);
238 					else
239 						printf("%02X", ((const unsigned char *)lladdr)[i]);
240 				}
241 			}
242 			break;
243 		default:
244 			printf(" af=%d len=%d", sa->sa_family, sa->sa_len);
245 	}
246 
247 	if (include_hexdump) {
248 		sa_print_hd(hdbuf, sizeof(hdbuf), ((char *)sa), sa->sa_len);
249 		printf(" hd={%s}", hdbuf);
250 	}
251 	printf("\n");
252 }
253 
254 /*
255 got message of size 240 on Mon Dec 16 09:23:31 2019
256 RTM_ADD: Add Route: len 240, pid: 25534, seq 2, errno 0, flags:<HOST,DONE,LLINFO,STATIC>
257 locks:  inits:
258 sockaddrs: <DST,GATEWAY>
259 */
260 
261 void
262 rtsock_print_rtm(struct rt_msghdr *rtm)
263 {
264 	struct timeval tv;
265 	struct tm tm_res;
266 	char buf[64];
267 
268 	gettimeofday(&tv, NULL);
269 	localtime_r(&tv.tv_sec, &tm_res);
270 	strftime(buf, sizeof(buf), "%F %T", &tm_res);
271 	printf("Got message of size %hu on %s\n", rtm->rtm_msglen, buf);
272 
273 	char flags_buf[256];
274 	rtsock_print_rtm_flags(flags_buf, sizeof(flags_buf), rtm->rtm_flags);
275 
276 	printf("%s: len %hu, pid: %d, seq %d, errno %d, flags: %s\n", msgtypes[rtm->rtm_type],
277 		rtm->rtm_msglen, rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno, flags_buf);
278 
279 	if (rtm->rtm_inits > 0) {
280 		_printb(flags_buf, sizeof(flags_buf), rtm->rtm_inits, metricnames);
281 		printf("metrics: %s\n", flags_buf);
282 		if (rtm->rtm_inits & RTV_MTU)
283 			printf("mtu: %lu\n", rtm->rtm_rmx.rmx_mtu);
284 		if (rtm->rtm_inits & RTV_EXPIRE) {
285 			struct timeval tv;
286 			gettimeofday(&tv, NULL);
287 			printf("expire: %d (%lu raw)\n",
288 			    (int)(rtm->rtm_rmx.rmx_expire - tv.tv_sec), rtm->rtm_rmx.rmx_expire);
289 		}
290 	}
291 
292 	_printb(flags_buf, sizeof(flags_buf), rtm->rtm_addrs, addrnames);
293 	printf("sockaddrs: 0x%X %s\n", rtm->rtm_addrs, flags_buf);
294 
295 	char *ptr = (char *)(rtm + 1);
296 	for (int i = 0; i < RTAX_MAX; i++) {
297 		if (rtm->rtm_addrs & (1 << i)) {
298 			struct sockaddr *sa = (struct sockaddr *)ptr;
299 			sa_print(sa, 1);
300 
301 			/* add */
302 			ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
303 		}
304 	}
305 
306 	printf("\n");
307 
308 }
309 
310 void
311 rtsock_print_ifa(struct ifa_msghdr *ifam)
312 {
313 	struct timeval tv;
314 	struct tm tm_res;
315 	char buf[64];
316 
317 	gettimeofday(&tv, NULL);
318 	localtime_r(&tv.tv_sec, &tm_res);
319 	strftime(buf, sizeof(buf), "%F %T", &tm_res);
320 	printf("Got message of size %hu on %s\n", ifam->ifam_msglen, buf);
321 
322 	char flags_buf[256];
323 	_printb(flags_buf, sizeof(flags_buf), ifam->ifam_flags, routeflags);
324 
325 	printf("%s: len %hu, ifindex: %d, flags: %s\n", msgtypes[ifam->ifam_type],
326 		ifam->ifam_msglen, ifam->ifam_index, flags_buf);
327 
328 	_printb(flags_buf, sizeof(flags_buf), ifam->ifam_addrs, addrnames);
329 	printf("sockaddrs: 0x%X %s\n", ifam->ifam_addrs, flags_buf);
330 
331 	char *ptr = (char *)(ifam + 1);
332 	for (int i = 0; i < RTAX_MAX; i++) {
333 		if (ifam->ifam_addrs & (1 << i)) {
334 			struct sockaddr *sa = (struct sockaddr *)ptr;
335 			sa_print(sa, 1);
336 
337 			/* add */
338 			ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
339 		}
340 	}
341 
342 	printf("\n");
343 
344 }
345 
346 void
347 rtsock_print_message_hd(struct rt_msghdr *rtm)
348 {
349 	struct timeval tv;
350 	struct tm tm_res;
351 	char buf[64];
352 	char dumpbuf[2048];
353 
354 	gettimeofday(&tv, NULL);
355 	localtime_r(&tv.tv_sec, &tm_res);
356 	strftime(buf, sizeof(buf), "%F %T", &tm_res);
357 	printf("Got message type %s of size %hu on %s\n",
358 	    rtsock_print_cmdtype(rtm->rtm_type),
359 	    rtm->rtm_msglen, buf);
360 
361 	sa_print_hd(dumpbuf, sizeof(dumpbuf), (char *)rtm, rtm->rtm_msglen);
362 	printf(" %s\n", dumpbuf);
363 }
364 
365 void
366 rtsock_print_message(struct rt_msghdr *rtm)
367 {
368 
369 	switch (rtm->rtm_type) {
370 	case RTM_GET:
371 	case RTM_ADD:
372 	case RTM_DELETE:
373 	case RTM_CHANGE:
374 		rtsock_print_rtm(rtm);
375 		break;
376 	case RTM_DELADDR:
377 	case RTM_NEWADDR:
378 		rtsock_print_ifa((struct ifa_msghdr *)rtm);
379 		break;
380 	default:
381 		printf("unknown rt message type %X\n", rtm->rtm_type);
382 	}
383 }
384 
385 static void
386 print_command(char *cmd)
387 {
388 	char line[1024];
389 
390 	FILE *fp = popen(cmd, "r");
391 	if (fp != NULL) {
392 		while (fgets(line, sizeof(line), fp) != NULL)
393 			printf("%s", line);
394 		pclose(fp);
395 	}
396 }
397 
398 void
399 rtsock_print_table(int family)
400 {
401 	char cmdbuf[128];
402 	char *key = (family == AF_INET) ? "4" : "6";
403 
404 	snprintf(cmdbuf, sizeof(cmdbuf), "/usr/bin/netstat -%srnW", key);
405 	printf("==== %s ===\n", cmdbuf);
406 	print_command(cmdbuf);
407 	snprintf(cmdbuf, sizeof(cmdbuf), "/usr/bin/netstat -%sonW", key);
408 	printf("==== %s ===\n", cmdbuf);
409 	print_command(cmdbuf);
410 }
411 
412 #endif
413