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