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