xref: /openbsd-src/sbin/iked/util.c (revision ce50f388b9e552c3ab6632184ba22d95c5d64369)
1*ce50f388Syasuoka /*	$OpenBSD: util.c,v 1.45 2024/07/01 14:15:15 yasuoka Exp $	*/
245ae9d61Sreyk 
345ae9d61Sreyk /*
4fcebd35dSreyk  * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
545ae9d61Sreyk  *
645ae9d61Sreyk  * Permission to use, copy, modify, and distribute this software for any
745ae9d61Sreyk  * purpose with or without fee is hereby granted, provided that the above
845ae9d61Sreyk  * copyright notice and this permission notice appear in all copies.
945ae9d61Sreyk  *
1045ae9d61Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1145ae9d61Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1245ae9d61Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1345ae9d61Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1445ae9d61Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1545ae9d61Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1645ae9d61Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1745ae9d61Sreyk  */
1845ae9d61Sreyk 
19f4faee91Sderaadt #include <sys/types.h>
2045ae9d61Sreyk #include <sys/queue.h>
2145ae9d61Sreyk #include <sys/socket.h>
2245ae9d61Sreyk #include <sys/uio.h>
2345ae9d61Sreyk 
2445ae9d61Sreyk #include <netdb.h>
2545ae9d61Sreyk #include <stdio.h>
2645ae9d61Sreyk #include <stdlib.h>
2745ae9d61Sreyk #include <unistd.h>
2845ae9d61Sreyk #include <string.h>
2945ae9d61Sreyk #include <errno.h>
30b9fc9a72Sderaadt #include <limits.h>
3145ae9d61Sreyk #include <fcntl.h>
3245ae9d61Sreyk #include <ctype.h>
3345ae9d61Sreyk #include <event.h>
3445ae9d61Sreyk 
3545ae9d61Sreyk #include "iked.h"
3645ae9d61Sreyk #include "ikev2.h"
3745ae9d61Sreyk 
3845ae9d61Sreyk int
socket_af(struct sockaddr * sa,in_port_t port)3945ae9d61Sreyk socket_af(struct sockaddr *sa, in_port_t port)
4045ae9d61Sreyk {
4145ae9d61Sreyk 	errno = 0;
4245ae9d61Sreyk 	switch (sa->sa_family) {
4345ae9d61Sreyk 	case AF_INET:
4445ae9d61Sreyk 		((struct sockaddr_in *)sa)->sin_port = port;
4545ae9d61Sreyk 		((struct sockaddr_in *)sa)->sin_len =
4645ae9d61Sreyk 		    sizeof(struct sockaddr_in);
4745ae9d61Sreyk 		break;
4845ae9d61Sreyk 	case AF_INET6:
4945ae9d61Sreyk 		((struct sockaddr_in6 *)sa)->sin6_port = port;
5045ae9d61Sreyk 		((struct sockaddr_in6 *)sa)->sin6_len =
5145ae9d61Sreyk 		    sizeof(struct sockaddr_in6);
5245ae9d61Sreyk 		break;
5345ae9d61Sreyk 	default:
5445ae9d61Sreyk 		errno = EPFNOSUPPORT;
5545ae9d61Sreyk 		return (-1);
5645ae9d61Sreyk 	}
5745ae9d61Sreyk 
5845ae9d61Sreyk 	return (0);
5945ae9d61Sreyk }
6045ae9d61Sreyk 
6145ae9d61Sreyk in_port_t
socket_getport(struct sockaddr * sa)6247d6a31cSmarkus socket_getport(struct sockaddr *sa)
6345ae9d61Sreyk {
6447d6a31cSmarkus 	switch (sa->sa_family) {
6545ae9d61Sreyk 	case AF_INET:
6647d6a31cSmarkus 		return (ntohs(((struct sockaddr_in *)sa)->sin_port));
6745ae9d61Sreyk 	case AF_INET6:
6847d6a31cSmarkus 		return (ntohs(((struct sockaddr_in6 *)sa)->sin6_port));
6945ae9d61Sreyk 	default:
7045ae9d61Sreyk 		return (0);
7145ae9d61Sreyk 	}
7245ae9d61Sreyk 
7345ae9d61Sreyk 	/* NOTREACHED */
7445ae9d61Sreyk 	return (0);
7545ae9d61Sreyk }
7645ae9d61Sreyk 
7745ae9d61Sreyk int
socket_setport(struct sockaddr * sa,in_port_t port)78bb108424Smarkus socket_setport(struct sockaddr *sa, in_port_t port)
79bb108424Smarkus {
80bb108424Smarkus 	switch (sa->sa_family) {
81bb108424Smarkus 	case AF_INET:
82bb108424Smarkus 		((struct sockaddr_in *)sa)->sin_port = htons(port);
83bb108424Smarkus 		break;
84bb108424Smarkus 	case AF_INET6:
85bb108424Smarkus 		((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
86bb108424Smarkus 		break;
87bb108424Smarkus 	default:
88bb108424Smarkus 		return (-1);
89bb108424Smarkus 	}
90bb108424Smarkus 	return (0);
91bb108424Smarkus }
92bb108424Smarkus 
93bb108424Smarkus int
socket_getaddr(int s,struct sockaddr_storage * ss)94b4fe66abSmikeb socket_getaddr(int s, struct sockaddr_storage *ss)
95b4fe66abSmikeb {
96f3ef7102Spatrick 	socklen_t sslen = sizeof(*ss);
97b4fe66abSmikeb 
98b4fe66abSmikeb 	return (getsockname(s, (struct sockaddr *)ss, &sslen));
99b4fe66abSmikeb }
100b4fe66abSmikeb 
101b4fe66abSmikeb int
socket_bypass(int s,struct sockaddr * sa)10245ae9d61Sreyk socket_bypass(int s, struct sockaddr *sa)
10345ae9d61Sreyk {
10445ae9d61Sreyk 	int	 v, *a;
10545ae9d61Sreyk 	int	 a4[] = {
10645ae9d61Sreyk 		    IPPROTO_IP,
10745ae9d61Sreyk 		    IP_AUTH_LEVEL,
10845ae9d61Sreyk 		    IP_ESP_TRANS_LEVEL,
10945ae9d61Sreyk 		    IP_ESP_NETWORK_LEVEL,
11045ae9d61Sreyk #ifdef IPV6_IPCOMP_LEVEL
11145ae9d61Sreyk 		    IP_IPCOMP_LEVEL
11245ae9d61Sreyk #endif
11345ae9d61Sreyk 	};
11445ae9d61Sreyk 	int	 a6[] = {
11545ae9d61Sreyk 		    IPPROTO_IPV6,
11645ae9d61Sreyk 		    IPV6_AUTH_LEVEL,
11745ae9d61Sreyk 		    IPV6_ESP_TRANS_LEVEL,
11845ae9d61Sreyk 		    IPV6_ESP_NETWORK_LEVEL,
11945ae9d61Sreyk #ifdef IPV6_IPCOMP_LEVEL
12045ae9d61Sreyk 		    IPV6_IPCOMP_LEVEL
12145ae9d61Sreyk #endif
12245ae9d61Sreyk 	};
12345ae9d61Sreyk 
12445ae9d61Sreyk 	switch (sa->sa_family) {
12545ae9d61Sreyk 	case AF_INET:
12645ae9d61Sreyk 		a = a4;
12745ae9d61Sreyk 		break;
12845ae9d61Sreyk 	case AF_INET6:
12945ae9d61Sreyk 		a = a6;
13045ae9d61Sreyk 		break;
13145ae9d61Sreyk 	default:
13245ae9d61Sreyk 		log_warn("%s: invalid address family", __func__);
13345ae9d61Sreyk 		return (-1);
13445ae9d61Sreyk 	}
13545ae9d61Sreyk 
13645ae9d61Sreyk 	v = IPSEC_LEVEL_BYPASS;
13745ae9d61Sreyk 	if (setsockopt(s, a[0], a[1], &v, sizeof(v)) == -1) {
13845ae9d61Sreyk 		log_warn("%s: AUTH_LEVEL", __func__);
13945ae9d61Sreyk 		return (-1);
14045ae9d61Sreyk 	}
14145ae9d61Sreyk 	if (setsockopt(s, a[0], a[2], &v, sizeof(v)) == -1) {
14245ae9d61Sreyk 		log_warn("%s: ESP_TRANS_LEVEL", __func__);
14345ae9d61Sreyk 		return (-1);
14445ae9d61Sreyk 	}
14545ae9d61Sreyk 	if (setsockopt(s, a[0], a[3], &v, sizeof(v)) == -1) {
14645ae9d61Sreyk 		log_warn("%s: ESP_NETWORK_LEVEL", __func__);
14745ae9d61Sreyk 		return (-1);
14845ae9d61Sreyk 	}
14945ae9d61Sreyk #ifdef IP_IPCOMP_LEVEL
15045ae9d61Sreyk 	if (setsockopt(s, a[0], a[4], &v, sizeof(v)) == -1) {
15145ae9d61Sreyk 		log_warn("%s: IPCOMP_LEVEL", __func__);
15245ae9d61Sreyk 		return (-1);
15345ae9d61Sreyk 	}
15445ae9d61Sreyk #endif
15545ae9d61Sreyk 
15645ae9d61Sreyk 	return (0);
15745ae9d61Sreyk }
15845ae9d61Sreyk 
15945ae9d61Sreyk int
udp_bind(struct sockaddr * sa,in_port_t port)16045ae9d61Sreyk udp_bind(struct sockaddr *sa, in_port_t port)
16145ae9d61Sreyk {
16245ae9d61Sreyk 	int	 s, val;
16345ae9d61Sreyk 
16445ae9d61Sreyk 	if (socket_af(sa, port) == -1) {
16545ae9d61Sreyk 		log_warn("%s: failed to set UDP port", __func__);
16645ae9d61Sreyk 		return (-1);
16745ae9d61Sreyk 	}
16845ae9d61Sreyk 
16952ab28dfSreyk 	if ((s = socket(sa->sa_family,
17052ab28dfSreyk 	    SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP)) == -1) {
17145ae9d61Sreyk 		log_warn("%s: failed to get UDP socket", __func__);
17245ae9d61Sreyk 		return (-1);
17345ae9d61Sreyk 	}
17445ae9d61Sreyk 
17545ae9d61Sreyk 	/* Skip IPsec processing (don't encrypt) for IKE messages */
17645ae9d61Sreyk 	if (socket_bypass(s, sa) == -1) {
17745ae9d61Sreyk 		log_warn("%s: failed to bypass IPsec on IKE socket",
17845ae9d61Sreyk 		    __func__);
17945ae9d61Sreyk 		goto bad;
18045ae9d61Sreyk 	}
18145ae9d61Sreyk 
18245ae9d61Sreyk 	val = 1;
18345ae9d61Sreyk 	if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(int)) == -1) {
18445ae9d61Sreyk 		log_warn("%s: failed to set reuseport", __func__);
18545ae9d61Sreyk 		goto bad;
18645ae9d61Sreyk 	}
18745ae9d61Sreyk 	val = 1;
18845ae9d61Sreyk 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) == -1) {
18945ae9d61Sreyk 		log_warn("%s: failed to set reuseaddr", __func__);
19045ae9d61Sreyk 		goto bad;
19145ae9d61Sreyk 	}
19245ae9d61Sreyk 
19345ae9d61Sreyk 	if (sa->sa_family == AF_INET) {
19445ae9d61Sreyk 		val = 1;
19545ae9d61Sreyk 		if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR,
19645ae9d61Sreyk 		    &val, sizeof(int)) == -1) {
19745ae9d61Sreyk 			log_warn("%s: failed to set IPv4 packet info",
19845ae9d61Sreyk 			    __func__);
19945ae9d61Sreyk 			goto bad;
20045ae9d61Sreyk 		}
20145ae9d61Sreyk 	} else {
20245ae9d61Sreyk 		val = 1;
20345ae9d61Sreyk 		if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
20445ae9d61Sreyk 		    &val, sizeof(int)) == -1) {
20545ae9d61Sreyk 			log_warn("%s: failed to set IPv6 packet info",
20645ae9d61Sreyk 			    __func__);
20745ae9d61Sreyk 			goto bad;
20845ae9d61Sreyk 		}
20945ae9d61Sreyk 	}
21045ae9d61Sreyk 
21145ae9d61Sreyk 	if (bind(s, sa, sa->sa_len) == -1) {
21245ae9d61Sreyk 		log_warn("%s: failed to bind UDP socket", __func__);
21345ae9d61Sreyk 		goto bad;
21445ae9d61Sreyk 	}
21545ae9d61Sreyk 
21645ae9d61Sreyk 	return (s);
21745ae9d61Sreyk  bad:
21845ae9d61Sreyk 	close(s);
21945ae9d61Sreyk 	return (-1);
22045ae9d61Sreyk }
22145ae9d61Sreyk 
22245ae9d61Sreyk int
sockaddr_cmp(struct sockaddr * a,struct sockaddr * b,int prefixlen)22345ae9d61Sreyk sockaddr_cmp(struct sockaddr *a, struct sockaddr *b, int prefixlen)
22445ae9d61Sreyk {
22545ae9d61Sreyk 	struct sockaddr_in	*a4, *b4;
22645ae9d61Sreyk 	struct sockaddr_in6	*a6, *b6;
227d09d3a7dSreyk 	uint32_t		 av[4], bv[4], mv[4];
22845ae9d61Sreyk 
229e2015428Sreyk 	if (a->sa_family == AF_UNSPEC || b->sa_family == AF_UNSPEC)
230e2015428Sreyk 		return (0);
231e2015428Sreyk 	else if (a->sa_family > b->sa_family)
23245ae9d61Sreyk 		return (1);
233e2015428Sreyk 	else if (a->sa_family < b->sa_family)
23445ae9d61Sreyk 		return (-1);
23545ae9d61Sreyk 
236c65faa91Sreyk 	if (prefixlen == -1)
237c65faa91Sreyk 		memset(&mv, 0xff, sizeof(mv));
238c65faa91Sreyk 
23945ae9d61Sreyk 	switch (a->sa_family) {
24045ae9d61Sreyk 	case AF_INET:
24145ae9d61Sreyk 		a4 = (struct sockaddr_in *)a;
24245ae9d61Sreyk 		b4 = (struct sockaddr_in *)b;
24345ae9d61Sreyk 
24445ae9d61Sreyk 		av[0] = a4->sin_addr.s_addr;
24545ae9d61Sreyk 		bv[0] = b4->sin_addr.s_addr;
246c65faa91Sreyk 		if (prefixlen != -1)
24745ae9d61Sreyk 			mv[0] = prefixlen2mask(prefixlen);
24845ae9d61Sreyk 
24945ae9d61Sreyk 		if ((av[0] & mv[0]) > (bv[0] & mv[0]))
25045ae9d61Sreyk 			return (1);
251c65faa91Sreyk 		if ((av[0] & mv[0]) < (bv[0] & mv[0]))
25245ae9d61Sreyk 			return (-1);
25345ae9d61Sreyk 		break;
25445ae9d61Sreyk 	case AF_INET6:
25545ae9d61Sreyk 		a6 = (struct sockaddr_in6 *)a;
25645ae9d61Sreyk 		b6 = (struct sockaddr_in6 *)b;
25745ae9d61Sreyk 
25845ae9d61Sreyk 		memcpy(&av, &a6->sin6_addr.s6_addr, 16);
25945ae9d61Sreyk 		memcpy(&bv, &b6->sin6_addr.s6_addr, 16);
260c65faa91Sreyk 		if (prefixlen != -1)
26145ae9d61Sreyk 			prefixlen2mask6(prefixlen, mv);
26245ae9d61Sreyk 
26345ae9d61Sreyk 		if ((av[3] & mv[3]) > (bv[3] & mv[3]))
26445ae9d61Sreyk 			return (1);
26545ae9d61Sreyk 		if ((av[3] & mv[3]) < (bv[3] & mv[3]))
26645ae9d61Sreyk 			return (-1);
26745ae9d61Sreyk 		if ((av[2] & mv[2]) > (bv[2] & mv[2]))
26845ae9d61Sreyk 			return (1);
26945ae9d61Sreyk 		if ((av[2] & mv[2]) < (bv[2] & mv[2]))
27045ae9d61Sreyk 			return (-1);
27145ae9d61Sreyk 		if ((av[1] & mv[1]) > (bv[1] & mv[1]))
27245ae9d61Sreyk 			return (1);
27345ae9d61Sreyk 		if ((av[1] & mv[1]) < (bv[1] & mv[1]))
27445ae9d61Sreyk 			return (-1);
27545ae9d61Sreyk 		if ((av[0] & mv[0]) > (bv[0] & mv[0]))
27645ae9d61Sreyk 			return (1);
27745ae9d61Sreyk 		if ((av[0] & mv[0]) < (bv[0] & mv[0]))
27845ae9d61Sreyk 			return (-1);
27945ae9d61Sreyk 		break;
28045ae9d61Sreyk 	}
28145ae9d61Sreyk 
28245ae9d61Sreyk 	return (0);
28345ae9d61Sreyk }
28445ae9d61Sreyk 
28545ae9d61Sreyk ssize_t
sendtofrom(int s,void * buf,size_t len,int flags,struct sockaddr * to,socklen_t tolen,struct sockaddr * from,socklen_t fromlen)2865ec2ede8Svgross sendtofrom(int s, void *buf, size_t len, int flags, struct sockaddr *to,
2875ec2ede8Svgross     socklen_t tolen, struct sockaddr *from, socklen_t fromlen)
2885ec2ede8Svgross {
2895ec2ede8Svgross 	struct iovec		 iov;
2905ec2ede8Svgross 	struct msghdr		 msg;
2915ec2ede8Svgross 	struct cmsghdr		*cmsg;
2925ec2ede8Svgross 	struct in6_pktinfo	*pkt6;
2935ec2ede8Svgross 	struct sockaddr_in	*in;
2945ec2ede8Svgross 	struct sockaddr_in6	*in6;
2955ec2ede8Svgross 	union {
2965ec2ede8Svgross 		struct cmsghdr	hdr;
2975ec2ede8Svgross 		char		inbuf[CMSG_SPACE(sizeof(struct in_addr))];
2985ec2ede8Svgross 		char		in6buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
2995ec2ede8Svgross 	} cmsgbuf;
3005ec2ede8Svgross 
3015ec2ede8Svgross 	bzero(&msg, sizeof(msg));
3025ec2ede8Svgross 	bzero(&cmsgbuf, sizeof(cmsgbuf));
3035ec2ede8Svgross 
3045ec2ede8Svgross 	iov.iov_base = buf;
3055ec2ede8Svgross 	iov.iov_len = len;
3065ec2ede8Svgross 	msg.msg_iov = &iov;
3075ec2ede8Svgross 	msg.msg_iovlen = 1;
3085ec2ede8Svgross 	msg.msg_name = to;
3095ec2ede8Svgross 	msg.msg_namelen = tolen;
3105ec2ede8Svgross 	msg.msg_control = &cmsgbuf;
3115ec2ede8Svgross 	msg.msg_controllen = sizeof(cmsgbuf);
3125ec2ede8Svgross 
3135ec2ede8Svgross 	cmsg = CMSG_FIRSTHDR(&msg);
3145ec2ede8Svgross 	switch (to->sa_family) {
3155ec2ede8Svgross 	case AF_INET:
3165ec2ede8Svgross 		msg.msg_controllen = sizeof(cmsgbuf.inbuf);
3175ec2ede8Svgross 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
3185ec2ede8Svgross 		cmsg->cmsg_level = IPPROTO_IP;
3195ec2ede8Svgross 		cmsg->cmsg_type = IP_SENDSRCADDR;
3205ec2ede8Svgross 		in = (struct sockaddr_in *)from;
3215ec2ede8Svgross 		memcpy(CMSG_DATA(cmsg), &in->sin_addr, sizeof(struct in_addr));
3225ec2ede8Svgross 		break;
3235ec2ede8Svgross 	case AF_INET6:
3245ec2ede8Svgross 		msg.msg_controllen = sizeof(cmsgbuf.in6buf);
3255ec2ede8Svgross 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
3265ec2ede8Svgross 		cmsg->cmsg_level = IPPROTO_IPV6;
3275ec2ede8Svgross 		cmsg->cmsg_type = IPV6_PKTINFO;
3285ec2ede8Svgross 		in6 = (struct sockaddr_in6 *)from;
3295ec2ede8Svgross 		pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
3305ec2ede8Svgross 		pkt6->ipi6_addr = in6->sin6_addr;
3315ec2ede8Svgross 		break;
3325ec2ede8Svgross 	}
3335ec2ede8Svgross 
3345ec2ede8Svgross 	return sendmsg(s, &msg, flags);
3355ec2ede8Svgross }
3365ec2ede8Svgross 
3375ec2ede8Svgross ssize_t
recvfromto(int s,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen,struct sockaddr * to,socklen_t * tolen)33845ae9d61Sreyk recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from,
33945ae9d61Sreyk     socklen_t *fromlen, struct sockaddr *to, socklen_t *tolen)
34045ae9d61Sreyk {
34145ae9d61Sreyk 	struct iovec		 iov;
34245ae9d61Sreyk 	struct msghdr		 msg;
34345ae9d61Sreyk 	struct cmsghdr		*cmsg;
34445ae9d61Sreyk 	struct in6_pktinfo	*pkt6;
34545ae9d61Sreyk 	struct sockaddr_in	*in;
34645ae9d61Sreyk 	struct sockaddr_in6	*in6;
34745ae9d61Sreyk 	ssize_t			 ret;
34845ae9d61Sreyk 	union {
34945ae9d61Sreyk 		struct cmsghdr hdr;
35045ae9d61Sreyk 		char	buf[CMSG_SPACE(sizeof(struct sockaddr_storage))];
35145ae9d61Sreyk 	} cmsgbuf;
35245ae9d61Sreyk 
35345ae9d61Sreyk 	bzero(&msg, sizeof(msg));
35445ae9d61Sreyk 	bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf));
35545ae9d61Sreyk 
35645ae9d61Sreyk 	iov.iov_base = buf;
35745ae9d61Sreyk 	iov.iov_len = len;
35845ae9d61Sreyk 	msg.msg_iov = &iov;
35945ae9d61Sreyk 	msg.msg_iovlen = 1;
36045ae9d61Sreyk 	msg.msg_name = from;
36145ae9d61Sreyk 	msg.msg_namelen = *fromlen;
36245ae9d61Sreyk 	msg.msg_control = &cmsgbuf.buf;
36345ae9d61Sreyk 	msg.msg_controllen = sizeof(cmsgbuf.buf);
36445ae9d61Sreyk 
365d1a35d0aSjca 	if ((ret = recvmsg(s, &msg, flags)) == -1)
36645ae9d61Sreyk 		return (-1);
36745ae9d61Sreyk 
36845ae9d61Sreyk 	*fromlen = from->sa_len;
36945ae9d61Sreyk 
37045ae9d61Sreyk 	if (getsockname(s, to, tolen) != 0)
37145ae9d61Sreyk 		*tolen = 0;
37245ae9d61Sreyk 
37345ae9d61Sreyk 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
37445ae9d61Sreyk 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
37545ae9d61Sreyk 		switch (from->sa_family) {
37645ae9d61Sreyk 		case AF_INET:
37745ae9d61Sreyk 			if (cmsg->cmsg_level == IPPROTO_IP &&
37845ae9d61Sreyk 			    cmsg->cmsg_type == IP_RECVDSTADDR) {
37945ae9d61Sreyk 				in = (struct sockaddr_in *)to;
38045ae9d61Sreyk 				in->sin_family = AF_INET;
38145ae9d61Sreyk 				in->sin_len = *tolen = sizeof(*in);
38245ae9d61Sreyk 				memcpy(&in->sin_addr, CMSG_DATA(cmsg),
38345ae9d61Sreyk 				    sizeof(struct in_addr));
38445ae9d61Sreyk 			}
38545ae9d61Sreyk 			break;
38645ae9d61Sreyk 		case AF_INET6:
38745ae9d61Sreyk 			if (cmsg->cmsg_level == IPPROTO_IPV6 &&
38845ae9d61Sreyk 			    cmsg->cmsg_type == IPV6_PKTINFO) {
38945ae9d61Sreyk 				in6 = (struct sockaddr_in6 *)to;
39045ae9d61Sreyk 				in6->sin6_family = AF_INET6;
39145ae9d61Sreyk 				in6->sin6_len = *tolen = sizeof(*in6);
39245ae9d61Sreyk 				pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
39345ae9d61Sreyk 				memcpy(&in6->sin6_addr, &pkt6->ipi6_addr,
39445ae9d61Sreyk 				    sizeof(struct in6_addr));
39545ae9d61Sreyk 				if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr))
39645ae9d61Sreyk 					in6->sin6_scope_id =
39745ae9d61Sreyk 					    pkt6->ipi6_ifindex;
39845ae9d61Sreyk 			}
39945ae9d61Sreyk 			break;
40045ae9d61Sreyk 		}
40145ae9d61Sreyk 	}
40245ae9d61Sreyk 
40345ae9d61Sreyk 	return (ret);
40445ae9d61Sreyk }
40545ae9d61Sreyk 
40645ae9d61Sreyk const char *
print_spi(uint64_t spi,int size)407d09d3a7dSreyk print_spi(uint64_t spi, int size)
40845ae9d61Sreyk {
40945ae9d61Sreyk 	static char		 buf[IKED_CYCLE_BUFFERS][32];
41045ae9d61Sreyk 	static int		 i = 0;
41145ae9d61Sreyk 	char			*ptr;
41245ae9d61Sreyk 
41345ae9d61Sreyk 	ptr = buf[i];
41445ae9d61Sreyk 
41545ae9d61Sreyk 	switch (size) {
41603f6ad09Smarkus 	case 2:
417d09d3a7dSreyk 		snprintf(ptr, 32, "0x%04x", (uint16_t)spi);
41803f6ad09Smarkus 		break;
41945ae9d61Sreyk 	case 4:
420d09d3a7dSreyk 		snprintf(ptr, 32, "0x%08x", (uint32_t)spi);
42145ae9d61Sreyk 		break;
42245ae9d61Sreyk 	case 8:
42345ae9d61Sreyk 		snprintf(ptr, 32, "0x%016llx", spi);
42445ae9d61Sreyk 		break;
42545ae9d61Sreyk 	default:
42645ae9d61Sreyk 		snprintf(ptr, 32, "%llu", spi);
42745ae9d61Sreyk 		break;
42845ae9d61Sreyk 	}
42945ae9d61Sreyk 
43045ae9d61Sreyk 	if (++i >= IKED_CYCLE_BUFFERS)
43145ae9d61Sreyk 		i = 0;
43245ae9d61Sreyk 
43345ae9d61Sreyk 	return (ptr);
43445ae9d61Sreyk }
43545ae9d61Sreyk 
43645ae9d61Sreyk const char *
print_map(unsigned int type,struct iked_constmap * map)437d09d3a7dSreyk print_map(unsigned int type, struct iked_constmap *map)
43845ae9d61Sreyk {
439d09d3a7dSreyk 	unsigned int		 i;
44045ae9d61Sreyk 	static char		 buf[IKED_CYCLE_BUFFERS][32];
44145ae9d61Sreyk 	static int		 idx = 0;
44245ae9d61Sreyk 	const char		*name = NULL;
44345ae9d61Sreyk 
44445ae9d61Sreyk 	if (idx >= IKED_CYCLE_BUFFERS)
44545ae9d61Sreyk 		idx = 0;
44645ae9d61Sreyk 	bzero(buf[idx], sizeof(buf[idx]));
44745ae9d61Sreyk 
44845ae9d61Sreyk 	for (i = 0; map[i].cm_name != NULL; i++) {
44945ae9d61Sreyk 		if (map[i].cm_type == type)
45045ae9d61Sreyk 			name = map[i].cm_name;
45145ae9d61Sreyk 	}
45245ae9d61Sreyk 
45345ae9d61Sreyk 	if (name == NULL)
45445ae9d61Sreyk 		snprintf(buf[idx], sizeof(buf[idx]), "<UNKNOWN:%u>", type);
45545ae9d61Sreyk 	else
45645ae9d61Sreyk 		strlcpy(buf[idx], name, sizeof(buf[idx]));
45745ae9d61Sreyk 
45845ae9d61Sreyk 	return (buf[idx++]);
45945ae9d61Sreyk }
46045ae9d61Sreyk 
46145ae9d61Sreyk void
lc_idtype(char * str)46223e03483Stobhe lc_idtype(char *str)
4639474eae8Sreyk {
46423e03483Stobhe 	for (; *str != '\0' && *str != '/'; str++)
465025f5691Sderaadt 		*str = tolower((unsigned char)*str);
4669474eae8Sreyk }
4679474eae8Sreyk 
4689474eae8Sreyk void
print_hex(const uint8_t * buf,off_t offset,size_t length)469e439be88Stobhe print_hex(const uint8_t *buf, off_t offset, size_t length)
47045ae9d61Sreyk {
471d09d3a7dSreyk 	unsigned int	 i;
47245ae9d61Sreyk 
473871fc12cSreyk 	if (log_getverbose() < 3 || !length)
47445ae9d61Sreyk 		return;
47545ae9d61Sreyk 
47645ae9d61Sreyk 	for (i = 0; i < length; i++) {
47745ae9d61Sreyk 		if (i && (i % 4) == 0) {
47845ae9d61Sreyk 			if ((i % 32) == 0)
47945ae9d61Sreyk 				print_debug("\n");
48045ae9d61Sreyk 			else
48145ae9d61Sreyk 				print_debug(" ");
48245ae9d61Sreyk 		}
48345ae9d61Sreyk 		print_debug("%02x", buf[offset + i]);
48445ae9d61Sreyk 	}
48545ae9d61Sreyk 	print_debug("\n");
48645ae9d61Sreyk }
48745ae9d61Sreyk 
48845ae9d61Sreyk void
print_hexval(const uint8_t * buf,off_t offset,size_t length)489e439be88Stobhe print_hexval(const uint8_t *buf, off_t offset, size_t length)
49045ae9d61Sreyk {
491d09d3a7dSreyk 	unsigned int	 i;
49245ae9d61Sreyk 
493871fc12cSreyk 	if (log_getverbose() < 2 || !length)
49445ae9d61Sreyk 		return;
49545ae9d61Sreyk 
49645ae9d61Sreyk 	print_debug("0x");
49745ae9d61Sreyk 	for (i = 0; i < length; i++)
49845ae9d61Sreyk 		print_debug("%02x", buf[offset + i]);
49945ae9d61Sreyk 	print_debug("\n");
50045ae9d61Sreyk }
50145ae9d61Sreyk 
502dca9e784Sclaudio void
print_hexbuf(struct ibuf * ibuf)503dca9e784Sclaudio print_hexbuf(struct ibuf *ibuf)
504dca9e784Sclaudio {
505dca9e784Sclaudio 	print_hex(ibuf_data(ibuf), 0, ibuf_size(ibuf));
506dca9e784Sclaudio }
507dca9e784Sclaudio 
50845ae9d61Sreyk const char *
print_bits(unsigned short v,unsigned char * bits)509d09d3a7dSreyk print_bits(unsigned short v, unsigned char *bits)
51045ae9d61Sreyk {
511e35e31bdSreyk 	static char	 buf[IKED_CYCLE_BUFFERS][BUFSIZ];
512e35e31bdSreyk 	static int	 idx = 0;
513d09d3a7dSreyk 	unsigned int	 i, any = 0, j = 0;
514d09d3a7dSreyk 	unsigned char	 c;
51545ae9d61Sreyk 
51645ae9d61Sreyk 	if (!bits)
51745ae9d61Sreyk 		return ("");
51845ae9d61Sreyk 
519e35e31bdSreyk 	if (++idx >= IKED_CYCLE_BUFFERS)
520e35e31bdSreyk 		idx = 0;
521e35e31bdSreyk 
522e35e31bdSreyk 	bzero(buf[idx], sizeof(buf[idx]));
52345ae9d61Sreyk 
52445ae9d61Sreyk 	bits++;
52545ae9d61Sreyk 	while ((i = *bits++)) {
52645ae9d61Sreyk 		if (v & (1 << (i-1))) {
52745ae9d61Sreyk 			if (any) {
528e35e31bdSreyk 				buf[idx][j++] = ',';
529e35e31bdSreyk 				if (j >= sizeof(buf[idx]))
530e35e31bdSreyk 					return (buf[idx]);
53145ae9d61Sreyk 			}
53245ae9d61Sreyk 			any = 1;
53345ae9d61Sreyk 			for (; (c = *bits) > 32; bits++) {
534025f5691Sderaadt 				buf[idx][j++] = tolower((unsigned char)c);
535e35e31bdSreyk 				if (j >= sizeof(buf[idx]))
536e35e31bdSreyk 					return (buf[idx]);
53745ae9d61Sreyk 			}
53845ae9d61Sreyk 		} else
53945ae9d61Sreyk 			for (; *bits > 32; bits++)
54045ae9d61Sreyk 				;
54145ae9d61Sreyk 	}
54245ae9d61Sreyk 
543e35e31bdSreyk 	return (buf[idx]);
54445ae9d61Sreyk }
54545ae9d61Sreyk 
546d09d3a7dSreyk uint8_t
mask2prefixlen(struct sockaddr * sa)547fc6664d7Smikeb mask2prefixlen(struct sockaddr *sa)
548fc6664d7Smikeb {
549fc6664d7Smikeb 	struct sockaddr_in	*sa_in = (struct sockaddr_in *)sa;
550fc6664d7Smikeb 	in_addr_t		 ina = sa_in->sin_addr.s_addr;
551fc6664d7Smikeb 
552fc6664d7Smikeb 	if (ina == 0)
553fc6664d7Smikeb 		return (0);
554fc6664d7Smikeb 	else
555fc6664d7Smikeb 		return (33 - ffs(ntohl(ina)));
556fc6664d7Smikeb }
557fc6664d7Smikeb 
558d09d3a7dSreyk uint8_t
mask2prefixlen6(struct sockaddr * sa)559fc6664d7Smikeb mask2prefixlen6(struct sockaddr *sa)
560fc6664d7Smikeb {
561fc6664d7Smikeb 	struct sockaddr_in6	*sa_in6 = (struct sockaddr_in6 *)sa;
5624ac228f9Sclaudio 	uint8_t			*ap, *ep;
5634ac228f9Sclaudio 	unsigned int		 l = 0;
564fc6664d7Smikeb 
565fc6664d7Smikeb 	/*
566fc6664d7Smikeb 	 * sin6_len is the size of the sockaddr so substract the offset of
567fc6664d7Smikeb 	 * the possibly truncated sin6_addr struct.
568fc6664d7Smikeb 	 */
569d09d3a7dSreyk 	ap = (uint8_t *)&sa_in6->sin6_addr;
570d09d3a7dSreyk 	ep = (uint8_t *)sa_in6 + sa_in6->sin6_len;
571fc6664d7Smikeb 	for (; ap < ep; ap++) {
572fc6664d7Smikeb 		/* this "beauty" is adopted from sbin/route/show.c ... */
573fc6664d7Smikeb 		switch (*ap) {
574fc6664d7Smikeb 		case 0xff:
575fc6664d7Smikeb 			l += 8;
576fc6664d7Smikeb 			break;
577fc6664d7Smikeb 		case 0xfe:
578fc6664d7Smikeb 			l += 7;
5794ac228f9Sclaudio 			goto done;
580fc6664d7Smikeb 		case 0xfc:
581fc6664d7Smikeb 			l += 6;
5824ac228f9Sclaudio 			goto done;
583fc6664d7Smikeb 		case 0xf8:
584fc6664d7Smikeb 			l += 5;
5854ac228f9Sclaudio 			goto done;
586fc6664d7Smikeb 		case 0xf0:
587fc6664d7Smikeb 			l += 4;
5884ac228f9Sclaudio 			goto done;
589fc6664d7Smikeb 		case 0xe0:
590fc6664d7Smikeb 			l += 3;
5914ac228f9Sclaudio 			goto done;
592fc6664d7Smikeb 		case 0xc0:
593fc6664d7Smikeb 			l += 2;
5944ac228f9Sclaudio 			goto done;
595fc6664d7Smikeb 		case 0x80:
596fc6664d7Smikeb 			l += 1;
5974ac228f9Sclaudio 			goto done;
598fc6664d7Smikeb 		case 0x00:
5994ac228f9Sclaudio 			goto done;
600fc6664d7Smikeb 		default:
6014ac228f9Sclaudio 			fatalx("non contiguous inet6 netmask");
602fc6664d7Smikeb 		}
603fc6664d7Smikeb 	}
604fc6664d7Smikeb 
6054ac228f9Sclaudio done:
6064ac228f9Sclaudio 	if (l > sizeof(struct in6_addr) * 8)
6074ac228f9Sclaudio 		fatalx("%s: prefixlen %d out of bound", __func__, l);
608fc6664d7Smikeb 	return (l);
609fc6664d7Smikeb }
610fc6664d7Smikeb 
611d09d3a7dSreyk uint32_t
prefixlen2mask(uint8_t prefixlen)612d09d3a7dSreyk prefixlen2mask(uint8_t prefixlen)
61345ae9d61Sreyk {
61445ae9d61Sreyk 	if (prefixlen == 0)
61545ae9d61Sreyk 		return (0);
61645ae9d61Sreyk 
61745ae9d61Sreyk 	if (prefixlen > 32)
61845ae9d61Sreyk 		prefixlen = 32;
61945ae9d61Sreyk 
62045ae9d61Sreyk 	return (htonl(0xffffffff << (32 - prefixlen)));
62145ae9d61Sreyk }
62245ae9d61Sreyk 
62345ae9d61Sreyk struct in6_addr *
prefixlen2mask6(uint8_t prefixlen,uint32_t * mask)624d09d3a7dSreyk prefixlen2mask6(uint8_t prefixlen, uint32_t *mask)
62545ae9d61Sreyk {
62645ae9d61Sreyk 	static struct in6_addr  s6;
62745ae9d61Sreyk 	int			i;
62845ae9d61Sreyk 
62945ae9d61Sreyk 	if (prefixlen > 128)
63045ae9d61Sreyk 		prefixlen = 128;
63145ae9d61Sreyk 
63245ae9d61Sreyk 	bzero(&s6, sizeof(s6));
63345ae9d61Sreyk 	for (i = 0; i < prefixlen / 8; i++)
63445ae9d61Sreyk 		s6.s6_addr[i] = 0xff;
63545ae9d61Sreyk 	i = prefixlen % 8;
63645ae9d61Sreyk 	if (i)
63745ae9d61Sreyk 		s6.s6_addr[prefixlen / 8] = 0xff00 >> i;
63845ae9d61Sreyk 
63945ae9d61Sreyk 	memcpy(mask, &s6, sizeof(s6));
64045ae9d61Sreyk 
64145ae9d61Sreyk 	return (&s6);
64245ae9d61Sreyk }
64345ae9d61Sreyk 
64445ae9d61Sreyk const char *
print_addr(void * addr)645a8c4b3e4Stb print_addr(void *addr)
64645ae9d61Sreyk {
647*ce50f388Syasuoka 	static char	 sbuf[IKED_CYCLE_BUFFERS][NI_MAXHOST + 9];
648a8c4b3e4Stb 	static int	 idx;
649a8c4b3e4Stb 	struct sockaddr	*sa = addr;
650*ce50f388Syasuoka 	char		*buf, *hbuf;
651*ce50f388Syasuoka 	size_t		 len, hlen;
65245ae9d61Sreyk 	char		 pbuf[7];
65345ae9d61Sreyk 	in_port_t	 port;
65445ae9d61Sreyk 
655*ce50f388Syasuoka 	hbuf = buf = sbuf[idx];
656*ce50f388Syasuoka 	hlen = len = sizeof(sbuf[idx]);
65745ae9d61Sreyk 	if (++idx >= IKED_CYCLE_BUFFERS)
65845ae9d61Sreyk 		idx = 0;
65945ae9d61Sreyk 
66047d6a31cSmarkus 	if (sa->sa_family == AF_UNSPEC) {
66145ae9d61Sreyk 		strlcpy(buf, "any", len);
66245ae9d61Sreyk 		return (buf);
66345ae9d61Sreyk 	}
66445ae9d61Sreyk 
665*ce50f388Syasuoka 	if ((port = socket_getport(sa)) != 0 && sa->sa_family == AF_INET6) {
666*ce50f388Syasuoka 		/* surround [] */
667*ce50f388Syasuoka 		*(hbuf++) = '[';
668*ce50f388Syasuoka 		hlen--;
669*ce50f388Syasuoka 	}
670*ce50f388Syasuoka 
67147d6a31cSmarkus 	if (getnameinfo(sa, sa->sa_len,
672*ce50f388Syasuoka 	    hbuf, hlen, NULL, 0, NI_NUMERICHOST) != 0) {
673f1b3bfc9Sclaudio 		strlcpy(buf, "unknown", len);
674f1b3bfc9Sclaudio 		return (buf);
67545ae9d61Sreyk 	}
67645ae9d61Sreyk 
677*ce50f388Syasuoka 	if (port != 0) {
678*ce50f388Syasuoka 		if (sa->sa_family == AF_INET6)
679*ce50f388Syasuoka 			(void)strlcat(buf, "]", len);
68045ae9d61Sreyk 		snprintf(pbuf, sizeof(pbuf), ":%d", port);
68145ae9d61Sreyk 		(void)strlcat(buf, pbuf, len);
68245ae9d61Sreyk 	}
68345ae9d61Sreyk 
68445ae9d61Sreyk 	return (buf);
68545ae9d61Sreyk }
68645ae9d61Sreyk 
68745ae9d61Sreyk char *
get_string(uint8_t * ptr,size_t len)688d09d3a7dSreyk get_string(uint8_t *ptr, size_t len)
68945ae9d61Sreyk {
69045ae9d61Sreyk 	size_t	 i;
69145ae9d61Sreyk 
69245ae9d61Sreyk 	for (i = 0; i < len; i++)
693025f5691Sderaadt 		if (!isprint(ptr[i]))
69445ae9d61Sreyk 			break;
69545ae9d61Sreyk 
696b52b3078Smmcc 	return strndup(ptr, i);
69745ae9d61Sreyk }
69845ae9d61Sreyk 
69945ae9d61Sreyk const char *
print_proto(uint8_t proto)700d09d3a7dSreyk print_proto(uint8_t proto)
70145ae9d61Sreyk {
70245ae9d61Sreyk 	struct protoent *p;
70345ae9d61Sreyk 	static char	 buf[IKED_CYCLE_BUFFERS][BUFSIZ];
70445ae9d61Sreyk 	static int	 idx = 0;
70545ae9d61Sreyk 
70645ae9d61Sreyk 	if (idx >= IKED_CYCLE_BUFFERS)
70745ae9d61Sreyk 		idx = 0;
70845ae9d61Sreyk 
70945ae9d61Sreyk 	if ((p = getprotobynumber(proto)) != NULL)
71045ae9d61Sreyk 		strlcpy(buf[idx], p->p_name, sizeof(buf[idx]));
71145ae9d61Sreyk 	else
712b8e36cffSjsg 		snprintf(buf[idx], sizeof(buf[idx]), "%u", proto);
71345ae9d61Sreyk 
71445ae9d61Sreyk 	return (buf[idx++]);
71545ae9d61Sreyk }
71645ae9d61Sreyk 
71745ae9d61Sreyk int
expand_string(char * label,size_t len,const char * srch,const char * repl)71845ae9d61Sreyk expand_string(char *label, size_t len, const char *srch, const char *repl)
71945ae9d61Sreyk {
72045ae9d61Sreyk 	char *tmp;
72145ae9d61Sreyk 	char *p, *q;
72245ae9d61Sreyk 
72345ae9d61Sreyk 	if ((tmp = calloc(1, len)) == NULL) {
724ca955bc9Srob 		log_debug("%s: calloc", __func__);
72545ae9d61Sreyk 		return (-1);
72645ae9d61Sreyk 	}
7279ebe96b0Stobhe 	p = label;
72845ae9d61Sreyk 	while ((q = strstr(p, srch)) != NULL) {
72945ae9d61Sreyk 		*q = '\0';
73045ae9d61Sreyk 		if ((strlcat(tmp, p, len) >= len) ||
73145ae9d61Sreyk 		    (strlcat(tmp, repl, len) >= len)) {
732ca955bc9Srob 			log_debug("%s: string too long", __func__);
733c0e316edSjsg 			free(tmp);
73445ae9d61Sreyk 			return (-1);
73545ae9d61Sreyk 		}
73645ae9d61Sreyk 		q += strlen(srch);
73745ae9d61Sreyk 		p = q;
73845ae9d61Sreyk 	}
73945ae9d61Sreyk 	if (strlcat(tmp, p, len) >= len) {
740ca955bc9Srob 		log_debug("%s: string too long", __func__);
741c0e316edSjsg 		free(tmp);
74245ae9d61Sreyk 		return (-1);
74345ae9d61Sreyk 	}
74445ae9d61Sreyk 	strlcpy(label, tmp, len);	/* always fits */
74545ae9d61Sreyk 	free(tmp);
74645ae9d61Sreyk 
74745ae9d61Sreyk 	return (0);
74845ae9d61Sreyk }
74945ae9d61Sreyk 
750d09d3a7dSreyk uint8_t *
string2unicode(const char * ascii,size_t * outlen)75145ae9d61Sreyk string2unicode(const char *ascii, size_t *outlen)
75245ae9d61Sreyk {
753d09d3a7dSreyk 	uint8_t		*uc = NULL;
75445ae9d61Sreyk 	size_t		 i, len = strlen(ascii);
75545ae9d61Sreyk 
75645ae9d61Sreyk 	if ((uc = calloc(1, (len * 2) + 2)) == NULL)
75745ae9d61Sreyk 		return (NULL);
75845ae9d61Sreyk 
75945ae9d61Sreyk 	for (i = 0; i < len; i++) {
76045ae9d61Sreyk 		/* XXX what about the byte order? */
76145ae9d61Sreyk 		uc[i * 2] = ascii[i];
76245ae9d61Sreyk 	}
76345ae9d61Sreyk 	*outlen = len * 2;
76445ae9d61Sreyk 
76545ae9d61Sreyk 	return (uc);
76645ae9d61Sreyk }
7676a7fa426Sreyk 
7686a7fa426Sreyk void
print_debug(const char * emsg,...)7696a7fa426Sreyk print_debug(const char *emsg, ...)
7706a7fa426Sreyk {
7716a7fa426Sreyk 	va_list	 ap;
7726a7fa426Sreyk 
773871fc12cSreyk 	if (log_getverbose() > 2) {
7746a7fa426Sreyk 		va_start(ap, emsg);
7756a7fa426Sreyk 		vfprintf(stderr, emsg, ap);
7766a7fa426Sreyk 		va_end(ap);
7776a7fa426Sreyk 	}
7786a7fa426Sreyk }
7796a7fa426Sreyk 
7806a7fa426Sreyk void
print_verbose(const char * emsg,...)7816a7fa426Sreyk print_verbose(const char *emsg, ...)
7826a7fa426Sreyk {
7836a7fa426Sreyk 	va_list	 ap;
7846a7fa426Sreyk 
785871fc12cSreyk 	if (log_getverbose()) {
7866a7fa426Sreyk 		va_start(ap, emsg);
7876a7fa426Sreyk 		vfprintf(stderr, emsg, ap);
7886a7fa426Sreyk 		va_end(ap);
7896a7fa426Sreyk 	}
7906a7fa426Sreyk }
791