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