1c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh/*	$NetBSD: sockmisc.c,v 1.8.6.1 2007/08/01 11:52:22 vanhu Exp $	*/
20a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
30a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/* Id: sockmisc.c,v 1.24 2006/05/07 21:32:59 manubsd Exp */
40a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
50a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/*
60a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
70a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * All rights reserved.
80a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang *
90a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * Redistribution and use in source and binary forms, with or without
100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * modification, are permitted provided that the following conditions
110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * are met:
120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 1. Redistributions of source code must retain the above copyright
130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang *    notice, this list of conditions and the following disclaimer.
140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 2. Redistributions in binary form must reproduce the above copyright
150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang *    notice, this list of conditions and the following disclaimer in the
160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang *    documentation and/or other materials provided with the distribution.
170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 3. Neither the name of the project nor the names of its contributors
180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang *    may be used to endorse or promote products derived from this software
190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang *    without specific prior written permission.
200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang *
210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * SUCH DAMAGE.
320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang */
330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "config.h"
350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <sys/types.h>
370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <sys/param.h>
380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <sys/socket.h>
390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <sys/uio.h>
400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <netinet/in.h>
420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include PATH_IPSEC_H
430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#if defined(INET6) && !defined(INET6_ADVAPI) && \
450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	defined(IP_RECVDSTADDR) && !defined(IPV6_RECVDSTADDR)
460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#define IPV6_RECVDSTADDR IP_RECVDSTADDR
470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <stdlib.h>
500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <stdio.h>
510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <string.h>
520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <errno.h>
530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifdef HAVE_UNISTD_H
540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <unistd.h>
550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "var.h"
580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "misc.h"
590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "plog.h"
600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "sockmisc.h"
610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "debug.h"
620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "gcmalloc.h"
630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "debugrm.h"
640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "libpfkey.h"
650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
66c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#ifndef IP_IPSEC_POLICY
67c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#define IP_IPSEC_POLICY 16	/* XXX: from linux/in.h */
68c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#endif
69c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
70c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#ifndef IPV6_IPSEC_POLICY
71c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#define IPV6_IPSEC_POLICY 34	/* XXX: from linux/???.h per
72c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh				   "Tom Lendacky" <toml@us.ibm.com> */
730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
75f8a6a7636d53a5730c58ae041e4e09ae12e1657cChia-chi Yehconst int niflags = 0;
760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/*
78c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh * compare two sockaddr without port number.
79c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh * OUT:	0: equal.
80c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh *	1: not equal.
81c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh */
82c91307af2622f6625525f3c1f9c954376df950adChia-chi Yehint
83c91307af2622f6625525f3c1f9c954376df950adChia-chi Yehcmpsaddrwop(addr1, addr2)
84c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	const struct sockaddr *addr1;
85c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	const struct sockaddr *addr2;
86c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh{
87c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	caddr_t sa1, sa2;
88c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
89c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1 == 0 && addr2 == 0)
90c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 0;
91c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1 == 0 || addr2 == 0)
92c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
93c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
94c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#ifdef __linux__
95c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1->sa_family != addr2->sa_family)
96c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
97c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#else
98c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1->sa_len != addr2->sa_len
99c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	 || addr1->sa_family != addr2->sa_family)
100c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
101c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
102c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#endif /* __linux__ */
103c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
104c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	switch (addr1->sa_family) {
105c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	case AF_INET:
106c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
107c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
108c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
109c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
110c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		break;
111c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#ifdef INET6
112c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	case AF_INET6:
113c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
114c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
115c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
116c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
117c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
118c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		    ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
119c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
120c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		break;
121c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#endif
122c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	default:
123c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
124c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	}
125c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
126c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	return 0;
127c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh}
128c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
129c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh/*
1300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * compare two sockaddr with port, taking care wildcard.
1310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * addr1 is a subject address, addr2 is in a database entry.
1320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * OUT:	0: equal.
1330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang *	1: not equal.
1340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang */
1350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangint
136c91307af2622f6625525f3c1f9c954376df950adChia-chi Yehcmpsaddrwild(addr1, addr2)
1370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	const struct sockaddr *addr1;
1380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	const struct sockaddr *addr2;
1390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
1400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	caddr_t sa1, sa2;
141c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	u_short port1, port2;
1420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
143c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1 == 0 && addr2 == 0)
144c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 0;
145c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1 == 0 || addr2 == 0)
146c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
1470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
148c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#ifdef __linux__
149c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1->sa_family != addr2->sa_family)
150c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
151c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#else
152c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1->sa_len != addr2->sa_len
153c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	 || addr1->sa_family != addr2->sa_family)
154c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
1550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
156c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#endif /* __linux__ */
1570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
1580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	switch (addr1->sa_family) {
1590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	case AF_INET:
1600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
1610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
1620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		port1 = ((struct sockaddr_in *)addr1)->sin_port;
1630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		port2 = ((struct sockaddr_in *)addr2)->sin_port;
164c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (!(port1 == IPSEC_PORT_ANY ||
165c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		      port2 == IPSEC_PORT_ANY ||
166c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		      port1 == port2))
167c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
1680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
169c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
1700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		break;
1710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifdef INET6
1720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	case AF_INET6:
1730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
1740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
1750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		port1 = ((struct sockaddr_in6 *)addr1)->sin6_port;
1760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		port2 = ((struct sockaddr_in6 *)addr2)->sin6_port;
177c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (!(port1 == IPSEC_PORT_ANY ||
178c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		      port2 == IPSEC_PORT_ANY ||
179c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		      port1 == port2))
180c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
1810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
182c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
1830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
1840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		    ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
185c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
1860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		break;
1870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
1880a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	default:
189c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
1900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
1910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
192c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	return 0;
193c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh}
194c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
195c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh/*
196c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh * compare two sockaddr with strict match on port.
197c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh * OUT:	0: equal.
198c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh *	1: not equal.
199c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh */
200c91307af2622f6625525f3c1f9c954376df950adChia-chi Yehint
201c91307af2622f6625525f3c1f9c954376df950adChia-chi Yehcmpsaddrstrict(addr1, addr2)
202c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	const struct sockaddr *addr1;
203c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	const struct sockaddr *addr2;
204c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh{
205c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	caddr_t sa1, sa2;
206c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	u_short port1, port2;
207c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
208c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1 == 0 && addr2 == 0)
209c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 0;
210c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1 == 0 || addr2 == 0)
211c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
2120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
213c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#ifdef __linux__
214c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1->sa_family != addr2->sa_family)
215c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
216c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#else
217c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (addr1->sa_len != addr2->sa_len
218c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	 || addr1->sa_family != addr2->sa_family)
219c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
2200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
221c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#endif /* __linux__ */
222c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
223c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	switch (addr1->sa_family) {
224c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	case AF_INET:
225c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
226c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
227c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		port1 = ((struct sockaddr_in *)addr1)->sin_port;
228c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		port2 = ((struct sockaddr_in *)addr2)->sin_port;
229c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (port1 != port2)
230c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
231c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
232c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
233c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		break;
234c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#ifdef INET6
235c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	case AF_INET6:
236c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
237c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
238c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		port1 = ((struct sockaddr_in6 *)addr1)->sin6_port;
239c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		port2 = ((struct sockaddr_in6 *)addr2)->sin6_port;
240c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (port1 != port2)
241c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
242c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
243c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
244c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
245c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		    ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
246c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			return 1;
247c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		break;
248c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#endif
249c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	default:
250c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		return 1;
251c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	}
252c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
253c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	return 0;
2540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
2550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
256c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh#ifdef ANDROID_PATCHED
257c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh
258c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yehstruct sockaddr *getlocaladdr(struct sockaddr *remote)
259c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh{
260c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    struct sockaddr_storage local;
261c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    socklen_t len = sysdep_sa_len(remote);
262c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh    int s = socket(remote->sa_family, SOCK_DGRAM, 0);
263c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    if (s == -1 || connect(s, remote, len) == -1 ||
264c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh        getsockname(s, (struct sockaddr *)&local, &len) == -1) {
265c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh        close(s);
266c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh        return NULL;
267c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    }
268c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    close(s);
269c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    return dupsaddr((struct sockaddr *)&local);
270c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh}
271c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh
272c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yehint recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from,
273c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh               socklen_t *fromlen, struct sockaddr *to, unsigned int *tolen)
274c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh{
275c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    if (getsockname(s, to, (socklen_t *)tolen) == -1) {
276c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh        return -1;
277c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    }
278c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    return recvfrom(s, buf, len, flags, from, fromlen);
279c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh}
280c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh
281c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yehint sendfromto(int s, const void *buf, size_t len, struct sockaddr *from,
282c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh               struct sockaddr *to, int count)
283c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh{
284c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    int i;
285c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    for (i = 0; i < count; ++i) {
286a6239141a335940e5f665e3f0dc99c9c5cad8966Chia-chi Yeh        if (sendto(s, buf, len, 0, to, sysdep_sa_len(to)) == -1) {
287c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh            return -1;
288c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh        }
289c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    }
290c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    return len;
291c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh}
292c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh
293c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yehint setsockopt_bypass(int s, int family)
294c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh{
295c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    struct sadb_x_policy p = {
296c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh        .sadb_x_policy_len = PFKEY_UNIT64(sizeof(struct sadb_x_policy)),
297c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh        .sadb_x_policy_exttype = SADB_X_EXT_POLICY,
298c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh        .sadb_x_policy_type = IPSEC_POLICY_BYPASS,
299c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh        .sadb_x_policy_dir = IPSEC_DIR_INBOUND,
300c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh#ifdef HAVE_PFKEY_POLICY_PRIORITY
301c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh        .sadb_x_policy_priority = PRIORITY_DEFAULT,
302c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh#endif
303c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    };
304c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    int level = (family == AF_INET) ? IPPROTO_IP : IPPROTO_IPV6;
305c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    int option = (family == AF_INET) ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
306c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    int len = PFKEY_EXTLEN(&p);
307a6239141a335940e5f665e3f0dc99c9c5cad8966Chia-chi Yeh    if (setsockopt(s, level, option, &p, len) == -1) {
308a6239141a335940e5f665e3f0dc99c9c5cad8966Chia-chi Yeh        plog(LLV_WARNING, LOCATION, NULL, "setsockopt in bypass: %s\n",
309a6239141a335940e5f665e3f0dc99c9c5cad8966Chia-chi Yeh                strerror(errno));
310a6239141a335940e5f665e3f0dc99c9c5cad8966Chia-chi Yeh    }
311a6239141a335940e5f665e3f0dc99c9c5cad8966Chia-chi Yeh    p.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
312a6239141a335940e5f665e3f0dc99c9c5cad8966Chia-chi Yeh    if (setsockopt(s, level, option, &p, len) == -1) {
313a6239141a335940e5f665e3f0dc99c9c5cad8966Chia-chi Yeh        plog(LLV_WARNING, LOCATION, NULL, "setsockopt out bypass: %s\n",
314a6239141a335940e5f665e3f0dc99c9c5cad8966Chia-chi Yeh                strerror(errno));
315c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    }
316c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh    return 0;
317c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh}
318a6239141a335940e5f665e3f0dc99c9c5cad8966Chia-chi Yeh
319c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh#else
320c454954382b81262dc81ac54e147f4dc7fc0af75Chia-chi Yeh
3210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/* get local address against the destination. */
3220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangstruct sockaddr *
3230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wanggetlocaladdr(remote)
3240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr *remote;
3250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
3260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr *local;
3270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	u_int local_len = sizeof(struct sockaddr_storage);
3280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	int s;	/* for dummy connection */
3290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
3300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	/* allocate buffer */
3310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if ((local = racoon_calloc(1, local_len)) == NULL) {
3320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
3330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"failed to get address buffer.\n");
3340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		goto err;
3350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
3360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
3370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	/* get real interface received packet */
338c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if ((s = socket(remote->sa_family, SOCK_DGRAM, 0)) < 0) {
3390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
3400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"socket (%s)\n", strerror(errno));
3410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		goto err;
3420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
3430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
3440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	setsockopt_bypass(s, remote->sa_family);
3450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
3460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (connect(s, remote, sysdep_sa_len(remote)) < 0) {
3470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
3480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"connect (%s)\n", strerror(errno));
3490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		close(s);
3500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		goto err;
3510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
3520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
3530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (getsockname(s, local, &local_len) < 0) {
3540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
3550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"getsockname (%s)\n", strerror(errno));
3560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		close(s);
3570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return NULL;
3580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
3590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
3600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	close(s);
3610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return local;
3620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
3630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang    err:
3640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (local != NULL)
3650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		racoon_free(local);
3660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return NULL;
3670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
3680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
3690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/*
3700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * Receive packet, with src/dst information.  It is assumed that necessary
3710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * setsockopt() have already performed on socket.
3720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang */
3730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangint
3740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangrecvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
3750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	int s;
3760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	void *buf;
3770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	size_t buflen;
3780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	int flags;
3790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr *from;
3800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	socklen_t *fromlen;
3810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr *to;
3820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	u_int *tolen;
3830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
3840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	int otolen;
385c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	u_int len;
386c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	struct sockaddr_storage ss;
3870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct msghdr m;
3880a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct cmsghdr *cm;
3890a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct iovec iov[2];
3900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	u_char cmsgbuf[256];
3910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#if defined(INET6) && defined(INET6_ADVAPI)
3920a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct in6_pktinfo *pi;
3930a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif /*INET6_ADVAPI*/
3940a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr_in *sin;
3950a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifdef INET6
3960a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr_in6 *sin6;
3970a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
3980a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
399c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	len = sizeof(ss);
400c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
4010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
4020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"getsockname (%s)\n", strerror(errno));
4030a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
4040a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
4050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
4060a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	m.msg_name = (caddr_t)from;
4070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	m.msg_namelen = *fromlen;
4080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	iov[0].iov_base = (caddr_t)buf;
4090a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	iov[0].iov_len = buflen;
4100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	m.msg_iov = iov;
4110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	m.msg_iovlen = 1;
4120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	memset(cmsgbuf, 0, sizeof(cmsgbuf));
4130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	cm = (struct cmsghdr *)cmsgbuf;
4140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	m.msg_control = (caddr_t)cm;
4150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	m.msg_controllen = sizeof(cmsgbuf);
4160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if ((len = recvmsg(s, &m, flags)) < 0) {
4170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
4180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"recvmsg (%s)\n", strerror(errno));
4190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
4200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
4210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	*fromlen = m.msg_namelen;
4220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
4230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	otolen = *tolen;
4240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	*tolen = 0;
4250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
4260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	     m.msg_controllen != 0 && cm;
4270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	     cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
4280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#if 0
4290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
4300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"cmsg %d %d\n", cm->cmsg_level, cm->cmsg_type);)
4310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
4320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#if defined(INET6) && defined(INET6_ADVAPI)
433c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (ss.ss_family == AF_INET6
4340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		 && cm->cmsg_level == IPPROTO_IPV6
4350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		 && cm->cmsg_type == IPV6_PKTINFO
4360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		 && otolen >= sizeof(*sin6)) {
4370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
4380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			*tolen = sizeof(*sin6);
4390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sin6 = (struct sockaddr_in6 *)to;
4400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			memset(sin6, 0, sizeof(*sin6));
4410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sin6->sin6_family = AF_INET6;
4420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifndef __linux__
4430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sin6->sin6_len = sizeof(*sin6);
4440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
4450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			memcpy(&sin6->sin6_addr, &pi->ipi6_addr,
4460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				sizeof(sin6->sin6_addr));
4470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			/* XXX other cases, such as site-local? */
4480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
4490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				sin6->sin6_scope_id = pi->ipi6_ifindex;
4500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			else
4510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				sin6->sin6_scope_id = 0;
452c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			sin6->sin6_port =
453c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh				((struct sockaddr_in6 *)&ss)->sin6_port;
4540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			otolen = -1;	/* "to" already set */
4550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			continue;
4560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		}
4570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
4580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifdef __linux__
459c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (ss.ss_family == AF_INET
4600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		 && cm->cmsg_level == IPPROTO_IP
4610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		 && cm->cmsg_type == IP_PKTINFO
4620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		 && otolen >= sizeof(sin)) {
4630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			struct in_pktinfo *pi = (struct in_pktinfo *)(CMSG_DATA(cm));
4640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			*tolen = sizeof(*sin);
4650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sin = (struct sockaddr_in *)to;
4660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			memset(sin, 0, sizeof(*sin));
4670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sin->sin_family = AF_INET;
4680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			memcpy(&sin->sin_addr, &pi->ipi_addr,
4690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				sizeof(sin->sin_addr));
470c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			sin->sin_port =
471c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh				((struct sockaddr_in *)&ss)->sin_port;
4720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			otolen = -1;	/* "to" already set */
4730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			continue;
4740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		}
4750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
4760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#if defined(INET6) && defined(IPV6_RECVDSTADDR)
477c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (ss.ss_family == AF_INET6
4780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		      && cm->cmsg_level == IPPROTO_IPV6
4790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		      && cm->cmsg_type == IPV6_RECVDSTADDR
4800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		      && otolen >= sizeof(*sin6)) {
4810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			*tolen = sizeof(*sin6);
4820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sin6 = (struct sockaddr_in6 *)to;
4830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			memset(sin6, 0, sizeof(*sin6));
4840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sin6->sin6_family = AF_INET6;
4850a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sin6->sin6_len = sizeof(*sin6);
4860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			memcpy(&sin6->sin6_addr, CMSG_DATA(cm),
4870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				sizeof(sin6->sin6_addr));
488c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			sin6->sin6_port =
489c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh				((struct sockaddr_in6 *)&ss)->sin6_port;
4900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			otolen = -1;	/* "to" already set */
4910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			continue;
4920a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		}
4930a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
4940a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifndef __linux__
495c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh		if (ss.ss_family == AF_INET
4960a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		 && cm->cmsg_level == IPPROTO_IP
4970a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		 && cm->cmsg_type == IP_RECVDSTADDR
4980a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		 && otolen >= sizeof(*sin)) {
4990a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			*tolen = sizeof(*sin);
5000a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sin = (struct sockaddr_in *)to;
5010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			memset(sin, 0, sizeof(*sin));
5020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sin->sin_family = AF_INET;
5030a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sin->sin_len = sizeof(*sin);
5040a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			memcpy(&sin->sin_addr, CMSG_DATA(cm),
5050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				sizeof(sin->sin_addr));
506c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			sin->sin_port = ((struct sockaddr_in *)&ss)->sin_port;
5070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			otolen = -1;	/* "to" already set */
5080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			continue;
5090a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		}
5100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
5110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
5120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return len;
5140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
5150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/* send packet, with fixing src/dst address pair. */
5170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangint
5180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangsendfromto(s, buf, buflen, src, dst, cnt)
5190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	int s, cnt;
5200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	const void *buf;
5210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	size_t buflen;
5220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr *src;
5230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr *dst;
5240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
5250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr_storage ss;
526c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	u_int len;
5270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	int i;
5280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (src->sa_family != dst->sa_family) {
5300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
5310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"address family mismatch\n");
5320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
5330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
5340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
535c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	len = sizeof(ss);
536c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
5370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
5380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"getsockname (%s)\n", strerror(errno));
5390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
5400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
5410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	plog(LLV_DEBUG, LOCATION, NULL,
5430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		"sockname %s\n", saddr2str((struct sockaddr *)&ss));
5440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	plog(LLV_DEBUG, LOCATION, NULL,
5450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		"send packet from %s\n", saddr2str(src));
5460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	plog(LLV_DEBUG, LOCATION, NULL,
5470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		"send packet to %s\n", saddr2str(dst));
5480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (src->sa_family != ss.ss_family) {
5500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
5510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"address family mismatch\n");
5520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
5530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
5540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	switch (src->sa_family) {
5560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#if defined(INET6) && defined(INET6_ADVAPI)
5570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang// XXX: This block wasn't compiled on Linux - does it work?
5580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	case AF_INET6:
5590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	    {
5600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		struct msghdr m;
5610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		struct cmsghdr *cm;
5620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		struct iovec iov[2];
5630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		u_char cmsgbuf[256];
5640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		struct in6_pktinfo *pi;
5650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		int ifindex;
5660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		struct sockaddr_in6 src6, dst6;
5670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		memcpy(&src6, src, sizeof(src6));
5690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		memcpy(&dst6, dst, sizeof(dst6));
5700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		/* XXX take care of other cases, such as site-local */
5720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		ifindex = 0;
5730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		if (IN6_IS_ADDR_LINKLOCAL(&src6.sin6_addr)
5740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		 || IN6_IS_ADDR_MULTICAST(&src6.sin6_addr)) {
5750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			ifindex = src6.sin6_scope_id;	/*???*/
5760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		}
5770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		/* XXX some sanity check on dst6.sin6_scope_id */
5790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		/* flowinfo for IKE?  mmm, maybe useful but for now make it 0 */
5810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		src6.sin6_flowinfo = dst6.sin6_flowinfo = 0;
5820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		memset(&m, 0, sizeof(m));
5840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_name = (caddr_t)&dst6;
5850a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_namelen = sizeof(dst6);
5860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		iov[0].iov_base = (char *)buf;
5870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		iov[0].iov_len = buflen;
5880a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_iov = iov;
5890a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_iovlen = 1;
5900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		memset(cmsgbuf, 0, sizeof(cmsgbuf));
5920a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		cm = (struct cmsghdr *)cmsgbuf;
5930a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_control = (caddr_t)cm;
5940a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
5950a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
5960a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
5970a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		cm->cmsg_level = IPPROTO_IPV6;
5980a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		cm->cmsg_type = IPV6_PKTINFO;
5990a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		pi = (struct in6_pktinfo *)CMSG_DATA(cm);
6000a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		memcpy(&pi->ipi6_addr, &src6.sin6_addr, sizeof(src6.sin6_addr));
6010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		pi->ipi6_ifindex = ifindex;
6020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
6030a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_DEBUG, LOCATION, NULL,
6040a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"src6 %s %d\n",
6050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			saddr2str((struct sockaddr *)&src6),
6060a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			src6.sin6_scope_id);
6070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_DEBUG, LOCATION, NULL,
6080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"dst6 %s %d\n",
6090a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			saddr2str((struct sockaddr *)&dst6),
6100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			dst6.sin6_scope_id);
6110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
6120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		for (i = 0; i < cnt; i++) {
6130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/);
6140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			if (len < 0) {
6150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				plog(LLV_ERROR, LOCATION, NULL,
6160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang					"sendmsg (%s)\n", strerror(errno));
6170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				return -1;
6180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			}
6190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			plog(LLV_DEBUG, LOCATION, NULL,
6200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				"%d times of %d bytes message will be sent "
6210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				"to %s\n",
6220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				i + 1, len, saddr2str(dst));
6230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		}
6240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plogdump(LLV_DEBUG, (char *)buf, buflen);
6250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
6260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return len;
6270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	    }
6280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
6290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifdef __linux__
6300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	case AF_INET:
6310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	    {
6320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		struct msghdr m;
6330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		struct cmsghdr *cm;
6340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		struct iovec iov[2];
6350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		u_char cmsgbuf[256];
6360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		struct in_pktinfo *pi;
6370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		int ifindex = 0;
6380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		struct sockaddr_in src6, dst6;
6390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
6400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		memcpy(&src6, src, sizeof(src6));
6410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		memcpy(&dst6, dst, sizeof(dst6));
6420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
6430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		memset(&m, 0, sizeof(m));
6440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_name = (caddr_t)&dst6;
6450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_namelen = sizeof(dst6);
6460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		iov[0].iov_base = (char *)buf;
6470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		iov[0].iov_len = buflen;
6480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_iov = iov;
6490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_iovlen = 1;
6500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
6510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		memset(cmsgbuf, 0, sizeof(cmsgbuf));
6520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		cm = (struct cmsghdr *)cmsgbuf;
6530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_control = (caddr_t)cm;
6540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		m.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
6550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
6560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		cm->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
6570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		cm->cmsg_level = IPPROTO_IP;
6580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		cm->cmsg_type = IP_PKTINFO;
6590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		pi = (struct in_pktinfo *)CMSG_DATA(cm);
6600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		memcpy(&pi->ipi_spec_dst, &src6.sin_addr, sizeof(src6.sin_addr));
6610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		pi->ipi_ifindex = ifindex;
6620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
6630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_DEBUG, LOCATION, NULL,
6640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"src4 %s\n",
6650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			saddr2str((struct sockaddr *)&src6));
6660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_DEBUG, LOCATION, NULL,
6670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"dst4 %s\n",
6680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			saddr2str((struct sockaddr *)&dst6));
6690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
6700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		for (i = 0; i < cnt; i++) {
6710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/);
6720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			if (len < 0) {
6730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				plog(LLV_ERROR, LOCATION, NULL,
6740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang					"sendmsg (%s)\n", strerror(errno));
6750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				return -1;
6760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			}
6770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			plog(LLV_DEBUG, LOCATION, NULL,
6780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				"%d times of %d bytes message will be sent "
6790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				"to %s\n",
6800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				i + 1, len, saddr2str(dst));
6810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		}
6820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plogdump(LLV_DEBUG, (char *)buf, buflen);
6830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
6840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return len;
6850a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	    }
6860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif /* __linux__ */
6870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	default:
6880a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	    {
6890a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		int needclose = 0;
6900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		int sendsock;
6910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
6920a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		if (ss.ss_family == src->sa_family && memcmp(&ss, src, sysdep_sa_len(src)) == 0) {
6930a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			sendsock = s;
6940a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			needclose = 0;
6950a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		} else {
6960a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			int yes = 1;
6970a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			/*
6980a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			 * Use newly opened socket for sending packets.
6990a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			 * NOTE: this is unsafe, because if the peer is quick enough
7000a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			 * the packet from the peer may be queued into sendsock.
7010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			 * Better approach is to prepare bind'ed udp sockets for
7020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			 * each of the interface addresses.
7030a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			 */
704c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			sendsock = socket(src->sa_family, SOCK_DGRAM, 0);
7050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			if (sendsock < 0) {
7060a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				plog(LLV_ERROR, LOCATION, NULL,
7070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang					"socket (%s)\n", strerror(errno));
7080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				return -1;
7090a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			}
7100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			if (setsockopt(sendsock, SOL_SOCKET,
7110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifdef __linux__
7120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				       SO_REUSEADDR,
7130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#else
7140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				       SO_REUSEPORT,
7150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
7160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				       (void *)&yes, sizeof(yes)) < 0) {
7170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				plog(LLV_ERROR, LOCATION, NULL,
7180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang					"setsockopt SO_REUSEPORT (%s)\n",
7190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang					strerror(errno));
7200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				close(sendsock);
7210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				return -1;
7220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			}
7230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifdef IPV6_USE_MIN_MTU
7240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			if (src->sa_family == AF_INET6 &&
7250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			    setsockopt(sendsock, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
7260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			    (void *)&yes, sizeof(yes)) < 0) {
7270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				plog(LLV_ERROR, LOCATION, NULL,
7280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang					"setsockopt IPV6_USE_MIN_MTU (%s)\n",
7290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang					strerror(errno));
7300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				close(sendsock);
7310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				return -1;
7320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			}
7330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
7340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			if (setsockopt_bypass(sendsock, src->sa_family) < 0) {
7350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				close(sendsock);
7360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				return -1;
7370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			}
7380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
739c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh			if (bind(sendsock, (struct sockaddr *)src, sysdep_sa_len(src)) < 0) {
7400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				plog(LLV_ERROR, LOCATION, NULL,
7410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang					"bind 1 (%s)\n", strerror(errno));
7420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				close(sendsock);
7430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				return -1;
7440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			}
7450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			needclose = 1;
7460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		}
7470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
7480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		for (i = 0; i < cnt; i++) {
7490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			len = sendto(sendsock, buf, buflen, 0, dst, sysdep_sa_len(dst));
7500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			if (len < 0) {
7510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				plog(LLV_ERROR, LOCATION, NULL,
7520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang					"sendto (%s)\n", strerror(errno));
7530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				if (needclose)
7540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang					close(sendsock);
7550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				return len;
7560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			}
7570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			plog(LLV_DEBUG, LOCATION, NULL,
7580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				"%d times of %d bytes message will be sent "
7590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				"to %s\n",
7600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang				i + 1, len, saddr2str(dst));
7610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		}
7620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plogdump(LLV_DEBUG, (char *)buf, buflen);
7630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
7640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		if (needclose)
7650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			close(sendsock);
7660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
7670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return len;
7680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	    }
7690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
7700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
7710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
7720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangint
7730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangsetsockopt_bypass(so, family)
7740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	int so, family;
7750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
7760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	int level;
7770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	char *buf;
7780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	char *policy;
7790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
7800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	switch (family) {
7810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	case AF_INET:
7820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		level = IPPROTO_IP;
7830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		break;
7840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifdef INET6
7850a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	case AF_INET6:
7860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		level = IPPROTO_IPV6;
7870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		break;
7880a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
7890a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	default:
7900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
7910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"unsupported address family %d\n", family);
7920a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
7930a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
7940a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
7950a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	policy = "in bypass";
7960a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	buf = ipsec_set_policy(policy, strlen(policy));
7970a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (buf == NULL) {
7980a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
7990a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"ipsec_set_policy (%s)\n",
8000a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			ipsec_strerror());
8010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
8020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
803c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (setsockopt(so, level,
8040a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	               (level == IPPROTO_IP ?
8050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	                         IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
8060a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	               buf, ipsec_get_policylen(buf)) < 0) {
8070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
8080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"setsockopt IP_IPSEC_POLICY (%s)\n",
8090a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			strerror(errno));
8100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
8110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
8120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	racoon_free(buf);
8130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	policy = "out bypass";
8150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	buf = ipsec_set_policy(policy, strlen(policy));
8160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (buf == NULL) {
8170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
8180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"ipsec_set_policy (%s)\n",
8190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			ipsec_strerror());
8200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
8210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
822c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (setsockopt(so, level,
8230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	               (level == IPPROTO_IP ?
8240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	                         IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
8250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	               buf, ipsec_get_policylen(buf)) < 0) {
8260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
8270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"setsockopt IP_IPSEC_POLICY (%s)\n",
8280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			strerror(errno));
8290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
8300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
8310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	racoon_free(buf);
8320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return 0;
8340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
8350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangstruct sockaddr *
8370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangnewsaddr(len)
8380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	int len;
8390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
8400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr *new;
8410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if ((new = racoon_calloc(1, len)) == NULL) {
8430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
8440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"%s\n", strerror(errno));
8450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		goto out;
8460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
8470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifdef __linux__
8490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (len == sizeof (struct sockaddr_in6))
8500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		new->sa_family = AF_INET6;
8510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	else
8520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		new->sa_family = AF_INET;
8530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#else
8540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	/* initial */
8550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	new->sa_len = len;
8560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
8570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangout:
8580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return new;
8590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
8600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
861c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh#endif
862c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh
8630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangstruct sockaddr *
8640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangdupsaddr(src)
8650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr *src;
8660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
8670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr *dst;
8680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	dst = racoon_calloc(1, sysdep_sa_len(src));
8700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (dst == NULL) {
8710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
8720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"%s\n", strerror(errno));
8730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return NULL;
8740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
8750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	memcpy(dst, src, sysdep_sa_len(src));
8770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return dst;
8790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
8800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangchar *
8820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangsaddr2str(saddr)
8830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	const struct sockaddr *saddr;
8840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
8850a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	static char buf[NI_MAXHOST + NI_MAXSERV + 10];
8860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	char addr[NI_MAXHOST], port[NI_MAXSERV];
8870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8880a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (saddr == NULL)
8890a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return NULL;
8900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (saddr->sa_family == AF_UNSPEC)
8920a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		snprintf (buf, sizeof(buf), "%s", "anonymous");
8930a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	else {
8940a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		GETNAMEINFO(saddr, addr, port);
8950a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		snprintf(buf, sizeof(buf), "%s[%s]", addr, port);
8960a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
8970a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
8980a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return buf;
8990a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
9000a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangchar *
9020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangsaddrwop2str(saddr)
9030a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	const struct sockaddr *saddr;
9040a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
9050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	static char buf[NI_MAXHOST + NI_MAXSERV + 10];
9060a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	char addr[NI_MAXHOST];
9070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (saddr == NULL)
9090a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return NULL;
9100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	GETNAMEINFO_NULL(saddr, addr);
9120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	snprintf(buf, sizeof(buf), "%s", addr);
9130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return buf;
9150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
9160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangchar *
9180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangnaddrwop2str(const struct netaddr *naddr)
9190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
9200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	static char buf[NI_MAXHOST + 10];
9210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	static const struct sockaddr sa_any;	/* this is initialized to all zeros */
9220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (naddr == NULL)
9240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return NULL;
9250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (memcmp(&naddr->sa, &sa_any, sizeof(sa_any)) == 0)
9270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		snprintf(buf, sizeof(buf), "%s", "any");
9280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	else {
9290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		snprintf(buf, sizeof(buf), "%s", saddrwop2str(&naddr->sa.sa));
9300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		snprintf(&buf[strlen(buf)], sizeof(buf) - strlen(buf), "/%ld", naddr->prefix);
9310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
9320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return buf;
9330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
9340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangchar *
9360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangnaddrwop2str_fromto(const char *format, const struct netaddr *saddr,
9370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		    const struct netaddr *daddr)
9380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
9390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	static char buf[2*(NI_MAXHOST + NI_MAXSERV + 10) + 100];
9400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	char *src, *dst;
9410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	src = racoon_strdup(naddrwop2str(saddr));
9430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	dst = racoon_strdup(naddrwop2str(daddr));
9440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	STRDUP_FATAL(src);
9450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	STRDUP_FATAL(dst);
9460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	/* WARNING: Be careful about the format string! Don't
9470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	   ever pass in something that a user can modify!!! */
9480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	snprintf (buf, sizeof(buf), format, src, dst);
9490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	racoon_free (src);
9500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	racoon_free (dst);
9510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return buf;
9530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
9540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangchar *
9560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangsaddr2str_fromto(format, saddr, daddr)
9570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	const char *format;
9580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	const struct sockaddr *saddr;
9590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	const struct sockaddr *daddr;
9600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
9610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	static char buf[2*(NI_MAXHOST + NI_MAXSERV + 10) + 100];
9620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	char *src, *dst;
9630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	src = racoon_strdup(saddr2str(saddr));
9650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	dst = racoon_strdup(saddr2str(daddr));
9660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	STRDUP_FATAL(src);
9670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	STRDUP_FATAL(dst);
9680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	/* WARNING: Be careful about the format string! Don't
9690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	   ever pass in something that a user can modify!!! */
9700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	snprintf (buf, sizeof(buf), format, src, dst);
9710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	racoon_free (src);
9720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	racoon_free (dst);
9730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return buf;
9750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
9760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangstruct sockaddr *
9780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangstr2saddr(host, port)
9790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	char *host;
9800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	char *port;
9810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
9820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct addrinfo hints, *res;
9830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr *saddr;
9840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	int error;
9850a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
9860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	memset(&hints, 0, sizeof(hints));
9870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	hints.ai_family = PF_UNSPEC;
9880a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	hints.ai_socktype = SOCK_DGRAM;
9890a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	hints.ai_flags = AI_NUMERICHOST;
9900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	error = getaddrinfo(host, port, &hints, &res);
9910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (error != 0) {
9920a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
9930a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"getaddrinfo(%s%s%s): %s\n",
9940a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			host, port ? "," : "", port ? port : "",
9950a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			gai_strerror(error));
9960a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return NULL;
9970a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
9980a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (res->ai_next != NULL) {
9990a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_WARNING, LOCATION, NULL,
10000a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"getaddrinfo(%s%s%s): "
10010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"resolved to multiple address, "
10020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"taking the first one\n",
10030a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			host, port ? "," : "", port ? port : "");
10040a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
10050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	saddr = racoon_malloc(res->ai_addrlen);
10060a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (saddr == NULL) {
10070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
10080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"failed to allocate buffer.\n");
10090a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		freeaddrinfo(res);
10100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return NULL;
10110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
10120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	memcpy(saddr, res->ai_addr, res->ai_addrlen);
10130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	freeaddrinfo(res);
10140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
10150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return saddr;
10160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
10170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
10180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangvoid
10190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangmask_sockaddr(a, b, l)
10200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr *a;
10210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	const struct sockaddr *b;
10220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	size_t l;
10230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
10240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	size_t i;
10250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	u_int8_t *p, alen;
10260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
10270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	switch (b->sa_family) {
10280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	case AF_INET:
10290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		alen = sizeof(struct in_addr);
10300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		p = (u_int8_t *)&((struct sockaddr_in *)a)->sin_addr;
10310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		break;
10320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifdef INET6
10330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	case AF_INET6:
10340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		alen = sizeof(struct in6_addr);
10350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		p = (u_int8_t *)&((struct sockaddr_in6 *)a)->sin6_addr;
10360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		break;
10370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif
10380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	default:
10390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
10400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"invalid family: %d\n", b->sa_family);
10410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		exit(1);
10420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
10430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
10440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if ((alen << 3) < l) {
10450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
10460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang			"unexpected inconsistency: %d %zu\n", b->sa_family, l);
10470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		exit(1);
10480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
10490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
10500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	memcpy(a, b, sysdep_sa_len(b));
10510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	p[l / 8] &= (0xff00 >> (l % 8)) & 0xff;
10520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	for (i = l / 8 + 1; i < alen; i++)
10530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		p[i] = 0x00;
10540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
10550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
10560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/* Compute a score describing how "accurate" a netaddr is for a given sockaddr.
10570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * Examples:
10580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 	Return values for address 10.20.30.40 [port 500] and given netaddresses...
10590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 		10.10.0.0/16	=> -1	... doesn't match
10600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 		0.0.0.0/0	=> 0	... matches, but only 0 bits.
10610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 		10.20.0.0/16	=> 16	... 16 bits match
10620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 		10.20.30.0/24	=> 24	... guess what ;-)
10630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 		10.20.30.40/32	=> 32	... whole address match
10640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 		10.20.30.40:500	=> 33	... both address and port match
10650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 		10.20.30.40:501	=> -1	... port doesn't match and isn't 0 (=any)
10660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang */
10670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangint
10680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangnaddr_score(const struct netaddr *naddr, const struct sockaddr *saddr)
10690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
10700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	static const struct netaddr naddr_any;	/* initialized to all-zeros */
10710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	struct sockaddr sa;
10720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	u_int16_t naddr_port, saddr_port;
10730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	int port_score;
10740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
10750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (!naddr || !saddr) {
10760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_ERROR, LOCATION, NULL,
10770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		     "Call with null args: naddr=%p, saddr=%p\n",
10780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		     naddr, saddr);
10790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
10800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
10810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
10820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	/* Wildcard address matches, but only 0 bits. */
10830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (memcmp(naddr, &naddr_any, sizeof(naddr_any)) == 0)
10840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return 0;
10850a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
10860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	/* If families don't match we really can't do much... */
10870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (naddr->sa.sa.sa_family != saddr->sa_family)
10880a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
10890a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
10900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	/* If port check fail don't bother to check addresses. */
10910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	naddr_port = extract_port(&naddr->sa.sa);
10920a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	saddr_port = extract_port(saddr);
10930a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (naddr_port == 0 || saddr_port == 0)	/* wildcard match */
10940a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		port_score = 0;
10950a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	else if (naddr_port == saddr_port)	/* exact match */
10960a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		port_score = 1;
10970a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	else					/* mismatch :-) */
10980a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return -1;
10990a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11000a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	/* Here it comes - compare network addresses. */
11010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	mask_sockaddr(&sa, saddr, naddr->prefix);
11020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	if (loglevel >= LLV_DEBUG) {	/* debug only */
11030a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		char *a1, *a2, *a3;
11040a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		a1 = racoon_strdup(naddrwop2str(naddr));
11050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		a2 = racoon_strdup(saddrwop2str(saddr));
11060a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		a3 = racoon_strdup(saddrwop2str(&sa));
11070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		STRDUP_FATAL(a1);
11080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		STRDUP_FATAL(a2);
11090a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		STRDUP_FATAL(a3);
11100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		plog(LLV_DEBUG, LOCATION, NULL,
11110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		     "naddr=%s, saddr=%s (masked=%s)\n",
11120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		     a1, a2, a3);
11130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		free(a1);
11140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		free(a2);
11150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		free(a3);
11160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	}
1117c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh	if (cmpsaddrwop(&sa, &naddr->sa.sa) == 0)
11180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang		return naddr->prefix + port_score;
11190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang	return -1;
11210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
11220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
1123c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh/* Some usefull functions for sockaddr port manipulations. */
11240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangu_int16_t
11250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangextract_port (const struct sockaddr *addr)
11260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
11270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  u_int16_t port = 0;
11280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  if (!addr)
11300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang    return port;
11310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  switch (addr->sa_family) {
11330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang    case AF_INET:
11340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      port = ((struct sockaddr_in *)addr)->sin_port;
11350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      break;
11360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang    case AF_INET6:
11370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      port = ((struct sockaddr_in6 *)addr)->sin6_port;
11380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      break;
11390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang    default:
11400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      plog(LLV_ERROR, LOCATION, NULL, "unknown AF: %u\n", addr->sa_family);
11410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      break;
11420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  }
11430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  return ntohs(port);
11450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
11460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangu_int16_t *
11480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangget_port_ptr (struct sockaddr *addr)
11490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
11500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  u_int16_t *port_ptr;
11510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  if (!addr)
11530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang    return NULL;
11540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  switch (addr->sa_family) {
11560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang    case AF_INET:
11570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      port_ptr = &(((struct sockaddr_in *)addr)->sin_port);
11580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      break;
11590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang    case AF_INET6:
11600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      port_ptr = &(((struct sockaddr_in6 *)addr)->sin6_port);
11610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      break;
11620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang    default:
11630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      plog(LLV_ERROR, LOCATION, NULL, "unknown AF: %u\n", addr->sa_family);
11640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      return NULL;
11650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang      break;
11660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  }
11670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  return port_ptr;
11690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
11700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangu_int16_t *
11720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangset_port (struct sockaddr *addr, u_int16_t new_port)
11730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{
11740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  u_int16_t *port_ptr;
11750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  port_ptr = get_port_ptr (addr);
11770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  if (port_ptr)
11790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang    *port_ptr = htons(new_port);
11800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang
11810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang  return port_ptr;
11820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang}
1183