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. 4560296Sitojun * 3. All advertising materials mentioning features or use of this software 4660296Sitojun * must display the following acknowledgement: 4760296Sitojun * This product includes software developed by the University of 4860296Sitojun * California, Berkeley and its contributors. 4960296Sitojun * 4. Neither the name of the University nor the names of its contributors 5060296Sitojun * may be used to endorse or promote products derived from this software 5160296Sitojun * without specific prior written permission. 5260296Sitojun * 5360296Sitojun * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5460296Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5560296Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5660296Sitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5760296Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5860296Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5960296Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6060296Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6160296Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6260296Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6360296Sitojun * SUCH DAMAGE. 6460296Sitojun * - 6560296Sitojun * Portions Copyright (c) 1993 by Digital Equipment Corporation. 6660296Sitojun * 6760296Sitojun * Permission to use, copy, modify, and distribute this software for any 6860296Sitojun * purpose with or without fee is hereby granted, provided that the above 6960296Sitojun * copyright notice and this permission notice appear in all copies, and that 7060296Sitojun * the name of Digital Equipment Corporation not be used in advertising or 7160296Sitojun * publicity pertaining to distribution of the document or software without 7260296Sitojun * specific, written prior permission. 7360296Sitojun * 7460296Sitojun * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 7560296Sitojun * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 7660296Sitojun * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 7760296Sitojun * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 7860296Sitojun * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 7960296Sitojun * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 8060296Sitojun * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 8160296Sitojun * SOFTWARE. 8260296Sitojun * - 8360296Sitojun * --Copyright-- 8455163Sshin */ 8560296Sitojun 8655163Sshin/* 8755163Sshin * Atsushi Onoe <onoe@sm.sony.co.jp> 8855163Sshin */ 8955163Sshin 9092986Sobrien#include <sys/cdefs.h> 9192986Sobrien__FBSDID("$FreeBSD$"); 9292986Sobrien 9371579Sdeischen#include "namespace.h" 9455163Sshin#include <sys/param.h> 9555163Sshin#include <sys/socket.h> 9655163Sshin#include <sys/time.h> 9759411Sshin#include <sys/queue.h> 9855163Sshin#include <netinet/in.h> 99126052Sume#ifdef INET6 100126052Sume#include <net/if.h> 101126052Sume#include <net/if_var.h> 102126052Sume#include <sys/sysctl.h> 103129984Sume#include <sys/ioctl.h> 104126052Sume#include <netinet6/in6_var.h> /* XXX */ 105126052Sume#endif 10655163Sshin 10755163Sshin#include <arpa/inet.h> 10855163Sshin#include <arpa/nameser.h> 10955163Sshin 11059411Sshin#include <errno.h> 11155163Sshin#include <netdb.h> 11255163Sshin#include <resolv.h> 11355163Sshin#include <stdio.h> 11455163Sshin#include <stdlib.h> 11555163Sshin#include <string.h> 11665532Snectar#include <stdarg.h> 11765532Snectar#include <nsswitch.h> 11855163Sshin#include <unistd.h> 11971579Sdeischen#include "un-namespace.h" 120145602Sume#include "netdb_private.h" 121156960Sume#include "res_private.h" 12255163Sshin 12355163Sshin#ifndef MAXALIASES 12455163Sshin#define MAXALIASES 10 12555163Sshin#endif 12655163Sshin#ifndef MAXADDRS 12755163Sshin#define MAXADDRS 20 12855163Sshin#endif 12955163Sshin#ifndef MAXDNAME 13055163Sshin#define MAXDNAME 1025 13155163Sshin#endif 13255163Sshin 13355163Sshin#ifdef INET6 13455163Sshin#define ADDRLEN(af) ((af) == AF_INET6 ? sizeof(struct in6_addr) : \ 13555163Sshin sizeof(struct in_addr)) 13655163Sshin#else 13755163Sshin#define ADDRLEN(af) sizeof(struct in_addr) 13855163Sshin#endif 13955163Sshin 14055163Sshin#define MAPADDR(ab, ina) \ 14155163Sshindo { \ 14255163Sshin memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr)); \ 14355163Sshin memset((ab)->map_zero, 0, sizeof((ab)->map_zero)); \ 14455163Sshin memset((ab)->map_one, 0xff, sizeof((ab)->map_one)); \ 14555163Sshin} while (0) 14655163Sshin#define MAPADDRENABLED(flags) \ 14755163Sshin (((flags) & AI_V4MAPPED) || \ 148171671Sbushman (((flags) & AI_V4MAPPED_CFG))) 14955163Sshin 15055163Sshinunion inx_addr { 15155163Sshin struct in_addr in_addr; 15255163Sshin#ifdef INET6 15355163Sshin struct in6_addr in6_addr; 15455163Sshin#endif 15555163Sshin struct { 15655163Sshin u_char mau_zero[10]; 15755163Sshin u_char mau_one[2]; 15855163Sshin struct in_addr mau_inaddr; 15955163Sshin } map_addr_un; 16055163Sshin#define map_zero map_addr_un.mau_zero 16155163Sshin#define map_one map_addr_un.mau_one 16255163Sshin#define map_inaddr map_addr_un.mau_inaddr 16355163Sshin}; 16455163Sshin 165126052Sumestruct policyqueue { 166126052Sume TAILQ_ENTRY(policyqueue) pc_entry; 167126052Sume#ifdef INET6 168126052Sume struct in6_addrpolicy pc_policy; 169126052Sume#endif 170126052Sume}; 171126052SumeTAILQ_HEAD(policyhead, policyqueue); 172126052Sume 173129984Sume#define AIO_SRCFLAG_DEPRECATED 0x1 174129984Sume 175129984Sumestruct hp_order { 176129984Sume union { 177129984Sume struct sockaddr_storage aiou_ss; 178129984Sume struct sockaddr aiou_sa; 179129984Sume } aio_src_un; 180129984Sume#define aio_srcsa aio_src_un.aiou_sa 181129984Sume u_int32_t aio_srcflag; 182129984Sume int aio_srcscope; 183129984Sume int aio_dstscope; 184129984Sume struct policyqueue *aio_srcpolicy; 185129984Sume struct policyqueue *aio_dstpolicy; 186129984Sume union { 187129984Sume struct sockaddr_storage aiou_ss; 188129984Sume struct sockaddr aiou_sa; 189129984Sume } aio_un; 190129984Sume#define aio_sa aio_un.aiou_sa 191129984Sume int aio_matchlen; 192146700Sume char *aio_h_addr; 193129984Sume}; 194129984Sume 195156960Sumestatic struct hostent *_hpcopy(struct hostent *, int *); 196156960Sumestatic struct hostent *_hpaddr(int, const char *, void *, int *); 197171671Sbushman#ifdef INET6 198156960Sumestatic struct hostent *_hpmerge(struct hostent *, struct hostent *, int *); 199156960Sumestatic struct hostent *_hpmapv6(struct hostent *, int *); 20055163Sshin#endif 201156960Sumestatic struct hostent *_hpsort(struct hostent *, res_state); 20255163Sshin 203245553Sume#ifdef INET6 204156960Sumestatic struct hostent *_hpreorder(struct hostent *); 205126052Sumestatic int get_addrselectpolicy(struct policyhead *); 206126052Sumestatic void free_addrselectpolicy(struct policyhead *); 207126052Sumestatic struct policyqueue *match_addrselectpolicy(struct sockaddr *, 208126052Sume struct policyhead *); 209129984Sumestatic void set_source(struct hp_order *, struct policyhead *); 210129984Sumestatic int matchlen(struct sockaddr *, struct sockaddr *); 211129984Sumestatic int comp_dst(const void *, const void *); 212129984Sumestatic int gai_addr2scopetype(struct sockaddr *); 213245553Sume#endif 214126052Sume 21555163Sshin/* 216171671Sbushman * Functions defined in RFC2553 217171671Sbushman * getipnodebyname, getipnodebyaddr, freehostent 21855163Sshin */ 21955163Sshin 220171671Sbushmanstruct hostent * 221171671Sbushmangetipnodebyname(const char *name, int af, int flags, int *errp) 22255163Sshin{ 223171671Sbushman struct hostent *hp; 224171671Sbushman union inx_addr addrbuf; 225158115Sume res_state statp; 226171671Sbushman u_long options; 227158115Sume 228171671Sbushman switch (af) { 229171671Sbushman case AF_INET: 230171671Sbushman#ifdef INET6 231171671Sbushman case AF_INET6: 232171671Sbushman#endif 233158115Sume break; 234158115Sume default: 235171671Sbushman *errp = NO_RECOVERY; 236171671Sbushman return NULL; 237158115Sume } 238158115Sume 23955163Sshin if (flags & AI_ADDRCONFIG) { 24055163Sshin int s; 24155163Sshin 242144527Sume if ((s = _socket(af, SOCK_DGRAM, 0)) < 0) 243144527Sume return NULL; 24455163Sshin /* 24555163Sshin * TODO: 24655163Sshin * Note that implementation dependent test for address 24755163Sshin * configuration should be done everytime called 24855163Sshin * (or apropriate interval), 24955163Sshin * because addresses will be dynamically assigned or deleted. 25055163Sshin */ 251144527Sume _close(s); 25255163Sshin } 253171671Sbushman 25455163Sshin#ifdef INET6 25555163Sshin /* special case for literal address */ 25655163Sshin if (inet_pton(AF_INET6, name, &addrbuf) == 1) { 25755163Sshin if (af != AF_INET6) { 25855163Sshin *errp = HOST_NOT_FOUND; 25955163Sshin return NULL; 26055163Sshin } 26155163Sshin return _hpaddr(af, name, &addrbuf, errp); 26255163Sshin } 26355163Sshin#endif 26457107Sshin if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) { 26555163Sshin if (af != AF_INET) { 26655163Sshin if (MAPADDRENABLED(flags)) { 26755163Sshin MAPADDR(&addrbuf, &addrbuf.in_addr); 26855163Sshin } else { 26955163Sshin *errp = HOST_NOT_FOUND; 27055163Sshin return NULL; 27155163Sshin } 27255163Sshin } 27355163Sshin return _hpaddr(af, name, &addrbuf, errp); 27455163Sshin } 27555163Sshin 276171671Sbushman 277156960Sume statp = __res_state(); 278156960Sume if ((statp->options & RES_INIT) == 0) { 279156960Sume if (res_ninit(statp) < 0) { 280156960Sume *errp = NETDB_INTERNAL; 281156960Sume return NULL; 282156960Sume } 283156960Sume } 284171671Sbushman 285171671Sbushman options = statp->options; 286171671Sbushman statp->options &= ~RES_USE_INET6; 287171671Sbushman 288171671Sbushman hp = gethostbyname2(name, af); 289171671Sbushman hp = _hpcopy(hp, errp); 290245553Sume#ifdef INET6 291245553Sume if (af == AF_INET6) 292245553Sume hp = _hpreorder(hp); 293156960Sume 294146192Sume if (af == AF_INET6 && ((flags & AI_ALL) || hp == NULL) && 295146192Sume MAPADDRENABLED(flags)) { 296171671Sbushman struct hostent *hp2 = gethostbyname2(name, AF_INET); 29755163Sshin if (hp == NULL) 298171671Sbushman if (hp2 == NULL) 299171671Sbushman *errp = statp->res_h_errno; 300171671Sbushman else 301171671Sbushman hp = _hpmapv6(hp2, errp); 30255163Sshin else { 303171671Sbushman if (hp2 && strcmp(hp->h_name, hp2->h_name) == 0) { 304171671Sbushman struct hostent *hpb = hp; 305171671Sbushman hp = _hpmerge(hpb, hp2, errp); 306171671Sbushman freehostent(hpb); 30755163Sshin } 30855163Sshin } 30955163Sshin } 31055163Sshin#endif 311171671Sbushman 312171671Sbushman if (hp == NULL) 313171671Sbushman *errp = statp->res_h_errno; 314171671Sbushman 315171671Sbushman statp->options = options; 316245553Sume return _hpsort(hp, statp); 31755163Sshin} 31855163Sshin 31955163Sshinstruct hostent * 32055163Sshingetipnodebyaddr(const void *src, size_t len, int af, int *errp) 32155163Sshin{ 32255163Sshin struct hostent *hp; 323171671Sbushman res_state statp; 324171671Sbushman u_long options; 325171671Sbushman 32655163Sshin#ifdef INET6 32755163Sshin struct in6_addr addrbuf; 32855163Sshin#else 32955163Sshin struct in_addr addrbuf; 33055163Sshin#endif 331171671Sbushman 33255163Sshin switch (af) { 33355163Sshin case AF_INET: 33455163Sshin if (len != sizeof(struct in_addr)) { 33555163Sshin *errp = NO_RECOVERY; 33655163Sshin return NULL; 33755163Sshin } 33855163Sshin if ((long)src & ~(sizeof(struct in_addr) - 1)) { 33955163Sshin memcpy(&addrbuf, src, len); 34055163Sshin src = &addrbuf; 34155163Sshin } 34255163Sshin if (((struct in_addr *)src)->s_addr == 0) 34355163Sshin return NULL; 34455163Sshin break; 34555163Sshin#ifdef INET6 34655163Sshin case AF_INET6: 34755163Sshin if (len != sizeof(struct in6_addr)) { 34855163Sshin *errp = NO_RECOVERY; 34955163Sshin return NULL; 35055163Sshin } 35155163Sshin if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) { /*XXX*/ 35255163Sshin memcpy(&addrbuf, src, len); 35355163Sshin src = &addrbuf; 35455163Sshin } 35555877Sshin if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src)) 35655877Sshin return NULL; 35755163Sshin if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src) 35855163Sshin || IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) { 35955163Sshin src = (char *)src + 36055163Sshin (sizeof(struct in6_addr) - sizeof(struct in_addr)); 36155163Sshin af = AF_INET; 36255163Sshin len = sizeof(struct in_addr); 36355163Sshin } 36455163Sshin break; 36555163Sshin#endif 36655163Sshin default: 36755163Sshin *errp = NO_RECOVERY; 36855163Sshin return NULL; 36955163Sshin } 37055163Sshin 371171671Sbushman statp = __res_state(); 372171671Sbushman if ((statp->options & RES_INIT) == 0) { 373171671Sbushman if (res_ninit(statp) < 0) { 374171671Sbushman RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 375171671Sbushman return NULL; 376171671Sbushman } 377171671Sbushman } 378171671Sbushman 379171671Sbushman options = statp->options; 380171671Sbushman statp->options &= ~RES_USE_INET6; 381171671Sbushman 382171671Sbushman hp = gethostbyaddr(src, len, af); 383171671Sbushman if (hp == NULL) 384171671Sbushman *errp = statp->res_h_errno; 385171671Sbushman 386171671Sbushman statp->options = options; 387171671Sbushman return (_hpcopy(hp, errp)); 38855163Sshin} 38955163Sshin 39055163Sshinvoid 39155163Sshinfreehostent(struct hostent *ptr) 39255163Sshin{ 39355163Sshin free(ptr); 39455163Sshin} 39555163Sshin 39655163Sshin/* 39755163Sshin * Private utility functions 39855163Sshin */ 39955163Sshin 40055163Sshin/* 40155163Sshin * _hpcopy: allocate and copy hostent structure 40255163Sshin */ 40355163Sshinstatic struct hostent * 40455163Sshin_hpcopy(struct hostent *hp, int *errp) 40555163Sshin{ 40655163Sshin struct hostent *nhp; 40755163Sshin char *cp, **pp; 40855163Sshin int size, addrsize; 40955163Sshin int nalias = 0, naddr = 0; 41055163Sshin int al_off; 41155163Sshin int i; 41255163Sshin 41355163Sshin if (hp == NULL) 41455163Sshin return hp; 41555163Sshin 41655163Sshin /* count size to be allocated */ 41755163Sshin size = sizeof(struct hostent); 41863490Sume if (hp->h_name != NULL) 41955163Sshin size += strlen(hp->h_name) + 1; 42055163Sshin if ((pp = hp->h_aliases) != NULL) { 42155163Sshin for (i = 0; *pp != NULL; i++, pp++) { 42255163Sshin if (**pp != '\0') { 42355163Sshin size += strlen(*pp) + 1; 42455163Sshin nalias++; 42555163Sshin } 42655163Sshin } 42755163Sshin } 42855163Sshin /* adjust alignment */ 42955163Sshin size = ALIGN(size); 43055163Sshin al_off = size; 43155163Sshin size += sizeof(char *) * (nalias + 1); 43255163Sshin addrsize = ALIGN(hp->h_length); 43355163Sshin if ((pp = hp->h_addr_list) != NULL) { 43455163Sshin while (*pp++ != NULL) 43555163Sshin naddr++; 43655163Sshin } 43755163Sshin size += addrsize * naddr; 43855163Sshin size += sizeof(char *) * (naddr + 1); 43955163Sshin 44055163Sshin /* copy */ 44155163Sshin if ((nhp = (struct hostent *)malloc(size)) == NULL) { 44255163Sshin *errp = TRY_AGAIN; 44355163Sshin return NULL; 44455163Sshin } 44555163Sshin cp = (char *)&nhp[1]; 44663490Sume if (hp->h_name != NULL) { 44755163Sshin nhp->h_name = cp; 44855163Sshin strcpy(cp, hp->h_name); 44955163Sshin cp += strlen(cp) + 1; 45055163Sshin } else 45155163Sshin nhp->h_name = NULL; 45255163Sshin nhp->h_aliases = (char **)((char *)nhp + al_off); 45355163Sshin if ((pp = hp->h_aliases) != NULL) { 45455163Sshin for (i = 0; *pp != NULL; pp++) { 45555163Sshin if (**pp != '\0') { 45655163Sshin nhp->h_aliases[i++] = cp; 45755163Sshin strcpy(cp, *pp); 45855163Sshin cp += strlen(cp) + 1; 45955163Sshin } 46055163Sshin } 46155163Sshin } 46255163Sshin nhp->h_aliases[nalias] = NULL; 46355163Sshin cp = (char *)&nhp->h_aliases[nalias + 1]; 46455163Sshin nhp->h_addrtype = hp->h_addrtype; 46555163Sshin nhp->h_length = hp->h_length; 46655163Sshin nhp->h_addr_list = (char **)cp; 46755163Sshin if ((pp = hp->h_addr_list) != NULL) { 46855163Sshin cp = (char *)&nhp->h_addr_list[naddr + 1]; 46955163Sshin for (i = 0; *pp != NULL; pp++) { 47055163Sshin nhp->h_addr_list[i++] = cp; 47155163Sshin memcpy(cp, *pp, hp->h_length); 47255163Sshin cp += addrsize; 47355163Sshin } 47455163Sshin } 47555163Sshin nhp->h_addr_list[naddr] = NULL; 47655163Sshin return nhp; 47755163Sshin} 47855163Sshin 47955163Sshin/* 48055163Sshin * _hpaddr: construct hostent structure with one address 48155163Sshin */ 48255163Sshinstatic struct hostent * 48355163Sshin_hpaddr(int af, const char *name, void *addr, int *errp) 48455163Sshin{ 48555163Sshin struct hostent *hp, hpbuf; 48655163Sshin char *addrs[2]; 48755163Sshin 48855163Sshin hp = &hpbuf; 48955163Sshin hp->h_name = (char *)name; 49055163Sshin hp->h_aliases = NULL; 49155163Sshin hp->h_addrtype = af; 49255163Sshin hp->h_length = ADDRLEN(af); 49355163Sshin hp->h_addr_list = addrs; 49455163Sshin addrs[0] = (char *)addr; 49555163Sshin addrs[1] = NULL; 496171671Sbushman return (_hpcopy(hp, errp)); 49755163Sshin} 49855163Sshin 499171671Sbushman#ifdef INET6 50055163Sshin/* 50155163Sshin * _hpmerge: merge 2 hostent structure, arguments will be freed 50255163Sshin */ 50355163Sshinstatic struct hostent * 50455163Sshin_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp) 50555163Sshin{ 50655163Sshin int i, j; 50755163Sshin int naddr, nalias; 50855163Sshin char **pp; 50955163Sshin struct hostent *hp, hpbuf; 51055163Sshin char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1]; 51155163Sshin union inx_addr addrbuf[MAXADDRS]; 51255163Sshin 51355163Sshin if (hp1 == NULL) 514171671Sbushman return _hpcopy(hp2, errp); 51555163Sshin if (hp2 == NULL) 516171671Sbushman return _hpcopy(hp1, errp); 51755163Sshin 51855163Sshin#define HP(i) (i == 1 ? hp1 : hp2) 51955163Sshin hp = &hpbuf; 52055163Sshin hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name); 52155163Sshin hp->h_aliases = aliases; 52255163Sshin nalias = 0; 52355163Sshin for (i = 1; i <= 2; i++) { 52455163Sshin if ((pp = HP(i)->h_aliases) == NULL) 52555163Sshin continue; 52655163Sshin for (; nalias < MAXALIASES && *pp != NULL; pp++) { 52755163Sshin /* check duplicates */ 52855163Sshin for (j = 0; j < nalias; j++) 52955163Sshin if (strcasecmp(*pp, aliases[j]) == 0) 53055163Sshin break; 53155163Sshin if (j == nalias) 53255163Sshin aliases[nalias++] = *pp; 53355163Sshin } 53455163Sshin } 53555163Sshin aliases[nalias] = NULL; 53655163Sshin if (hp1->h_length != hp2->h_length) { 53755163Sshin hp->h_addrtype = AF_INET6; 53855163Sshin hp->h_length = sizeof(struct in6_addr); 53955163Sshin } else { 54055163Sshin hp->h_addrtype = hp1->h_addrtype; 54155163Sshin hp->h_length = hp1->h_length; 54255163Sshin } 543171671Sbushman 54455163Sshin hp->h_addr_list = addrs; 54555163Sshin naddr = 0; 54655163Sshin for (i = 1; i <= 2; i++) { 54755163Sshin if ((pp = HP(i)->h_addr_list) == NULL) 54855163Sshin continue; 54955163Sshin if (HP(i)->h_length == hp->h_length) { 55055163Sshin while (naddr < MAXADDRS && *pp != NULL) 55155163Sshin addrs[naddr++] = *pp++; 55255163Sshin } else { 55355163Sshin /* copy IPv4 addr as mapped IPv6 addr */ 55455163Sshin while (naddr < MAXADDRS && *pp != NULL) { 55555163Sshin MAPADDR(&addrbuf[naddr], *pp++); 55655163Sshin addrs[naddr] = (char *)&addrbuf[naddr]; 55755163Sshin naddr++; 55855163Sshin } 55955163Sshin } 56055163Sshin } 56155163Sshin addrs[naddr] = NULL; 562171671Sbushman return (_hpcopy(hp, errp)); 56355163Sshin} 564171671Sbushman#endif 56555163Sshin 56655163Sshin/* 56755163Sshin * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses 56855163Sshin */ 56955163Sshin#ifdef INET6 57055163Sshinstatic struct hostent * 57155163Sshin_hpmapv6(struct hostent *hp, int *errp) 57255163Sshin{ 573171671Sbushman struct hostent hp6; 57455163Sshin 57555163Sshin if (hp == NULL) 57655163Sshin return NULL; 57755163Sshin if (hp->h_addrtype == AF_INET6) 578171671Sbushman return _hpcopy(hp, errp); 57955163Sshin 580171671Sbushman memset(&hp6, 0, sizeof(struct hostent)); 581171671Sbushman hp6.h_addrtype = AF_INET6; 582171671Sbushman hp6.h_length = sizeof(struct in6_addr); 583171671Sbushman return _hpmerge(&hp6, hp, errp); 58455163Sshin} 58555163Sshin#endif 58655163Sshin 58755163Sshin/* 58855163Sshin * _hpsort: sort address by sortlist 58955163Sshin */ 59055163Sshinstatic struct hostent * 591156960Sume_hpsort(struct hostent *hp, res_state statp) 59255163Sshin{ 59355163Sshin int i, j, n; 59455163Sshin u_char *ap, *sp, *mp, **pp; 59555163Sshin char t; 59655163Sshin char order[MAXADDRS]; 597156960Sume int nsort = statp->nsort; 59855163Sshin 59955163Sshin if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0) 60055163Sshin return hp; 60155163Sshin for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) { 60255163Sshin for (j = 0; j < nsort; j++) { 60355163Sshin#ifdef INET6 604156960Sume if (statp->_u._ext.ext->sort_list[j].af != 605156960Sume hp->h_addrtype) 60655163Sshin continue; 607156960Sume sp = (u_char *)&statp->_u._ext.ext->sort_list[j].addr; 608156960Sume mp = (u_char *)&statp->_u._ext.ext->sort_list[j].mask; 60955163Sshin#else 610156960Sume sp = (u_char *)&statp->sort_list[j].addr; 611156960Sume mp = (u_char *)&statp->sort_list[j].mask; 61255163Sshin#endif 61355163Sshin for (n = 0; n < hp->h_length; n++) { 61455163Sshin if ((ap[n] & mp[n]) != sp[n]) 61555163Sshin break; 61655163Sshin } 61755163Sshin if (n == hp->h_length) 61855163Sshin break; 61955163Sshin } 62055163Sshin order[i] = j; 62155163Sshin } 62255163Sshin n = i; 62355163Sshin pp = (u_char **)hp->h_addr_list; 62455163Sshin for (i = 0; i < n - 1; i++) { 62555163Sshin for (j = i + 1; j < n; j++) { 62655163Sshin if (order[i] > order[j]) { 62755163Sshin ap = pp[i]; 62855163Sshin pp[i] = pp[j]; 62955163Sshin pp[j] = ap; 63055163Sshin t = order[i]; 63155163Sshin order[i] = order[j]; 63255163Sshin order[j] = t; 63355163Sshin } 63455163Sshin } 63555163Sshin } 63655163Sshin return hp; 63755163Sshin} 63855163Sshin 639245553Sume#ifdef INET6 64055163Sshin/* 641126052Sume * _hpreorder: sort address by default address selection 642126052Sume */ 643126052Sumestatic struct hostent * 644126052Sume_hpreorder(struct hostent *hp) 645126052Sume{ 646129984Sume struct hp_order *aio; 647129984Sume int i, n; 648146700Sume char *ap; 649129984Sume struct sockaddr *sa; 650126052Sume struct policyhead policyhead; 651126052Sume 652129984Sume if (hp == NULL) 653126052Sume return hp; 654126052Sume 655129984Sume switch (hp->h_addrtype) { 656129984Sume case AF_INET: 657129984Sume#ifdef INET6 658129984Sume case AF_INET6: 659129984Sume#endif 660129984Sume break; 661129984Sume default: 662129984Sume free_addrselectpolicy(&policyhead); 663129984Sume return hp; 664129984Sume } 665129984Sume 666129984Sume /* count the number of addrinfo elements for sorting. */ 667129984Sume for (n = 0; hp->h_addr_list[n] != NULL; n++) 668129984Sume ; 669129984Sume 670129984Sume /* 671129984Sume * If the number is small enough, we can skip the reordering process. 672129984Sume */ 673129984Sume if (n <= 1) 674129984Sume return hp; 675129984Sume 676129984Sume /* allocate a temporary array for sort and initialization of it. */ 677129984Sume if ((aio = malloc(sizeof(*aio) * n)) == NULL) 678129984Sume return hp; /* give up reordering */ 679129984Sume memset(aio, 0, sizeof(*aio) * n); 680129984Sume 681126052Sume /* retrieve address selection policy from the kernel */ 682126052Sume TAILQ_INIT(&policyhead); 683126052Sume if (!get_addrselectpolicy(&policyhead)) { 684126052Sume /* no policy is installed into kernel, we don't sort. */ 685129984Sume free(aio); 686126052Sume return hp; 687126052Sume } 688126052Sume 689129984Sume for (i = 0; i < n; i++) { 690146700Sume ap = hp->h_addr_list[i]; 691129984Sume aio[i].aio_h_addr = ap; 692129984Sume sa = &aio[i].aio_sa; 693129984Sume switch (hp->h_addrtype) { 694129984Sume case AF_INET: 695129984Sume sa->sa_family = AF_INET; 696129984Sume sa->sa_len = sizeof(struct sockaddr_in); 697129984Sume memcpy(&((struct sockaddr_in *)sa)->sin_addr, ap, 698126052Sume sizeof(struct in_addr)); 699129984Sume break; 700126052Sume#ifdef INET6 701129984Sume case AF_INET6: 702126052Sume if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { 703129984Sume sa->sa_family = AF_INET; 704129984Sume sa->sa_len = sizeof(struct sockaddr_in); 705129984Sume memcpy(&((struct sockaddr_in *)sa)->sin_addr, 706126052Sume &ap[12], sizeof(struct in_addr)); 707126052Sume } else { 708129984Sume sa->sa_family = AF_INET6; 709129984Sume sa->sa_len = sizeof(struct sockaddr_in6); 710129984Sume memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr, 711126052Sume ap, sizeof(struct in6_addr)); 712126052Sume } 713129984Sume break; 714129984Sume#endif 715126052Sume } 716129984Sume aio[i].aio_dstscope = gai_addr2scopetype(sa); 717129984Sume aio[i].aio_dstpolicy = match_addrselectpolicy(sa, &policyhead); 718129984Sume set_source(&aio[i], &policyhead); 719126052Sume } 720126052Sume 721126052Sume /* perform sorting. */ 722129984Sume qsort(aio, n, sizeof(*aio), comp_dst); 723126052Sume 724129984Sume /* reorder the h_addr_list. */ 725129984Sume for (i = 0; i < n; i++) 726129984Sume hp->h_addr_list[i] = aio[i].aio_h_addr; 727129984Sume 728126052Sume /* cleanup and return */ 729129984Sume free(aio); 730126052Sume free_addrselectpolicy(&policyhead); 731126052Sume return hp; 732126052Sume} 733126052Sume 734126052Sumestatic int 735157119Sumeget_addrselectpolicy(struct policyhead *head) 736126052Sume{ 737126052Sume#ifdef INET6 738126052Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; 739126052Sume size_t l; 740126052Sume char *buf; 741126052Sume struct in6_addrpolicy *pol, *ep; 742126052Sume 743126052Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) 744126052Sume return (0); 745126052Sume if ((buf = malloc(l)) == NULL) 746126052Sume return (0); 747126052Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 748126052Sume free(buf); 749126052Sume return (0); 750126052Sume } 751126052Sume 752126052Sume ep = (struct in6_addrpolicy *)(buf + l); 753126052Sume for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { 754126052Sume struct policyqueue *new; 755126052Sume 756126052Sume if ((new = malloc(sizeof(*new))) == NULL) { 757126052Sume free_addrselectpolicy(head); /* make the list empty */ 758126052Sume break; 759126052Sume } 760126052Sume new->pc_policy = *pol; 761126052Sume TAILQ_INSERT_TAIL(head, new, pc_entry); 762126052Sume } 763126052Sume 764126052Sume free(buf); 765126052Sume return (1); 766126052Sume#else 767126052Sume return (0); 768126052Sume#endif 769126052Sume} 770126052Sume 771126052Sumestatic void 772157119Sumefree_addrselectpolicy(struct policyhead *head) 773126052Sume{ 774126052Sume struct policyqueue *ent, *nent; 775126052Sume 776126052Sume for (ent = TAILQ_FIRST(head); ent; ent = nent) { 777126052Sume nent = TAILQ_NEXT(ent, pc_entry); 778126052Sume TAILQ_REMOVE(head, ent, pc_entry); 779126052Sume free(ent); 780126052Sume } 781126052Sume} 782126052Sume 783126052Sumestatic struct policyqueue * 784157119Sumematch_addrselectpolicy(struct sockaddr *addr, struct policyhead *head) 785126052Sume{ 786126052Sume#ifdef INET6 787126052Sume struct policyqueue *ent, *bestent = NULL; 788126052Sume struct in6_addrpolicy *pol; 789126052Sume int matchlen, bestmatchlen = -1; 790126052Sume u_char *mp, *ep, *k, *p, m; 791126052Sume struct sockaddr_in6 key; 792126052Sume 793126052Sume switch(addr->sa_family) { 794126052Sume case AF_INET6: 795126052Sume key = *(struct sockaddr_in6 *)addr; 796126052Sume break; 797126052Sume case AF_INET: 798126052Sume /* convert the address into IPv4-mapped IPv6 address. */ 799126052Sume memset(&key, 0, sizeof(key)); 800126052Sume key.sin6_family = AF_INET6; 801126052Sume key.sin6_len = sizeof(key); 802126052Sume key.sin6_addr.s6_addr[10] = 0xff; 803126052Sume key.sin6_addr.s6_addr[11] = 0xff; 804126052Sume memcpy(&key.sin6_addr.s6_addr[12], 805126052Sume &((struct sockaddr_in *)addr)->sin_addr, 4); 806126052Sume break; 807126052Sume default: 808126052Sume return(NULL); 809126052Sume } 810126052Sume 811126052Sume for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { 812126052Sume pol = &ent->pc_policy; 813126052Sume matchlen = 0; 814126052Sume 815126052Sume mp = (u_char *)&pol->addrmask.sin6_addr; 816126052Sume ep = mp + 16; /* XXX: scope field? */ 817126052Sume k = (u_char *)&key.sin6_addr; 818126052Sume p = (u_char *)&pol->addr.sin6_addr; 819126052Sume for (; mp < ep && *mp; mp++, k++, p++) { 820126052Sume m = *mp; 821126052Sume if ((*k & m) != *p) 822126052Sume goto next; /* not match */ 823126052Sume if (m == 0xff) /* short cut for a typical case */ 824126052Sume matchlen += 8; 825126052Sume else { 826126052Sume while (m >= 0x80) { 827126052Sume matchlen++; 828126052Sume m <<= 1; 829126052Sume } 830126052Sume } 831126052Sume } 832126052Sume 833126052Sume /* matched. check if this is better than the current best. */ 834126052Sume if (matchlen > bestmatchlen) { 835126052Sume bestent = ent; 836126052Sume bestmatchlen = matchlen; 837126052Sume } 838126052Sume 839126052Sume next: 840126052Sume continue; 841126052Sume } 842126052Sume 843126052Sume return(bestent); 844126052Sume#else 845126052Sume return(NULL); 846126052Sume#endif 847126052Sume 848126052Sume} 849126052Sume 850129984Sumestatic void 851157119Sumeset_source(struct hp_order *aio, struct policyhead *ph) 852129984Sume{ 853129984Sume struct sockaddr_storage ss = aio->aio_un.aiou_ss; 854145786Sume socklen_t srclen; 855145786Sume int s; 856129984Sume 857129984Sume /* set unspec ("no source is available"), just in case */ 858129984Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 859129984Sume aio->aio_srcscope = -1; 860129984Sume 861129984Sume switch(ss.ss_family) { 862129984Sume case AF_INET: 863129984Sume ((struct sockaddr_in *)&ss)->sin_port = htons(1); 864129984Sume break; 865129984Sume#ifdef INET6 866129984Sume case AF_INET6: 867129984Sume ((struct sockaddr_in6 *)&ss)->sin6_port = htons(1); 868129984Sume break; 869129984Sume#endif 870129984Sume default: /* ignore unsupported AFs explicitly */ 871129984Sume return; 872129984Sume } 873129984Sume 874129984Sume /* open a socket to get the source address for the given dst */ 875129984Sume if ((s = _socket(ss.ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) 876129984Sume return; /* give up */ 877129984Sume if (_connect(s, (struct sockaddr *)&ss, ss.ss_len) < 0) 878129984Sume goto cleanup; 879129984Sume srclen = ss.ss_len; 880129984Sume if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { 881129984Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 882129984Sume goto cleanup; 883129984Sume } 884129984Sume aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); 885129984Sume aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); 886129984Sume aio->aio_matchlen = matchlen(&aio->aio_srcsa, (struct sockaddr *)&ss); 887129984Sume#ifdef INET6 888129984Sume if (ss.ss_family == AF_INET6) { 889129984Sume struct in6_ifreq ifr6; 890129984Sume u_int32_t flags6; 891129984Sume 892129984Sume memset(&ifr6, 0, sizeof(ifr6)); 893129984Sume memcpy(&ifr6.ifr_addr, &ss, ss.ss_len); 894129984Sume if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { 895129984Sume flags6 = ifr6.ifr_ifru.ifru_flags6; 896129984Sume if ((flags6 & IN6_IFF_DEPRECATED)) 897129984Sume aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; 898129984Sume } 899129984Sume } 900129984Sume#endif 901129984Sume 902129984Sume cleanup: 903129984Sume _close(s); 904129984Sume return; 905129984Sume} 906129984Sume 907129984Sumestatic int 908157119Sumematchlen(struct sockaddr *src, struct sockaddr *dst) 909129984Sume{ 910129984Sume int match = 0; 911129984Sume u_char *s, *d; 912129984Sume u_char *lim, r; 913129984Sume int addrlen; 914129984Sume 915129984Sume switch (src->sa_family) { 916129984Sume#ifdef INET6 917129984Sume case AF_INET6: 918129984Sume s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; 919129984Sume d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; 920129984Sume addrlen = sizeof(struct in6_addr); 921129984Sume lim = s + addrlen; 922129984Sume break; 923129984Sume#endif 924129984Sume case AF_INET: 925146222Sgnn s = (u_char *)&((struct sockaddr_in *)src)->sin_addr; 926146222Sgnn d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr; 927129984Sume addrlen = sizeof(struct in_addr); 928129984Sume lim = s + addrlen; 929129984Sume break; 930129984Sume default: 931129984Sume return(0); 932129984Sume } 933129984Sume 934129984Sume while (s < lim) 935129984Sume if ((r = (*d++ ^ *s++)) != 0) { 936129984Sume while (r < addrlen * 8) { 937129984Sume match++; 938129984Sume r <<= 1; 939129984Sume } 940129984Sume break; 941129984Sume } else 942129984Sume match += 8; 943129984Sume return(match); 944129984Sume} 945129984Sume 946129984Sumestatic int 947157119Sumecomp_dst(const void *arg1, const void *arg2) 948129984Sume{ 949129984Sume const struct hp_order *dst1 = arg1, *dst2 = arg2; 950129984Sume 951129984Sume /* 952129984Sume * Rule 1: Avoid unusable destinations. 953129984Sume * XXX: we currently do not consider if an appropriate route exists. 954129984Sume */ 955129984Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 956129984Sume dst2->aio_srcsa.sa_family == AF_UNSPEC) { 957129984Sume return(-1); 958129984Sume } 959129984Sume if (dst1->aio_srcsa.sa_family == AF_UNSPEC && 960129984Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 961129984Sume return(1); 962129984Sume } 963129984Sume 964129984Sume /* Rule 2: Prefer matching scope. */ 965129984Sume if (dst1->aio_dstscope == dst1->aio_srcscope && 966129984Sume dst2->aio_dstscope != dst2->aio_srcscope) { 967129984Sume return(-1); 968129984Sume } 969129984Sume if (dst1->aio_dstscope != dst1->aio_srcscope && 970129984Sume dst2->aio_dstscope == dst2->aio_srcscope) { 971129984Sume return(1); 972129984Sume } 973129984Sume 974129984Sume /* Rule 3: Avoid deprecated addresses. */ 975129984Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 976129984Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 977129984Sume if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 978129984Sume (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 979129984Sume return(-1); 980129984Sume } 981129984Sume if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 982129984Sume !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 983129984Sume return(1); 984129984Sume } 985129984Sume } 986129984Sume 987129984Sume /* Rule 4: Prefer home addresses. */ 988129984Sume /* XXX: not implemented yet */ 989129984Sume 990129984Sume /* Rule 5: Prefer matching label. */ 991129984Sume#ifdef INET6 992129984Sume if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && 993129984Sume dst1->aio_srcpolicy->pc_policy.label == 994129984Sume dst1->aio_dstpolicy->pc_policy.label && 995129984Sume (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || 996129984Sume dst2->aio_srcpolicy->pc_policy.label != 997129984Sume dst2->aio_dstpolicy->pc_policy.label)) { 998129984Sume return(-1); 999129984Sume } 1000129984Sume if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && 1001129984Sume dst2->aio_srcpolicy->pc_policy.label == 1002129984Sume dst2->aio_dstpolicy->pc_policy.label && 1003129984Sume (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || 1004129984Sume dst1->aio_srcpolicy->pc_policy.label != 1005129984Sume dst1->aio_dstpolicy->pc_policy.label)) { 1006129984Sume return(1); 1007129984Sume } 1008129984Sume#endif 1009129984Sume 1010129984Sume /* Rule 6: Prefer higher precedence. */ 1011129984Sume#ifdef INET6 1012129984Sume if (dst1->aio_dstpolicy && 1013129984Sume (dst2->aio_dstpolicy == NULL || 1014129984Sume dst1->aio_dstpolicy->pc_policy.preced > 1015129984Sume dst2->aio_dstpolicy->pc_policy.preced)) { 1016129984Sume return(-1); 1017129984Sume } 1018129984Sume if (dst2->aio_dstpolicy && 1019129984Sume (dst1->aio_dstpolicy == NULL || 1020129984Sume dst2->aio_dstpolicy->pc_policy.preced > 1021129984Sume dst1->aio_dstpolicy->pc_policy.preced)) { 1022129984Sume return(1); 1023129984Sume } 1024129984Sume#endif 1025129984Sume 1026129984Sume /* Rule 7: Prefer native transport. */ 1027129984Sume /* XXX: not implemented yet */ 1028129984Sume 1029129984Sume /* Rule 8: Prefer smaller scope. */ 1030129984Sume if (dst1->aio_dstscope >= 0 && 1031129984Sume dst1->aio_dstscope < dst2->aio_dstscope) { 1032129984Sume return(-1); 1033129984Sume } 1034129984Sume if (dst2->aio_dstscope >= 0 && 1035129984Sume dst2->aio_dstscope < dst1->aio_dstscope) { 1036129984Sume return(1); 1037129984Sume } 1038129984Sume 1039129984Sume /* 1040129984Sume * Rule 9: Use longest matching prefix. 1041129984Sume * We compare the match length in a same AF only. 1042129984Sume */ 1043129984Sume if (dst1->aio_sa.sa_family == dst2->aio_sa.sa_family) { 1044129984Sume if (dst1->aio_matchlen > dst2->aio_matchlen) { 1045129984Sume return(-1); 1046129984Sume } 1047129984Sume if (dst1->aio_matchlen < dst2->aio_matchlen) { 1048129984Sume return(1); 1049129984Sume } 1050129984Sume } 1051129984Sume 1052129984Sume /* Rule 10: Otherwise, leave the order unchanged. */ 1053129984Sume return(-1); 1054129984Sume} 1055129984Sume 1056126052Sume/* 1057129984Sume * Copy from scope.c. 1058129984Sume * XXX: we should standardize the functions and link them as standard 1059129984Sume * library. 1060129984Sume */ 1061129984Sumestatic int 1062157119Sumegai_addr2scopetype(struct sockaddr *sa) 1063129984Sume{ 1064129984Sume#ifdef INET6 1065129984Sume struct sockaddr_in6 *sa6; 1066129984Sume#endif 1067129984Sume struct sockaddr_in *sa4; 1068129984Sume 1069129984Sume switch(sa->sa_family) { 1070129984Sume#ifdef INET6 1071129984Sume case AF_INET6: 1072129984Sume sa6 = (struct sockaddr_in6 *)sa; 1073129984Sume if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 1074129984Sume /* just use the scope field of the multicast address */ 1075129984Sume return(sa6->sin6_addr.s6_addr[2] & 0x0f); 1076129984Sume } 1077129984Sume /* 1078129984Sume * Unicast addresses: map scope type to corresponding scope 1079129984Sume * value defined for multcast addresses. 1080129984Sume * XXX: hardcoded scope type values are bad... 1081129984Sume */ 1082129984Sume if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) 1083129984Sume return(1); /* node local scope */ 1084129984Sume if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) 1085129984Sume return(2); /* link-local scope */ 1086129984Sume if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) 1087129984Sume return(5); /* site-local scope */ 1088129984Sume return(14); /* global scope */ 1089129984Sume break; 1090129984Sume#endif 1091129984Sume case AF_INET: 1092129984Sume /* 1093129984Sume * IPv4 pseudo scoping according to RFC 3484. 1094129984Sume */ 1095129984Sume sa4 = (struct sockaddr_in *)sa; 1096129984Sume /* IPv4 autoconfiguration addresses have link-local scope. */ 1097129984Sume if (((u_char *)&sa4->sin_addr)[0] == 169 && 1098129984Sume ((u_char *)&sa4->sin_addr)[1] == 254) 1099129984Sume return(2); 1100129984Sume /* Private addresses have site-local scope. */ 1101129984Sume if (((u_char *)&sa4->sin_addr)[0] == 10 || 1102129984Sume (((u_char *)&sa4->sin_addr)[0] == 172 && 1103129984Sume (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || 1104129984Sume (((u_char *)&sa4->sin_addr)[0] == 192 && 1105129984Sume ((u_char *)&sa4->sin_addr)[1] == 168)) 1106129984Sume return(14); /* XXX: It should be 5 unless NAT */ 1107129984Sume /* Loopback addresses have link-local scope. */ 1108129984Sume if (((u_char *)&sa4->sin_addr)[0] == 127) 1109129984Sume return(2); 1110129984Sume return(14); 1111129984Sume break; 1112129984Sume default: 1113129984Sume errno = EAFNOSUPPORT; /* is this a good error? */ 1114129984Sume return(-1); 1115129984Sume } 1116129984Sume} 1117245553Sume#endif 1118