1 /* $NetBSD: sockmisc.c,v 1.16 2009/07/03 06:41:47 tteras Exp $ */
3 /* Id: sockmisc.c,v 1.24 2006/05/07 21:32:59 manubsd Exp */
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/socket.h>
41 #include <netinet/in.h>
44 #if defined(INET6) && !defined(INET6_ADVAPI) && \
45 defined(IP_RECVDSTADDR) && !defined(IPV6_RECVDSTADDR)
46 #define IPV6_RECVDSTADDR IP_RECVDSTADDR
66 #include "isakmp_var.h"
71 #define SETSOCKOPT setsockopt
75 #define BIND privsep_bind
76 #define SOCKET privsep_socket
77 #define SETSOCKOPT privsep_setsockopt
80 const int niflags
= 0;
83 * compare two sockaddr with port, taking care wildcard.
84 * addr1 is a subject address, addr2 is in a database entry.
89 cmpsaddr(addr1
, addr2
)
90 const struct sockaddr
*addr1
;
91 const struct sockaddr
*addr2
;
94 u_short port1
= IPSEC_PORT_ANY
;
95 u_short port2
= IPSEC_PORT_ANY
;
97 if (addr1
== NULL
&& addr2
== NULL
)
98 return CMPSADDR_MATCH
;
100 if (addr1
== NULL
|| addr2
== NULL
)
101 return CMPSADDR_MISMATCH
;
103 if (addr1
->sa_family
!= addr2
->sa_family
||
104 sysdep_sa_len(addr1
) != sysdep_sa_len(addr2
))
105 return CMPSADDR_MISMATCH
;
107 switch (addr1
->sa_family
) {
111 sa1
= (caddr_t
)&((struct sockaddr_in
*)addr1
)->sin_addr
;
112 sa2
= (caddr_t
)&((struct sockaddr_in
*)addr2
)->sin_addr
;
113 port1
= ((struct sockaddr_in
*)addr1
)->sin_port
;
114 port2
= ((struct sockaddr_in
*)addr2
)->sin_port
;
115 if (memcmp(sa1
, sa2
, sizeof(struct in_addr
)) != 0)
116 return CMPSADDR_MISMATCH
;
120 sa1
= (caddr_t
)&((struct sockaddr_in6
*)addr1
)->sin6_addr
;
121 sa2
= (caddr_t
)&((struct sockaddr_in6
*)addr2
)->sin6_addr
;
122 port1
= ((struct sockaddr_in6
*)addr1
)->sin6_port
;
123 port2
= ((struct sockaddr_in6
*)addr2
)->sin6_port
;
124 if (memcmp(sa1
, sa2
, sizeof(struct in6_addr
)) != 0)
125 return CMPSADDR_MISMATCH
;
126 if (((struct sockaddr_in6
*)addr1
)->sin6_scope_id
!=
127 ((struct sockaddr_in6
*)addr2
)->sin6_scope_id
)
128 return CMPSADDR_MISMATCH
;
132 return CMPSADDR_MISMATCH
;
135 if (port1
== port2
||
136 port1
== IPSEC_PORT_ANY
||
137 port2
== IPSEC_PORT_ANY
)
138 return CMPSADDR_MATCH
;
140 return CMPSADDR_WOP_MATCH
;
143 /* get local address against the destination. */
146 struct sockaddr
*remote
;
148 struct sockaddr
*local
;
149 u_int local_len
= sizeof(struct sockaddr_storage
);
150 int s
; /* for dummy connection */
152 /* allocate buffer */
153 if ((local
= racoon_calloc(1, local_len
)) == NULL
) {
154 plog(LLV_ERROR
, LOCATION
, NULL
,
155 "failed to get address buffer.\n");
159 /* get real interface received packet */
160 if ((s
= SOCKET(remote
->sa_family
, SOCK_DGRAM
, 0)) < 0) {
161 plog(LLV_ERROR
, LOCATION
, NULL
,
162 "socket (%s)\n", strerror(errno
));
166 setsockopt_bypass(s
, remote
->sa_family
);
168 if (connect(s
, remote
, sysdep_sa_len(remote
)) < 0) {
169 plog(LLV_ERROR
, LOCATION
, NULL
,
170 "connect (%s)\n", strerror(errno
));
175 if (getsockname(s
, local
, &local_len
) < 0) {
176 plog(LLV_ERROR
, LOCATION
, NULL
,
177 "getsockname (%s)\n", strerror(errno
));
192 * Receive packet, with src/dst information. It is assumed that necessary
193 * setsockopt() have already performed on socket.
196 recvfromto(s
, buf
, buflen
, flags
, from
, fromlen
, to
, tolen
)
201 struct sockaddr
*from
;
209 union sockaddr_any sa
;
214 #if defined(INET6) && defined(INET6_ADVAPI)
215 struct in6_pktinfo
*pi
;
216 #endif /*INET6_ADVAPI*/
217 struct sockaddr_in
*sin
;
219 struct sockaddr_in6
*sin6
;
223 if (getsockname(s
, &sa
.sa
, &slen
) < 0) {
224 plog(LLV_ERROR
, LOCATION
, NULL
,
225 "getsockname (%s)\n", strerror(errno
));
229 m
.msg_name
= (caddr_t
)from
;
230 m
.msg_namelen
= *fromlen
;
231 iov
[0].iov_base
= (caddr_t
)buf
;
232 iov
[0].iov_len
= buflen
;
235 memset(cmsgbuf
, 0, sizeof(cmsgbuf
));
236 cm
= (struct cmsghdr
*)cmsgbuf
;
237 m
.msg_control
= (caddr_t
)cm
;
238 m
.msg_controllen
= sizeof(cmsgbuf
);
239 if ((len
= recvmsg(s
, &m
, flags
)) < 0) {
240 plog(LLV_ERROR
, LOCATION
, NULL
,
241 "recvmsg (%s)\n", strerror(errno
));
244 *fromlen
= m
.msg_namelen
;
248 for (cm
= (struct cmsghdr
*)CMSG_FIRSTHDR(&m
);
249 m
.msg_controllen
!= 0 && cm
;
250 cm
= (struct cmsghdr
*)CMSG_NXTHDR(&m
, cm
)) {
252 plog(LLV_ERROR
, LOCATION
, NULL
,
253 "cmsg %d %d\n", cm
->cmsg_level
, cm
->cmsg_type
);)
255 #if defined(INET6) && defined(INET6_ADVAPI)
256 if (sa
.sa
.sa_family
== AF_INET6
257 && cm
->cmsg_level
== IPPROTO_IPV6
258 && cm
->cmsg_type
== IPV6_PKTINFO
259 && otolen
>= sizeof(*sin6
)) {
260 pi
= (struct in6_pktinfo
*)(CMSG_DATA(cm
));
261 *tolen
= sizeof(*sin6
);
262 sin6
= (struct sockaddr_in6
*)to
;
263 memset(sin6
, 0, sizeof(*sin6
));
264 sin6
->sin6_family
= AF_INET6
;
266 sin6
->sin6_len
= sizeof(*sin6
);
268 memcpy(&sin6
->sin6_addr
, &pi
->ipi6_addr
,
269 sizeof(sin6
->sin6_addr
));
270 /* XXX other cases, such as site-local? */
271 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
))
272 sin6
->sin6_scope_id
= pi
->ipi6_ifindex
;
274 sin6
->sin6_scope_id
= 0;
275 sin6
->sin6_port
= sa
.sin6
.sin6_port
;
276 otolen
= -1; /* "to" already set */
281 if (sa
.sa
.sa_family
== AF_INET
282 && cm
->cmsg_level
== IPPROTO_IP
283 && cm
->cmsg_type
== IP_PKTINFO
284 && otolen
>= sizeof(sin
)) {
285 struct in_pktinfo
*pi
= (struct in_pktinfo
*)(CMSG_DATA(cm
));
286 *tolen
= sizeof(*sin
);
287 sin
= (struct sockaddr_in
*)to
;
288 memset(sin
, 0, sizeof(*sin
));
289 sin
->sin_family
= AF_INET
;
290 memcpy(&sin
->sin_addr
, &pi
->ipi_addr
,
291 sizeof(sin
->sin_addr
));
292 sin
->sin_port
= sa
.sin
.sin_port
;
293 otolen
= -1; /* "to" already set */
297 #if defined(INET6) && defined(IPV6_RECVDSTADDR)
298 if (sa
.sa
.sa_family
== AF_INET6
299 && cm
->cmsg_level
== IPPROTO_IPV6
300 && cm
->cmsg_type
== IPV6_RECVDSTADDR
301 && otolen
>= sizeof(*sin6
)) {
302 *tolen
= sizeof(*sin6
);
303 sin6
= (struct sockaddr_in6
*)to
;
304 memset(sin6
, 0, sizeof(*sin6
));
305 sin6
->sin6_family
= AF_INET6
;
306 sin6
->sin6_len
= sizeof(*sin6
);
307 memcpy(&sin6
->sin6_addr
, CMSG_DATA(cm
),
308 sizeof(sin6
->sin6_addr
));
309 sin6
->sin6_port
= sa
.sin6
.sin6_port
;
310 otolen
= -1; /* "to" already set */
315 if (sa
.sa
.sa_family
== AF_INET
316 && cm
->cmsg_level
== IPPROTO_IP
317 && cm
->cmsg_type
== IP_RECVDSTADDR
318 && otolen
>= sizeof(*sin
)) {
319 *tolen
= sizeof(*sin
);
320 sin
= (struct sockaddr_in
*)to
;
321 memset(sin
, 0, sizeof(*sin
));
322 sin
->sin_family
= AF_INET
;
323 sin
->sin_len
= sizeof(*sin
);
324 memcpy(&sin
->sin_addr
, CMSG_DATA(cm
),
325 sizeof(sin
->sin_addr
));
326 sin
->sin_port
= sa
.sin
.sin_port
;
327 otolen
= -1; /* "to" already set */
336 /* send packet, with fixing src/dst address pair. */
338 sendfromto(s
, buf
, buflen
, src
, dst
, cnt
)
342 struct sockaddr
*src
;
343 struct sockaddr
*dst
;
345 struct sockaddr_storage ss
;
350 if (src
->sa_family
!= dst
->sa_family
) {
351 plog(LLV_ERROR
, LOCATION
, NULL
,
352 "address family mismatch\n");
357 if (getsockname(s
, (struct sockaddr
*)&ss
, &slen
) < 0) {
358 plog(LLV_ERROR
, LOCATION
, NULL
,
359 "getsockname (%s)\n", strerror(errno
));
363 plog(LLV_DEBUG
, LOCATION
, NULL
,
364 "sockname %s\n", saddr2str((struct sockaddr
*)&ss
));
365 plog(LLV_DEBUG
, LOCATION
, NULL
,
366 "send packet from %s\n", saddr2str(src
));
367 plog(LLV_DEBUG
, LOCATION
, NULL
,
368 "send packet to %s\n", saddr2str(dst
));
370 if (src
->sa_family
!= ss
.ss_family
) {
371 plog(LLV_ERROR
, LOCATION
, NULL
,
372 "address family mismatch\n");
376 switch (src
->sa_family
) {
377 #if defined(INET6) && defined(INET6_ADVAPI)
378 // XXX: This block wasn't compiled on Linux - does it work?
385 struct in6_pktinfo
*pi
;
387 struct sockaddr_in6 src6
, dst6
;
389 memcpy(&src6
, src
, sizeof(src6
));
390 memcpy(&dst6
, dst
, sizeof(dst6
));
392 /* XXX take care of other cases, such as site-local */
394 if (IN6_IS_ADDR_LINKLOCAL(&src6
.sin6_addr
)
395 || IN6_IS_ADDR_MULTICAST(&src6
.sin6_addr
)) {
396 ifindex
= src6
.sin6_scope_id
; /*???*/
399 /* XXX some sanity check on dst6.sin6_scope_id */
401 /* flowinfo for IKE? mmm, maybe useful but for now make it 0 */
402 src6
.sin6_flowinfo
= dst6
.sin6_flowinfo
= 0;
404 memset(&m
, 0, sizeof(m
));
405 m
.msg_name
= (caddr_t
)&dst6
;
406 m
.msg_namelen
= sizeof(dst6
);
407 iov
[0].iov_base
= (char *)buf
;
408 iov
[0].iov_len
= buflen
;
412 memset(cmsgbuf
, 0, sizeof(cmsgbuf
));
413 cm
= (struct cmsghdr
*)cmsgbuf
;
414 m
.msg_control
= (caddr_t
)cm
;
415 m
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
417 cm
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
418 cm
->cmsg_level
= IPPROTO_IPV6
;
419 cm
->cmsg_type
= IPV6_PKTINFO
;
420 pi
= (struct in6_pktinfo
*)CMSG_DATA(cm
);
421 memcpy(&pi
->ipi6_addr
, &src6
.sin6_addr
, sizeof(src6
.sin6_addr
));
422 pi
->ipi6_ifindex
= ifindex
;
424 plog(LLV_DEBUG
, LOCATION
, NULL
,
426 saddr2str((struct sockaddr
*)&src6
),
428 plog(LLV_DEBUG
, LOCATION
, NULL
,
430 saddr2str((struct sockaddr
*)&dst6
),
433 for (i
= 0; i
< cnt
; i
++) {
434 len
= sendmsg(s
, &m
, 0 /*MSG_DONTROUTE*/);
436 plog(LLV_ERROR
, LOCATION
, NULL
,
437 "sendmsg (%s)\n", strerror(errno
));
440 plog(LLV_DEBUG
, LOCATION
, NULL
,
441 "%d times of %d bytes message will be sent "
443 i
+ 1, len
, saddr2str(dst
));
445 plogdump(LLV_DEBUG
, (char *)buf
, buflen
);
457 struct in_pktinfo
*pi
;
459 struct sockaddr_in src6
, dst6
;
461 memcpy(&src6
, src
, sizeof(src6
));
462 memcpy(&dst6
, dst
, sizeof(dst6
));
464 memset(&m
, 0, sizeof(m
));
465 m
.msg_name
= (caddr_t
)&dst6
;
466 m
.msg_namelen
= sizeof(dst6
);
467 iov
[0].iov_base
= (char *)buf
;
468 iov
[0].iov_len
= buflen
;
472 memset(cmsgbuf
, 0, sizeof(cmsgbuf
));
473 cm
= (struct cmsghdr
*)cmsgbuf
;
474 m
.msg_control
= (caddr_t
)cm
;
475 m
.msg_controllen
= CMSG_SPACE(sizeof(struct in_pktinfo
));
477 cm
->cmsg_len
= CMSG_LEN(sizeof(struct in_pktinfo
));
478 cm
->cmsg_level
= IPPROTO_IP
;
479 cm
->cmsg_type
= IP_PKTINFO
;
480 pi
= (struct in_pktinfo
*)CMSG_DATA(cm
);
481 memcpy(&pi
->ipi_spec_dst
, &src6
.sin_addr
, sizeof(src6
.sin_addr
));
482 pi
->ipi_ifindex
= ifindex
;
484 plog(LLV_DEBUG
, LOCATION
, NULL
,
486 saddr2str((struct sockaddr
*)&src6
));
487 plog(LLV_DEBUG
, LOCATION
, NULL
,
489 saddr2str((struct sockaddr
*)&dst6
));
491 for (i
= 0; i
< cnt
; i
++) {
492 len
= sendmsg(s
, &m
, 0 /*MSG_DONTROUTE*/);
494 plog(LLV_ERROR
, LOCATION
, NULL
,
495 "sendmsg (%s)\n", strerror(errno
));
498 plog(LLV_DEBUG
, LOCATION
, NULL
,
499 "%d times of %d bytes message will be sent "
501 i
+ 1, len
, saddr2str(dst
));
503 plogdump(LLV_DEBUG
, (char *)buf
, buflen
);
507 #endif /* __linux__ */
513 if (ss
.ss_family
== src
->sa_family
&& memcmp(&ss
, src
, sysdep_sa_len(src
)) == 0) {
519 * Use newly opened socket for sending packets.
520 * NOTE: this is unsafe, because if the peer is quick enough
521 * the packet from the peer may be queued into sendsock.
522 * Better approach is to prepare bind'ed udp sockets for
523 * each of the interface addresses.
525 sendsock
= SOCKET(src
->sa_family
, SOCK_DGRAM
, 0);
527 plog(LLV_ERROR
, LOCATION
, NULL
,
528 "socket (%s)\n", strerror(errno
));
531 if (setsockopt(sendsock
, SOL_SOCKET
,
537 (void *)&yes
, sizeof(yes
)) < 0) {
538 plog(LLV_ERROR
, LOCATION
, NULL
,
539 "setsockopt SO_REUSEPORT (%s)\n",
544 #ifdef IPV6_USE_MIN_MTU
545 if (src
->sa_family
== AF_INET6
&&
546 setsockopt(sendsock
, IPPROTO_IPV6
, IPV6_USE_MIN_MTU
,
547 (void *)&yes
, sizeof(yes
)) < 0) {
548 plog(LLV_ERROR
, LOCATION
, NULL
,
549 "setsockopt IPV6_USE_MIN_MTU (%s)\n",
555 if (setsockopt_bypass(sendsock
, src
->sa_family
) < 0) {
560 if (BIND(sendsock
, (struct sockaddr
*)src
,
561 sysdep_sa_len(src
)) < 0) {
562 plog(LLV_ERROR
, LOCATION
, NULL
,
563 "bind 1 (%s)\n", strerror(errno
));
570 for (i
= 0; i
< cnt
; i
++) {
571 len
= sendto(sendsock
, buf
, buflen
, 0, dst
, sysdep_sa_len(dst
));
573 plog(LLV_ERROR
, LOCATION
, NULL
,
574 "sendto (%s)\n", strerror(errno
));
579 plog(LLV_DEBUG
, LOCATION
, NULL
,
580 "%d times of %d bytes message will be sent "
582 i
+ 1, len
, saddr2str(dst
));
584 plogdump(LLV_DEBUG
, (char *)buf
, buflen
);
595 setsockopt_bypass(so
, family
)
608 level
= IPPROTO_IPV6
;
612 plog(LLV_ERROR
, LOCATION
, NULL
,
613 "unsupported address family %d\n", family
);
617 policy
= "in bypass";
618 buf
= ipsec_set_policy(policy
, strlen(policy
));
620 plog(LLV_ERROR
, LOCATION
, NULL
,
621 "ipsec_set_policy (%s)\n",
625 if (SETSOCKOPT(so
, level
,
626 (level
== IPPROTO_IP
?
627 IP_IPSEC_POLICY
: IPV6_IPSEC_POLICY
),
628 buf
, ipsec_get_policylen(buf
)) < 0) {
629 plog(LLV_ERROR
, LOCATION
, NULL
,
630 "setsockopt IP_IPSEC_POLICY (%s)\n",
636 policy
= "out bypass";
637 buf
= ipsec_set_policy(policy
, strlen(policy
));
639 plog(LLV_ERROR
, LOCATION
, NULL
,
640 "ipsec_set_policy (%s)\n",
644 if (SETSOCKOPT(so
, level
,
645 (level
== IPPROTO_IP
?
646 IP_IPSEC_POLICY
: IPV6_IPSEC_POLICY
),
647 buf
, ipsec_get_policylen(buf
)) < 0) {
648 plog(LLV_ERROR
, LOCATION
, NULL
,
649 "setsockopt IP_IPSEC_POLICY (%s)\n",
662 struct sockaddr
*new;
664 if ((new = racoon_calloc(1, len
)) == NULL
) {
665 plog(LLV_ERROR
, LOCATION
, NULL
,
666 "%s\n", strerror(errno
));
671 if (len
== sizeof (struct sockaddr_in6
))
672 new->sa_family
= AF_INET6
;
674 new->sa_family
= AF_INET
;
685 struct sockaddr
*src
;
687 struct sockaddr
*dst
;
689 dst
= racoon_calloc(1, sysdep_sa_len(src
));
691 plog(LLV_ERROR
, LOCATION
, NULL
,
692 "%s\n", strerror(errno
));
696 memcpy(dst
, src
, sysdep_sa_len(src
));
703 const struct sockaddr
*saddr
;
705 static char buf
[NI_MAXHOST
+ NI_MAXSERV
+ 10];
706 char addr
[NI_MAXHOST
], port
[NI_MAXSERV
];
711 if (saddr
->sa_family
== AF_UNSPEC
)
712 snprintf (buf
, sizeof(buf
), "%s", "anonymous");
714 GETNAMEINFO(saddr
, addr
, port
);
715 snprintf(buf
, sizeof(buf
), "%s[%s]", addr
, port
);
723 const struct sockaddr
*saddr
;
725 static char buf
[NI_MAXHOST
+ NI_MAXSERV
+ 10];
726 char addr
[NI_MAXHOST
];
731 GETNAMEINFO_NULL(saddr
, addr
);
732 snprintf(buf
, sizeof(buf
), "%s", addr
);
738 naddrwop2str(const struct netaddr
*naddr
)
740 static char buf
[NI_MAXHOST
+ 10];
741 static const struct sockaddr sa_any
; /* this is initialized to all zeros */
746 if (memcmp(&naddr
->sa
, &sa_any
, sizeof(sa_any
)) == 0)
747 snprintf(buf
, sizeof(buf
), "%s", "any");
749 snprintf(buf
, sizeof(buf
), "%s", saddrwop2str(&naddr
->sa
.sa
));
750 snprintf(&buf
[strlen(buf
)], sizeof(buf
) - strlen(buf
), "/%ld", naddr
->prefix
);
756 naddrwop2str_fromto(const char *format
, const struct netaddr
*saddr
,
757 const struct netaddr
*daddr
)
759 static char buf
[2*(NI_MAXHOST
+ NI_MAXSERV
+ 10) + 100];
762 src
= racoon_strdup(naddrwop2str(saddr
));
763 dst
= racoon_strdup(naddrwop2str(daddr
));
766 /* WARNING: Be careful about the format string! Don't
767 ever pass in something that a user can modify!!! */
768 snprintf (buf
, sizeof(buf
), format
, src
, dst
);
776 saddr2str_fromto(format
, saddr
, daddr
)
778 const struct sockaddr
*saddr
;
779 const struct sockaddr
*daddr
;
781 static char buf
[2*(NI_MAXHOST
+ NI_MAXSERV
+ 10) + 100];
784 src
= racoon_strdup(saddr2str(saddr
));
785 dst
= racoon_strdup(saddr2str(daddr
));
788 /* WARNING: Be careful about the format string! Don't
789 ever pass in something that a user can modify!!! */
790 snprintf (buf
, sizeof(buf
), format
, src
, dst
);
798 str2saddr(host
, port
)
802 struct addrinfo hints
, *res
;
803 struct sockaddr
*saddr
;
806 memset(&hints
, 0, sizeof(hints
));
807 hints
.ai_family
= PF_UNSPEC
;
808 hints
.ai_socktype
= SOCK_DGRAM
;
809 hints
.ai_flags
= AI_NUMERICHOST
;
810 error
= getaddrinfo(host
, port
, &hints
, &res
);
812 plog(LLV_ERROR
, LOCATION
, NULL
,
813 "getaddrinfo(%s%s%s): %s\n",
814 host
, port
? "," : "", port
? port
: "",
815 gai_strerror(error
));
818 if (res
->ai_next
!= NULL
) {
819 plog(LLV_WARNING
, LOCATION
, NULL
,
820 "getaddrinfo(%s%s%s): "
821 "resolved to multiple address, "
822 "taking the first one\n",
823 host
, port
? "," : "", port
? port
: "");
825 saddr
= racoon_malloc(res
->ai_addrlen
);
827 plog(LLV_ERROR
, LOCATION
, NULL
,
828 "failed to allocate buffer.\n");
832 memcpy(saddr
, res
->ai_addr
, res
->ai_addrlen
);
839 mask_sockaddr(a
, b
, l
)
841 const struct sockaddr
*b
;
847 switch (b
->sa_family
) {
849 alen
= sizeof(struct in_addr
);
850 p
= (u_int8_t
*)&((struct sockaddr_in
*)a
)->sin_addr
;
854 alen
= sizeof(struct in6_addr
);
855 p
= (u_int8_t
*)&((struct sockaddr_in6
*)a
)->sin6_addr
;
859 plog(LLV_ERROR
, LOCATION
, NULL
,
860 "invalid family: %d\n", b
->sa_family
);
864 if ((alen
<< 3) < l
) {
865 plog(LLV_ERROR
, LOCATION
, NULL
,
866 "unexpected inconsistency: %d %zu\n", b
->sa_family
, l
);
870 memcpy(a
, b
, sysdep_sa_len(b
));
871 p
[l
/ 8] &= (0xff00 >> (l
% 8)) & 0xff;
872 for (i
= l
/ 8 + 1; i
< alen
; i
++)
876 /* Compute a score describing how "accurate" a netaddr is for a given sockaddr.
878 * Return values for address 10.20.30.40 [port 500] and given netaddresses...
879 * 10.10.0.0/16 => -1 ... doesn't match
880 * 0.0.0.0/0 => 0 ... matches, but only 0 bits.
881 * 10.20.0.0/16 => 16 ... 16 bits match
882 * 10.20.30.0/24 => 24 ... guess what ;-)
883 * 10.20.30.40/32 => 32 ... whole address match
884 * 10.20.30.40:500 => 33 ... both address and port match
885 * 10.20.30.40:501 => -1 ... port doesn't match and isn't 0 (=any)
888 naddr_score(const struct netaddr
*naddr
, const struct sockaddr
*saddr
)
890 static const struct netaddr naddr_any
; /* initialized to all-zeros */
892 u_int16_t naddr_port
, saddr_port
;
895 if (!naddr
|| !saddr
) {
896 plog(LLV_ERROR
, LOCATION
, NULL
,
897 "Call with null args: naddr=%p, saddr=%p\n",
902 /* Wildcard address matches, but only 0 bits. */
903 if (memcmp(naddr
, &naddr_any
, sizeof(naddr_any
)) == 0)
906 /* If families don't match we really can't do much... */
907 if (naddr
->sa
.sa
.sa_family
!= saddr
->sa_family
)
910 /* If port check fail don't bother to check addresses. */
911 naddr_port
= extract_port(&naddr
->sa
.sa
);
912 saddr_port
= extract_port(saddr
);
913 if (naddr_port
== 0 || saddr_port
== 0) /* wildcard match */
915 else if (naddr_port
== saddr_port
) /* exact match */
917 else /* mismatch :-) */
920 /* Here it comes - compare network addresses. */
921 mask_sockaddr(&sa
, saddr
, naddr
->prefix
);
922 if (loglevel
>= LLV_DEBUG
) { /* debug only */
924 a1
= racoon_strdup(naddrwop2str(naddr
));
925 a2
= racoon_strdup(saddrwop2str(saddr
));
926 a3
= racoon_strdup(saddrwop2str(&sa
));
930 plog(LLV_DEBUG
, LOCATION
, NULL
,
931 "naddr=%s, saddr=%s (masked=%s)\n",
937 if (cmpsaddr(&sa
, &naddr
->sa
.sa
) == 0)
938 return naddr
->prefix
+ port_score
;
943 /* Some usefull functions for sockaddr port manipulations. */
945 extract_port (const struct sockaddr
*addr
)
952 switch (addr
->sa_family
) {
956 port
= ((struct sockaddr_in
*)addr
)->sin_port
;
959 port
= ((struct sockaddr_in6
*)addr
)->sin6_port
;
962 plog(LLV_ERROR
, LOCATION
, NULL
, "unknown AF: %u\n", addr
->sa_family
);
970 get_port_ptr (struct sockaddr
*addr
)
977 switch (addr
->sa_family
) {
979 port_ptr
= &(((struct sockaddr_in
*)addr
)->sin_port
);
982 port_ptr
= &(((struct sockaddr_in6
*)addr
)->sin6_port
);
985 plog(LLV_ERROR
, LOCATION
, NULL
, "unknown AF: %u\n", addr
->sa_family
);
994 set_port (struct sockaddr
*addr
, u_int16_t new_port
)
998 port_ptr
= get_port_ptr (addr
);
1001 *port_ptr
= htons(new_port
);