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; 189305316Sache int aio_initial_sequence; 190129984Sume}; 191129984Sume 192156960Sumestatic struct hostent *_hpcopy(struct hostent *, int *); 193156960Sumestatic struct hostent *_hpaddr(int, const char *, void *, int *); 194171671Sbushman#ifdef INET6 195156960Sumestatic struct hostent *_hpmerge(struct hostent *, struct hostent *, int *); 196156960Sumestatic struct hostent *_hpmapv6(struct hostent *, int *); 19755163Sshin#endif 198156960Sumestatic struct hostent *_hpsort(struct hostent *, res_state); 19955163Sshin 200245256Sume#ifdef INET6 201156960Sumestatic struct hostent *_hpreorder(struct hostent *); 202126052Sumestatic int get_addrselectpolicy(struct policyhead *); 203126052Sumestatic void free_addrselectpolicy(struct policyhead *); 204126052Sumestatic struct policyqueue *match_addrselectpolicy(struct sockaddr *, 205126052Sume struct policyhead *); 206129984Sumestatic void set_source(struct hp_order *, struct policyhead *); 207129984Sumestatic int matchlen(struct sockaddr *, struct sockaddr *); 208129984Sumestatic int comp_dst(const void *, const void *); 209129984Sumestatic int gai_addr2scopetype(struct sockaddr *); 210245225Sume#endif 211126052Sume 21255163Sshin/* 213171671Sbushman * Functions defined in RFC2553 214171671Sbushman * getipnodebyname, getipnodebyaddr, freehostent 21555163Sshin */ 21655163Sshin 217171671Sbushmanstruct hostent * 218171671Sbushmangetipnodebyname(const char *name, int af, int flags, int *errp) 21955163Sshin{ 220171671Sbushman struct hostent *hp; 221171671Sbushman union inx_addr addrbuf; 222158115Sume res_state statp; 223171671Sbushman u_long options; 224158115Sume 225171671Sbushman switch (af) { 226171671Sbushman case AF_INET: 227171671Sbushman#ifdef INET6 228171671Sbushman case AF_INET6: 229171671Sbushman#endif 230158115Sume break; 231158115Sume default: 232171671Sbushman *errp = NO_RECOVERY; 233171671Sbushman return NULL; 234158115Sume } 235158115Sume 23655163Sshin if (flags & AI_ADDRCONFIG) { 23755163Sshin int s; 23855163Sshin 239255328Sjilles if ((s = _socket(af, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) 240144527Sume return NULL; 24155163Sshin /* 24255163Sshin * TODO: 24355163Sshin * Note that implementation dependent test for address 24455163Sshin * configuration should be done everytime called 24555163Sshin * (or apropriate interval), 24655163Sshin * because addresses will be dynamically assigned or deleted. 24755163Sshin */ 248144527Sume _close(s); 24955163Sshin } 250171671Sbushman 25155163Sshin#ifdef INET6 25255163Sshin /* special case for literal address */ 25355163Sshin if (inet_pton(AF_INET6, name, &addrbuf) == 1) { 25455163Sshin if (af != AF_INET6) { 25555163Sshin *errp = HOST_NOT_FOUND; 25655163Sshin return NULL; 25755163Sshin } 25855163Sshin return _hpaddr(af, name, &addrbuf, errp); 25955163Sshin } 26055163Sshin#endif 26157107Sshin if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) { 26255163Sshin if (af != AF_INET) { 26355163Sshin if (MAPADDRENABLED(flags)) { 26455163Sshin MAPADDR(&addrbuf, &addrbuf.in_addr); 26555163Sshin } else { 26655163Sshin *errp = HOST_NOT_FOUND; 26755163Sshin return NULL; 26855163Sshin } 26955163Sshin } 27055163Sshin return _hpaddr(af, name, &addrbuf, errp); 27155163Sshin } 27255163Sshin 273171671Sbushman 274156960Sume statp = __res_state(); 275156960Sume if ((statp->options & RES_INIT) == 0) { 276156960Sume if (res_ninit(statp) < 0) { 277156960Sume *errp = NETDB_INTERNAL; 278156960Sume return NULL; 279156960Sume } 280156960Sume } 281171671Sbushman 282171671Sbushman options = statp->options; 283171671Sbushman statp->options &= ~RES_USE_INET6; 284171671Sbushman 285171671Sbushman hp = gethostbyname2(name, af); 286171671Sbushman hp = _hpcopy(hp, errp); 287245256Sume#ifdef INET6 288245256Sume if (af == AF_INET6) 289245256Sume hp = _hpreorder(hp); 290156960Sume 291146192Sume if (af == AF_INET6 && ((flags & AI_ALL) || hp == NULL) && 292146192Sume MAPADDRENABLED(flags)) { 293171671Sbushman struct hostent *hp2 = gethostbyname2(name, AF_INET); 29455163Sshin if (hp == NULL) 295171671Sbushman if (hp2 == NULL) 296171671Sbushman *errp = statp->res_h_errno; 297171671Sbushman else 298171671Sbushman hp = _hpmapv6(hp2, errp); 29955163Sshin else { 300171671Sbushman if (hp2 && strcmp(hp->h_name, hp2->h_name) == 0) { 301171671Sbushman struct hostent *hpb = hp; 302171671Sbushman hp = _hpmerge(hpb, hp2, errp); 303171671Sbushman freehostent(hpb); 30455163Sshin } 30555163Sshin } 30655163Sshin } 30755163Sshin#endif 308171671Sbushman 309171671Sbushman if (hp == NULL) 310171671Sbushman *errp = statp->res_h_errno; 311171671Sbushman 312171671Sbushman statp->options = options; 313245225Sume return _hpsort(hp, statp); 31455163Sshin} 31555163Sshin 31655163Sshinstruct hostent * 31755163Sshingetipnodebyaddr(const void *src, size_t len, int af, int *errp) 31855163Sshin{ 31955163Sshin struct hostent *hp; 320171671Sbushman res_state statp; 321171671Sbushman u_long options; 322171671Sbushman 32355163Sshin#ifdef INET6 32455163Sshin struct in6_addr addrbuf; 32555163Sshin#else 32655163Sshin struct in_addr addrbuf; 32755163Sshin#endif 328171671Sbushman 32955163Sshin switch (af) { 33055163Sshin case AF_INET: 33155163Sshin if (len != sizeof(struct in_addr)) { 33255163Sshin *errp = NO_RECOVERY; 33355163Sshin return NULL; 33455163Sshin } 33555163Sshin if ((long)src & ~(sizeof(struct in_addr) - 1)) { 33655163Sshin memcpy(&addrbuf, src, len); 33755163Sshin src = &addrbuf; 33855163Sshin } 33955163Sshin if (((struct in_addr *)src)->s_addr == 0) 34055163Sshin return NULL; 34155163Sshin break; 34255163Sshin#ifdef INET6 34355163Sshin case AF_INET6: 34455163Sshin if (len != sizeof(struct in6_addr)) { 34555163Sshin *errp = NO_RECOVERY; 34655163Sshin return NULL; 34755163Sshin } 34855163Sshin if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) { /*XXX*/ 34955163Sshin memcpy(&addrbuf, src, len); 35055163Sshin src = &addrbuf; 35155163Sshin } 35255877Sshin if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src)) 35355877Sshin return NULL; 35455163Sshin if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src) 35555163Sshin || IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) { 35655163Sshin src = (char *)src + 35755163Sshin (sizeof(struct in6_addr) - sizeof(struct in_addr)); 35855163Sshin af = AF_INET; 35955163Sshin len = sizeof(struct in_addr); 36055163Sshin } 36155163Sshin break; 36255163Sshin#endif 36355163Sshin default: 36455163Sshin *errp = NO_RECOVERY; 36555163Sshin return NULL; 36655163Sshin } 36755163Sshin 368171671Sbushman statp = __res_state(); 369171671Sbushman if ((statp->options & RES_INIT) == 0) { 370171671Sbushman if (res_ninit(statp) < 0) { 371171671Sbushman RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 372171671Sbushman return NULL; 373171671Sbushman } 374171671Sbushman } 375171671Sbushman 376171671Sbushman options = statp->options; 377171671Sbushman statp->options &= ~RES_USE_INET6; 378171671Sbushman 379171671Sbushman hp = gethostbyaddr(src, len, af); 380171671Sbushman if (hp == NULL) 381171671Sbushman *errp = statp->res_h_errno; 382171671Sbushman 383171671Sbushman statp->options = options; 384171671Sbushman return (_hpcopy(hp, errp)); 38555163Sshin} 38655163Sshin 38755163Sshinvoid 38855163Sshinfreehostent(struct hostent *ptr) 38955163Sshin{ 39055163Sshin free(ptr); 39155163Sshin} 39255163Sshin 39355163Sshin/* 39455163Sshin * Private utility functions 39555163Sshin */ 39655163Sshin 39755163Sshin/* 39855163Sshin * _hpcopy: allocate and copy hostent structure 39955163Sshin */ 40055163Sshinstatic struct hostent * 40155163Sshin_hpcopy(struct hostent *hp, int *errp) 40255163Sshin{ 40355163Sshin struct hostent *nhp; 40455163Sshin char *cp, **pp; 40555163Sshin int size, addrsize; 40655163Sshin int nalias = 0, naddr = 0; 40755163Sshin int al_off; 40855163Sshin int i; 40955163Sshin 41055163Sshin if (hp == NULL) 41155163Sshin return hp; 41255163Sshin 41355163Sshin /* count size to be allocated */ 41455163Sshin size = sizeof(struct hostent); 41563490Sume if (hp->h_name != NULL) 41655163Sshin size += strlen(hp->h_name) + 1; 41755163Sshin if ((pp = hp->h_aliases) != NULL) { 41855163Sshin for (i = 0; *pp != NULL; i++, pp++) { 41955163Sshin if (**pp != '\0') { 42055163Sshin size += strlen(*pp) + 1; 42155163Sshin nalias++; 42255163Sshin } 42355163Sshin } 42455163Sshin } 42555163Sshin /* adjust alignment */ 42655163Sshin size = ALIGN(size); 42755163Sshin al_off = size; 42855163Sshin size += sizeof(char *) * (nalias + 1); 42955163Sshin addrsize = ALIGN(hp->h_length); 43055163Sshin if ((pp = hp->h_addr_list) != NULL) { 43155163Sshin while (*pp++ != NULL) 43255163Sshin naddr++; 43355163Sshin } 43455163Sshin size += addrsize * naddr; 43555163Sshin size += sizeof(char *) * (naddr + 1); 43655163Sshin 43755163Sshin /* copy */ 43855163Sshin if ((nhp = (struct hostent *)malloc(size)) == NULL) { 43955163Sshin *errp = TRY_AGAIN; 44055163Sshin return NULL; 44155163Sshin } 44255163Sshin cp = (char *)&nhp[1]; 44363490Sume if (hp->h_name != NULL) { 44455163Sshin nhp->h_name = cp; 44555163Sshin strcpy(cp, hp->h_name); 44655163Sshin cp += strlen(cp) + 1; 44755163Sshin } else 44855163Sshin nhp->h_name = NULL; 44955163Sshin nhp->h_aliases = (char **)((char *)nhp + al_off); 45055163Sshin if ((pp = hp->h_aliases) != NULL) { 45155163Sshin for (i = 0; *pp != NULL; pp++) { 45255163Sshin if (**pp != '\0') { 45355163Sshin nhp->h_aliases[i++] = cp; 45455163Sshin strcpy(cp, *pp); 45555163Sshin cp += strlen(cp) + 1; 45655163Sshin } 45755163Sshin } 45855163Sshin } 45955163Sshin nhp->h_aliases[nalias] = NULL; 46055163Sshin cp = (char *)&nhp->h_aliases[nalias + 1]; 46155163Sshin nhp->h_addrtype = hp->h_addrtype; 46255163Sshin nhp->h_length = hp->h_length; 46355163Sshin nhp->h_addr_list = (char **)cp; 46455163Sshin if ((pp = hp->h_addr_list) != NULL) { 46555163Sshin cp = (char *)&nhp->h_addr_list[naddr + 1]; 46655163Sshin for (i = 0; *pp != NULL; pp++) { 46755163Sshin nhp->h_addr_list[i++] = cp; 46855163Sshin memcpy(cp, *pp, hp->h_length); 46955163Sshin cp += addrsize; 47055163Sshin } 47155163Sshin } 47255163Sshin nhp->h_addr_list[naddr] = NULL; 47355163Sshin return nhp; 47455163Sshin} 47555163Sshin 47655163Sshin/* 47755163Sshin * _hpaddr: construct hostent structure with one address 47855163Sshin */ 47955163Sshinstatic struct hostent * 48055163Sshin_hpaddr(int af, const char *name, void *addr, int *errp) 48155163Sshin{ 48255163Sshin struct hostent *hp, hpbuf; 48355163Sshin char *addrs[2]; 48455163Sshin 48555163Sshin hp = &hpbuf; 48655163Sshin hp->h_name = (char *)name; 48755163Sshin hp->h_aliases = NULL; 48855163Sshin hp->h_addrtype = af; 48955163Sshin hp->h_length = ADDRLEN(af); 49055163Sshin hp->h_addr_list = addrs; 49155163Sshin addrs[0] = (char *)addr; 49255163Sshin addrs[1] = NULL; 493171671Sbushman return (_hpcopy(hp, errp)); 49455163Sshin} 49555163Sshin 496171671Sbushman#ifdef INET6 49755163Sshin/* 49855163Sshin * _hpmerge: merge 2 hostent structure, arguments will be freed 49955163Sshin */ 50055163Sshinstatic struct hostent * 50155163Sshin_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp) 50255163Sshin{ 50355163Sshin int i, j; 50455163Sshin int naddr, nalias; 50555163Sshin char **pp; 50655163Sshin struct hostent *hp, hpbuf; 50755163Sshin char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1]; 50855163Sshin union inx_addr addrbuf[MAXADDRS]; 50955163Sshin 51055163Sshin if (hp1 == NULL) 511171671Sbushman return _hpcopy(hp2, errp); 51255163Sshin if (hp2 == NULL) 513171671Sbushman return _hpcopy(hp1, errp); 51455163Sshin 51555163Sshin#define HP(i) (i == 1 ? hp1 : hp2) 51655163Sshin hp = &hpbuf; 51755163Sshin hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name); 51855163Sshin hp->h_aliases = aliases; 51955163Sshin nalias = 0; 52055163Sshin for (i = 1; i <= 2; i++) { 52155163Sshin if ((pp = HP(i)->h_aliases) == NULL) 52255163Sshin continue; 52355163Sshin for (; nalias < MAXALIASES && *pp != NULL; pp++) { 52455163Sshin /* check duplicates */ 52555163Sshin for (j = 0; j < nalias; j++) 52655163Sshin if (strcasecmp(*pp, aliases[j]) == 0) 52755163Sshin break; 52855163Sshin if (j == nalias) 52955163Sshin aliases[nalias++] = *pp; 53055163Sshin } 53155163Sshin } 53255163Sshin aliases[nalias] = NULL; 53355163Sshin if (hp1->h_length != hp2->h_length) { 53455163Sshin hp->h_addrtype = AF_INET6; 53555163Sshin hp->h_length = sizeof(struct in6_addr); 53655163Sshin } else { 53755163Sshin hp->h_addrtype = hp1->h_addrtype; 53855163Sshin hp->h_length = hp1->h_length; 53955163Sshin } 540171671Sbushman 54155163Sshin hp->h_addr_list = addrs; 54255163Sshin naddr = 0; 54355163Sshin for (i = 1; i <= 2; i++) { 54455163Sshin if ((pp = HP(i)->h_addr_list) == NULL) 54555163Sshin continue; 54655163Sshin if (HP(i)->h_length == hp->h_length) { 54755163Sshin while (naddr < MAXADDRS && *pp != NULL) 54855163Sshin addrs[naddr++] = *pp++; 54955163Sshin } else { 55055163Sshin /* copy IPv4 addr as mapped IPv6 addr */ 55155163Sshin while (naddr < MAXADDRS && *pp != NULL) { 55255163Sshin MAPADDR(&addrbuf[naddr], *pp++); 55355163Sshin addrs[naddr] = (char *)&addrbuf[naddr]; 55455163Sshin naddr++; 55555163Sshin } 55655163Sshin } 55755163Sshin } 55855163Sshin addrs[naddr] = NULL; 559171671Sbushman return (_hpcopy(hp, errp)); 56055163Sshin} 561171671Sbushman#endif 56255163Sshin 56355163Sshin/* 56455163Sshin * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses 56555163Sshin */ 56655163Sshin#ifdef INET6 56755163Sshinstatic struct hostent * 56855163Sshin_hpmapv6(struct hostent *hp, int *errp) 56955163Sshin{ 570171671Sbushman struct hostent hp6; 57155163Sshin 57255163Sshin if (hp == NULL) 57355163Sshin return NULL; 57455163Sshin if (hp->h_addrtype == AF_INET6) 575171671Sbushman return _hpcopy(hp, errp); 57655163Sshin 577171671Sbushman memset(&hp6, 0, sizeof(struct hostent)); 578171671Sbushman hp6.h_addrtype = AF_INET6; 579171671Sbushman hp6.h_length = sizeof(struct in6_addr); 580171671Sbushman return _hpmerge(&hp6, hp, errp); 58155163Sshin} 58255163Sshin#endif 58355163Sshin 58455163Sshin/* 58555163Sshin * _hpsort: sort address by sortlist 58655163Sshin */ 58755163Sshinstatic struct hostent * 588156960Sume_hpsort(struct hostent *hp, res_state statp) 58955163Sshin{ 59055163Sshin int i, j, n; 59155163Sshin u_char *ap, *sp, *mp, **pp; 59255163Sshin char t; 59355163Sshin char order[MAXADDRS]; 594156960Sume int nsort = statp->nsort; 59555163Sshin 59655163Sshin if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0) 59755163Sshin return hp; 59855163Sshin for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) { 59955163Sshin for (j = 0; j < nsort; j++) { 60055163Sshin#ifdef INET6 601156960Sume if (statp->_u._ext.ext->sort_list[j].af != 602156960Sume hp->h_addrtype) 60355163Sshin continue; 604156960Sume sp = (u_char *)&statp->_u._ext.ext->sort_list[j].addr; 605156960Sume mp = (u_char *)&statp->_u._ext.ext->sort_list[j].mask; 60655163Sshin#else 607156960Sume sp = (u_char *)&statp->sort_list[j].addr; 608156960Sume mp = (u_char *)&statp->sort_list[j].mask; 60955163Sshin#endif 61055163Sshin for (n = 0; n < hp->h_length; n++) { 61155163Sshin if ((ap[n] & mp[n]) != sp[n]) 61255163Sshin break; 61355163Sshin } 61455163Sshin if (n == hp->h_length) 61555163Sshin break; 61655163Sshin } 61755163Sshin order[i] = j; 61855163Sshin } 61955163Sshin n = i; 62055163Sshin pp = (u_char **)hp->h_addr_list; 62155163Sshin for (i = 0; i < n - 1; i++) { 62255163Sshin for (j = i + 1; j < n; j++) { 62355163Sshin if (order[i] > order[j]) { 62455163Sshin ap = pp[i]; 62555163Sshin pp[i] = pp[j]; 62655163Sshin pp[j] = ap; 62755163Sshin t = order[i]; 62855163Sshin order[i] = order[j]; 62955163Sshin order[j] = t; 63055163Sshin } 63155163Sshin } 63255163Sshin } 63355163Sshin return hp; 63455163Sshin} 63555163Sshin 636245256Sume#ifdef INET6 63755163Sshin/* 638126052Sume * _hpreorder: sort address by default address selection 639126052Sume */ 640126052Sumestatic struct hostent * 641126052Sume_hpreorder(struct hostent *hp) 642126052Sume{ 643129984Sume struct hp_order *aio; 644129984Sume int i, n; 645146700Sume char *ap; 646129984Sume struct sockaddr *sa; 647126052Sume struct policyhead policyhead; 648126052Sume 649129984Sume if (hp == NULL) 650126052Sume return hp; 651126052Sume 652129984Sume switch (hp->h_addrtype) { 653129984Sume case AF_INET: 654129984Sume#ifdef INET6 655129984Sume case AF_INET6: 656129984Sume#endif 657129984Sume break; 658129984Sume default: 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); 715305316Sache aio[i].aio_initial_sequence = i; 716126052Sume } 717126052Sume 718126052Sume /* perform sorting. */ 719129984Sume qsort(aio, n, sizeof(*aio), comp_dst); 720126052Sume 721129984Sume /* reorder the h_addr_list. */ 722129984Sume for (i = 0; i < n; i++) 723129984Sume hp->h_addr_list[i] = aio[i].aio_h_addr; 724129984Sume 725126052Sume /* cleanup and return */ 726129984Sume free(aio); 727126052Sume free_addrselectpolicy(&policyhead); 728126052Sume return hp; 729126052Sume} 730126052Sume 731126052Sumestatic int 732157119Sumeget_addrselectpolicy(struct policyhead *head) 733126052Sume{ 734126052Sume#ifdef INET6 735126052Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; 736126052Sume size_t l; 737126052Sume char *buf; 738126052Sume struct in6_addrpolicy *pol, *ep; 739126052Sume 740126052Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) 741126052Sume return (0); 742126052Sume if ((buf = malloc(l)) == NULL) 743126052Sume return (0); 744126052Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 745126052Sume free(buf); 746126052Sume return (0); 747126052Sume } 748126052Sume 749126052Sume ep = (struct in6_addrpolicy *)(buf + l); 750126052Sume for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { 751126052Sume struct policyqueue *new; 752126052Sume 753126052Sume if ((new = malloc(sizeof(*new))) == NULL) { 754126052Sume free_addrselectpolicy(head); /* make the list empty */ 755126052Sume break; 756126052Sume } 757126052Sume new->pc_policy = *pol; 758126052Sume TAILQ_INSERT_TAIL(head, new, pc_entry); 759126052Sume } 760126052Sume 761126052Sume free(buf); 762126052Sume return (1); 763126052Sume#else 764126052Sume return (0); 765126052Sume#endif 766126052Sume} 767126052Sume 768126052Sumestatic void 769157119Sumefree_addrselectpolicy(struct policyhead *head) 770126052Sume{ 771126052Sume struct policyqueue *ent, *nent; 772126052Sume 773126052Sume for (ent = TAILQ_FIRST(head); ent; ent = nent) { 774126052Sume nent = TAILQ_NEXT(ent, pc_entry); 775126052Sume TAILQ_REMOVE(head, ent, pc_entry); 776126052Sume free(ent); 777126052Sume } 778126052Sume} 779126052Sume 780126052Sumestatic struct policyqueue * 781157119Sumematch_addrselectpolicy(struct sockaddr *addr, struct policyhead *head) 782126052Sume{ 783126052Sume#ifdef INET6 784126052Sume struct policyqueue *ent, *bestent = NULL; 785126052Sume struct in6_addrpolicy *pol; 786126052Sume int matchlen, bestmatchlen = -1; 787126052Sume u_char *mp, *ep, *k, *p, m; 788126052Sume struct sockaddr_in6 key; 789126052Sume 790126052Sume switch(addr->sa_family) { 791126052Sume case AF_INET6: 792126052Sume key = *(struct sockaddr_in6 *)addr; 793126052Sume break; 794126052Sume case AF_INET: 795126052Sume /* convert the address into IPv4-mapped IPv6 address. */ 796126052Sume memset(&key, 0, sizeof(key)); 797126052Sume key.sin6_family = AF_INET6; 798126052Sume key.sin6_len = sizeof(key); 799292826Sume _map_v4v6_address( 800292826Sume (char *)&((struct sockaddr_in *)addr)->sin_addr, 801292826Sume (char *)&key.sin6_addr); 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) { 933305401Sache while ((r & 0x80) == 0) { 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. */ 1050305316Sache 1051305316Sache /* 1052305316Sache * Note that qsort is unstable; so, we can't return zero and 1053305316Sache * expect the order to be unchanged. 1054305316Sache * That also means we can't depend on the current position of 1055305316Sache * dst2 being after dst1. We must enforce the initial order 1056305316Sache * with an explicit compare on the original position. 1057305316Sache * The qsort specification requires that "When the same objects 1058305316Sache * (consisting of width bytes, irrespective of their current 1059305316Sache * positions in the array) are passed more than once to the 1060305316Sache * comparison function, the results shall be consistent with one 1061305316Sache * another." 1062305316Sache * In other words, If A < B, then we must also return B > A. 1063305316Sache */ 1064305316Sache if (dst2->aio_initial_sequence < dst1->aio_initial_sequence) 1065305316Sache return(1); 1066305316Sache 1067129984Sume return(-1); 1068129984Sume} 1069129984Sume 1070126052Sume/* 1071129984Sume * Copy from scope.c. 1072129984Sume * XXX: we should standardize the functions and link them as standard 1073129984Sume * library. 1074129984Sume */ 1075129984Sumestatic int 1076157119Sumegai_addr2scopetype(struct sockaddr *sa) 1077129984Sume{ 1078129984Sume#ifdef INET6 1079129984Sume struct sockaddr_in6 *sa6; 1080129984Sume#endif 1081129984Sume struct sockaddr_in *sa4; 1082129984Sume 1083129984Sume switch(sa->sa_family) { 1084129984Sume#ifdef INET6 1085129984Sume case AF_INET6: 1086129984Sume sa6 = (struct sockaddr_in6 *)sa; 1087129984Sume if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 1088129984Sume /* just use the scope field of the multicast address */ 1089129984Sume return(sa6->sin6_addr.s6_addr[2] & 0x0f); 1090129984Sume } 1091129984Sume /* 1092129984Sume * Unicast addresses: map scope type to corresponding scope 1093129984Sume * value defined for multcast addresses. 1094129984Sume * XXX: hardcoded scope type values are bad... 1095129984Sume */ 1096129984Sume if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) 1097129984Sume return(1); /* node local scope */ 1098129984Sume if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) 1099129984Sume return(2); /* link-local scope */ 1100129984Sume if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) 1101129984Sume return(5); /* site-local scope */ 1102129984Sume return(14); /* global scope */ 1103129984Sume break; 1104129984Sume#endif 1105129984Sume case AF_INET: 1106129984Sume /* 1107129984Sume * IPv4 pseudo scoping according to RFC 3484. 1108129984Sume */ 1109129984Sume sa4 = (struct sockaddr_in *)sa; 1110129984Sume /* IPv4 autoconfiguration addresses have link-local scope. */ 1111129984Sume if (((u_char *)&sa4->sin_addr)[0] == 169 && 1112129984Sume ((u_char *)&sa4->sin_addr)[1] == 254) 1113129984Sume return(2); 1114129984Sume /* Private addresses have site-local scope. */ 1115129984Sume if (((u_char *)&sa4->sin_addr)[0] == 10 || 1116129984Sume (((u_char *)&sa4->sin_addr)[0] == 172 && 1117129984Sume (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || 1118129984Sume (((u_char *)&sa4->sin_addr)[0] == 192 && 1119129984Sume ((u_char *)&sa4->sin_addr)[1] == 168)) 1120129984Sume return(14); /* XXX: It should be 5 unless NAT */ 1121129984Sume /* Loopback addresses have link-local scope. */ 1122129984Sume if (((u_char *)&sa4->sin_addr)[0] == 127) 1123129984Sume return(2); 1124129984Sume return(14); 1125129984Sume break; 1126129984Sume default: 1127129984Sume errno = EAFNOSUPPORT; /* is this a good error? */ 1128129984Sume return(-1); 1129129984Sume } 1130129984Sume} 1131245225Sume#endif 1132