2 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: stable/10/usr.sbin/rtadvctl/rtadvctl.c 253970 2013-08-05 20:13:02Z hrs $
30 #include <sys/queue.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
37 #include <net/if_dl.h>
38 #include <net/if_types.h>
39 #include <net/if_var.h>
40 #include <net/ethernet.h>
41 #include <netinet/in.h>
42 #include <netinet/ip6.h>
43 #include <netinet/icmp6.h>
44 #include <netinet6/in6_var.h>
45 #include <netinet6/nd6.h>
46 #include <arpa/inet.h>
61 #include "pathnames.h"
64 #include "timer_subr.h"
67 #include "control_client.h"
69 #define RA_IFSTATUS_INACTIVE 0
70 #define RA_IFSTATUS_RA_RECV 1
71 #define RA_IFSTATUS_RA_SEND 2
73 static int vflag
= LOG_ERR
;
75 static void usage(void);
77 static int action_propset(char *);
78 static int action_propget(char *, struct ctrl_msg_pl
*);
79 static int action_plgeneric(int, char *, char *);
81 static int action_enable(int, char **);
82 static int action_disable(int, char **);
83 static int action_reload(int, char **);
84 static int action_echo(int, char **);
85 static int action_version(int, char **);
86 static int action_shutdown(int, char **);
88 static int action_show(int, char **);
89 static int action_show_prefix(struct prefix
*);
90 static int action_show_rtinfo(struct rtinfo
*);
91 static int action_show_rdnss(void *);
92 static int action_show_dnssl(void *);
94 static int csock_client_open(struct sockinfo
*);
95 static size_t dname_labeldec(char *, size_t, const char *);
96 static void mysyslog(int, const char *, ...);
98 static const char *rtpref_str
[] = {
105 static struct dispatch_table
{
107 int (*dt_act
)(int, char **);
109 { "show", action_show
},
110 { "reload", action_reload
},
111 { "shutdown", action_shutdown
},
112 { "enable", action_enable
},
113 { "disable", action_disable
},
115 { "echo", action_echo
},
116 { "version", action_version
},
120 static char errmsgbuf
[1024];
121 static char *errmsg
= NULL
;
124 mysyslog(int priority
, const char * restrict fmt
, ...)
128 if (vflag
>= priority
) {
130 vfprintf(stderr
, fmt
, ap
);
131 fprintf(stderr
, "\n");
141 for (i
= 0; (size_t)i
< sizeof(dtable
)/sizeof(dtable
[0]); i
++) {
142 if (dtable
[i
].dt_comm
== NULL
)
144 printf("%s\n", dtable
[i
].dt_comm
);
151 main(int argc
, char *argv
[])
155 int (*action
)(int, char **) = NULL
;
158 while ((ch
= getopt(argc
, argv
, "Dv")) != -1) {
176 for (i
= 0; (size_t)i
< sizeof(dtable
)/sizeof(dtable
[0]); i
++) {
177 if (dtable
[i
].dt_comm
== NULL
||
178 strcmp(dtable
[i
].dt_comm
, argv
[0]) == 0) {
179 action
= dtable
[i
].dt_act
;
187 error
= (dtable
[i
].dt_act
)(--argc
, ++argv
);
189 fprintf(stderr
, "%s failed", dtable
[i
].dt_comm
);
191 fprintf(stderr
, ": %s", errmsg
);
192 fprintf(stderr
, ".\n");
199 csock_client_open(struct sockinfo
*s
)
201 struct sockaddr_un sun
;
203 if ((s
->si_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) == -1)
204 err(1, "cannot open control socket.");
206 memset(&sun
, 0, sizeof(sun
));
207 sun
.sun_family
= AF_UNIX
;
208 sun
.sun_len
= sizeof(sun
);
209 strlcpy(sun
.sun_path
, s
->si_name
, sizeof(sun
.sun_path
));
211 if (connect(s
->si_fd
, (struct sockaddr
*)&sun
, sizeof(sun
)) == -1)
212 err(1, "connect: %s", s
->si_name
);
215 "<%s> connected to %s", __func__
, sun
.sun_path
);
221 action_plgeneric(int action
, char *plstr
, char *buf
)
223 struct ctrl_msg_hdr
*cm
;
224 struct ctrl_msg_pl cp
;
231 csock_client_open(s
);
233 cm
= (struct ctrl_msg_hdr
*)buf
;
234 msg
= (char *)buf
+ sizeof(*cm
);
236 cm
->cm_version
= CM_VERSION
;
237 cm
->cm_type
= action
;
238 cm
->cm_len
= sizeof(*cm
);
241 memset(&cp
, 0, sizeof(cp
));
242 p
= strchr(plstr
, ':');
243 q
= strchr(plstr
, '=');
244 if (p
!= NULL
&& q
!= NULL
&& p
> q
)
247 if (p
== NULL
) { /* No : */
250 } else if (p
== plstr
) { /* empty */
252 cp
.cp_key
= plstr
+ 1;
255 cp
.cp_ifname
= plstr
;
264 cm
->cm_len
+= cm_pl2bin(msg
, &cp
);
266 mysyslog(LOG_DEBUG
, "<%s> key=%s, val_len=%d, ifname=%s",
267 __func__
,cp
.cp_key
, cp
.cp_val_len
, cp
.cp_ifname
);
270 return (cm_handler_client(s
->si_fd
, CM_STATE_MSG_DISPATCH
, buf
));
274 action_propget(char *argv
, struct ctrl_msg_pl
*cp
)
277 struct ctrl_msg_hdr
*cm
;
278 char buf
[CM_MSG_MAXLEN
];
281 memset(cp
, 0, sizeof(*cp
));
282 cm
= (struct ctrl_msg_hdr
*)buf
;
283 msg
= (char *)buf
+ sizeof(*cm
);
285 error
= action_plgeneric(CM_TYPE_REQ_GET_PROP
, argv
, buf
);
286 if (error
|| cm
->cm_len
<= sizeof(*cm
))
290 mysyslog(LOG_DEBUG
, "<%s> type=%d, len=%d",
291 __func__
, cm
->cm_type
, cm
->cm_len
);
292 mysyslog(LOG_DEBUG
, "<%s> key=%s, val_len=%d, ifname=%s",
293 __func__
,cp
->cp_key
, cp
->cp_val_len
, cp
->cp_ifname
);
299 action_propset(char *argv
)
301 char buf
[CM_MSG_MAXLEN
];
303 return (action_plgeneric(CM_TYPE_REQ_SET_PROP
, argv
, buf
));
307 action_disable(int argc
, char **argv
)
310 char argv_disable
[IFNAMSIZ
+ sizeof(":disable=")];
318 for (i
= 0; i
< argc
; i
++) {
319 sprintf(argv_disable
, "%s:disable=", argv
[i
]);
320 action_argv
= argv_disable
;
321 error
+= action_propset(action_argv
);
328 action_enable(int argc
, char **argv
)
331 char argv_enable
[IFNAMSIZ
+ sizeof(":enable=")];
339 for (i
= 0; i
< argc
; i
++) {
340 sprintf(argv_enable
, "%s:enable=", argv
[i
]);
341 action_argv
= argv_enable
;
342 error
+= action_propset(action_argv
);
349 action_reload(int argc
, char **argv
)
352 char argv_reload
[IFNAMSIZ
+ sizeof(":reload=")];
357 action_argv
= strdup(":reload=");
358 return (action_propset(action_argv
));
362 for (i
= 0; i
< argc
; i
++) {
363 sprintf(argv_reload
, "%s:reload=", argv
[i
]);
364 action_argv
= argv_reload
;
365 error
+= action_propset(action_argv
);
372 action_echo(int argc __unused
, char **argv __unused
)
376 action_argv
= strdup("echo");
377 return (action_propset(action_argv
));
381 action_shutdown(int argc __unused
, char **argv __unused
)
385 action_argv
= strdup("shutdown");
386 return (action_propset(action_argv
));
391 action_version(int argc __unused
, char **argv __unused
)
394 struct ctrl_msg_pl cp
;
397 action_argv
= strdup(":version=");
398 error
= action_propget(action_argv
, &cp
);
402 printf("version=%s\n", cp
.cp_val
);
407 action_show(int argc
, char **argv
)
410 char argv_ifilist
[sizeof(":ifilist=")] = ":ifilist=";
411 char argv_ifi
[IFNAMSIZ
+ sizeof(":ifi=")];
412 char argv_rai
[IFNAMSIZ
+ sizeof(":rai=")];
413 char argv_rti
[IFNAMSIZ
+ sizeof(":rti=")];
414 char argv_pfx
[IFNAMSIZ
+ sizeof(":pfx=")];
415 char argv_ifi_ra_timer
[IFNAMSIZ
+ sizeof(":ifi_ra_timer=")];
416 char argv_rdnss
[IFNAMSIZ
+ sizeof(":rdnss=")];
417 char argv_dnssl
[IFNAMSIZ
+ sizeof(":dnssl=")];
418 char ssbuf
[SSBUFLEN
];
420 struct timespec now
, ts0
, ts
;
421 struct ctrl_msg_pl cp
;
423 TAILQ_HEAD(, ifinfo
) ifl
= TAILQ_HEAD_INITIALIZER(ifl
);
431 action_argv
= argv_ifilist
;
432 error
= action_propget(action_argv
, &cp
);
437 endp
= p
+ cp
.cp_val_len
;
439 ifi
= malloc(sizeof(*ifi
));
442 memset(ifi
, 0, sizeof(*ifi
));
444 strcpy(ifi
->ifi_ifname
, p
);
445 ifi
->ifi_ifindex
= if_nametoindex(ifi
->ifi_ifname
);
446 TAILQ_INSERT_TAIL(&ifl
, ifi
, ifi_next
);
447 p
+= strlen(ifi
->ifi_ifname
) + 1;
450 for (i
= 0; i
< argc
; i
++) {
451 ifi
= malloc(sizeof(*ifi
));
454 memset(ifi
, 0, sizeof(*ifi
));
456 strcpy(ifi
->ifi_ifname
, argv
[i
]);
457 ifi
->ifi_ifindex
= if_nametoindex(ifi
->ifi_ifname
);
458 if (ifi
->ifi_ifindex
== 0) {
459 sprintf(errmsgbuf
, "invalid interface %s",
465 TAILQ_INSERT_TAIL(&ifl
, ifi
, ifi_next
);
469 clock_gettime(CLOCK_REALTIME_FAST
, &now
);
470 clock_gettime(CLOCK_MONOTONIC_FAST
, &ts
);
471 TS_SUB(&now
, &ts
, &ts0
);
473 TAILQ_FOREACH(ifi
, &ifl
, ifi_next
) {
474 struct ifinfo
*ifi_s
;
475 struct rtadvd_timer
*rat
;
482 sprintf(argv_ifi
, "%s:ifi=", ifi
->ifi_ifname
);
483 action_argv
= argv_ifi
;
484 error
= action_propget(action_argv
, &cp
);
487 ifi_s
= (struct ifinfo
*)cp
.cp_val
;
489 if (!(ifi_s
->ifi_persist
) && vflag
< LOG_NOTICE
)
492 printf("%s: flags=<", ifi
->ifi_ifname
);
495 if (ifi_s
->ifi_ifindex
== 0)
496 c
+= printf("NONEXISTENT");
498 c
+= printf("%s", (ifi_s
->ifi_flags
& IFF_UP
) ?
500 switch (ifi_s
->ifi_state
) {
501 case IFI_STATE_CONFIGURED
:
502 c
+= printf("%s%s", (c
) ? "," : "", "CONFIGURED");
504 case IFI_STATE_TRANSITIVE
:
505 c
+= printf("%s%s", (c
) ? "," : "", "TRANSITIVE");
508 if (ifi_s
->ifi_persist
)
509 c
+= printf("%s%s", (c
) ? "," : "", "PERSIST");
512 ra_ifstatus
= RA_IFSTATUS_INACTIVE
;
513 if ((ifi_s
->ifi_flags
& IFF_UP
) &&
514 ((ifi_s
->ifi_state
== IFI_STATE_CONFIGURED
) ||
515 (ifi_s
->ifi_state
== IFI_STATE_TRANSITIVE
))) {
517 * RA_RECV: ND6_IFF_ACCEPT_RTADV
518 * RA_SEND: ip6.forwarding
520 if (ifi_s
->ifi_nd_flags
& ND6_IFF_ACCEPT_RTADV
)
521 ra_ifstatus
= RA_IFSTATUS_RA_RECV
;
522 else if (getinet6sysctl(IPV6CTL_FORWARDING
))
523 ra_ifstatus
= RA_IFSTATUS_RA_SEND
;
525 ra_ifstatus
= RA_IFSTATUS_INACTIVE
;
530 if (ra_ifstatus
== RA_IFSTATUS_INACTIVE
)
531 printf("%s%s", (c
) ? "," : "", "INACTIVE");
532 else if (ra_ifstatus
== RA_IFSTATUS_RA_RECV
)
533 printf("%s%s", (c
) ? "," : "", "RA_RECV");
534 else if (ra_ifstatus
== RA_IFSTATUS_RA_SEND
)
535 printf("%s%s", (c
) ? "," : "", "RA_SEND");
538 switch (ifi_s
->ifi_state
) {
539 case IFI_STATE_CONFIGURED
:
540 case IFI_STATE_TRANSITIVE
:
547 printf("mtu %d\n", ifi_s
->ifi_phymtu
);
549 sprintf(argv_rai
, "%s:rai=", ifi
->ifi_ifname
);
550 action_argv
= argv_rai
;
552 error
= action_propget(action_argv
, &cp
);
556 rai
= (struct rainfo
*)cp
.cp_val
;
558 printf("\tDefaultLifetime: %s",
559 sec2str(rai
->rai_lifetime
, ssbuf
));
560 if (ra_ifstatus
!= RA_IFSTATUS_RA_SEND
&&
561 rai
->rai_lifetime
== 0)
562 printf(" (RAs will be sent with zero lifetime)");
566 printf("\tMinAdvInterval/MaxAdvInterval: ");
567 printf("%s/", sec2str(rai
->rai_mininterval
, ssbuf
));
568 printf("%s\n", sec2str(rai
->rai_maxinterval
, ssbuf
));
569 if (rai
->rai_linkmtu
)
570 printf("\tAdvLinkMTU: %d", rai
->rai_linkmtu
);
572 printf("\tAdvLinkMTU: <none>");
577 if (rai
->rai_managedflg
|| rai
->rai_otherflg
) {
578 printf("%s", rai
->rai_managedflg
? "M" : "");
579 printf("%s", rai
->rai_otherflg
? "O" : "");
585 printf("Preference: %s\n",
586 rtpref_str
[(rai
->rai_rtpref
>> 3) & 0xff]);
588 printf("\tReachableTime: %s, ",
589 sec2str(rai
->rai_reachabletime
, ssbuf
));
590 printf("RetransTimer: %s, "
592 sec2str(rai
->rai_retranstimer
, ssbuf
),
594 printf("\tAdvIfPrefixes: %s\n",
595 rai
->rai_advifprefix
? "yes" : "no");
599 if (ifi_s
->ifi_ra_timer
!= NULL
) {
600 sprintf(argv_ifi_ra_timer
, "%s:ifi_ra_timer=",
602 action_argv
= argv_ifi_ra_timer
;
604 error
= action_propget(action_argv
, &cp
);
608 rat
= (struct rtadvd_timer
*)cp
.cp_val
;
610 printf("\tNext RA send: ");
614 ts
.tv_sec
= rat
->rat_tm
.tv_sec
+ ts0
.tv_sec
;
615 printf("%s", ctime(&ts
.tv_sec
));
617 printf("\tLast RA send: ");
618 if (ifi_s
->ifi_ra_lastsent
.tv_sec
== 0)
621 ts
.tv_sec
= ifi_s
->ifi_ra_lastsent
.tv_sec
+ ts0
.tv_sec
;
622 printf("%s", ctime(&ts
.tv_sec
));
624 if (rai
->rai_clockskew
)
625 printf("\tClock skew: %" PRIu16
"sec\n",
628 if (vflag
< LOG_WARNING
)
631 /* route information */
632 sprintf(argv_rti
, "%s:rti=", ifi
->ifi_ifname
);
633 action_argv
= argv_rti
;
634 error
= action_propget(action_argv
, &cp
);
638 rti
= (struct rtinfo
*)cp
.cp_val
;
639 len
= cp
.cp_val_len
/ sizeof(*rti
);
641 printf("\tRoute Info:\n");
643 for (i
= 0; i
< len
; i
++)
644 action_show_rtinfo(&rti
[i
]);
647 /* prefix information */
648 sprintf(argv_pfx
, "%s:pfx=", ifi
->ifi_ifname
);
649 action_argv
= argv_pfx
;
651 error
= action_propget(action_argv
, &cp
);
655 pfx
= (struct prefix
*)cp
.cp_val
;
656 len
= cp
.cp_val_len
/ sizeof(*pfx
);
659 printf("\tPrefixes (%d):\n", len
);
661 for (i
= 0; i
< len
; i
++)
662 action_show_prefix(&pfx
[i
]);
665 /* RDNSS information */
666 sprintf(argv_rdnss
, "%s:rdnss=", ifi
->ifi_ifname
);
667 action_argv
= argv_rdnss
;
669 error
= action_propget(action_argv
, &cp
);
673 len
= *((uint16_t *)cp
.cp_val
);
676 printf("\tRDNSS entries:\n");
677 action_show_rdnss(cp
.cp_val
);
680 /* DNSSL information */
681 sprintf(argv_dnssl
, "%s:dnssl=", ifi
->ifi_ifname
);
682 action_argv
= argv_dnssl
;
684 error
= action_propget(action_argv
, &cp
);
688 len
= *((uint16_t *)cp
.cp_val
);
691 printf("\tDNSSL entries:\n");
692 action_show_dnssl(cp
.cp_val
);
695 if (vflag
< LOG_NOTICE
)
700 printf("\tCounters\n"
701 "\t RA burst counts: %" PRIu16
" (interval: %s)\n"
702 "\t RS wait counts: %" PRIu16
"\n",
703 ifi_s
->ifi_burstcount
,
704 sec2str(ifi_s
->ifi_burstinterval
, ssbuf
),
705 ifi_s
->ifi_rs_waitcount
);
708 "\t RA: %" PRIu64
"\n", ifi_s
->ifi_raoutput
);
711 "\t RA: %" PRIu64
" (normal)\n"
712 "\t RA: %" PRIu64
" (inconsistent)\n"
713 "\t RS: %" PRIu64
"\n",
715 ifi_s
->ifi_rainconsistent
,
720 #if 0 /* Not implemented yet */
721 printf("\tReceived RAs:\n");
729 action_show_rtinfo(struct rtinfo
*rti
)
731 char ntopbuf
[INET6_ADDRSTRLEN
];
732 char ssbuf
[SSBUFLEN
];
734 printf("\t %s/%d (pref: %s, ltime: %s)\n",
735 inet_ntop(AF_INET6
, &rti
->rti_prefix
,
736 ntopbuf
, sizeof(ntopbuf
)),
738 rtpref_str
[0xff & (rti
->rti_rtpref
>> 3)],
739 (rti
->rti_ltime
== ND6_INFINITE_LIFETIME
) ?
740 "infinity" : sec2str(rti
->rti_ltime
, ssbuf
));
746 action_show_prefix(struct prefix
*pfx
)
748 char ntopbuf
[INET6_ADDRSTRLEN
];
749 char ssbuf
[SSBUFLEN
];
752 clock_gettime(CLOCK_MONOTONIC_FAST
, &now
);
753 printf("\t %s/%d", inet_ntop(AF_INET6
, &pfx
->pfx_prefix
,
754 ntopbuf
, sizeof(ntopbuf
)), pfx
->pfx_prefixlen
);
757 switch (pfx
->pfx_origin
) {
758 case PREFIX_FROM_KERNEL
:
761 case PREFIX_FROM_CONFIG
:
764 case PREFIX_FROM_DYNAMIC
:
772 (pfx
->pfx_validlifetime
== ND6_INFINITE_LIFETIME
) ?
773 "infinity" : sec2str(pfx
->pfx_validlifetime
, ssbuf
));
775 if (pfx
->pfx_vltimeexpire
> 0)
776 printf("(expire: %s)",
777 ((long)pfx
->pfx_vltimeexpire
> now
.tv_sec
) ?
778 sec2str(pfx
->pfx_vltimeexpire
- now
.tv_sec
, ssbuf
) :
784 (pfx
->pfx_preflifetime
== ND6_INFINITE_LIFETIME
) ?
785 "infinity" : sec2str(pfx
->pfx_preflifetime
, ssbuf
));
787 if (pfx
->pfx_pltimeexpire
> 0)
788 printf("(expire %s)",
789 ((long)pfx
->pfx_pltimeexpire
> now
.tv_sec
) ?
790 sec2str(pfx
->pfx_pltimeexpire
- now
.tv_sec
, ssbuf
) :
796 if (pfx
->pfx_onlinkflg
|| pfx
->pfx_autoconfflg
) {
797 printf("%s", pfx
->pfx_onlinkflg
? "L" : "");
798 printf("%s", pfx
->pfx_autoconfflg
? "A" : "");
802 if (pfx
->pfx_timer
) {
803 struct timespec
*rest
;
805 rest
= rtadvd_timer_rest(pfx
->pfx_timer
);
806 if (rest
) { /* XXX: what if not? */
807 printf(" expire=%s", sec2str(rest
->tv_sec
, ssbuf
));
817 action_show_rdnss(void *msg
)
820 struct rdnss_addr
*rda
;
827 char ntopbuf
[INET6_ADDRSTRLEN
];
828 char ssbuf
[SSBUFLEN
];
831 rdn_cnt
= (uint16_t *)p
;
832 p
+= sizeof(*rdn_cnt
);
835 for (i
= 0; i
< *rdn_cnt
; i
++) {
836 rdn
= (struct rdnss
*)p
;
837 ltime
= rdn
->rd_ltime
;
840 rda_cnt
= (uint16_t *)p
;
841 p
+= sizeof(*rda_cnt
);
843 for (j
= 0; j
< *rda_cnt
; j
++) {
844 rda
= (struct rdnss_addr
*)p
;
845 printf("\t %s (ltime=%s)\n",
850 sec2str(ltime
, ssbuf
));
860 action_show_dnssl(void *msg
)
863 struct dnssl_addr
*dna
;
870 char hbuf
[NI_MAXHOST
];
871 char ssbuf
[SSBUFLEN
];
874 dns_cnt
= (uint16_t *)p
;
875 p
+= sizeof(*dns_cnt
);
878 for (i
= 0; i
< *dns_cnt
; i
++) {
879 dns
= (struct dnssl
*)p
;
880 ltime
= dns
->dn_ltime
;
883 dna_cnt
= (uint16_t *)p
;
884 p
+= sizeof(*dna_cnt
);
886 for (j
= 0; j
< *dna_cnt
; j
++) {
887 dna
= (struct dnssl_addr
*)p
;
888 dname_labeldec(hbuf
, sizeof(hbuf
),
890 printf("\t %s (ltime=%s)\n",
891 hbuf
, sec2str(ltime
, ssbuf
));
900 /* Decode domain name label encoding in RFC 1035 Section 3.1 */
902 dname_labeldec(char *dst
, size_t dlen
, const char *src
)
905 const char *src_origin
;
906 const char *src_last
;
907 const char *dst_origin
;
910 src_last
= strchr(src
, '\0');
912 memset(dst
, '\0', dlen
);
913 while (src
&& (len
= (uint8_t)(*src
++) & 0x3f) &&
914 (src
+ len
) <= src_last
) {
915 if (dst
!= dst_origin
)
917 mysyslog(LOG_DEBUG
, "<%s> labellen = %zd", __func__
, len
);
918 memcpy(dst
, src
, len
);
924 return (src
- src_origin
);