162428Skris/* $KAME: name6.c,v 1.25 2000/06/26 16:44:40 itojun Exp $ */ 260296Sitojun 355163Sshin/* 455163Sshin * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 555163Sshin * All rights reserved. 655163Sshin * 755163Sshin * Redistribution and use in source and binary forms, with or without 855163Sshin * modification, are permitted provided that the following conditions 955163Sshin * are met: 1055163Sshin * 1. Redistributions of source code must retain the above copyright 1155163Sshin * notice, this list of conditions and the following disclaimer. 1255163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1355163Sshin * notice, this list of conditions and the following disclaimer in the 1455163Sshin * documentation and/or other materials provided with the distribution. 1555163Sshin * 3. Neither the name of the project nor the names of its contributors 1655163Sshin * may be used to endorse or promote products derived from this software 1755163Sshin * without specific prior written permission. 1855163Sshin * 1955163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2055163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2355163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955163Sshin * SUCH DAMAGE. 3060296Sitojun */ 3160296Sitojun/* 3260296Sitojun * ++Copyright++ 1985, 1988, 1993 3360296Sitojun * - 3460296Sitojun * Copyright (c) 1985, 1988, 1993 3560296Sitojun * The Regents of the University of California. All rights reserved. 3655163Sshin * 3760296Sitojun * Redistribution and use in source and binary forms, with or without 3860296Sitojun * modification, are permitted provided that the following conditions 3960296Sitojun * are met: 4060296Sitojun * 1. Redistributions of source code must retain the above copyright 4160296Sitojun * notice, this list of conditions and the following disclaimer. 4260296Sitojun * 2. Redistributions in binary form must reproduce the above copyright 4360296Sitojun * notice, this list of conditions and the following disclaimer in the 4460296Sitojun * documentation and/or other materials provided with the distribution. 45251071Semaste * 3. Neither the name of the University nor the names of its contributors 4660296Sitojun * may be used to endorse or promote products derived from this software 4760296Sitojun * without specific prior written permission. 4860296Sitojun * 4960296Sitojun * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5060296Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5160296Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5260296Sitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5360296Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5460296Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5560296Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5660296Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5760296Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5860296Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5960296Sitojun * SUCH DAMAGE. 6060296Sitojun * - 6160296Sitojun * Portions Copyright (c) 1993 by Digital Equipment Corporation. 6260296Sitojun * 6360296Sitojun * Permission to use, copy, modify, and distribute this software for any 6460296Sitojun * purpose with or without fee is hereby granted, provided that the above 6560296Sitojun * copyright notice and this permission notice appear in all copies, and that 6660296Sitojun * the name of Digital Equipment Corporation not be used in advertising or 6760296Sitojun * publicity pertaining to distribution of the document or software without 6860296Sitojun * specific, written prior permission. 6960296Sitojun * 7060296Sitojun * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 7160296Sitojun * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 7260296Sitojun * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 7360296Sitojun * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 7460296Sitojun * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 7560296Sitojun * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 7660296Sitojun * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 7760296Sitojun * SOFTWARE. 7860296Sitojun * - 7960296Sitojun * --Copyright-- 8055163Sshin */ 8160296Sitojun 8255163Sshin/* 8355163Sshin * Atsushi Onoe <onoe@sm.sony.co.jp> 8455163Sshin */ 8555163Sshin 8692986Sobrien#include <sys/cdefs.h> 8792986Sobrien__FBSDID("$FreeBSD$"); 8892986Sobrien 8971579Sdeischen#include "namespace.h" 9055163Sshin#include <sys/param.h> 9155163Sshin#include <sys/socket.h> 9255163Sshin#include <sys/time.h> 9359411Sshin#include <sys/queue.h> 9455163Sshin#include <netinet/in.h> 95126052Sume#ifdef INET6 96126052Sume#include <net/if.h> 97126052Sume#include <net/if_var.h> 98126052Sume#include <sys/sysctl.h> 99129984Sume#include <sys/ioctl.h> 100126052Sume#include <netinet6/in6_var.h> /* XXX */ 101126052Sume#endif 10255163Sshin 10355163Sshin#include <arpa/inet.h> 10455163Sshin#include <arpa/nameser.h> 10555163Sshin 10659411Sshin#include <errno.h> 10755163Sshin#include <netdb.h> 10855163Sshin#include <resolv.h> 10955163Sshin#include <stdio.h> 11055163Sshin#include <stdlib.h> 11155163Sshin#include <string.h> 11265532Snectar#include <stdarg.h> 11365532Snectar#include <nsswitch.h> 11455163Sshin#include <unistd.h> 11571579Sdeischen#include "un-namespace.h" 116145602Sume#include "netdb_private.h" 117156960Sume#include "res_private.h" 11855163Sshin 11955163Sshin#ifndef MAXALIASES 12055163Sshin#define MAXALIASES 10 12155163Sshin#endif 12255163Sshin#ifndef MAXADDRS 12355163Sshin#define MAXADDRS 20 12455163Sshin#endif 12555163Sshin#ifndef MAXDNAME 12655163Sshin#define MAXDNAME 1025 12755163Sshin#endif 12855163Sshin 12955163Sshin#ifdef INET6 13055163Sshin#define ADDRLEN(af) ((af) == AF_INET6 ? sizeof(struct in6_addr) : \ 13155163Sshin sizeof(struct in_addr)) 13255163Sshin#else 13355163Sshin#define ADDRLEN(af) sizeof(struct in_addr) 13455163Sshin#endif 13555163Sshin 13655163Sshin#define MAPADDR(ab, ina) \ 13755163Sshindo { \ 13855163Sshin memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr)); \ 13955163Sshin memset((ab)->map_zero, 0, sizeof((ab)->map_zero)); \ 14055163Sshin memset((ab)->map_one, 0xff, sizeof((ab)->map_one)); \ 14155163Sshin} while (0) 14255163Sshin#define MAPADDRENABLED(flags) \ 14355163Sshin (((flags) & AI_V4MAPPED) || \ 144171671Sbushman (((flags) & AI_V4MAPPED_CFG))) 14555163Sshin 14655163Sshinunion inx_addr { 14755163Sshin struct in_addr in_addr; 14855163Sshin#ifdef INET6 14955163Sshin struct in6_addr in6_addr; 15055163Sshin#endif 15155163Sshin struct { 15255163Sshin u_char mau_zero[10]; 15355163Sshin u_char mau_one[2]; 15455163Sshin struct in_addr mau_inaddr; 15555163Sshin } map_addr_un; 15655163Sshin#define map_zero map_addr_un.mau_zero 15755163Sshin#define map_one map_addr_un.mau_one 15855163Sshin#define map_inaddr map_addr_un.mau_inaddr 15955163Sshin}; 16055163Sshin 161126052Sumestruct policyqueue { 162126052Sume TAILQ_ENTRY(policyqueue) pc_entry; 163126052Sume#ifdef INET6 164126052Sume struct in6_addrpolicy pc_policy; 165126052Sume#endif 166126052Sume}; 167126052SumeTAILQ_HEAD(policyhead, policyqueue); 168126052Sume 169129984Sume#define AIO_SRCFLAG_DEPRECATED 0x1 170129984Sume 171129984Sumestruct hp_order { 172129984Sume union { 173129984Sume struct sockaddr_storage aiou_ss; 174129984Sume struct sockaddr aiou_sa; 175129984Sume } aio_src_un; 176129984Sume#define aio_srcsa aio_src_un.aiou_sa 177129984Sume u_int32_t aio_srcflag; 178129984Sume int aio_srcscope; 179129984Sume int aio_dstscope; 180129984Sume struct policyqueue *aio_srcpolicy; 181129984Sume struct policyqueue *aio_dstpolicy; 182129984Sume union { 183129984Sume struct sockaddr_storage aiou_ss; 184129984Sume struct sockaddr aiou_sa; 185129984Sume } aio_un; 186129984Sume#define aio_sa aio_un.aiou_sa 187129984Sume int aio_matchlen; 188146700Sume char *aio_h_addr; 189129984Sume}; 190129984Sume 191156960Sumestatic struct hostent *_hpcopy(struct hostent *, int *); 192156960Sumestatic struct hostent *_hpaddr(int, const char *, void *, int *); 193171671Sbushman#ifdef INET6 194156960Sumestatic struct hostent *_hpmerge(struct hostent *, struct hostent *, int *); 195156960Sumestatic struct hostent *_hpmapv6(struct hostent *, int *); 19655163Sshin#endif 197156960Sumestatic struct hostent *_hpsort(struct hostent *, res_state); 19855163Sshin 199245256Sume#ifdef INET6 200156960Sumestatic struct hostent *_hpreorder(struct hostent *); 201126052Sumestatic int get_addrselectpolicy(struct policyhead *); 202126052Sumestatic void free_addrselectpolicy(struct policyhead *); 203126052Sumestatic struct policyqueue *match_addrselectpolicy(struct sockaddr *, 204126052Sume struct policyhead *); 205129984Sumestatic void set_source(struct hp_order *, struct policyhead *); 206129984Sumestatic int matchlen(struct sockaddr *, struct sockaddr *); 207129984Sumestatic int comp_dst(const void *, const void *); 208129984Sumestatic int gai_addr2scopetype(struct sockaddr *); 209245225Sume#endif 210126052Sume 21155163Sshin/* 212171671Sbushman * Functions defined in RFC2553 213171671Sbushman * getipnodebyname, getipnodebyaddr, freehostent 21455163Sshin */ 21555163Sshin 216171671Sbushmanstruct hostent * 217171671Sbushmangetipnodebyname(const char *name, int af, int flags, int *errp) 21855163Sshin{ 219171671Sbushman struct hostent *hp; 220171671Sbushman union inx_addr addrbuf; 221158115Sume res_state statp; 222171671Sbushman u_long options; 223158115Sume 224171671Sbushman switch (af) { 225171671Sbushman case AF_INET: 226171671Sbushman#ifdef INET6 227171671Sbushman case AF_INET6: 228171671Sbushman#endif 229158115Sume break; 230158115Sume default: 231171671Sbushman *errp = NO_RECOVERY; 232171671Sbushman return NULL; 233158115Sume } 234158115Sume 23555163Sshin if (flags & AI_ADDRCONFIG) { 23655163Sshin int s; 23755163Sshin 238255328Sjilles if ((s = _socket(af, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) 239144527Sume return NULL; 24055163Sshin /* 24155163Sshin * TODO: 24255163Sshin * Note that implementation dependent test for address 24355163Sshin * configuration should be done everytime called 24455163Sshin * (or apropriate interval), 24555163Sshin * because addresses will be dynamically assigned or deleted. 24655163Sshin */ 247144527Sume _close(s); 24855163Sshin } 249171671Sbushman 25055163Sshin#ifdef INET6 25155163Sshin /* special case for literal address */ 25255163Sshin if (inet_pton(AF_INET6, name, &addrbuf) == 1) { 25355163Sshin if (af != AF_INET6) { 25455163Sshin *errp = HOST_NOT_FOUND; 25555163Sshin return NULL; 25655163Sshin } 25755163Sshin return _hpaddr(af, name, &addrbuf, errp); 25855163Sshin } 25955163Sshin#endif 26057107Sshin if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) { 26155163Sshin if (af != AF_INET) { 26255163Sshin if (MAPADDRENABLED(flags)) { 26355163Sshin MAPADDR(&addrbuf, &addrbuf.in_addr); 26455163Sshin } else { 26555163Sshin *errp = HOST_NOT_FOUND; 26655163Sshin return NULL; 26755163Sshin } 26855163Sshin } 26955163Sshin return _hpaddr(af, name, &addrbuf, errp); 27055163Sshin } 27155163Sshin 272171671Sbushman 273156960Sume statp = __res_state(); 274156960Sume if ((statp->options & RES_INIT) == 0) { 275156960Sume if (res_ninit(statp) < 0) { 276156960Sume *errp = NETDB_INTERNAL; 277156960Sume return NULL; 278156960Sume } 279156960Sume } 280171671Sbushman 281171671Sbushman options = statp->options; 282171671Sbushman statp->options &= ~RES_USE_INET6; 283171671Sbushman 284171671Sbushman hp = gethostbyname2(name, af); 285171671Sbushman hp = _hpcopy(hp, errp); 286245256Sume#ifdef INET6 287245256Sume if (af == AF_INET6) 288245256Sume hp = _hpreorder(hp); 289156960Sume 290146192Sume if (af == AF_INET6 && ((flags & AI_ALL) || hp == NULL) && 291146192Sume MAPADDRENABLED(flags)) { 292171671Sbushman struct hostent *hp2 = gethostbyname2(name, AF_INET); 29355163Sshin if (hp == NULL) 294171671Sbushman if (hp2 == NULL) 295171671Sbushman *errp = statp->res_h_errno; 296171671Sbushman else 297171671Sbushman hp = _hpmapv6(hp2, errp); 29855163Sshin else { 299171671Sbushman if (hp2 && strcmp(hp->h_name, hp2->h_name) == 0) { 300171671Sbushman struct hostent *hpb = hp; 301171671Sbushman hp = _hpmerge(hpb, hp2, errp); 302171671Sbushman freehostent(hpb); 30355163Sshin } 30455163Sshin } 30555163Sshin } 30655163Sshin#endif 307171671Sbushman 308171671Sbushman if (hp == NULL) 309171671Sbushman *errp = statp->res_h_errno; 310171671Sbushman 311171671Sbushman statp->options = options; 312245225Sume return _hpsort(hp, statp); 31355163Sshin} 31455163Sshin 31555163Sshinstruct hostent * 31655163Sshingetipnodebyaddr(const void *src, size_t len, int af, int *errp) 31755163Sshin{ 31855163Sshin struct hostent *hp; 319171671Sbushman res_state statp; 320171671Sbushman u_long options; 321171671Sbushman 32255163Sshin#ifdef INET6 32355163Sshin struct in6_addr addrbuf; 32455163Sshin#else 32555163Sshin struct in_addr addrbuf; 32655163Sshin#endif 327171671Sbushman 32855163Sshin switch (af) { 32955163Sshin case AF_INET: 33055163Sshin if (len != sizeof(struct in_addr)) { 33155163Sshin *errp = NO_RECOVERY; 33255163Sshin return NULL; 33355163Sshin } 33455163Sshin if ((long)src & ~(sizeof(struct in_addr) - 1)) { 33555163Sshin memcpy(&addrbuf, src, len); 33655163Sshin src = &addrbuf; 33755163Sshin } 33855163Sshin if (((struct in_addr *)src)->s_addr == 0) 33955163Sshin return NULL; 34055163Sshin break; 34155163Sshin#ifdef INET6 34255163Sshin case AF_INET6: 34355163Sshin if (len != sizeof(struct in6_addr)) { 34455163Sshin *errp = NO_RECOVERY; 34555163Sshin return NULL; 34655163Sshin } 34755163Sshin if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) { /*XXX*/ 34855163Sshin memcpy(&addrbuf, src, len); 34955163Sshin src = &addrbuf; 35055163Sshin } 35155877Sshin if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src)) 35255877Sshin return NULL; 35355163Sshin if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src) 35455163Sshin || IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) { 35555163Sshin src = (char *)src + 35655163Sshin (sizeof(struct in6_addr) - sizeof(struct in_addr)); 35755163Sshin af = AF_INET; 35855163Sshin len = sizeof(struct in_addr); 35955163Sshin } 36055163Sshin break; 36155163Sshin#endif 36255163Sshin default: 36355163Sshin *errp = NO_RECOVERY; 36455163Sshin return NULL; 36555163Sshin } 36655163Sshin 367171671Sbushman statp = __res_state(); 368171671Sbushman if ((statp->options & RES_INIT) == 0) { 369171671Sbushman if (res_ninit(statp) < 0) { 370171671Sbushman RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 371171671Sbushman return NULL; 372171671Sbushman } 373171671Sbushman } 374171671Sbushman 375171671Sbushman options = statp->options; 376171671Sbushman statp->options &= ~RES_USE_INET6; 377171671Sbushman 378171671Sbushman hp = gethostbyaddr(src, len, af); 379171671Sbushman if (hp == NULL) 380171671Sbushman *errp = statp->res_h_errno; 381171671Sbushman 382171671Sbushman statp->options = options; 383171671Sbushman return (_hpcopy(hp, errp)); 38455163Sshin} 38555163Sshin 38655163Sshinvoid 38755163Sshinfreehostent(struct hostent *ptr) 38855163Sshin{ 38955163Sshin free(ptr); 39055163Sshin} 39155163Sshin 39255163Sshin/* 39355163Sshin * Private utility functions 39455163Sshin */ 39555163Sshin 39655163Sshin/* 39755163Sshin * _hpcopy: allocate and copy hostent structure 39855163Sshin */ 39955163Sshinstatic struct hostent * 40055163Sshin_hpcopy(struct hostent *hp, int *errp) 40155163Sshin{ 40255163Sshin struct hostent *nhp; 40355163Sshin char *cp, **pp; 40455163Sshin int size, addrsize; 40555163Sshin int nalias = 0, naddr = 0; 40655163Sshin int al_off; 40755163Sshin int i; 40855163Sshin 40955163Sshin if (hp == NULL) 41055163Sshin return hp; 41155163Sshin 41255163Sshin /* count size to be allocated */ 41355163Sshin size = sizeof(struct hostent); 41463490Sume if (hp->h_name != NULL) 41555163Sshin size += strlen(hp->h_name) + 1; 41655163Sshin if ((pp = hp->h_aliases) != NULL) { 41755163Sshin for (i = 0; *pp != NULL; i++, pp++) { 41855163Sshin if (**pp != '\0') { 41955163Sshin size += strlen(*pp) + 1; 42055163Sshin nalias++; 42155163Sshin } 42255163Sshin } 42355163Sshin } 42455163Sshin /* adjust alignment */ 42555163Sshin size = ALIGN(size); 42655163Sshin al_off = size; 42755163Sshin size += sizeof(char *) * (nalias + 1); 42855163Sshin addrsize = ALIGN(hp->h_length); 42955163Sshin if ((pp = hp->h_addr_list) != NULL) { 43055163Sshin while (*pp++ != NULL) 43155163Sshin naddr++; 43255163Sshin } 43355163Sshin size += addrsize * naddr; 43455163Sshin size += sizeof(char *) * (naddr + 1); 43555163Sshin 43655163Sshin /* copy */ 43755163Sshin if ((nhp = (struct hostent *)malloc(size)) == NULL) { 43855163Sshin *errp = TRY_AGAIN; 43955163Sshin return NULL; 44055163Sshin } 44155163Sshin cp = (char *)&nhp[1]; 44263490Sume if (hp->h_name != NULL) { 44355163Sshin nhp->h_name = cp; 44455163Sshin strcpy(cp, hp->h_name); 44555163Sshin cp += strlen(cp) + 1; 44655163Sshin } else 44755163Sshin nhp->h_name = NULL; 44855163Sshin nhp->h_aliases = (char **)((char *)nhp + al_off); 44955163Sshin if ((pp = hp->h_aliases) != NULL) { 45055163Sshin for (i = 0; *pp != NULL; pp++) { 45155163Sshin if (**pp != '\0') { 45255163Sshin nhp->h_aliases[i++] = cp; 45355163Sshin strcpy(cp, *pp); 45455163Sshin cp += strlen(cp) + 1; 45555163Sshin } 45655163Sshin } 45755163Sshin } 45855163Sshin nhp->h_aliases[nalias] = NULL; 45955163Sshin cp = (char *)&nhp->h_aliases[nalias + 1]; 46055163Sshin nhp->h_addrtype = hp->h_addrtype; 46155163Sshin nhp->h_length = hp->h_length; 46255163Sshin nhp->h_addr_list = (char **)cp; 46355163Sshin if ((pp = hp->h_addr_list) != NULL) { 46455163Sshin cp = (char *)&nhp->h_addr_list[naddr + 1]; 46555163Sshin for (i = 0; *pp != NULL; pp++) { 46655163Sshin nhp->h_addr_list[i++] = cp; 46755163Sshin memcpy(cp, *pp, hp->h_length); 46855163Sshin cp += addrsize; 46955163Sshin } 47055163Sshin } 47155163Sshin nhp->h_addr_list[naddr] = NULL; 47255163Sshin return nhp; 47355163Sshin} 47455163Sshin 47555163Sshin/* 47655163Sshin * _hpaddr: construct hostent structure with one address 47755163Sshin */ 47855163Sshinstatic struct hostent * 47955163Sshin_hpaddr(int af, const char *name, void *addr, int *errp) 48055163Sshin{ 48155163Sshin struct hostent *hp, hpbuf; 48255163Sshin char *addrs[2]; 48355163Sshin 48455163Sshin hp = &hpbuf; 48555163Sshin hp->h_name = (char *)name; 48655163Sshin hp->h_aliases = NULL; 48755163Sshin hp->h_addrtype = af; 48855163Sshin hp->h_length = ADDRLEN(af); 48955163Sshin hp->h_addr_list = addrs; 49055163Sshin addrs[0] = (char *)addr; 49155163Sshin addrs[1] = NULL; 492171671Sbushman return (_hpcopy(hp, errp)); 49355163Sshin} 49455163Sshin 495171671Sbushman#ifdef INET6 49655163Sshin/* 49755163Sshin * _hpmerge: merge 2 hostent structure, arguments will be freed 49855163Sshin */ 49955163Sshinstatic struct hostent * 50055163Sshin_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp) 50155163Sshin{ 50255163Sshin int i, j; 50355163Sshin int naddr, nalias; 50455163Sshin char **pp; 50555163Sshin struct hostent *hp, hpbuf; 50655163Sshin char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1]; 50755163Sshin union inx_addr addrbuf[MAXADDRS]; 50855163Sshin 50955163Sshin if (hp1 == NULL) 510171671Sbushman return _hpcopy(hp2, errp); 51155163Sshin if (hp2 == NULL) 512171671Sbushman return _hpcopy(hp1, errp); 51355163Sshin 51455163Sshin#define HP(i) (i == 1 ? hp1 : hp2) 51555163Sshin hp = &hpbuf; 51655163Sshin hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name); 51755163Sshin hp->h_aliases = aliases; 51855163Sshin nalias = 0; 51955163Sshin for (i = 1; i <= 2; i++) { 52055163Sshin if ((pp = HP(i)->h_aliases) == NULL) 52155163Sshin continue; 52255163Sshin for (; nalias < MAXALIASES && *pp != NULL; pp++) { 52355163Sshin /* check duplicates */ 52455163Sshin for (j = 0; j < nalias; j++) 52555163Sshin if (strcasecmp(*pp, aliases[j]) == 0) 52655163Sshin break; 52755163Sshin if (j == nalias) 52855163Sshin aliases[nalias++] = *pp; 52955163Sshin } 53055163Sshin } 53155163Sshin aliases[nalias] = NULL; 53255163Sshin if (hp1->h_length != hp2->h_length) { 53355163Sshin hp->h_addrtype = AF_INET6; 53455163Sshin hp->h_length = sizeof(struct in6_addr); 53555163Sshin } else { 53655163Sshin hp->h_addrtype = hp1->h_addrtype; 53755163Sshin hp->h_length = hp1->h_length; 53855163Sshin } 539171671Sbushman 54055163Sshin hp->h_addr_list = addrs; 54155163Sshin naddr = 0; 54255163Sshin for (i = 1; i <= 2; i++) { 54355163Sshin if ((pp = HP(i)->h_addr_list) == NULL) 54455163Sshin continue; 54555163Sshin if (HP(i)->h_length == hp->h_length) { 54655163Sshin while (naddr < MAXADDRS && *pp != NULL) 54755163Sshin addrs[naddr++] = *pp++; 54855163Sshin } else { 54955163Sshin /* copy IPv4 addr as mapped IPv6 addr */ 55055163Sshin while (naddr < MAXADDRS && *pp != NULL) { 55155163Sshin MAPADDR(&addrbuf[naddr], *pp++); 55255163Sshin addrs[naddr] = (char *)&addrbuf[naddr]; 55355163Sshin naddr++; 55455163Sshin } 55555163Sshin } 55655163Sshin } 55755163Sshin addrs[naddr] = NULL; 558171671Sbushman return (_hpcopy(hp, errp)); 55955163Sshin} 560171671Sbushman#endif 56155163Sshin 56255163Sshin/* 56355163Sshin * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses 56455163Sshin */ 56555163Sshin#ifdef INET6 56655163Sshinstatic struct hostent * 56755163Sshin_hpmapv6(struct hostent *hp, int *errp) 56855163Sshin{ 569171671Sbushman struct hostent hp6; 57055163Sshin 57155163Sshin if (hp == NULL) 57255163Sshin return NULL; 57355163Sshin if (hp->h_addrtype == AF_INET6) 574171671Sbushman return _hpcopy(hp, errp); 57555163Sshin 576171671Sbushman memset(&hp6, 0, sizeof(struct hostent)); 577171671Sbushman hp6.h_addrtype = AF_INET6; 578171671Sbushman hp6.h_length = sizeof(struct in6_addr); 579171671Sbushman return _hpmerge(&hp6, hp, errp); 58055163Sshin} 58155163Sshin#endif 58255163Sshin 58355163Sshin/* 58455163Sshin * _hpsort: sort address by sortlist 58555163Sshin */ 58655163Sshinstatic struct hostent * 587156960Sume_hpsort(struct hostent *hp, res_state statp) 58855163Sshin{ 58955163Sshin int i, j, n; 59055163Sshin u_char *ap, *sp, *mp, **pp; 59155163Sshin char t; 59255163Sshin char order[MAXADDRS]; 593156960Sume int nsort = statp->nsort; 59455163Sshin 59555163Sshin if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0) 59655163Sshin return hp; 59755163Sshin for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) { 59855163Sshin for (j = 0; j < nsort; j++) { 59955163Sshin#ifdef INET6 600156960Sume if (statp->_u._ext.ext->sort_list[j].af != 601156960Sume hp->h_addrtype) 60255163Sshin continue; 603156960Sume sp = (u_char *)&statp->_u._ext.ext->sort_list[j].addr; 604156960Sume mp = (u_char *)&statp->_u._ext.ext->sort_list[j].mask; 60555163Sshin#else 606156960Sume sp = (u_char *)&statp->sort_list[j].addr; 607156960Sume mp = (u_char *)&statp->sort_list[j].mask; 60855163Sshin#endif 60955163Sshin for (n = 0; n < hp->h_length; n++) { 61055163Sshin if ((ap[n] & mp[n]) != sp[n]) 61155163Sshin break; 61255163Sshin } 61355163Sshin if (n == hp->h_length) 61455163Sshin break; 61555163Sshin } 61655163Sshin order[i] = j; 61755163Sshin } 61855163Sshin n = i; 61955163Sshin pp = (u_char **)hp->h_addr_list; 62055163Sshin for (i = 0; i < n - 1; i++) { 62155163Sshin for (j = i + 1; j < n; j++) { 62255163Sshin if (order[i] > order[j]) { 62355163Sshin ap = pp[i]; 62455163Sshin pp[i] = pp[j]; 62555163Sshin pp[j] = ap; 62655163Sshin t = order[i]; 62755163Sshin order[i] = order[j]; 62855163Sshin order[j] = t; 62955163Sshin } 63055163Sshin } 63155163Sshin } 63255163Sshin return hp; 63355163Sshin} 63455163Sshin 635245256Sume#ifdef INET6 63655163Sshin/* 637126052Sume * _hpreorder: sort address by default address selection 638126052Sume */ 639126052Sumestatic struct hostent * 640126052Sume_hpreorder(struct hostent *hp) 641126052Sume{ 642129984Sume struct hp_order *aio; 643129984Sume int i, n; 644146700Sume char *ap; 645129984Sume struct sockaddr *sa; 646126052Sume struct policyhead policyhead; 647126052Sume 648129984Sume if (hp == NULL) 649126052Sume return hp; 650126052Sume 651129984Sume switch (hp->h_addrtype) { 652129984Sume case AF_INET: 653129984Sume#ifdef INET6 654129984Sume case AF_INET6: 655129984Sume#endif 656129984Sume break; 657129984Sume default: 658129984Sume free_addrselectpolicy(&policyhead); 659129984Sume return hp; 660129984Sume } 661129984Sume 662129984Sume /* count the number of addrinfo elements for sorting. */ 663129984Sume for (n = 0; hp->h_addr_list[n] != NULL; n++) 664129984Sume ; 665129984Sume 666129984Sume /* 667129984Sume * If the number is small enough, we can skip the reordering process. 668129984Sume */ 669129984Sume if (n <= 1) 670129984Sume return hp; 671129984Sume 672129984Sume /* allocate a temporary array for sort and initialization of it. */ 673129984Sume if ((aio = malloc(sizeof(*aio) * n)) == NULL) 674129984Sume return hp; /* give up reordering */ 675129984Sume memset(aio, 0, sizeof(*aio) * n); 676129984Sume 677126052Sume /* retrieve address selection policy from the kernel */ 678126052Sume TAILQ_INIT(&policyhead); 679126052Sume if (!get_addrselectpolicy(&policyhead)) { 680126052Sume /* no policy is installed into kernel, we don't sort. */ 681129984Sume free(aio); 682126052Sume return hp; 683126052Sume } 684126052Sume 685129984Sume for (i = 0; i < n; i++) { 686146700Sume ap = hp->h_addr_list[i]; 687129984Sume aio[i].aio_h_addr = ap; 688129984Sume sa = &aio[i].aio_sa; 689129984Sume switch (hp->h_addrtype) { 690129984Sume case AF_INET: 691129984Sume sa->sa_family = AF_INET; 692129984Sume sa->sa_len = sizeof(struct sockaddr_in); 693129984Sume memcpy(&((struct sockaddr_in *)sa)->sin_addr, ap, 694126052Sume sizeof(struct in_addr)); 695129984Sume break; 696126052Sume#ifdef INET6 697129984Sume case AF_INET6: 698126052Sume if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { 699129984Sume sa->sa_family = AF_INET; 700129984Sume sa->sa_len = sizeof(struct sockaddr_in); 701129984Sume memcpy(&((struct sockaddr_in *)sa)->sin_addr, 702126052Sume &ap[12], sizeof(struct in_addr)); 703126052Sume } else { 704129984Sume sa->sa_family = AF_INET6; 705129984Sume sa->sa_len = sizeof(struct sockaddr_in6); 706129984Sume memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr, 707126052Sume ap, sizeof(struct in6_addr)); 708126052Sume } 709129984Sume break; 710129984Sume#endif 711126052Sume } 712129984Sume aio[i].aio_dstscope = gai_addr2scopetype(sa); 713129984Sume aio[i].aio_dstpolicy = match_addrselectpolicy(sa, &policyhead); 714129984Sume set_source(&aio[i], &policyhead); 715126052Sume } 716126052Sume 717126052Sume /* perform sorting. */ 718129984Sume qsort(aio, n, sizeof(*aio), comp_dst); 719126052Sume 720129984Sume /* reorder the h_addr_list. */ 721129984Sume for (i = 0; i < n; i++) 722129984Sume hp->h_addr_list[i] = aio[i].aio_h_addr; 723129984Sume 724126052Sume /* cleanup and return */ 725129984Sume free(aio); 726126052Sume free_addrselectpolicy(&policyhead); 727126052Sume return hp; 728126052Sume} 729126052Sume 730126052Sumestatic int 731157119Sumeget_addrselectpolicy(struct policyhead *head) 732126052Sume{ 733126052Sume#ifdef INET6 734126052Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; 735126052Sume size_t l; 736126052Sume char *buf; 737126052Sume struct in6_addrpolicy *pol, *ep; 738126052Sume 739126052Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) 740126052Sume return (0); 741126052Sume if ((buf = malloc(l)) == NULL) 742126052Sume return (0); 743126052Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 744126052Sume free(buf); 745126052Sume return (0); 746126052Sume } 747126052Sume 748126052Sume ep = (struct in6_addrpolicy *)(buf + l); 749126052Sume for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { 750126052Sume struct policyqueue *new; 751126052Sume 752126052Sume if ((new = malloc(sizeof(*new))) == NULL) { 753126052Sume free_addrselectpolicy(head); /* make the list empty */ 754126052Sume break; 755126052Sume } 756126052Sume new->pc_policy = *pol; 757126052Sume TAILQ_INSERT_TAIL(head, new, pc_entry); 758126052Sume } 759126052Sume 760126052Sume free(buf); 761126052Sume return (1); 762126052Sume#else 763126052Sume return (0); 764126052Sume#endif 765126052Sume} 766126052Sume 767126052Sumestatic void 768157119Sumefree_addrselectpolicy(struct policyhead *head) 769126052Sume{ 770126052Sume struct policyqueue *ent, *nent; 771126052Sume 772126052Sume for (ent = TAILQ_FIRST(head); ent; ent = nent) { 773126052Sume nent = TAILQ_NEXT(ent, pc_entry); 774126052Sume TAILQ_REMOVE(head, ent, pc_entry); 775126052Sume free(ent); 776126052Sume } 777126052Sume} 778126052Sume 779126052Sumestatic struct policyqueue * 780157119Sumematch_addrselectpolicy(struct sockaddr *addr, struct policyhead *head) 781126052Sume{ 782126052Sume#ifdef INET6 783126052Sume struct policyqueue *ent, *bestent = NULL; 784126052Sume struct in6_addrpolicy *pol; 785126052Sume int matchlen, bestmatchlen = -1; 786126052Sume u_char *mp, *ep, *k, *p, m; 787126052Sume struct sockaddr_in6 key; 788126052Sume 789126052Sume switch(addr->sa_family) { 790126052Sume case AF_INET6: 791126052Sume key = *(struct sockaddr_in6 *)addr; 792126052Sume break; 793126052Sume case AF_INET: 794126052Sume /* convert the address into IPv4-mapped IPv6 address. */ 795126052Sume memset(&key, 0, sizeof(key)); 796126052Sume key.sin6_family = AF_INET6; 797126052Sume key.sin6_len = sizeof(key); 798126052Sume key.sin6_addr.s6_addr[10] = 0xff; 799126052Sume key.sin6_addr.s6_addr[11] = 0xff; 800126052Sume memcpy(&key.sin6_addr.s6_addr[12], 801126052Sume &((struct sockaddr_in *)addr)->sin_addr, 4); 802126052Sume break; 803126052Sume default: 804126052Sume return(NULL); 805126052Sume } 806126052Sume 807126052Sume for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { 808126052Sume pol = &ent->pc_policy; 809126052Sume matchlen = 0; 810126052Sume 811126052Sume mp = (u_char *)&pol->addrmask.sin6_addr; 812126052Sume ep = mp + 16; /* XXX: scope field? */ 813126052Sume k = (u_char *)&key.sin6_addr; 814126052Sume p = (u_char *)&pol->addr.sin6_addr; 815126052Sume for (; mp < ep && *mp; mp++, k++, p++) { 816126052Sume m = *mp; 817126052Sume if ((*k & m) != *p) 818126052Sume goto next; /* not match */ 819126052Sume if (m == 0xff) /* short cut for a typical case */ 820126052Sume matchlen += 8; 821126052Sume else { 822126052Sume while (m >= 0x80) { 823126052Sume matchlen++; 824126052Sume m <<= 1; 825126052Sume } 826126052Sume } 827126052Sume } 828126052Sume 829126052Sume /* matched. check if this is better than the current best. */ 830126052Sume if (matchlen > bestmatchlen) { 831126052Sume bestent = ent; 832126052Sume bestmatchlen = matchlen; 833126052Sume } 834126052Sume 835126052Sume next: 836126052Sume continue; 837126052Sume } 838126052Sume 839126052Sume return(bestent); 840126052Sume#else 841126052Sume return(NULL); 842126052Sume#endif 843126052Sume 844126052Sume} 845126052Sume 846129984Sumestatic void 847157119Sumeset_source(struct hp_order *aio, struct policyhead *ph) 848129984Sume{ 849129984Sume struct sockaddr_storage ss = aio->aio_un.aiou_ss; 850145786Sume socklen_t srclen; 851145786Sume int s; 852129984Sume 853129984Sume /* set unspec ("no source is available"), just in case */ 854129984Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 855129984Sume aio->aio_srcscope = -1; 856129984Sume 857129984Sume switch(ss.ss_family) { 858129984Sume case AF_INET: 859129984Sume ((struct sockaddr_in *)&ss)->sin_port = htons(1); 860129984Sume break; 861129984Sume#ifdef INET6 862129984Sume case AF_INET6: 863129984Sume ((struct sockaddr_in6 *)&ss)->sin6_port = htons(1); 864129984Sume break; 865129984Sume#endif 866129984Sume default: /* ignore unsupported AFs explicitly */ 867129984Sume return; 868129984Sume } 869129984Sume 870129984Sume /* open a socket to get the source address for the given dst */ 871255328Sjilles if ((s = _socket(ss.ss_family, SOCK_DGRAM | SOCK_CLOEXEC, 872255328Sjilles IPPROTO_UDP)) < 0) 873129984Sume return; /* give up */ 874129984Sume if (_connect(s, (struct sockaddr *)&ss, ss.ss_len) < 0) 875129984Sume goto cleanup; 876129984Sume srclen = ss.ss_len; 877129984Sume if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { 878129984Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 879129984Sume goto cleanup; 880129984Sume } 881129984Sume aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); 882129984Sume aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); 883129984Sume aio->aio_matchlen = matchlen(&aio->aio_srcsa, (struct sockaddr *)&ss); 884129984Sume#ifdef INET6 885129984Sume if (ss.ss_family == AF_INET6) { 886129984Sume struct in6_ifreq ifr6; 887129984Sume u_int32_t flags6; 888129984Sume 889129984Sume memset(&ifr6, 0, sizeof(ifr6)); 890129984Sume memcpy(&ifr6.ifr_addr, &ss, ss.ss_len); 891129984Sume if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { 892129984Sume flags6 = ifr6.ifr_ifru.ifru_flags6; 893129984Sume if ((flags6 & IN6_IFF_DEPRECATED)) 894129984Sume aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; 895129984Sume } 896129984Sume } 897129984Sume#endif 898129984Sume 899129984Sume cleanup: 900129984Sume _close(s); 901129984Sume return; 902129984Sume} 903129984Sume 904129984Sumestatic int 905157119Sumematchlen(struct sockaddr *src, struct sockaddr *dst) 906129984Sume{ 907129984Sume int match = 0; 908129984Sume u_char *s, *d; 909129984Sume u_char *lim, r; 910129984Sume int addrlen; 911129984Sume 912129984Sume switch (src->sa_family) { 913129984Sume#ifdef INET6 914129984Sume case AF_INET6: 915129984Sume s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; 916129984Sume d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; 917129984Sume addrlen = sizeof(struct in6_addr); 918129984Sume lim = s + addrlen; 919129984Sume break; 920129984Sume#endif 921129984Sume case AF_INET: 922146222Sgnn s = (u_char *)&((struct sockaddr_in *)src)->sin_addr; 923146222Sgnn d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr; 924129984Sume addrlen = sizeof(struct in_addr); 925129984Sume lim = s + addrlen; 926129984Sume break; 927129984Sume default: 928129984Sume return(0); 929129984Sume } 930129984Sume 931129984Sume while (s < lim) 932129984Sume if ((r = (*d++ ^ *s++)) != 0) { 933129984Sume while (r < addrlen * 8) { 934129984Sume match++; 935129984Sume r <<= 1; 936129984Sume } 937129984Sume break; 938129984Sume } else 939129984Sume match += 8; 940129984Sume return(match); 941129984Sume} 942129984Sume 943129984Sumestatic int 944157119Sumecomp_dst(const void *arg1, const void *arg2) 945129984Sume{ 946129984Sume const struct hp_order *dst1 = arg1, *dst2 = arg2; 947129984Sume 948129984Sume /* 949129984Sume * Rule 1: Avoid unusable destinations. 950129984Sume * XXX: we currently do not consider if an appropriate route exists. 951129984Sume */ 952129984Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 953129984Sume dst2->aio_srcsa.sa_family == AF_UNSPEC) { 954129984Sume return(-1); 955129984Sume } 956129984Sume if (dst1->aio_srcsa.sa_family == AF_UNSPEC && 957129984Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 958129984Sume return(1); 959129984Sume } 960129984Sume 961129984Sume /* Rule 2: Prefer matching scope. */ 962129984Sume if (dst1->aio_dstscope == dst1->aio_srcscope && 963129984Sume dst2->aio_dstscope != dst2->aio_srcscope) { 964129984Sume return(-1); 965129984Sume } 966129984Sume if (dst1->aio_dstscope != dst1->aio_srcscope && 967129984Sume dst2->aio_dstscope == dst2->aio_srcscope) { 968129984Sume return(1); 969129984Sume } 970129984Sume 971129984Sume /* Rule 3: Avoid deprecated addresses. */ 972129984Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 973129984Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 974129984Sume if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 975129984Sume (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 976129984Sume return(-1); 977129984Sume } 978129984Sume if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 979129984Sume !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 980129984Sume return(1); 981129984Sume } 982129984Sume } 983129984Sume 984129984Sume /* Rule 4: Prefer home addresses. */ 985129984Sume /* XXX: not implemented yet */ 986129984Sume 987129984Sume /* Rule 5: Prefer matching label. */ 988129984Sume#ifdef INET6 989129984Sume if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && 990129984Sume dst1->aio_srcpolicy->pc_policy.label == 991129984Sume dst1->aio_dstpolicy->pc_policy.label && 992129984Sume (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || 993129984Sume dst2->aio_srcpolicy->pc_policy.label != 994129984Sume dst2->aio_dstpolicy->pc_policy.label)) { 995129984Sume return(-1); 996129984Sume } 997129984Sume if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && 998129984Sume dst2->aio_srcpolicy->pc_policy.label == 999129984Sume dst2->aio_dstpolicy->pc_policy.label && 1000129984Sume (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || 1001129984Sume dst1->aio_srcpolicy->pc_policy.label != 1002129984Sume dst1->aio_dstpolicy->pc_policy.label)) { 1003129984Sume return(1); 1004129984Sume } 1005129984Sume#endif 1006129984Sume 1007129984Sume /* Rule 6: Prefer higher precedence. */ 1008129984Sume#ifdef INET6 1009129984Sume if (dst1->aio_dstpolicy && 1010129984Sume (dst2->aio_dstpolicy == NULL || 1011129984Sume dst1->aio_dstpolicy->pc_policy.preced > 1012129984Sume dst2->aio_dstpolicy->pc_policy.preced)) { 1013129984Sume return(-1); 1014129984Sume } 1015129984Sume if (dst2->aio_dstpolicy && 1016129984Sume (dst1->aio_dstpolicy == NULL || 1017129984Sume dst2->aio_dstpolicy->pc_policy.preced > 1018129984Sume dst1->aio_dstpolicy->pc_policy.preced)) { 1019129984Sume return(1); 1020129984Sume } 1021129984Sume#endif 1022129984Sume 1023129984Sume /* Rule 7: Prefer native transport. */ 1024129984Sume /* XXX: not implemented yet */ 1025129984Sume 1026129984Sume /* Rule 8: Prefer smaller scope. */ 1027129984Sume if (dst1->aio_dstscope >= 0 && 1028129984Sume dst1->aio_dstscope < dst2->aio_dstscope) { 1029129984Sume return(-1); 1030129984Sume } 1031129984Sume if (dst2->aio_dstscope >= 0 && 1032129984Sume dst2->aio_dstscope < dst1->aio_dstscope) { 1033129984Sume return(1); 1034129984Sume } 1035129984Sume 1036129984Sume /* 1037129984Sume * Rule 9: Use longest matching prefix. 1038129984Sume * We compare the match length in a same AF only. 1039129984Sume */ 1040129984Sume if (dst1->aio_sa.sa_family == dst2->aio_sa.sa_family) { 1041129984Sume if (dst1->aio_matchlen > dst2->aio_matchlen) { 1042129984Sume return(-1); 1043129984Sume } 1044129984Sume if (dst1->aio_matchlen < dst2->aio_matchlen) { 1045129984Sume return(1); 1046129984Sume } 1047129984Sume } 1048129984Sume 1049129984Sume /* Rule 10: Otherwise, leave the order unchanged. */ 1050129984Sume return(-1); 1051129984Sume} 1052129984Sume 1053126052Sume/* 1054129984Sume * Copy from scope.c. 1055129984Sume * XXX: we should standardize the functions and link them as standard 1056129984Sume * library. 1057129984Sume */ 1058129984Sumestatic int 1059157119Sumegai_addr2scopetype(struct sockaddr *sa) 1060129984Sume{ 1061129984Sume#ifdef INET6 1062129984Sume struct sockaddr_in6 *sa6; 1063129984Sume#endif 1064129984Sume struct sockaddr_in *sa4; 1065129984Sume 1066129984Sume switch(sa->sa_family) { 1067129984Sume#ifdef INET6 1068129984Sume case AF_INET6: 1069129984Sume sa6 = (struct sockaddr_in6 *)sa; 1070129984Sume if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 1071129984Sume /* just use the scope field of the multicast address */ 1072129984Sume return(sa6->sin6_addr.s6_addr[2] & 0x0f); 1073129984Sume } 1074129984Sume /* 1075129984Sume * Unicast addresses: map scope type to corresponding scope 1076129984Sume * value defined for multcast addresses. 1077129984Sume * XXX: hardcoded scope type values are bad... 1078129984Sume */ 1079129984Sume if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) 1080129984Sume return(1); /* node local scope */ 1081129984Sume if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) 1082129984Sume return(2); /* link-local scope */ 1083129984Sume if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) 1084129984Sume return(5); /* site-local scope */ 1085129984Sume return(14); /* global scope */ 1086129984Sume break; 1087129984Sume#endif 1088129984Sume case AF_INET: 1089129984Sume /* 1090129984Sume * IPv4 pseudo scoping according to RFC 3484. 1091129984Sume */ 1092129984Sume sa4 = (struct sockaddr_in *)sa; 1093129984Sume /* IPv4 autoconfiguration addresses have link-local scope. */ 1094129984Sume if (((u_char *)&sa4->sin_addr)[0] == 169 && 1095129984Sume ((u_char *)&sa4->sin_addr)[1] == 254) 1096129984Sume return(2); 1097129984Sume /* Private addresses have site-local scope. */ 1098129984Sume if (((u_char *)&sa4->sin_addr)[0] == 10 || 1099129984Sume (((u_char *)&sa4->sin_addr)[0] == 172 && 1100129984Sume (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || 1101129984Sume (((u_char *)&sa4->sin_addr)[0] == 192 && 1102129984Sume ((u_char *)&sa4->sin_addr)[1] == 168)) 1103129984Sume return(14); /* XXX: It should be 5 unless NAT */ 1104129984Sume /* Loopback addresses have link-local scope. */ 1105129984Sume if (((u_char *)&sa4->sin_addr)[0] == 127) 1106129984Sume return(2); 1107129984Sume return(14); 1108129984Sume break; 1109129984Sume default: 1110129984Sume errno = EAFNOSUPPORT; /* is this a good error? */ 1111129984Sume return(-1); 1112129984Sume } 1113129984Sume} 1114245225Sume#endif 1115