1224006Shrs/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4224006Shrs * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> 5224006Shrs * All rights reserved. 6224006Shrs * 7224006Shrs * Redistribution and use in source and binary forms, with or without 8224006Shrs * modification, are permitted provided that the following conditions 9224006Shrs * are met: 10224006Shrs * 1. Redistributions of source code must retain the above copyright 11224006Shrs * notice, this list of conditions and the following disclaimer. 12224006Shrs * 2. Redistributions in binary form must reproduce the above copyright 13224006Shrs * notice, this list of conditions and the following disclaimer in the 14224006Shrs * documentation and/or other materials provided with the distribution. 15224006Shrs * 16224006Shrs * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 17224006Shrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18224006Shrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19224006Shrs * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS 20224006Shrs * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21224006Shrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22224006Shrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23224006Shrs * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24224006Shrs * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25224006Shrs * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26224006Shrs * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27224006Shrs * 28224006Shrs * $FreeBSD: stable/11/usr.sbin/rtadvctl/rtadvctl.c 330449 2018-03-05 07:26:05Z eadler $ 29224006Shrs * 30224006Shrs */ 31224006Shrs 32224006Shrs#include <sys/queue.h> 33224006Shrs#include <sys/types.h> 34224006Shrs#include <sys/socket.h> 35224006Shrs#include <sys/stat.h> 36224006Shrs#include <sys/un.h> 37224006Shrs#include <sys/uio.h> 38224006Shrs#include <net/if.h> 39224006Shrs#include <net/if_dl.h> 40224006Shrs#include <net/if_types.h> 41224006Shrs#include <net/ethernet.h> 42224006Shrs#include <netinet/in.h> 43224006Shrs#include <netinet/ip6.h> 44224006Shrs#include <netinet/icmp6.h> 45224006Shrs#include <netinet6/in6_var.h> 46224006Shrs#include <netinet6/nd6.h> 47224006Shrs#include <arpa/inet.h> 48224006Shrs#include <fcntl.h> 49224006Shrs#include <errno.h> 50224144Shrs#include <inttypes.h> 51224006Shrs#include <netdb.h> 52224006Shrs#include <unistd.h> 53224006Shrs#include <string.h> 54224006Shrs#include <stdarg.h> 55224006Shrs#include <stdio.h> 56224006Shrs#include <stdlib.h> 57224006Shrs#include <stdarg.h> 58224006Shrs#include <syslog.h> 59253970Shrs#include <time.h> 60224006Shrs#include <err.h> 61224006Shrs 62224006Shrs#include "pathnames.h" 63224006Shrs#include "rtadvd.h" 64224006Shrs#include "if.h" 65224006Shrs#include "timer_subr.h" 66224144Shrs#include "timer.h" 67224006Shrs#include "control.h" 68224006Shrs#include "control_client.h" 69224006Shrs 70224006Shrs#define RA_IFSTATUS_INACTIVE 0 71224006Shrs#define RA_IFSTATUS_RA_RECV 1 72224006Shrs#define RA_IFSTATUS_RA_SEND 2 73224006Shrs 74224006Shrsstatic int vflag = LOG_ERR; 75224006Shrs 76224006Shrsstatic void usage(void); 77224006Shrs 78224006Shrsstatic int action_propset(char *); 79224006Shrsstatic int action_propget(char *, struct ctrl_msg_pl *); 80224006Shrsstatic int action_plgeneric(int, char *, char *); 81224006Shrs 82224006Shrsstatic int action_enable(int, char **); 83224006Shrsstatic int action_disable(int, char **); 84224006Shrsstatic int action_reload(int, char **); 85224006Shrsstatic int action_echo(int, char **); 86224006Shrsstatic int action_version(int, char **); 87224006Shrsstatic int action_shutdown(int, char **); 88224006Shrs 89224006Shrsstatic int action_show(int, char **); 90224006Shrsstatic int action_show_prefix(struct prefix *); 91224006Shrsstatic int action_show_rtinfo(struct rtinfo *); 92224006Shrsstatic int action_show_rdnss(void *); 93224006Shrsstatic int action_show_dnssl(void *); 94224006Shrs 95224006Shrsstatic int csock_client_open(struct sockinfo *); 96224006Shrsstatic size_t dname_labeldec(char *, size_t, const char *); 97224006Shrsstatic void mysyslog(int, const char *, ...); 98224006Shrs 99224006Shrsstatic const char *rtpref_str[] = { 100224006Shrs "medium", /* 00 */ 101224006Shrs "high", /* 01 */ 102224006Shrs "rsv", /* 10 */ 103224006Shrs "low" /* 11 */ 104224006Shrs}; 105224006Shrs 106224006Shrsstatic struct dispatch_table { 107224006Shrs const char *dt_comm; 108224006Shrs int (*dt_act)(int, char **); 109224006Shrs} dtable[] = { 110224006Shrs { "show", action_show }, 111224006Shrs { "reload", action_reload }, 112224006Shrs { "shutdown", action_shutdown }, 113224006Shrs { "enable", action_enable }, 114224006Shrs { "disable", action_disable }, 115224144Shrs { NULL, NULL }, 116224006Shrs { "echo", action_echo }, 117224006Shrs { "version", action_version }, 118224006Shrs { NULL, NULL }, 119224006Shrs}; 120224006Shrs 121224144Shrsstatic char errmsgbuf[1024]; 122224144Shrsstatic char *errmsg = NULL; 123224144Shrs 124224006Shrsstatic void 125224006Shrsmysyslog(int priority, const char * restrict fmt, ...) 126224006Shrs{ 127224006Shrs va_list ap; 128224006Shrs 129224006Shrs if (vflag >= priority) { 130224006Shrs va_start(ap, fmt); 131224006Shrs vfprintf(stderr, fmt, ap); 132224006Shrs fprintf(stderr, "\n"); 133224006Shrs va_end(ap); 134224006Shrs } 135224006Shrs} 136224006Shrs 137224006Shrsstatic void 138224006Shrsusage(void) 139224006Shrs{ 140224006Shrs int i; 141224006Shrs 142224006Shrs for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) { 143224006Shrs if (dtable[i].dt_comm == NULL) 144224006Shrs break; 145224006Shrs printf("%s\n", dtable[i].dt_comm); 146224006Shrs } 147224006Shrs 148224006Shrs exit(1); 149224006Shrs} 150224006Shrs 151224006Shrsint 152224006Shrsmain(int argc, char *argv[]) 153224006Shrs{ 154224006Shrs int i; 155224006Shrs int ch; 156224006Shrs int (*action)(int, char **) = NULL; 157224006Shrs int error; 158224006Shrs 159224006Shrs while ((ch = getopt(argc, argv, "Dv")) != -1) { 160224006Shrs switch (ch) { 161224006Shrs case 'D': 162224006Shrs vflag = LOG_DEBUG; 163224006Shrs break; 164224006Shrs case 'v': 165224006Shrs vflag++; 166224006Shrs break; 167224006Shrs default: 168224006Shrs usage(); 169224006Shrs } 170224006Shrs } 171224006Shrs argc -= optind; 172224006Shrs argv += optind; 173224006Shrs 174224006Shrs if (argc == 0) 175224006Shrs usage(); 176224006Shrs 177224006Shrs for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) { 178224006Shrs if (dtable[i].dt_comm == NULL || 179224006Shrs strcmp(dtable[i].dt_comm, argv[0]) == 0) { 180224006Shrs action = dtable[i].dt_act; 181224006Shrs break; 182224006Shrs } 183224006Shrs } 184224006Shrs 185224144Shrs if (action == NULL) 186224006Shrs usage(); 187224006Shrs 188224144Shrs error = (dtable[i].dt_act)(--argc, ++argv); 189224144Shrs if (error) { 190224144Shrs fprintf(stderr, "%s failed", dtable[i].dt_comm); 191224144Shrs if (errmsg != NULL) 192224144Shrs fprintf(stderr, ": %s", errmsg); 193224144Shrs fprintf(stderr, ".\n"); 194224144Shrs } 195224144Shrs 196224006Shrs return (error); 197224006Shrs} 198224006Shrs 199224006Shrsstatic int 200224006Shrscsock_client_open(struct sockinfo *s) 201224006Shrs{ 202224006Shrs struct sockaddr_un sun; 203224006Shrs 204224006Shrs if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 205224006Shrs err(1, "cannot open control socket."); 206224006Shrs 207224006Shrs memset(&sun, 0, sizeof(sun)); 208224006Shrs sun.sun_family = AF_UNIX; 209224006Shrs sun.sun_len = sizeof(sun); 210224006Shrs strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path)); 211224006Shrs 212224006Shrs if (connect(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) 213224006Shrs err(1, "connect: %s", s->si_name); 214224006Shrs 215224006Shrs mysyslog(LOG_DEBUG, 216224006Shrs "<%s> connected to %s", __func__, sun.sun_path); 217224006Shrs 218224006Shrs return (0); 219224006Shrs} 220224006Shrs 221224006Shrsstatic int 222224006Shrsaction_plgeneric(int action, char *plstr, char *buf) 223224006Shrs{ 224224006Shrs struct ctrl_msg_hdr *cm; 225224006Shrs struct ctrl_msg_pl cp; 226224006Shrs struct sockinfo *s; 227224006Shrs char *msg; 228224006Shrs char *p; 229224006Shrs char *q; 230224006Shrs 231224006Shrs s = &ctrlsock; 232224006Shrs csock_client_open(s); 233224006Shrs 234224006Shrs cm = (struct ctrl_msg_hdr *)buf; 235224006Shrs msg = (char *)buf + sizeof(*cm); 236224006Shrs 237224006Shrs cm->cm_version = CM_VERSION; 238224006Shrs cm->cm_type = action; 239224006Shrs cm->cm_len = sizeof(*cm); 240224006Shrs 241224006Shrs if (plstr != NULL) { 242224006Shrs memset(&cp, 0, sizeof(cp)); 243224006Shrs p = strchr(plstr, ':'); 244224006Shrs q = strchr(plstr, '='); 245224006Shrs if (p != NULL && q != NULL && p > q) 246224006Shrs return (1); 247224006Shrs 248224006Shrs if (p == NULL) { /* No : */ 249224006Shrs cp.cp_ifname = NULL; 250224006Shrs cp.cp_key = plstr; 251224006Shrs } else if (p == plstr) { /* empty */ 252224006Shrs cp.cp_ifname = NULL; 253224006Shrs cp.cp_key = plstr + 1; 254224006Shrs } else { 255224006Shrs *p++ = '\0'; 256224006Shrs cp.cp_ifname = plstr; 257224006Shrs cp.cp_key = p; 258224006Shrs } 259224006Shrs if (q == NULL) 260224006Shrs cp.cp_val = NULL; 261224006Shrs else { 262224006Shrs *q++ = '\0'; 263224006Shrs cp.cp_val = q; 264224006Shrs } 265225519Shrs cm->cm_len += cm_pl2bin(msg, &cp); 266224006Shrs 267224006Shrs mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s", 268224006Shrs __func__,cp.cp_key, cp.cp_val_len, cp.cp_ifname); 269224006Shrs } 270224006Shrs 271225519Shrs return (cm_handler_client(s->si_fd, CM_STATE_MSG_DISPATCH, buf)); 272224006Shrs} 273224006Shrs 274224006Shrsstatic int 275224006Shrsaction_propget(char *argv, struct ctrl_msg_pl *cp) 276224006Shrs{ 277224006Shrs int error; 278224006Shrs struct ctrl_msg_hdr *cm; 279224006Shrs char buf[CM_MSG_MAXLEN]; 280224006Shrs char *msg; 281224006Shrs 282224006Shrs memset(cp, 0, sizeof(*cp)); 283224006Shrs cm = (struct ctrl_msg_hdr *)buf; 284224006Shrs msg = (char *)buf + sizeof(*cm); 285224006Shrs 286224006Shrs error = action_plgeneric(CM_TYPE_REQ_GET_PROP, argv, buf); 287224006Shrs if (error || cm->cm_len <= sizeof(*cm)) 288224006Shrs return (1); 289224006Shrs 290225519Shrs cm_bin2pl(msg, cp); 291224006Shrs mysyslog(LOG_DEBUG, "<%s> type=%d, len=%d", 292224006Shrs __func__, cm->cm_type, cm->cm_len); 293224006Shrs mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s", 294224006Shrs __func__,cp->cp_key, cp->cp_val_len, cp->cp_ifname); 295224006Shrs 296224006Shrs return (0); 297224006Shrs} 298224006Shrs 299224006Shrsstatic int 300224006Shrsaction_propset(char *argv) 301224006Shrs{ 302224006Shrs char buf[CM_MSG_MAXLEN]; 303224006Shrs 304224006Shrs return (action_plgeneric(CM_TYPE_REQ_SET_PROP, argv, buf)); 305224006Shrs} 306224006Shrs 307224006Shrsstatic int 308224144Shrsaction_disable(int argc, char **argv) 309224006Shrs{ 310224144Shrs char *action_argv; 311224144Shrs char argv_disable[IFNAMSIZ + sizeof(":disable=")]; 312224144Shrs int i; 313224144Shrs int error; 314224006Shrs 315224144Shrs if (argc < 1) 316224144Shrs return (1); 317224144Shrs 318224144Shrs error = 0; 319224144Shrs for (i = 0; i < argc; i++) { 320224144Shrs sprintf(argv_disable, "%s:disable=", argv[i]); 321224144Shrs action_argv = argv_disable; 322224144Shrs error += action_propset(action_argv); 323224144Shrs } 324224144Shrs 325224144Shrs return (error); 326224006Shrs} 327224006Shrs 328224006Shrsstatic int 329224144Shrsaction_enable(int argc, char **argv) 330224006Shrs{ 331224144Shrs char *action_argv; 332224144Shrs char argv_enable[IFNAMSIZ + sizeof(":enable=")]; 333224144Shrs int i; 334224144Shrs int error; 335224006Shrs 336224144Shrs if (argc < 1) 337224144Shrs return (1); 338224144Shrs 339224144Shrs error = 0; 340224144Shrs for (i = 0; i < argc; i++) { 341224144Shrs sprintf(argv_enable, "%s:enable=", argv[i]); 342224144Shrs action_argv = argv_enable; 343224144Shrs error += action_propset(action_argv); 344224144Shrs } 345224144Shrs 346224144Shrs return (error); 347224006Shrs} 348224006Shrs 349224006Shrsstatic int 350224144Shrsaction_reload(int argc, char **argv) 351224006Shrs{ 352224006Shrs char *action_argv; 353224144Shrs char argv_reload[IFNAMSIZ + sizeof(":reload=")]; 354224144Shrs int i; 355224144Shrs int error; 356224006Shrs 357224144Shrs if (argc == 0) { 358224144Shrs action_argv = strdup(":reload="); 359224144Shrs return (action_propset(action_argv)); 360224144Shrs } 361224144Shrs 362224144Shrs error = 0; 363224144Shrs for (i = 0; i < argc; i++) { 364224144Shrs sprintf(argv_reload, "%s:reload=", argv[i]); 365224144Shrs action_argv = argv_reload; 366224144Shrs error += action_propset(action_argv); 367224144Shrs } 368224144Shrs 369224144Shrs return (error); 370224006Shrs} 371224006Shrs 372224006Shrsstatic int 373224006Shrsaction_echo(int argc __unused, char **argv __unused) 374224006Shrs{ 375224006Shrs char *action_argv; 376224006Shrs 377224006Shrs action_argv = strdup("echo"); 378224144Shrs return (action_propset(action_argv)); 379224006Shrs} 380224006Shrs 381224006Shrsstatic int 382224006Shrsaction_shutdown(int argc __unused, char **argv __unused) 383224006Shrs{ 384224006Shrs char *action_argv; 385224006Shrs 386224006Shrs action_argv = strdup("shutdown"); 387224144Shrs return (action_propset(action_argv)); 388224006Shrs} 389224006Shrs 390224006Shrs/* XXX */ 391224006Shrsstatic int 392224006Shrsaction_version(int argc __unused, char **argv __unused) 393224006Shrs{ 394224006Shrs char *action_argv; 395224006Shrs struct ctrl_msg_pl cp; 396224006Shrs int error; 397224006Shrs 398224006Shrs action_argv = strdup(":version="); 399224006Shrs error = action_propget(action_argv, &cp); 400224006Shrs if (error) 401224006Shrs return (error); 402224006Shrs 403224006Shrs printf("version=%s\n", cp.cp_val); 404224006Shrs return (0); 405224006Shrs} 406224006Shrs 407224006Shrsstatic int 408224006Shrsaction_show(int argc, char **argv) 409224006Shrs{ 410224006Shrs char *action_argv; 411224006Shrs char argv_ifilist[sizeof(":ifilist=")] = ":ifilist="; 412224006Shrs char argv_ifi[IFNAMSIZ + sizeof(":ifi=")]; 413224006Shrs char argv_rai[IFNAMSIZ + sizeof(":rai=")]; 414224006Shrs char argv_rti[IFNAMSIZ + sizeof(":rti=")]; 415224006Shrs char argv_pfx[IFNAMSIZ + sizeof(":pfx=")]; 416224144Shrs char argv_ifi_ra_timer[IFNAMSIZ + sizeof(":ifi_ra_timer=")]; 417224006Shrs char argv_rdnss[IFNAMSIZ + sizeof(":rdnss=")]; 418224006Shrs char argv_dnssl[IFNAMSIZ + sizeof(":dnssl=")]; 419224006Shrs char ssbuf[SSBUFLEN]; 420224006Shrs 421253970Shrs struct timespec now, ts0, ts; 422224006Shrs struct ctrl_msg_pl cp; 423224006Shrs struct ifinfo *ifi; 424224006Shrs TAILQ_HEAD(, ifinfo) ifl = TAILQ_HEAD_INITIALIZER(ifl); 425224006Shrs char *endp; 426224006Shrs char *p; 427224006Shrs int error; 428224006Shrs int i; 429224006Shrs int len; 430224006Shrs 431224006Shrs if (argc == 0) { 432224006Shrs action_argv = argv_ifilist; 433224006Shrs error = action_propget(action_argv, &cp); 434224006Shrs if (error) 435224006Shrs return (error); 436224006Shrs 437224006Shrs p = cp.cp_val; 438224006Shrs endp = p + cp.cp_val_len; 439224006Shrs while (p < endp) { 440224006Shrs ifi = malloc(sizeof(*ifi)); 441224006Shrs if (ifi == NULL) 442224144Shrs return (1); 443224006Shrs memset(ifi, 0, sizeof(*ifi)); 444224006Shrs 445224006Shrs strcpy(ifi->ifi_ifname, p); 446224006Shrs ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname); 447224006Shrs TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next); 448224006Shrs p += strlen(ifi->ifi_ifname) + 1; 449224006Shrs } 450224006Shrs } else { 451224006Shrs for (i = 0; i < argc; i++) { 452224006Shrs ifi = malloc(sizeof(*ifi)); 453224006Shrs if (ifi == NULL) 454224144Shrs return (1); 455224006Shrs memset(ifi, 0, sizeof(*ifi)); 456224006Shrs 457224006Shrs strcpy(ifi->ifi_ifname, argv[i]); 458224006Shrs ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname); 459224144Shrs if (ifi->ifi_ifindex == 0) { 460224144Shrs sprintf(errmsgbuf, "invalid interface %s", 461224144Shrs ifi->ifi_ifname); 462224144Shrs errmsg = errmsgbuf; 463224144Shrs return (1); 464224144Shrs } 465224144Shrs 466224006Shrs TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next); 467224006Shrs } 468224006Shrs } 469224006Shrs 470253970Shrs clock_gettime(CLOCK_REALTIME_FAST, &now); 471253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, &ts); 472253970Shrs TS_SUB(&now, &ts, &ts0); 473253970Shrs 474224006Shrs TAILQ_FOREACH(ifi, &ifl, ifi_next) { 475224006Shrs struct ifinfo *ifi_s; 476224144Shrs struct rtadvd_timer *rat; 477224006Shrs struct rainfo *rai; 478224006Shrs struct rtinfo *rti; 479224006Shrs struct prefix *pfx; 480224006Shrs int c; 481224006Shrs int ra_ifstatus; 482224006Shrs 483224006Shrs sprintf(argv_ifi, "%s:ifi=", ifi->ifi_ifname); 484224006Shrs action_argv = argv_ifi; 485224006Shrs error = action_propget(action_argv, &cp); 486224006Shrs if (error) 487224006Shrs return (error); 488224006Shrs ifi_s = (struct ifinfo *)cp.cp_val; 489224006Shrs 490224006Shrs if (!(ifi_s->ifi_persist) && vflag < LOG_NOTICE) 491224006Shrs continue; 492224006Shrs 493224006Shrs printf("%s: flags=<", ifi->ifi_ifname); 494224006Shrs 495224006Shrs c = 0; 496224006Shrs if (ifi_s->ifi_ifindex == 0) 497224006Shrs c += printf("NONEXISTENT"); 498224006Shrs else 499224006Shrs c += printf("%s", (ifi_s->ifi_flags & IFF_UP) ? 500224006Shrs "UP" : "DOWN"); 501224144Shrs switch (ifi_s->ifi_state) { 502224144Shrs case IFI_STATE_CONFIGURED: 503224006Shrs c += printf("%s%s", (c) ? "," : "", "CONFIGURED"); 504224144Shrs break; 505224144Shrs case IFI_STATE_TRANSITIVE: 506224144Shrs c += printf("%s%s", (c) ? "," : "", "TRANSITIVE"); 507224144Shrs break; 508224144Shrs } 509224006Shrs if (ifi_s->ifi_persist) 510224006Shrs c += printf("%s%s", (c) ? "," : "", "PERSIST"); 511224006Shrs printf(">"); 512224006Shrs 513224006Shrs ra_ifstatus = RA_IFSTATUS_INACTIVE; 514224006Shrs if ((ifi_s->ifi_flags & IFF_UP) && 515224144Shrs ((ifi_s->ifi_state == IFI_STATE_CONFIGURED) || 516224144Shrs (ifi_s->ifi_state == IFI_STATE_TRANSITIVE))) { 517224144Shrs#if (__FreeBSD_version < 900000) 518224144Shrs /* 519224144Shrs * RA_RECV: !ip6.forwarding && ip6.accept_rtadv 520224144Shrs * RA_SEND: ip6.forwarding 521224144Shrs */ 522224144Shrs if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) { 523224144Shrs if (getinet6sysctl(IPV6CTL_ACCEPT_RTADV)) 524224144Shrs ra_ifstatus = RA_IFSTATUS_RA_RECV; 525224144Shrs else 526224144Shrs ra_ifstatus = RA_IFSTATUS_INACTIVE; 527224144Shrs } else 528224144Shrs ra_ifstatus = RA_IFSTATUS_RA_SEND; 529224144Shrs#else 530224144Shrs /* 531224144Shrs * RA_RECV: ND6_IFF_ACCEPT_RTADV 532224144Shrs * RA_SEND: ip6.forwarding 533224144Shrs */ 534224006Shrs if (ifi_s->ifi_nd_flags & ND6_IFF_ACCEPT_RTADV) 535224006Shrs ra_ifstatus = RA_IFSTATUS_RA_RECV; 536224006Shrs else if (getinet6sysctl(IPV6CTL_FORWARDING)) 537224006Shrs ra_ifstatus = RA_IFSTATUS_RA_SEND; 538224006Shrs else 539224006Shrs ra_ifstatus = RA_IFSTATUS_INACTIVE; 540224144Shrs#endif 541224006Shrs } 542224006Shrs 543224006Shrs c = 0; 544224006Shrs printf(" status=<"); 545224006Shrs if (ra_ifstatus == RA_IFSTATUS_INACTIVE) 546224006Shrs printf("%s%s", (c) ? "," : "", "INACTIVE"); 547224006Shrs else if (ra_ifstatus == RA_IFSTATUS_RA_RECV) 548224006Shrs printf("%s%s", (c) ? "," : "", "RA_RECV"); 549224006Shrs else if (ra_ifstatus == RA_IFSTATUS_RA_SEND) 550224006Shrs printf("%s%s", (c) ? "," : "", "RA_SEND"); 551224006Shrs printf("> "); 552224006Shrs 553224144Shrs switch (ifi_s->ifi_state) { 554224144Shrs case IFI_STATE_CONFIGURED: 555224144Shrs case IFI_STATE_TRANSITIVE: 556224144Shrs break; 557224144Shrs default: 558224006Shrs printf("\n"); 559224006Shrs continue; 560224006Shrs } 561224006Shrs 562224006Shrs printf("mtu %d\n", ifi_s->ifi_phymtu); 563224006Shrs 564224006Shrs sprintf(argv_rai, "%s:rai=", ifi->ifi_ifname); 565224006Shrs action_argv = argv_rai; 566224006Shrs 567224006Shrs error = action_propget(action_argv, &cp); 568224006Shrs if (error) 569224006Shrs continue; 570224006Shrs 571224006Shrs rai = (struct rainfo *)cp.cp_val; 572224006Shrs 573224006Shrs printf("\tDefaultLifetime: %s", 574224006Shrs sec2str(rai->rai_lifetime, ssbuf)); 575224006Shrs if (ra_ifstatus != RA_IFSTATUS_RA_SEND && 576224006Shrs rai->rai_lifetime == 0) 577224006Shrs printf(" (RAs will be sent with zero lifetime)"); 578224006Shrs 579224006Shrs printf("\n"); 580224006Shrs 581225519Shrs printf("\tMinAdvInterval/MaxAdvInterval: "); 582225519Shrs printf("%s/", sec2str(rai->rai_mininterval, ssbuf)); 583225519Shrs printf("%s\n", sec2str(rai->rai_maxinterval, ssbuf)); 584224006Shrs if (rai->rai_linkmtu) 585224006Shrs printf("\tAdvLinkMTU: %d", rai->rai_linkmtu); 586224006Shrs else 587224006Shrs printf("\tAdvLinkMTU: <none>"); 588224006Shrs 589224006Shrs printf(", "); 590224006Shrs 591224006Shrs printf("Flags: "); 592224006Shrs if (rai->rai_managedflg || rai->rai_otherflg) { 593224006Shrs printf("%s", rai->rai_managedflg ? "M" : ""); 594224006Shrs printf("%s", rai->rai_otherflg ? "O" : ""); 595224006Shrs } else 596224006Shrs printf("<none>"); 597224006Shrs 598224006Shrs printf(", "); 599224006Shrs 600224006Shrs printf("Preference: %s\n", 601224006Shrs rtpref_str[(rai->rai_rtpref >> 3) & 0xff]); 602224006Shrs 603225519Shrs printf("\tReachableTime: %s, ", 604225519Shrs sec2str(rai->rai_reachabletime, ssbuf)); 605225519Shrs printf("RetransTimer: %s, " 606224006Shrs "CurHopLimit: %d\n", 607224006Shrs sec2str(rai->rai_retranstimer, ssbuf), 608224006Shrs rai->rai_hoplimit); 609224006Shrs printf("\tAdvIfPrefixes: %s\n", 610224006Shrs rai->rai_advifprefix ? "yes" : "no"); 611224144Shrs 612224144Shrs /* RA timer */ 613224144Shrs rat = NULL; 614224144Shrs if (ifi_s->ifi_ra_timer != NULL) { 615224144Shrs sprintf(argv_ifi_ra_timer, "%s:ifi_ra_timer=", 616224144Shrs ifi->ifi_ifname); 617224144Shrs action_argv = argv_ifi_ra_timer; 618224144Shrs 619224144Shrs error = action_propget(action_argv, &cp); 620224144Shrs if (error) 621224144Shrs return (error); 622224144Shrs 623224144Shrs rat = (struct rtadvd_timer *)cp.cp_val; 624224144Shrs } 625253970Shrs printf("\tNext RA send: "); 626253970Shrs if (rat == NULL) 627253970Shrs printf("never\n"); 628253970Shrs else { 629253970Shrs ts.tv_sec = rat->rat_tm.tv_sec + ts0.tv_sec; 630253970Shrs printf("%s", ctime(&ts.tv_sec)); 631253970Shrs } 632253970Shrs printf("\tLast RA send: "); 633253970Shrs if (ifi_s->ifi_ra_lastsent.tv_sec == 0) 634253970Shrs printf("never\n"); 635253970Shrs else { 636253970Shrs ts.tv_sec = ifi_s->ifi_ra_lastsent.tv_sec + ts0.tv_sec; 637253970Shrs printf("%s", ctime(&ts.tv_sec)); 638253970Shrs } 639224006Shrs if (rai->rai_clockskew) 640224144Shrs printf("\tClock skew: %" PRIu16 "sec\n", 641224006Shrs rai->rai_clockskew); 642224006Shrs 643224006Shrs if (vflag < LOG_WARNING) 644224006Shrs continue; 645224006Shrs 646224006Shrs /* route information */ 647224006Shrs sprintf(argv_rti, "%s:rti=", ifi->ifi_ifname); 648224006Shrs action_argv = argv_rti; 649224006Shrs error = action_propget(action_argv, &cp); 650224006Shrs if (error) 651224006Shrs return (error); 652224006Shrs 653224006Shrs rti = (struct rtinfo *)cp.cp_val; 654224006Shrs len = cp.cp_val_len / sizeof(*rti); 655224006Shrs if (len > 0) { 656224006Shrs printf("\tRoute Info:\n"); 657224006Shrs 658224006Shrs for (i = 0; i < len; i++) 659224006Shrs action_show_rtinfo(&rti[i]); 660224006Shrs } 661224144Shrs 662224006Shrs /* prefix information */ 663224006Shrs sprintf(argv_pfx, "%s:pfx=", ifi->ifi_ifname); 664224006Shrs action_argv = argv_pfx; 665224006Shrs 666224006Shrs error = action_propget(action_argv, &cp); 667224006Shrs if (error) 668224006Shrs continue; 669224006Shrs 670224006Shrs pfx = (struct prefix *)cp.cp_val; 671224006Shrs len = cp.cp_val_len / sizeof(*pfx); 672224006Shrs 673224006Shrs if (len > 0) { 674224006Shrs printf("\tPrefixes (%d):\n", len); 675224006Shrs 676224006Shrs for (i = 0; i < len; i++) 677224006Shrs action_show_prefix(&pfx[i]); 678224006Shrs } 679224006Shrs 680224006Shrs /* RDNSS information */ 681224006Shrs sprintf(argv_rdnss, "%s:rdnss=", ifi->ifi_ifname); 682224006Shrs action_argv = argv_rdnss; 683224006Shrs 684224006Shrs error = action_propget(action_argv, &cp); 685224006Shrs if (error) 686224006Shrs continue; 687224006Shrs 688224144Shrs len = *((uint16_t *)cp.cp_val); 689224006Shrs 690224006Shrs if (len > 0) { 691224006Shrs printf("\tRDNSS entries:\n"); 692224006Shrs action_show_rdnss(cp.cp_val); 693224006Shrs } 694224006Shrs 695224006Shrs /* DNSSL information */ 696224006Shrs sprintf(argv_dnssl, "%s:dnssl=", ifi->ifi_ifname); 697224006Shrs action_argv = argv_dnssl; 698224006Shrs 699224006Shrs error = action_propget(action_argv, &cp); 700224006Shrs if (error) 701224006Shrs continue; 702224006Shrs 703224144Shrs len = *((uint16_t *)cp.cp_val); 704224006Shrs 705224006Shrs if (len > 0) { 706224006Shrs printf("\tDNSSL entries:\n"); 707224006Shrs action_show_dnssl(cp.cp_val); 708224006Shrs } 709224006Shrs 710224006Shrs if (vflag < LOG_NOTICE) 711224006Shrs continue; 712224006Shrs 713224006Shrs printf("\n"); 714224006Shrs 715224144Shrs printf("\tCounters\n" 716224144Shrs "\t RA burst counts: %" PRIu16 " (interval: %s)\n" 717224144Shrs "\t RS wait counts: %" PRIu16 "\n", 718224144Shrs ifi_s->ifi_burstcount, 719224144Shrs sec2str(ifi_s->ifi_burstinterval, ssbuf), 720224144Shrs ifi_s->ifi_rs_waitcount); 721224144Shrs 722224144Shrs printf("\tOutputs\n" 723224144Shrs "\t RA: %" PRIu64 "\n", ifi_s->ifi_raoutput); 724224144Shrs 725224144Shrs printf("\tInputs\n" 726224144Shrs "\t RA: %" PRIu64 " (normal)\n" 727224144Shrs "\t RA: %" PRIu64 " (inconsistent)\n" 728224144Shrs "\t RS: %" PRIu64 "\n", 729224006Shrs ifi_s->ifi_rainput, 730224144Shrs ifi_s->ifi_rainconsistent, 731224006Shrs ifi_s->ifi_rsinput); 732224006Shrs 733224006Shrs printf("\n"); 734224006Shrs 735224144Shrs#if 0 /* Not implemented yet */ 736224006Shrs printf("\tReceived RAs:\n"); 737224144Shrs#endif 738224006Shrs } 739224006Shrs 740224006Shrs return (0); 741224006Shrs} 742224006Shrs 743224006Shrsstatic int 744224006Shrsaction_show_rtinfo(struct rtinfo *rti) 745224006Shrs{ 746224006Shrs char ntopbuf[INET6_ADDRSTRLEN]; 747224006Shrs char ssbuf[SSBUFLEN]; 748224006Shrs 749224006Shrs printf("\t %s/%d (pref: %s, ltime: %s)\n", 750224006Shrs inet_ntop(AF_INET6, &rti->rti_prefix, 751224006Shrs ntopbuf, sizeof(ntopbuf)), 752224006Shrs rti->rti_prefixlen, 753224006Shrs rtpref_str[0xff & (rti->rti_rtpref >> 3)], 754224006Shrs (rti->rti_ltime == ND6_INFINITE_LIFETIME) ? 755224006Shrs "infinity" : sec2str(rti->rti_ltime, ssbuf)); 756224006Shrs 757224006Shrs return (0); 758224006Shrs} 759224006Shrs 760224006Shrsstatic int 761224006Shrsaction_show_prefix(struct prefix *pfx) 762224006Shrs{ 763224006Shrs char ntopbuf[INET6_ADDRSTRLEN]; 764224006Shrs char ssbuf[SSBUFLEN]; 765253970Shrs struct timespec now; 766224006Shrs 767253970Shrs clock_gettime(CLOCK_MONOTONIC_FAST, &now); 768224006Shrs printf("\t %s/%d", inet_ntop(AF_INET6, &pfx->pfx_prefix, 769224006Shrs ntopbuf, sizeof(ntopbuf)), pfx->pfx_prefixlen); 770224006Shrs 771224006Shrs printf(" ("); 772224006Shrs switch (pfx->pfx_origin) { 773224006Shrs case PREFIX_FROM_KERNEL: 774224006Shrs printf("KERNEL"); 775224006Shrs break; 776224006Shrs case PREFIX_FROM_CONFIG: 777224006Shrs printf("CONFIG"); 778224006Shrs break; 779224006Shrs case PREFIX_FROM_DYNAMIC: 780224006Shrs printf("DYNAMIC"); 781224006Shrs break; 782224006Shrs } 783224006Shrs 784224006Shrs printf(","); 785224006Shrs 786224006Shrs printf(" vltime=%s", 787224006Shrs (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME) ? 788224006Shrs "infinity" : sec2str(pfx->pfx_validlifetime, ssbuf)); 789224006Shrs 790224006Shrs if (pfx->pfx_vltimeexpire > 0) 791224006Shrs printf("(expire: %s)", 792224006Shrs ((long)pfx->pfx_vltimeexpire > now.tv_sec) ? 793224006Shrs sec2str(pfx->pfx_vltimeexpire - now.tv_sec, ssbuf) : 794224006Shrs "0"); 795224006Shrs 796224006Shrs printf(","); 797224006Shrs 798224006Shrs printf(" pltime=%s", 799224006Shrs (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME) ? 800224006Shrs "infinity" : sec2str(pfx->pfx_preflifetime, ssbuf)); 801224006Shrs 802224006Shrs if (pfx->pfx_pltimeexpire > 0) 803224006Shrs printf("(expire %s)", 804224006Shrs ((long)pfx->pfx_pltimeexpire > now.tv_sec) ? 805224006Shrs sec2str(pfx->pfx_pltimeexpire - now.tv_sec, ssbuf) : 806224006Shrs "0"); 807224006Shrs 808224006Shrs printf(","); 809224006Shrs 810224006Shrs printf(" flags="); 811224006Shrs if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) { 812224006Shrs printf("%s", pfx->pfx_onlinkflg ? "L" : ""); 813224006Shrs printf("%s", pfx->pfx_autoconfflg ? "A" : ""); 814224006Shrs } else 815224006Shrs printf("<none>"); 816224006Shrs 817224006Shrs if (pfx->pfx_timer) { 818253970Shrs struct timespec *rest; 819224006Shrs 820224006Shrs rest = rtadvd_timer_rest(pfx->pfx_timer); 821224006Shrs if (rest) { /* XXX: what if not? */ 822224006Shrs printf(" expire=%s", sec2str(rest->tv_sec, ssbuf)); 823224006Shrs } 824224006Shrs } 825224006Shrs 826224006Shrs printf(")\n"); 827224006Shrs 828224006Shrs return (0); 829224006Shrs} 830224006Shrs 831224006Shrsstatic int 832224006Shrsaction_show_rdnss(void *msg) 833224006Shrs{ 834224006Shrs struct rdnss *rdn; 835224006Shrs struct rdnss_addr *rda; 836224144Shrs uint16_t *rdn_cnt; 837224144Shrs uint16_t *rda_cnt; 838224006Shrs int i; 839224006Shrs int j; 840224006Shrs char *p; 841224144Shrs uint32_t ltime; 842224006Shrs char ntopbuf[INET6_ADDRSTRLEN]; 843224006Shrs char ssbuf[SSBUFLEN]; 844224006Shrs 845224006Shrs p = msg; 846224144Shrs rdn_cnt = (uint16_t *)p; 847224006Shrs p += sizeof(*rdn_cnt); 848224006Shrs 849224006Shrs if (*rdn_cnt > 0) { 850224006Shrs for (i = 0; i < *rdn_cnt; i++) { 851224006Shrs rdn = (struct rdnss *)p; 852224006Shrs ltime = rdn->rd_ltime; 853224006Shrs p += sizeof(*rdn); 854224006Shrs 855224144Shrs rda_cnt = (uint16_t *)p; 856224006Shrs p += sizeof(*rda_cnt); 857224006Shrs if (*rda_cnt > 0) 858224006Shrs for (j = 0; j < *rda_cnt; j++) { 859224006Shrs rda = (struct rdnss_addr *)p; 860224006Shrs printf("\t %s (ltime=%s)\n", 861224006Shrs inet_ntop(AF_INET6, 862224006Shrs &rda->ra_dns, 863224006Shrs ntopbuf, 864224006Shrs sizeof(ntopbuf)), 865224006Shrs sec2str(ltime, ssbuf)); 866224006Shrs p += sizeof(*rda); 867224006Shrs } 868224006Shrs } 869224006Shrs } 870224006Shrs 871224006Shrs return (0); 872224006Shrs} 873224006Shrs 874224006Shrsstatic int 875224006Shrsaction_show_dnssl(void *msg) 876224006Shrs{ 877224006Shrs struct dnssl *dns; 878224006Shrs struct dnssl_addr *dna; 879224144Shrs uint16_t *dns_cnt; 880224144Shrs uint16_t *dna_cnt; 881224006Shrs int i; 882224006Shrs int j; 883224006Shrs char *p; 884224144Shrs uint32_t ltime; 885224006Shrs char hbuf[NI_MAXHOST]; 886224006Shrs char ssbuf[SSBUFLEN]; 887224006Shrs 888224006Shrs p = msg; 889224144Shrs dns_cnt = (uint16_t *)p; 890224006Shrs p += sizeof(*dns_cnt); 891224006Shrs 892224006Shrs if (*dns_cnt > 0) { 893224006Shrs for (i = 0; i < *dns_cnt; i++) { 894224006Shrs dns = (struct dnssl *)p; 895224006Shrs ltime = dns->dn_ltime; 896224006Shrs p += sizeof(*dns); 897224006Shrs 898224144Shrs dna_cnt = (uint16_t *)p; 899224006Shrs p += sizeof(*dna_cnt); 900224006Shrs if (*dna_cnt > 0) 901224006Shrs for (j = 0; j < *dna_cnt; j++) { 902224006Shrs dna = (struct dnssl_addr *)p; 903224006Shrs dname_labeldec(hbuf, sizeof(hbuf), 904224006Shrs dna->da_dom); 905224006Shrs printf("\t %s (ltime=%s)\n", 906224006Shrs hbuf, sec2str(ltime, ssbuf)); 907224006Shrs p += sizeof(*dna); 908224006Shrs } 909224006Shrs } 910224006Shrs } 911224006Shrs 912224006Shrs return (0); 913224006Shrs} 914224006Shrs 915224006Shrs/* Decode domain name label encoding in RFC 1035 Section 3.1 */ 916224006Shrsstatic size_t 917224006Shrsdname_labeldec(char *dst, size_t dlen, const char *src) 918224006Shrs{ 919224006Shrs size_t len; 920224006Shrs const char *src_origin; 921224006Shrs const char *src_last; 922224006Shrs const char *dst_origin; 923224006Shrs 924224006Shrs src_origin = src; 925224006Shrs src_last = strchr(src, '\0'); 926224006Shrs dst_origin = dst; 927224006Shrs memset(dst, '\0', dlen); 928224006Shrs while (src && (len = (uint8_t)(*src++) & 0x3f) && 929224006Shrs (src + len) <= src_last) { 930224006Shrs if (dst != dst_origin) 931224006Shrs *dst++ = '.'; 932224006Shrs mysyslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len); 933224006Shrs memcpy(dst, src, len); 934224006Shrs src += len; 935224006Shrs dst += len; 936224006Shrs } 937224006Shrs *dst = '\0'; 938224006Shrs 939224006Shrs return (src - src_origin); 940224006Shrs} 941