1 /* $KAME: rtsol.c,v 1.27 2003/10/05 00:09:36 itojun Exp $ */
4 * SPDX-License-Identifier: BSD-3-Clause
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Copyright (C) 2011 Hiroki Sato
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the project nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/param.h>
38 #include <sys/capsicum.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
46 #include <net/route.h>
47 #include <net/if_dl.h>
49 #define __BSD_VISIBLE 1 /* IN6ADDR_LINKLOCAL_ALLROUTERS_INIT */
50 #include <netinet/in.h>
52 #include <netinet/ip6.h>
53 #include <netinet6/ip6_var.h>
54 #include <netinet/icmp6.h>
56 #include <arpa/inet.h>
58 #include <capsicum_helpers.h>
72 static char rsid[IFNAMSIZ + 1 + sizeof(DNSINFO_ORIGIN_LABEL) + 1 + NI_MAXHOST];
73 struct ifinfo_head_t ifinfo_head = TAILQ_HEAD_INITIALIZER(ifinfo_head);
75 static void call_script(const char *const *, struct script_msg_head_t *);
76 static size_t dname_labeldec(char *, size_t, const char *);
77 static struct ra_opt *find_raopt(struct rainfo *, int, void *, size_t);
78 static int ra_opt_rdnss_dispatch(struct ifinfo *, struct rainfo *,
79 struct script_msg_head_t *, struct script_msg_head_t *);
80 static char *make_rsid(const char *, const char *, struct rainfo *);
82 #define _ARGS_OTHER otherconf_script, ifi->ifname
83 #define _ARGS_RESADD resolvconf_script, "-a", rsid
84 #define _ARGS_RESDEL resolvconf_script, "-d", rsid
86 #define CALL_SCRIPT(name, sm_head) do { \
87 const char *const sarg[] = { _ARGS_##name, NULL }; \
88 call_script(sarg, sm_head); \
91 #define ELM_MALLOC(p, error_action) do { \
92 p = malloc(sizeof(*p)); \
94 warnmsg(LOG_ERR, __func__, "malloc failed: %s", \
98 memset(p, 0, sizeof(*p)); \
104 struct icmp6_filter filt;
108 if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
109 warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
113 /* Provide info about the receiving interface. */
115 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
117 warnmsg(LOG_ERR, __func__, "setsockopt(IPV6_RECVPKTINFO): %s",
122 /* Include the hop limit from the received header. */
124 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
126 warnmsg(LOG_ERR, __func__, "setsockopt(IPV6_RECVHOPLIMIT): %s",
131 /* Filter out everything except for Router Advertisements. */
132 ICMP6_FILTER_SETBLOCKALL(&filt);
133 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
134 if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
135 sizeof(filt)) == -1) {
136 warnmsg(LOG_ERR, __func__, "setsockopt(ICMP6_FILTER): %s",
141 cap_rights_init(&rights, CAP_EVENT, CAP_RECV);
142 if (caph_rights_limit(sock, &rights) < 0) {
143 warnmsg(LOG_ERR, __func__, "caph_rights_limit(): %s",
157 rtsol_input(int sock)
159 uint8_t cmsg[CMSG_SPACE(sizeof(struct in6_pktinfo)) +
160 CMSG_SPACE(sizeof(int))];
163 struct sockaddr_in6 from;
164 char answer[1500], ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
165 int l, ifindex = 0, *hlimp = NULL;
167 struct in6_pktinfo *pi = NULL;
168 struct ifinfo *ifi = NULL;
169 struct ra_opt *rao = NULL;
170 struct icmp6_hdr *icp;
171 struct nd_router_advert *nd_ra;
175 struct in6_addr *addr;
176 struct nd_opt_hdr *ndo;
177 struct nd_opt_rdnss *rdnss;
178 struct nd_opt_dnssl *dnssl;
180 char nsbuf[INET6_ADDRSTRLEN + 1 + IFNAMSIZ + 1];
181 char dname[NI_MAXHOST];
182 struct timespec lifetime, now;
183 int newent_rai, newent_rao;
185 memset(&hdr, 0, sizeof(hdr));
188 hdr.msg_name = &from;
189 hdr.msg_namelen = sizeof(from);
190 hdr.msg_control = cmsg;
191 hdr.msg_controllen = sizeof(cmsg);
193 iov.iov_base = (caddr_t)answer;
194 iov.iov_len = sizeof(answer);
196 if ((msglen = recvmsg(sock, &hdr, 0)) < 0) {
197 warnmsg(LOG_ERR, __func__, "recvmsg: %s", strerror(errno));
201 /* Extract control message info. */
202 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&hdr); cm != NULL;
203 cm = (struct cmsghdr *)CMSG_NXTHDR(&hdr, cm)) {
204 if (cm->cmsg_level == IPPROTO_IPV6 &&
205 cm->cmsg_type == IPV6_PKTINFO &&
206 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
207 pi = (struct in6_pktinfo *)(void *)(CMSG_DATA(cm));
208 ifindex = pi->ipi6_ifindex;
210 if (cm->cmsg_level == IPPROTO_IPV6 &&
211 cm->cmsg_type == IPV6_HOPLIMIT &&
212 cm->cmsg_len == CMSG_LEN(sizeof(int)))
213 hlimp = (int *)(void *)CMSG_DATA(cm);
217 warnmsg(LOG_ERR, __func__,
218 "failed to get receiving interface");
222 warnmsg(LOG_ERR, __func__,
223 "failed to get receiving hop limit");
227 if ((size_t)msglen < sizeof(struct nd_router_advert)) {
228 warnmsg(LOG_INFO, __func__,
229 "packet size(%zd) is too short", msglen);
233 icp = (struct icmp6_hdr *)iov.iov_base;
234 if (icp->icmp6_type != ND_ROUTER_ADVERT) {
236 * this should not happen because we configured a filter
237 * that only passes RAs on the receiving socket.
239 warnmsg(LOG_ERR, __func__,
240 "invalid icmp type(%d) from %s on %s", icp->icmp6_type,
241 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
243 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
247 if (icp->icmp6_code != 0) {
248 warnmsg(LOG_INFO, __func__,
249 "invalid icmp code(%d) from %s on %s", icp->icmp6_code,
250 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
252 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
257 warnmsg(LOG_INFO, __func__,
258 "invalid RA with hop limit(%d) from %s on %s",
260 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
262 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
266 if (pi && !IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
267 warnmsg(LOG_INFO, __func__,
268 "invalid RA with non link-local source from %s on %s",
269 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
271 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
275 /* xxx: more validation? */
277 if ((ifi = find_ifinfo(pi->ipi6_ifindex)) == NULL) {
278 warnmsg(LOG_DEBUG, __func__,
279 "received RA from %s on an unexpected IF(%s)",
280 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
282 if_indextoname(pi->ipi6_ifindex, ifnamebuf));
286 warnmsg(LOG_DEBUG, __func__,
287 "received RA from %s on %s, state is %d",
288 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, sizeof(ntopbuf)),
289 ifi->ifname, ifi->state);
291 nd_ra = (struct nd_router_advert *)icp;
294 * Process the "O bit."
295 * If the value of OtherConfigFlag changes from FALSE to TRUE, the
296 * host should invoke the stateful autoconfiguration protocol,
297 * requesting information.
298 * [RFC 2462 Section 5.5.3]
300 if (((nd_ra->nd_ra_flags_reserved) & ND_RA_FLAG_OTHER) &&
302 warnmsg(LOG_DEBUG, __func__,
303 "OtherConfigFlag on %s is turned on", ifi->ifname);
304 ifi->otherconfig = 1;
305 CALL_SCRIPT(OTHER, NULL);
307 clock_gettime(CLOCK_MONOTONIC_FAST, &now);
309 rai = find_rainfo(ifi, &from);
311 ELM_MALLOC(rai, exit(1));
312 rai->rai_ifinfo = ifi;
313 TAILQ_INIT(&rai->rai_ra_opt);
314 rai->rai_saddr.sin6_family = AF_INET6;
315 rai->rai_saddr.sin6_len = sizeof(rai->rai_saddr);
316 memcpy(&rai->rai_saddr.sin6_addr, &from.sin6_addr,
317 sizeof(rai->rai_saddr.sin6_addr));
321 #define RA_OPT_NEXT_HDR(x) (struct nd_opt_hdr *)((char *)x + \
322 (((struct nd_opt_hdr *)x)->nd_opt_len * 8))
323 /* Process RA options. */
324 warnmsg(LOG_DEBUG, __func__, "Processing RA");
325 raoptp = (char *)icp + sizeof(struct nd_router_advert);
326 while (raoptp < (char *)icp + msglen) {
327 ndo = (struct nd_opt_hdr *)raoptp;
328 warnmsg(LOG_DEBUG, __func__, "ndo = %p", raoptp);
329 warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_type = %d",
331 warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_len = %d",
334 switch (ndo->nd_opt_type) {
336 rdnss = (struct nd_opt_rdnss *)raoptp;
338 /* Optlen sanity check (Section 5.3.1 in RFC 6106) */
339 if (rdnss->nd_opt_rdnss_len < 3) {
340 warnmsg(LOG_INFO, __func__,
341 "too short RDNSS option"
342 "in RA from %s was ignored.",
343 inet_ntop(AF_INET6, &from.sin6_addr,
344 ntopbuf, sizeof(ntopbuf)));
348 addr = (struct in6_addr *)(void *)(raoptp + sizeof(*rdnss));
349 while ((char *)addr < (char *)RA_OPT_NEXT_HDR(raoptp)) {
350 if (inet_ntop(AF_INET6, addr, ntopbuf,
351 sizeof(ntopbuf)) == NULL) {
352 warnmsg(LOG_INFO, __func__,
353 "an invalid address in RDNSS option"
354 " in RA from %s was ignored.",
355 inet_ntop(AF_INET6, &from.sin6_addr,
356 ntopbuf, sizeof(ntopbuf)));
360 if (IN6_IS_ADDR_LINKLOCAL(addr))
361 /* XXX: % has to be escaped here */
362 l = snprintf(nsbuf, sizeof(nsbuf),
367 l = snprintf(nsbuf, sizeof(nsbuf),
369 if (l < 0 || (size_t)l >= sizeof(nsbuf)) {
370 warnmsg(LOG_ERR, __func__,
371 "address copying error in "
372 "RDNSS option: %d.", l);
376 warnmsg(LOG_DEBUG, __func__, "nsbuf = %s",
380 rao = find_raopt(rai, ndo->nd_opt_type, nsbuf,
383 ELM_MALLOC(rao, break);
384 rao->rao_type = ndo->nd_opt_type;
385 rao->rao_len = strlen(nsbuf);
386 rao->rao_msg = strdup(nsbuf);
387 if (rao->rao_msg == NULL) {
388 warnmsg(LOG_ERR, __func__,
397 /* Set expiration timer */
398 memset(&rao->rao_expire, 0,
399 sizeof(rao->rao_expire));
400 memset(&lifetime, 0, sizeof(lifetime));
402 ntohl(rdnss->nd_opt_rdnss_lifetime);
403 TS_ADD(&now, &lifetime, &rao->rao_expire);
406 TAILQ_INSERT_TAIL(&rai->rai_ra_opt,
412 dnssl = (struct nd_opt_dnssl *)raoptp;
414 /* Optlen sanity check (Section 5.3.1 in RFC 6106) */
415 if (dnssl->nd_opt_dnssl_len < 2) {
416 warnmsg(LOG_INFO, __func__,
417 "too short DNSSL option"
418 "in RA from %s was ignored.",
419 inet_ntop(AF_INET6, &from.sin6_addr,
420 ntopbuf, sizeof(ntopbuf)));
425 * Ensure NUL-termination in DNSSL in case of
428 p = (char *)RA_OPT_NEXT_HDR(raoptp);
431 p = raoptp + sizeof(*dnssl);
432 while (1 < (len = dname_labeldec(dname, sizeof(dname),
434 /* length == 1 means empty string */
435 warnmsg(LOG_DEBUG, __func__, "dname = %s",
439 rao = find_raopt(rai, ndo->nd_opt_type, dname,
442 ELM_MALLOC(rao, break);
443 rao->rao_type = ndo->nd_opt_type;
444 rao->rao_len = strlen(dname);
445 rao->rao_msg = strdup(dname);
446 if (rao->rao_msg == NULL) {
447 warnmsg(LOG_ERR, __func__,
456 /* Set expiration timer */
457 memset(&rao->rao_expire, 0,
458 sizeof(rao->rao_expire));
459 memset(&lifetime, 0, sizeof(lifetime));
461 ntohl(dnssl->nd_opt_dnssl_lifetime);
462 TS_ADD(&now, &lifetime, &rao->rao_expire);
465 TAILQ_INSERT_TAIL(&rai->rai_ra_opt,
471 /* nothing to do for other options */
474 raoptp = (char *)RA_OPT_NEXT_HDR(raoptp);
477 TAILQ_INSERT_TAIL(&ifi->ifi_rainfo, rai, rai_next);
482 switch (ifi->state) {
483 case IFS_IDLE: /* should be ignored */
484 case IFS_DELAY: /* right? */
487 ifi->state = IFS_IDLE;
489 rtsol_timer_update(ifi);
494 static char resstr_ns_prefix[] = "nameserver ";
495 static char resstr_sh_prefix[] = "search ";
496 static char resstr_nl[] = "\n";
497 static char resstr_sp[] = " ";
500 ra_opt_handler(struct ifinfo *ifi)
504 struct script_msg *smp1, *smp2, *smp3;
506 struct script_msg_head_t sm_rdnss_head =
507 TAILQ_HEAD_INITIALIZER(sm_rdnss_head);
508 struct script_msg_head_t sm_dnssl_head =
509 TAILQ_HEAD_INITIALIZER(sm_dnssl_head);
514 dlen = strlen(resstr_sh_prefix) + strlen(resstr_nl);
515 clock_gettime(CLOCK_MONOTONIC_FAST, &now);
518 * All options from multiple RAs with the same or different
519 * source addresses on a single interface will be gathered and
520 * handled, not overridden. [RFC 4861 6.3.4]
522 TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next) {
523 TAILQ_FOREACH(rao, &rai->rai_ra_opt, rao_next) {
524 switch (rao->rao_type) {
526 if (TS_CMP(&now, &rao->rao_expire, >)) {
527 warnmsg(LOG_INFO, __func__,
528 "expired rdnss entry: %s",
529 (char *)rao->rao_msg);
532 ELM_MALLOC(smp1, continue);
533 ELM_MALLOC(smp2, goto free1);
534 ELM_MALLOC(smp3, goto free2);
535 smp1->sm_msg = resstr_ns_prefix;
536 TAILQ_INSERT_TAIL(&sm_rdnss_head, smp1,
538 smp2->sm_msg = rao->rao_msg;
539 TAILQ_INSERT_TAIL(&sm_rdnss_head, smp2,
541 smp3->sm_msg = resstr_nl;
542 TAILQ_INSERT_TAIL(&sm_rdnss_head, smp3,
544 ifi->ifi_rdnss = IFI_DNSOPT_STATE_RECEIVED;
547 if (TS_CMP(&now, &rao->rao_expire, >)) {
548 warnmsg(LOG_INFO, __func__,
549 "expired dnssl entry: %s",
550 (char *)rao->rao_msg);
554 /* Check resolv.conf(5) restrictions. */
556 warnmsg(LOG_INFO, __func__,
557 "dnssl entry exceeding maximum count (%d>6)"
558 ": %s", dcount, (char *)rao->rao_msg);
561 if (256 < dlen + strlen(rao->rao_msg) +
563 warnmsg(LOG_INFO, __func__,
564 "dnssl entry exceeding maximum length "
565 "(>256): %s", (char *)rao->rao_msg);
568 ELM_MALLOC(smp1, continue);
569 ELM_MALLOC(smp2, goto free1);
570 if (TAILQ_EMPTY(&sm_dnssl_head)) {
571 ELM_MALLOC(smp3, goto free2);
572 smp3->sm_msg = resstr_sh_prefix;
573 TAILQ_INSERT_TAIL(&sm_dnssl_head, smp3,
576 smp1->sm_msg = rao->rao_msg;
577 TAILQ_INSERT_TAIL(&sm_dnssl_head, smp1,
579 smp2->sm_msg = resstr_sp;
580 TAILQ_INSERT_TAIL(&sm_dnssl_head, smp2,
582 dlen += strlen(rao->rao_msg) +
584 ifi->ifi_dnssl = IFI_DNSOPT_STATE_RECEIVED;
593 /* Call the script for each information source. */
595 ra_opt_rdnss_dispatch(ifi, rai, &sm_rdnss_head,
598 /* Call the script for each interface. */
600 ra_opt_rdnss_dispatch(ifi, NULL, &sm_rdnss_head,
606 make_rsid(const char *ifname, const char *origin, struct rainfo *rai)
608 char hbuf[NI_MAXHOST];
611 sprintf(rsid, "%s:%s", ifname, origin);
613 if (!IN6_IS_ADDR_LINKLOCAL(&rai->rai_saddr.sin6_addr))
615 if (getnameinfo((struct sockaddr *)&rai->rai_saddr,
616 rai->rai_saddr.sin6_len, hbuf, sizeof(hbuf), NULL, 0,
617 NI_NUMERICHOST) != 0)
619 sprintf(rsid, "%s:%s:[%s]", ifname, origin, hbuf);
621 warnmsg(LOG_DEBUG, __func__, "rsid = [%s]", rsid);
626 ra_opt_rdnss_dispatch(struct ifinfo *ifi, struct rainfo *rai,
627 struct script_msg_head_t *sm_rdnss_head,
628 struct script_msg_head_t *sm_dnssl_head)
630 struct script_msg *smp1;
635 /* Add \n for DNSSL list. */
636 if (!TAILQ_EMPTY(sm_dnssl_head)) {
637 ELM_MALLOC(smp1, goto ra_opt_rdnss_freeit);
638 smp1->sm_msg = resstr_nl;
639 TAILQ_INSERT_TAIL(sm_dnssl_head, smp1, sm_next);
641 TAILQ_CONCAT(sm_rdnss_head, sm_dnssl_head, sm_next);
643 r = make_rsid(ifi->ifname, DNSINFO_ORIGIN_LABEL, uflag ? rai : NULL);
645 warnmsg(LOG_ERR, __func__, "make_rsid() failed. "
646 "Script was not invoked.");
648 goto ra_opt_rdnss_freeit;
650 if (!TAILQ_EMPTY(sm_rdnss_head))
651 CALL_SCRIPT(RESADD, sm_rdnss_head);
652 else if (ifi->ifi_rdnss == IFI_DNSOPT_STATE_RECEIVED ||
653 ifi->ifi_dnssl == IFI_DNSOPT_STATE_RECEIVED) {
654 CALL_SCRIPT(RESDEL, NULL);
655 ifi->ifi_rdnss = IFI_DNSOPT_STATE_NOINFO;
656 ifi->ifi_dnssl = IFI_DNSOPT_STATE_NOINFO;
660 /* Clear script message queue. */
661 if (!TAILQ_EMPTY(sm_rdnss_head)) {
662 while ((smp1 = TAILQ_FIRST(sm_rdnss_head)) != NULL) {
663 TAILQ_REMOVE(sm_rdnss_head, smp1, sm_next);
667 if (!TAILQ_EMPTY(sm_dnssl_head)) {
668 while ((smp1 = TAILQ_FIRST(sm_dnssl_head)) != NULL) {
669 TAILQ_REMOVE(sm_dnssl_head, smp1, sm_next);
676 static struct ra_opt *
677 find_raopt(struct rainfo *rai, int type, void *msg, size_t len)
681 TAILQ_FOREACH(rao, &rai->rai_ra_opt, rao_next) {
682 if (rao->rao_type == type &&
683 rao->rao_len == strlen(msg) &&
684 memcmp(rao->rao_msg, msg, len) == 0)
692 call_script(const char *const argv[], struct script_msg_head_t *sm_head)
694 struct script_msg *smp;
701 wfd = cap_script_run(capscript, argv);
703 warnmsg(LOG_ERR, __func__,
704 "failed to run %s: %s", argv[0], strerror(errno));
708 if (sm_head != NULL) {
709 TAILQ_FOREACH(smp, sm_head, sm_next) {
710 len = strlen(smp->sm_msg);
711 warnmsg(LOG_DEBUG, __func__, "write to child = %s(%zd)",
713 if (write(wfd, smp->sm_msg, len) != len) {
714 warnmsg(LOG_ERR, __func__,
715 "write to child failed: %s",
724 if (cap_script_wait(capscript, &status) != 0)
725 warnmsg(LOG_ERR, __func__, "wait(): %s", strerror(errno));
727 warnmsg(LOG_DEBUG, __func__, "script \"%s\" status %d",
731 /* Decode domain name label encoding in RFC 1035 Section 3.1 */
733 dname_labeldec(char *dst, size_t dlen, const char *src)
736 const char *src_origin;
737 const char *src_last;
738 const char *dst_origin;
741 src_last = strchr(src, '\0');
743 memset(dst, '\0', dlen);
744 while (src && (len = (uint8_t)(*src++) & 0x3f) &&
745 (src + len) <= src_last &&
746 (dst - dst_origin < (ssize_t)dlen)) {
747 if (dst != dst_origin)
749 warnmsg(LOG_DEBUG, __func__, "labellen = %zd", len);
750 memcpy(dst, src, len);
757 * XXX validate that domain name only contains valid characters
758 * for two reasons: 1) correctness, 2) we do not want to pass
759 * possible malicious, unescaped characters like `` to a script
760 * or program that could be exploited that way.
763 return (src - src_origin);