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