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