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 * $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