add IPv6 support functions.

get{addr,name} info are implemented to have as little impact to existing
resolver code as possible, so they are NOT the optimal implementation.
They are at this moment not very thread safe (as they call
gethostby{name,addr}).

(shlib minor version)++, as new interfaces are added.

TODO: getipnodeby{name,addr} - which needs total reimplementation of
gethostby{name,addr}.
upgrade rcmd.c for multiple af support (needed for IPv6-ready rsh/rlogin)
This commit is contained in:
itojun 1999-07-01 18:23:53 +00:00
parent e5e0b59b78
commit 37e8159125
11 changed files with 2523 additions and 3 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile.inc,v 1.42 1999/04/22 00:37:42 mycroft Exp $
# $NetBSD: Makefile.inc,v 1.43 1999/07/01 18:23:53 itojun Exp $
# @(#)Makefile.inc 8.2 (Berkeley) 9/5/93
# net sources
@ -16,6 +16,13 @@ SRCS+= base64.c ethers.c gethnamaddr.c getnetnamadr.c getnetent.c getproto.c \
SRCS+= __dn_comp.c __res_close.c __res_send.c
CPPFLAGS+=-DRESOLVSORT -I.
# IPv6
SRCS+= getaddrinfo.c getnameinfo.c ifname.c ip6opt.c rthdr.c vars6.c
CPPFLAGS+= -DINET6
# need to revisit
#SRCS+= name6.c rresvport_af.c freehostent.c
#CPPFLAGS+= -DUSE_GETIPNODEBY
LPREFIX=_nsyy
YPREFIX=_nsyy
YHEADER=1
@ -62,3 +69,12 @@ MLINKS+=rcmd.3 iruserok.3 rcmd.3 rresvport.3 rcmd.3 ruserok.3 rcmd.3 orcmd.3
MLINKS+=resolver.3 dn_comp.3 resolver.3 dn_expand.3 resolver.3 res_init.3 \
resolver.3 res_mkquery.3 resolver.3 res_send.3 resolver.3 res_query.3 \
resolver.3 res_search.3
# IPv6
MAN+= getaddrinfo.3 getnameinfo.3 if_indextoname.3
MLINKS+=if_indextoname.3 if_nametoindex.3 if_indextoname.3 if_nameindex.3 \
if_indextoname.3 if_freenameindex.3
# need to revisit
#MAN+= getipnodebyname.3 rresvport_af.3
#MLINKS+=getipnodebyname.3 getipnodebyaddr.3 getipnodebyname.3 freehostent.3 \
# getaddrinfo.3 freeaddrinfo.3 getaddrinfo.3 gai_strerror.3 \

361
lib/libc/net/getaddrinfo.3 Normal file
View File

@ -0,0 +1,361 @@
.\" Copyright (c) 1983, 1987, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95
.\" $Id: getaddrinfo.3,v 1.1 1999/07/01 18:23:54 itojun Exp $
.\"
.Dd May 25, 1995
.Dt GETADDRINFO 3
.Os KAME
.Sh NAME
.Nm getaddrinfo
.Nm freeaddrinfo ,
.Nm gai_strerror
.Nd nodename-to-address translation in protocol-independent manner
.Sh SYNOPSIS
.Fd #include <sys/socket.h>
.Fd #include <netdb.h>
.Ft int
.Fn getaddrinfo "const char *nodename" "const char *servname" \
"const struct addrinfo *hints" "struct addrinfo **res"
.Ft void
.Fn freeaddrinfo "struct addrinfo *ai"
.Ft "char *"
.Fn gai_strerror "int ecode"
.Sh DESCRIPTION
The
.Fn getaddrinfo
function is defined for protocol-independent nodename-to-address translation.
It performs functionality of
.Xr gethostbyname 3
and
.Xr getservbyname 3 ,
in more sophisticated manner.
.Pp
The addrinfo structure is defined as a result of including the
.Li <netdb.h>
header:
.Bd -literal -offset
struct addrinfo { *
int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
size_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for nodename */
struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* next structure in linked list */
};
.Ed
.Pp
The
.Fa nodename
and
.Fa servname
arguments are pointers to null-terminated strings or
.Dv NULL .
One or both of these two arguments must be a
.Pf non Dv -NULL
pointer.
In the normal client scenario, both the
.Fa nodename
and
.Fa servname
are specified.
In the normal server scenario, only the
.Fa servname
is specified.
A
.Pf non Dv -NULL
.Fa nodename
string can be either a node name or a numeric host address string
.Po
i.e., a dotted-decimal IPv4 address or an IPv6 hex address
.Pc .
A
.Pf non Dv -NULL
.Fa servname
string can be either a service name or a decimal port number.
.Pp
The caller can optionally pass an
.Li addrinfo
structure, pointed to by the third argument,
to provide hints concerning the type of socket that the caller supports.
In this
.Fa hints
structure all members other than
.Fa ai_flags ,
.Fa ai_family ,
.Fa ai_socktype ,
and
.Fa ai_protocol
must be zero or a
.Dv NULL
pointer.
A value of
.Dv PF_UNSPEC
for
.Fa ai_family
means the caller will accept any protocol family.
A value of 0 for
.Fa ai_socktype
means the caller will accept any socket type.
A value of 0 for
.Fa ai_protocol
means the caller will accept any protocol.
For example, if the caller handles only TCP and not UDP, then the
.Fa ai_socktype
member of the hints structure should be set to
.Dv SOCK_STREAM
when
.Fn getaddrinfo
is called.
If the caller handles only IPv4 and not IPv6, then the
.Fa ai_family
member of the
.Fa hints
structure should be set to
.Dv PF_INET
when
.Fn getaddrinfo
is called.
If the third argument to
.Fn getaddrinfo
is a
.Dv NULL
pointer, this is the same as if the caller had filled in an
.Li addrinfo
structure initialized to zero with
.Fa ai_family
set to PF_UNSPEC.
.Pp
Upon successful return a pointer to a linked list of one or more
.Li addrinfo
structures is returned through the final argument.
The caller can process each
.Li addrinfo
structure in this list by following the
.Fa ai_next
pointer, until a
.Dv NULL
pointer is encountered.
In each returned
.Li addrinfo
structure the three members
.Fa ai_family ,
.Fa ai_socktype ,
and
.Fa ai_protocol
are the corresponding arguments for a call to the
.Fn socket
function.
In each
.Li addrinfo
structure the
.Fa ai_addr
member points to a filled-in socket address structure whose length is
specified by the
.Fa ai_addrlen
member.
.Pp
If the
.Dv AI_PASSIVE
bit is set in the
.Fa ai_flags
member of the
.Fa hints
structure, then the caller plans to use the returned socket address
structure in a call to
.Fn bind .
In this case, if the
.Fa nodename
argument is a
.Dv NULL
pointer, then the IP address portion of the socket
address structure will be set to
.Dv INADDR_ANY
for an IPv4 address or
.Dv IN6ADDR_ANY_INIT
for an IPv6 address.
.Pp
If the
.Dv AI_PASSIVE
bit is not set in the
.Fa ai_flags
member of the
.Fa hints
structure, then the returned socket address structure will be ready for a
call to
.Fn connect
.Pq for a connection-oriented protocol
or either
.Fn connect ,
.Fn sendto , or
.Fn sendmsg
.Pq for a connectionless protocol .
In this case, if the
.Fa nodename
argument is a
.Dv NULL
pointer, then the IP address portion of the
socket address structure will be set to the loopback address.
.Pp
If the
.Dv AI_CANONNAME
bit is set in the
.Fa ai_flags
member of the
.Fa hints
structure, then upon successful return the
.Fa ai_canonname
member of the first
.Li addrinfo
structure in the linked list will point to a null-terminated string
containing the canonical name of the specified
.Fa nodename .
.Pp
If the
.Dv AI_NUMERICHOST
bit is set in the
.Fa ai_flags
member of the
.Fa hints
structure, then a
.Pf non Dv -NULL
.Fa nodename
string must be a numeric host address string.
Otherwise an error of
.Dv EAI_NONAME
is returned.
This flag prevents any type of name resolution service (e.g., the DNS)
from being called.
.Pp
All of the information returned by
.Fn getaddrinfo
is dynamically allocated:
the
.Li addrinfo
structures, and the socket address structures and canonical node name
strings pointed to by the addrinfo structures.
To return this information to the system the function
.Fn freeaddrinfo
is called.
The
.Fa addrinfo
structure pointed to by the
.Fa ai argument
is freed, along with any dynamic storage pointed to by the structure.
This operation is repeated until a
.Dv NULL
.Fa ai_next
pointer is encountered.
.Pp
To aid applications in printing error messages based on the
.Dv EAI_xxx
codes returned by
.Fn getaddrinfo ,
.Fn gai_strerror
is defined.
The argument is one of the
.Dv EAI_xxx
values defined earlier and the return value points to a string describing
the error.
If the argument is not one of the
.Dv EAI_xxx
values, the function still returns a pointer to a string whose contents
indicate an unknown error.
.Sh FILES
.Bl -tag -width /etc/resolv.conf -compact
.It Pa /etc/hosts
.It Pa /etc/host.conf
.It Pa /etc/resolv.conf
.El
.Sh DIAGNOSTICS
Error return status from
.Fn getaddrinfo
is zero on success and non-zero on errors.
Non-zero error codes are defined in
.Li <netdb.h> ,
and as follows:
.Pp
.Bl -tag -width EAI_ADDRFAMILY -compact
.It Dv EAI_ADDRFAMILY
address family for nodename not supported
.It Dv EAI_AGAIN
temporary failure in name resolution
.It Dv EAI_BADFLAGS
invalid value for ai_flags
.It Dv EAI_FAIL
non-recoverable failure in name resolution
.It Dv EAI_FAMILY
ai_family not supported
.It Dv EAI_MEMORY
memory allocation failure
.It Dv EAI_NODATA
no address associated with nodename
.It Dv EAI_NONAME
nodename nor servname provided, or not known
.It Dv EAI_SERVICE
servname not supported for ai_socktype
.It Dv EAI_SOCKTYPE
ai_socktype not supported
.It Dv EAI_SYSTEM
system error returned in errno
.El
.Pp
If called with proper argument,
.Fn gai_strerror
returns a pointer to a string describing the given error code.
If the argument is not one of the
.Dv EAI_xxx
values, the function still returns a pointer to a string whose contents
indicate an unknown error.
.Sh SEE ALSO
.Xr getnameinfo 3 ,
.Xr gethostbyname 3 ,
.Xr getservbyname 3 ,
.Xr hosts 5 ,
.Xr services 5 ,
.Xr hostname 7 ,
.Xr named 8
.Pp
R. Gilligan, S. Thomson, J. Bound, and W. Stevens,
``Basic Socket Interface Extensions for IPv6,'' RFC2553, March 1999.
.Sh HISTORY
The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit.
.Sh STANDARDS
The
.Fn getaddrinfo
function is defined IEEE POSIX 1003.1g draft specification,
and documented in ``Basic Socket Interface Extensions for IPv6''
.Pq RFC2533 .
.Sh BUGS
The text was shamelessly copied from RFC2553.

668
lib/libc/net/getaddrinfo.c Normal file
View File

@ -0,0 +1,668 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
*
* Issues to be discussed:
* - Thread safe-ness must be checked.
* - Return values. There are nonstandard return values defined and used
* in the source code. This is because RFC2133 is silent about which error
* code must be returned for which situation.
* - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include <unistd.h>
#if 0 /*quickhack*/
#if defined(__KAME__) && defined(INET6)
# define FAITH
#endif
#endif
#define SUCCESS 0
#define ANY 0
#define YES 1
#define NO 0
#ifdef FAITH
static int translate = NO;
static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
#endif
static const char in_addrany[] = { 0, 0, 0, 0 };
static const char in6_addrany[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static const char in_loopback[] = { 127, 0, 0, 1 };
static const char in6_loopback[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
};
struct sockinet {
u_char si_len;
u_char si_family;
u_short si_port;
};
static struct afd {
int a_af;
int a_addrlen;
int a_socklen;
int a_off;
const char *a_addrany;
const char *a_loopback;
} afdl [] = {
#ifdef INET6
#define N_INET6 0
{PF_INET6, sizeof(struct in6_addr),
sizeof(struct sockaddr_in6),
offsetof(struct sockaddr_in6, sin6_addr),
in6_addrany, in6_loopback},
#define N_INET 1
#else
#define N_INET 0
#endif
{PF_INET, sizeof(struct in_addr),
sizeof(struct sockaddr_in),
offsetof(struct sockaddr_in, sin_addr),
in_addrany, in_loopback},
{0, 0, 0, 0, NULL, NULL},
};
#ifdef INET6
#define PTON_MAX 16
#else
#define PTON_MAX 4
#endif
static int get_name __P((const char *, struct afd *,
struct addrinfo **, char *, struct addrinfo *,
int));
static int get_addr __P((const char *, int, struct addrinfo **,
struct addrinfo *, int));
static int get_addr0 __P((const char *, int, struct addrinfo **,
struct addrinfo *, int));
static int str_isnumber __P((const char *));
static char *ai_errlist[] = {
"success.",
"address family for hostname not supported.", /* EAI_ADDRFAMILY */
"temporary failure in name resolution.", /* EAI_AGAIN */
"invalid value for ai_flags.", /* EAI_BADFLAGS */
"non-recoverable failure in name resolution.", /* EAI_FAIL */
"ai_family not supported.", /* EAI_FAMILY */
"memory allocation failure.", /* EAI_MEMORY */
"no address associated with hostname.", /* EAI_NODATA */
"hostname nor servname provided, or not known.",/* EAI_NONAME */
"servname not supported for ai_socktype.", /* EAI_SERVICE */
"ai_socktype not supported.", /* EAI_SOCKTYPE */
"system error returned in errno.", /* EAI_SYSTEM */
"invalid value for hints.", /* EAI_BADHINTS */
"resolved protocol is unknown.", /* EAI_PROTOCOL */
"unknown error.", /* EAI_MAX */
};
#define GET_CANONNAME(ai, str) \
if (pai->ai_flags & AI_CANONNAME) {\
if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
strcpy((ai)->ai_canonname, (str));\
} else {\
error = EAI_MEMORY;\
goto free;\
}\
}
#define GET_AI(ai, afd, addr, port) {\
char *p;\
if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
((afd)->a_socklen)))\
== NULL) {\
error = EAI_MEMORY;\
goto free;\
}\
memcpy(ai, pai, sizeof(struct addrinfo));\
(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
memset((ai)->ai_addr, 0, (afd)->a_socklen);\
(ai)->ai_addr->sa_len = (ai)->ai_addrlen = (afd)->a_socklen;\
(ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\
((struct sockinet *)(ai)->ai_addr)->si_port = port;\
p = (char *)((ai)->ai_addr);\
memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\
}
#define ERR(err) { error = (err); goto bad; }
char *
gai_strerror(ecode)
int ecode;
{
if (ecode < 0 || ecode > EAI_MAX)
ecode = EAI_MAX;
return ai_errlist[ecode];
}
void
freeaddrinfo(ai)
struct addrinfo *ai;
{
struct addrinfo *next;
do {
next = ai->ai_next;
if (ai->ai_canonname)
free(ai->ai_canonname);
/* no need to free(ai->ai_addr) */
free(ai);
} while ((ai = next) != NULL);
}
static int
str_isnumber(p)
const char *p;
{
char *q = (char *)p;
while (*q) {
if (! isdigit(*q))
return NO;
q++;
}
return YES;
}
int
getaddrinfo(hostname, servname, hints, res)
const char *hostname, *servname;
const struct addrinfo *hints;
struct addrinfo **res;
{
struct addrinfo sentinel;
struct addrinfo *top = NULL;
struct addrinfo *cur;
int i, error = 0;
char pton[PTON_MAX];
struct addrinfo ai;
struct addrinfo *pai;
u_short port;
#ifdef FAITH
static int firsttime = 1;
if (firsttime) {
/* translator hack */
{
char *q = getenv("GAI");
if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
translate = YES;
}
firsttime = 0;
}
#endif
/* initialize file static vars */
sentinel.ai_next = NULL;
cur = &sentinel;
pai = &ai;
pai->ai_flags = 0;
pai->ai_family = PF_UNSPEC;
pai->ai_socktype = ANY;
pai->ai_protocol = ANY;
pai->ai_addrlen = 0;
pai->ai_canonname = NULL;
pai->ai_addr = NULL;
pai->ai_next = NULL;
port = ANY;
if (hostname == NULL && servname == NULL)
return EAI_NONAME;
if (hints) {
/* error check for hints */
if (hints->ai_addrlen || hints->ai_canonname ||
hints->ai_addr || hints->ai_next)
ERR(EAI_BADHINTS); /* xxx */
if (hints->ai_flags & ~AI_MASK)
ERR(EAI_BADFLAGS);
switch (hints->ai_family) {
case PF_UNSPEC:
case PF_INET:
#ifdef INET6
case PF_INET6:
#endif
break;
default:
ERR(EAI_FAMILY);
}
memcpy(pai, hints, sizeof(*pai));
switch (pai->ai_socktype) {
case ANY:
switch (pai->ai_protocol) {
case ANY:
break;
case IPPROTO_UDP:
pai->ai_socktype = SOCK_DGRAM;
break;
case IPPROTO_TCP:
pai->ai_socktype = SOCK_STREAM;
break;
default:
pai->ai_socktype = SOCK_RAW;
break;
}
break;
case SOCK_RAW:
break;
case SOCK_DGRAM:
if (pai->ai_protocol != IPPROTO_UDP &&
pai->ai_protocol != ANY)
ERR(EAI_BADHINTS); /*xxx*/
pai->ai_protocol = IPPROTO_UDP;
break;
case SOCK_STREAM:
if (pai->ai_protocol != IPPROTO_TCP &&
pai->ai_protocol != ANY)
ERR(EAI_BADHINTS); /*xxx*/
pai->ai_protocol = IPPROTO_TCP;
break;
default:
ERR(EAI_SOCKTYPE);
break;
}
}
/*
* service port
*/
if (servname) {
if (str_isnumber(servname)) {
if (pai->ai_socktype == ANY) {
/* caller accept *ANY* socktype */
pai->ai_socktype = SOCK_DGRAM;
pai->ai_protocol = IPPROTO_UDP;
}
port = htons(atoi(servname));
} else {
struct servent *sp;
char *proto;
proto = NULL;
switch (pai->ai_socktype) {
case ANY:
proto = NULL;
break;
case SOCK_DGRAM:
proto = "udp";
break;
case SOCK_STREAM:
proto = "tcp";
break;
default:
fprintf(stderr, "panic!\n");
break;
}
if ((sp = getservbyname(servname, proto)) == NULL)
ERR(EAI_SERVICE);
port = sp->s_port;
if (pai->ai_socktype == ANY) {
if (strcmp(sp->s_proto, "udp") == 0) {
pai->ai_socktype = SOCK_DGRAM;
pai->ai_protocol = IPPROTO_UDP;
} else if (strcmp(sp->s_proto, "tcp") == 0) {
pai->ai_socktype = SOCK_STREAM;
pai->ai_protocol = IPPROTO_TCP;
} else
ERR(EAI_PROTOCOL); /*xxx*/
}
}
}
/*
* hostname == NULL.
* passive socket -> anyaddr (0.0.0.0 or ::)
* non-passive socket -> localhost (127.0.0.1 or ::1)
*/
if (hostname == NULL) {
struct afd *afd;
int s;
for (afd = &afdl[0]; afd->a_af; afd++) {
if (!(pai->ai_family == PF_UNSPEC
|| pai->ai_family == afd->a_af)) {
continue;
}
/*
* filter out AFs that are not supported by the kernel
* XXX errno?
*/
s = socket(afd->a_af, SOCK_DGRAM, 0);
if (s < 0)
continue;
close(s);
if (pai->ai_flags & AI_PASSIVE) {
GET_AI(cur->ai_next, afd, afd->a_addrany, port);
/* xxx meaningless?
* GET_CANONNAME(cur->ai_next, "anyaddr");
*/
} else {
GET_AI(cur->ai_next, afd, afd->a_loopback,
port);
/* xxx meaningless?
* GET_CANONNAME(cur->ai_next, "localhost");
*/
}
cur = cur->ai_next;
}
top = sentinel.ai_next;
if (top)
goto good;
else
ERR(EAI_FAMILY);
}
/* hostname as numeric name */
for (i = 0; afdl[i].a_af; i++) {
if (inet_pton(afdl[i].a_af, hostname, pton)) {
u_long v4a;
u_char pfx;
switch (afdl[i].a_af) {
case AF_INET:
v4a = ntohl(((struct in_addr *)pton)->s_addr);
if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
pai->ai_flags &= ~AI_CANONNAME;
v4a >>= IN_CLASSA_NSHIFT;
if (v4a == 0 || v4a == IN_LOOPBACKNET)
pai->ai_flags &= ~AI_CANONNAME;
break;
#ifdef INET6
case AF_INET6:
pfx = ((struct in6_addr *)pton)->s6_addr8[0];
if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
pai->ai_flags &= ~AI_CANONNAME;
break;
#endif
}
if (pai->ai_family == afdl[i].a_af ||
pai->ai_family == PF_UNSPEC) {
if (! (pai->ai_flags & AI_CANONNAME)) {
GET_AI(top, &afdl[i], pton, port);
goto good;
}
/*
* if AI_CANONNAME and if reverse lookup
* fail, return ai anyway to pacify
* calling application.
*
* XXX getaddrinfo() is a name->address
* translation function, and it looks strange
* that we do addr->name translation here.
*/
get_name(pton, &afdl[i], &top, pton, pai, port);
goto good;
} else
ERR(EAI_FAMILY); /*xxx*/
}
}
if (pai->ai_flags & AI_NUMERICHOST)
ERR(EAI_NONAME);
/* hostname as alphabetical name */
error = get_addr(hostname, pai->ai_family, &top, pai, port);
if (error == 0) {
if (top) {
good:
*res = top;
return SUCCESS;
} else
error = EAI_FAIL;
}
free:
if (top)
freeaddrinfo(top);
bad:
*res = NULL;
return error;
}
static int
get_name(addr, afd, res, numaddr, pai, port0)
const char *addr;
struct afd *afd;
struct addrinfo **res;
char *numaddr;
struct addrinfo *pai;
int port0;
{
u_short port = port0 & 0xffff;
struct hostent *hp;
struct addrinfo *cur;
int error = 0;
#ifdef USE_GETIPNODEBY
int h_error;
hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
#else
hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
#endif
if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
GET_AI(cur, afd, hp->h_addr_list[0], port);
GET_CANONNAME(cur, hp->h_name);
} else
GET_AI(cur, afd, numaddr, port);
#ifdef USE_GETIPNODEBY
if (hp)
freehostent(hp);
#endif
*res = cur;
return SUCCESS;
free:
if (cur)
freeaddrinfo(cur);
#ifdef USE_GETIPNODEBY
if (hp)
freehostent(hp);
#endif
/* bad: */
*res = NULL;
return error;
}
static int
get_addr(hostname, af, res, pai, port0)
const char *hostname;
int af;
struct addrinfo **res;
struct addrinfo *pai;
int port0;
{
int i, error;
struct addrinfo *cur;
#ifdef USE_GETIPNODEBY
return get_addr0(hostname, af, res, pai, port0);
#else
for (i = 0; afdl[i].a_af; i++) {
if (af == AF_UNSPEC || af == afdl[i].a_af)
;
else
continue;
error = get_addr0(hostname, afdl[i].a_af, res, pai, port0);
if (error == EAI_FAIL)
return error;
else
error = 0;
if (*res) {
/* make chain of addrs */
for (cur = *res;
cur && cur->ai_next;
cur = cur->ai_next)
;
if (!cur)
return EAI_FAIL;
res = &cur->ai_next;
}
}
return error;
#endif
}
static int
get_addr0(hostname, af, res, pai, port0)
const char *hostname;
int af;
struct addrinfo **res;
struct addrinfo *pai;
int port0;
{
u_short port = port0 & 0xffff;
struct addrinfo sentinel;
struct hostent *hp;
struct addrinfo *top, *cur;
struct afd *afd;
int i, error = 0, h_error;
char *ap;
#ifndef USE_GETIPNODEBY
extern int h_errno;
#endif
top = NULL;
sentinel.ai_next = NULL;
cur = &sentinel;
#ifdef USE_GETIPNODEBY
if (af == AF_UNSPEC) {
hp = getipnodebyname(hostname, AF_INET6,
AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
} else
hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
#else
if (af == AF_UNSPEC) {
error = EAI_FAIL;
goto bad;
}
hp = gethostbyname2(hostname, af);
h_error = h_errno;
#endif
if (hp == NULL) {
switch (h_error) {
case HOST_NOT_FOUND:
case NO_DATA:
error = EAI_NODATA;
break;
case TRY_AGAIN:
error = EAI_AGAIN;
break;
case NO_RECOVERY:
default:
error = EAI_FAIL;
break;
}
goto bad;
}
if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
(hp->h_addr_list[0] == NULL))
ERR(EAI_FAIL);
for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
switch (af) {
#ifdef INET6
case AF_INET6:
afd = &afdl[N_INET6];
break;
#endif
#ifndef INET6
default: /* AF_UNSPEC */
#endif
case AF_INET:
afd = &afdl[N_INET];
break;
#ifdef INET6
default: /* AF_UNSPEC */
if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
ap += sizeof(struct in6_addr) -
sizeof(struct in_addr);
afd = &afdl[N_INET];
} else
afd = &afdl[N_INET6];
break;
#endif
}
#ifdef FAITH
if (translate && afd->a_af == AF_INET) {
struct in6_addr *in6;
GET_AI(cur->ai_next, &afdl[N_INET6], ap, port);
in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
memcpy(&in6->s6_addr32[0], &faith_prefix,
sizeof(struct in6_addr) - sizeof(struct in_addr));
memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
} else
#endif /* FAITH */
GET_AI(cur->ai_next, afd, ap, port);
if (cur == &sentinel) {
top = cur->ai_next;
GET_CANONNAME(top, hp->h_name);
}
cur = cur->ai_next;
}
#ifdef USE_GETIPNODEBY
freehostent(hp);
#endif
*res = top;
return SUCCESS;
free:
if (top)
freeaddrinfo(top);
#ifdef USE_GETIPNODEBY
if (hp)
freehostent(hp);
#endif
bad:
*res = NULL;
return error;
}

201
lib/libc/net/getnameinfo.3 Normal file
View File

@ -0,0 +1,201 @@
.\" Copyright (c) 1983, 1987, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95
.\" $Id: getnameinfo.3,v 1.1 1999/07/01 18:23:54 itojun Exp $
.\"
.Dd May 25, 1995
.Dt GETNAMEINFO 3
.Os KAME
.Sh NAME
.Nm getnameinfo
.Nd address-to-nodename translation in protocol-independent manner
.Sh SYNOPSIS
.Fd #include <sys/socket.h>
.Fd #include <netdb.h>
.Ft int
.Fn getnameinfo "const struct sockaddr *sa" "socklen_t salen" \
"char *host" "size_t hostlen" "char *serv" "size_t servlen" "int flags"
.Sh DESCRIPTION
The
.Fn getnameinfo
function is defined for protocol-independent address-to-nodename translation.
Its functionality is a reverse conversion of
.Xr getaddrinfo 3 ,
and implements similar functionality with
.Xr gethostbyaddr 3 and
.Xr getservbyport 3
in more sophisticated manner.
.Pp
This function looks up an IP address and port number provided by the
caller in the DNS and system-specific database, and returns text
strings for both in buffers provided by the caller.
The function indicates successful completion by a zero return value;
a non-zero return value indicates failure.
.Pp
The first argument,
.Fa sa ,
points to either a
.Fa sockaddr_in
structure (for IPv4) or a
.Fa sockaddr_in6
structure (for IPv6) that holds the IP address and port number.
The
.Fa salen
argument gives the length of the
.Fa sockaddr_in
or
.Fa sockaddr_in6
structure.
.Pp
The function returns the nodename associated with the IP address in
the buffer pointed to by the
.Fa host
argument.
The caller provides the size of this buffer via the
.Fa hostlen
argument.
The service name associated with the port number is returned in the buffer
pointed to by
.Fa serv ,
and the
.Fa servlen
argument gives the length of this buffer.
The caller specifies not to return either string by providing a zero
value for the
.Fa hostlen
or
.Fa servlen
arguments.
Otherwise, the caller must provide buffers large enough to hold the
nodename and the service name, including the terminating null characters.
.Pp
Unfortunately most systems do not provide constants that specify the
maximum size of either a fully-qualified domain name or a service name.
Therefore to aid the application in allocating buffers for these two
returned strings the following constants are defined in
.Li <netdb.h> :
.Bd -literal -offset
#define NI_MAXHOST 1025
#define NI_MAXSERV 32
.Ed
.Pp
The first value is actually defined as the constant
.Dv MAXDNAME
in recent versions of BIND's
.Li <arpa/nameser.h>
header
.Po
older versions of BIND define this constant to be 256
.Pc
and the second is a guess based on the services listed in the current
Assigned Numbers RFC.
.Pp
The final argument is a
.Fa flag
that changes the default actions of this function.
By default the fully-qualified domain name (FQDN) for the host is
looked up in the DNS and returned.
If the flag bit
.Dv NI_NOFQDN
is set, only the nodename portion of the FQDN is returned for local hosts.
.Pp
If the
.Fa flag
bit
.Dv NI_NUMERICHOST
is set, or if the host's name cannot be located in the DNS,
the numeric form of the host's address is returned instead of its name
.Po
e.g., by calling
.Fn inet_ntop
instead of
.Fn getnodebyaddr
.Pc .
If the
.Fa flag
bit
.Dv NI_NAMEREQD
is set, an error is returned if the host's name cannot be located in the DNS.
.Pp
If the flag bit
.Dv NI_NUMERICSERV
is set, the numeric form of the service address is returned
.Pq e.g., its port number
instead of its name.
The two
.Dv NI_NUMERICxxx
flags are required to support the
.Li "-n"
flag that many commands provide.
.Pp
A fifth flag bit,
.Dv NI_DGRAM ,
specifies that the service is a datagram service, and causes
.Fn getservbyport
to be called with a second argument of "udp" instead of its default of "tcp".
This is required for the few ports (512-514)
that have different services for UDP and TCP.
.Pp
These
.Dv NI_xxx
flags are defined in
.Li <netdb.h> .
.Sh FILES
.Bl -tag -width /etc/resolv.conf -compact
.It Pa /etc/hosts
.It Pa /etc/host.conf
.It Pa /etc/resolv.conf
.El
.Sh DIAGNOSTICS
The function indicates successful completion by a zero return value;
a non-zero return value indicates failure.
.Sh SEE ALSO
.Xr getaddrinfo 3 ,
.Xr gethostbyaddr 3 ,
.Xr getservbyport 3 ,
.Xr hosts 5 ,
.Xr services 5 ,
.Xr hostname 7 ,
.Xr named 8
.Pp
R. Gilligan, S. Thomson, J. Bound, and W. Stevens,
``Basic Socket Interface Extensions for IPv6,'' RFC2553, March 1999.
.Sh HISTORY
The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit.
.Sh STANDARDS
The
.Fn getaddrinfo
function is defined IEEE POSIX 1003.1g draft specification,
and documented in ``Basic Socket Interface Extensions for IPv6''
.Pq RFC2533 .
.Sh BUGS
The text was shamelessly copied from RFC2553.

201
lib/libc/net/getnameinfo.c Normal file
View File

@ -0,0 +1,201 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Issues to be discussed:
* - Thread safe-ness must be checked
* - Return values. There seems to be no standard for return value (RFC2133)
* but INRIA implementation returns EAI_xxx defined for getaddrinfo().
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
#include <string.h>
#include <stddef.h>
#define SUCCESS 0
#define ANY 0
#define YES 1
#define NO 0
static struct afd {
int a_af;
int a_addrlen;
int a_socklen;
int a_off;
} afdl [] = {
#ifdef INET6
{PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
offsetof(struct sockaddr_in6, sin6_addr)},
#endif
{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
offsetof(struct sockaddr_in, sin_addr)},
{0, 0, 0},
};
struct sockinet {
u_char si_len;
u_char si_family;
u_short si_port;
};
#define ENI_NOSOCKET 0
#define ENI_NOSERVNAME 1
#define ENI_NOHOSTNAME 2
#define ENI_MEMORY 3
#define ENI_SYSTEM 4
#define ENI_FAMILY 5
#define ENI_SALEN 6
int
getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
const struct sockaddr *sa;
size_t salen;
char *host;
size_t hostlen;
char *serv;
size_t servlen;
int flags;
{
struct afd *afd;
struct servent *sp;
struct hostent *hp;
u_short port;
int family, len, i;
char *addr, *p;
u_long v4a;
u_char pfx;
int h_error;
char numserv[512];
char numaddr[512];
if (sa == NULL)
return ENI_NOSOCKET;
len = sa->sa_len;
if (len != salen) return ENI_SALEN;
family = sa->sa_family;
for (i = 0; afdl[i].a_af; i++)
if (afdl[i].a_af == family) {
afd = &afdl[i];
goto found;
}
return ENI_FAMILY;
found:
if (len != afd->a_socklen) return ENI_SALEN;
port = ((struct sockinet *)sa)->si_port; /* network byte order */
addr = (char *)sa + afd->a_off;
if (serv == NULL || servlen == 0) {
/* what we should do? */
} else if (flags & NI_NUMERICSERV) {
snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
if (strlen(numserv) > servlen)
return ENI_MEMORY;
strcpy(serv, numserv);
} else {
sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
if (sp) {
if (strlen(sp->s_name) > servlen)
return ENI_MEMORY;
strcpy(serv, sp->s_name);
} else
return ENI_NOSERVNAME;
}
switch (sa->sa_family) {
case AF_INET:
v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
flags |= NI_NUMERICHOST;
v4a >>= IN_CLASSA_NSHIFT;
if (v4a == 0 || v4a == IN_LOOPBACKNET)
flags |= NI_NUMERICHOST;
break;
#ifdef INET6
case AF_INET6:
pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
flags |= NI_NUMERICHOST;
break;
#endif
}
if (host == NULL || hostlen == 0) {
/* what should we do? */
} else if (flags & NI_NUMERICHOST) {
if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
== NULL)
return ENI_SYSTEM;
if (strlen(numaddr) > hostlen)
return ENI_MEMORY;
strcpy(host, numaddr);
} else {
#ifdef USE_GETIPNODEBY
hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
#else
hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
h_error = h_errno;
#endif
if (hp) {
if (flags & NI_NOFQDN) {
p = strchr(hp->h_name, '.');
if (p) *p = '\0';
}
if (strlen(hp->h_name) > hostlen) {
#ifdef USE_GETIPNODEBY
freehostent(hp);
#endif
return ENI_MEMORY;
}
strcpy(host, hp->h_name);
#ifdef USE_GETIPNODEBY
freehostent(hp);
#endif
} else {
if (flags & NI_NAMEREQD)
return ENI_NOHOSTNAME;
if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
== NULL)
return ENI_NOHOSTNAME;
if (strlen(numaddr) > hostlen)
return ENI_MEMORY;
strcpy(host, numaddr);
}
}
return SUCCESS;
}

View File

@ -0,0 +1,142 @@
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" From: @(#)rcmd.3 8.1 (Berkeley) 6/4/93
.\" $Id: if_indextoname.3,v 1.1 1999/07/01 18:23:54 itojun Exp $
.\"
.Dd May 21, 1998
.Dt IF_NAMETOINDEX 3
.Os KAME
.Sh NAME
.Nm if_nametoindex ,
.Nm if_indextoname ,
.Nm if_nameindex ,
.Nm if_freenameindex
.Nd convert interface index to name, and vice versa
.Sh SYNOPSIS
.Fd #include <net/if.h>
.Ft "unsigned int"
.Fn if_nametoindex "const char *ifname"
.Ft "char *"
.Fn if_indextoname "unsigned int ifindex" "char *ifname"
.Ft "struct if_nameindex *"
.Fn if_nameindex "void"
.Ft "void"
.Fn if_freenameindex "struct if_nameindex *ptr"
.Sh DESCRIPTION
The functions map interface index to readable interface name
.Po
such as
.Li ``lo0''
.Pc
, and vice versa.
.Pp
.Fn if_nametoindex
converts readable interface name to interface index
.Pp positive integer value .
If the specified interface does not exist, 0 will be returned.
.Pp
.Fn if_indextoname
converts interface index to readable interface name.
The
.Fa ifname
argument must point to a buffer of at least
.Dv IF_NAMESIZE
bytes into which the interface name corresponding to the specified index is
returned.
.Po
.Dv IF_NAMESIZE
is also defined in
.Li <net/if.h>
and its value includes a terminating null byte at the end of the
interface name.
.Pc
This pointer is also the return value of the function.
If there is no interface corresponding to the specified index,
.Dv NULL
is returned.
.Pp
.Fn if_nameindex
returns an array of
.Fa if_nameindex
structures.
.Fa if_nametoindex
is also defined in
.Li <net/if.h> ,
and is as follows:
.Bd -literal -offset
struct if_nameindex {
unsigned int if_index; /* 1, 2, ... */
char *if_name; /* null terminated name: "le0", ... */
};
.Ed
.Pp
The end of the array of structures is indicated by a structure with
an
.Fa if_index
of 0 and an
.Fa if_name
of
.Dv NULL .
The function returns a
.Dv NULL
pointer upon an error.
The memory used for this array of structures along with the interface
names pointed to by the
.Fa if_name
members is obtained dynamically.
This memory is freed by the
.Fn if_freenameindex
function.
.Pp
.Fn if_freenameindex
takes a pointer that was returned by
.Fn if_nameindex
as argument
.Pq Fa ptr ,
and it reclaims the region allocated.
.Sh DIAGNOSTICS
.Fn if_nametoindex
returns 0 on error, positive integer on success.
.Fn if_indextoname
and
.Fn if_nameindex
return
.Dv NULL
on errors.
.Sh SEE ALSO
R. Gilligan, S. Thomson, J. Bound, and W. Stevens,
``Basic Socket Interface Extensions for IPv6,'' RFC2553, March 1999.
.Sh HISTORY
The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit.
.Sh STANDARDS
These functions are defined in ``Basic Socket Interface Extensions for IPv6''
.Pq RFC2533 .

211
lib/libc/net/ifname.c Normal file
View File

@ -0,0 +1,211 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* TODO:
* - prototype defs into arpa/inet.h, not net/if.h (bsd-api-new-02)
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/errno.h>
#include <net/if.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <stdlib.h>
#include <string.h>
extern int errno;
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
unsigned int
if_nametoindex(ifname)
const char *ifname;
{
struct if_nameindex *iff = if_nameindex(), *ifx;
int ret;
if (iff == NULL) return 0;
ifx = iff;
while (ifx->if_name != NULL) {
if (strcmp(ifx->if_name, ifname) == 0) {
ret = ifx->if_index;
if_freenameindex(iff);
return ret;
}
ifx++;
}
if_freenameindex(iff);
errno = ENXIO;
return 0;
}
char *
if_indextoname(ifindex, ifname)
unsigned int ifindex;
char *ifname; /* at least IF_NAMESIZE */
{
struct if_nameindex *iff = if_nameindex(), *ifx;
char *cp, *dp;
if (iff == NULL) return NULL;
ifx = iff;
while (ifx->if_index != 0) {
if (ifx->if_index == ifindex) {
cp = ifname;
dp = ifx->if_name;
while ((*cp++ = *dp++)) ;
if_freenameindex(iff);
return (ifname);
}
ifx++;
}
if_freenameindex(iff);
errno = ENXIO;
return NULL;
}
struct if_nameindex *
if_nameindex()
{
size_t needed;
int mib[6], i, ifn = 0, off = 0, hlen;
char *buf = NULL, *lim, *next, *cp, *ifbuf = NULL;
struct rt_msghdr *rtm;
struct if_msghdr *ifm;
struct sockaddr *sa;
struct sockaddr_dl *sdl;
struct if_nameindex *ret = NULL;
static int ifxs = 64; /* initial upper limit */
struct _ifx {
int if_index;
int if_off;
} *ifx = NULL;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0; /* protocol */
mib[3] = 0; /* wildcard address family */
mib[4] = NET_RT_IFLIST;
mib[5] = 0; /* no flags */
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
return NULL;
if ((buf = malloc(needed)) == NULL) {
errno = ENOMEM;
goto end;
}
/* XXX: we may have allocated too much than necessary */
if ((ifbuf = malloc(needed)) == NULL) {
errno = ENOMEM;
goto end;
}
if ((ifx = (struct _ifx *)malloc(sizeof(*ifx) * ifxs)) == NULL) {
errno = ENOMEM;
goto end;
}
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
/* sysctl has set errno */
goto end;
}
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
if (rtm->rtm_version != RTM_VERSION) {
errno = EPROTONOSUPPORT;
goto end;
}
switch (rtm->rtm_type) {
case RTM_IFINFO:
ifm = (struct if_msghdr *)rtm;
ifx[ifn].if_index = ifm->ifm_index;
ifx[ifn].if_off = off;
cp = (char *)(ifm + 1);
for (i = 1; i; i <<= 1) {
if (i & ifm->ifm_addrs) {
sa = (struct sockaddr *)cp;
if (i == RTA_IFP &&
sa->sa_family == AF_LINK) {
sdl = (struct sockaddr_dl *)sa;
memcpy(ifbuf + off,
sdl->sdl_data,
sdl->sdl_nlen);
off += sdl->sdl_nlen;
*(ifbuf + off) = '\0';
off++;
}
ADVANCE(cp, sa);
}
}
if (++ifn == ifxs) {
/* we need more memory */
struct _ifx *newifx;
ifxs *= 2;
if ((newifx = (struct _ifx *)malloc(sizeof(*newifx) * ifxs)) == NULL) {
errno = ENOMEM;
goto end;
}
/* copy and free old data */
memcpy(newifx, ifx, (sizeof(*ifx) * ifxs) / 2);
free(ifx);
ifx = newifx;
}
}
}
hlen = sizeof(struct if_nameindex) * (ifn + 1);
if ((cp = (char *)malloc(hlen + off)) == NULL) {
errno = ENOMEM;
goto end;
}
bcopy(ifbuf, cp + hlen, off);
ret = (struct if_nameindex *)cp;
for (i = 0; i < ifn; i++) {
ret[i].if_index = ifx[i].if_index;
ret[i].if_name = cp + hlen + ifx[i].if_off;
}
ret[ifn].if_index = 0;
ret[ifn].if_name = NULL;
end:
if (buf) free(buf);
if (ifbuf) free(ifbuf);
if (ifx) free(ifx);
return ret;
}
void if_freenameindex(ptr)
struct if_nameindex *ptr;
{
free(ptr);
}

384
lib/libc/net/ip6opt.c Normal file
View File

@ -0,0 +1,384 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <string.h>
#include <stdio.h>
static int ip6optlen(u_int8_t *opt, u_int8_t *lim);
static void inet6_insert_padopt(u_char *p, int len);
/*
* This function returns the number of bytes required to hold an option
* when it is stored as ancillary data, including the cmsghdr structure
* at the beginning, and any padding at the end (to make its size a
* multiple of 8 bytes). The argument is the size of the structure
* defining the option, which must include any pad bytes at the
* beginning (the value y in the alignment term "xn + y"), the type
* byte, the length byte, and the option data.
*/
int
inet6_option_space(nbytes)
int nbytes;
{
nbytes += 2; /* we need space for nxt-hdr and length fields */
return(CMSG_SPACE((nbytes + 7) & ~7));
}
/*
* This function is called once per ancillary data object that will
* contain either Hop-by-Hop or Destination options. It returns 0 on
* success or -1 on an error.
*/
int
inet6_option_init(bp, cmsgp, type)
void *bp;
struct cmsghdr **cmsgp;
int type;
{
register struct cmsghdr *ch = (struct cmsghdr *)bp;
/* argument validation */
if (type != IPV6_HOPOPTS && type != IPV6_DSTOPTS)
return(-1);
ch->cmsg_level = IPPROTO_IPV6;
ch->cmsg_type = type;
ch->cmsg_len = CMSG_LEN(0);
*cmsgp = ch;
return(0);
}
/*
* This function appends a Hop-by-Hop option or a Destination option
* into an ancillary data object that has been initialized by
* inet6_option_init(). This function returns 0 if it succeeds or -1 on
* an error.
* multx is the value x in the alignment term "xn + y" described
* earlier. It must have a value of 1, 2, 4, or 8.
* plusy is the value y in the alignment term "xn + y" described
* earlier. It must have a value between 0 and 7, inclusive.
*/
int
inet6_option_append(cmsg, typep, multx, plusy)
struct cmsghdr *cmsg;
const u_int8_t *typep;
int multx;
int plusy;
{
int padlen, optlen, off;
register u_char *bp = (u_char *)cmsg + cmsg->cmsg_len;
struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg);
/* argument validation */
if (multx != 1 && multx != 2 && multx != 4 && multx != 8)
return(-1);
if (plusy < 0 || plusy > 7)
return(-1);
if (typep[0] > 255)
return(-1);
/*
* If this is the first option, allocate space for the
* first 2 bytes(for next header and length fields) of
* the option header.
*/
if (bp == (u_char *)eh) {
bp += 2;
cmsg->cmsg_len += 2;
}
/* calculate pad length before the option. */
off = bp - (u_char *)eh;
padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
(off % multx);
padlen += plusy;
/* insert padding */
inet6_insert_padopt(bp, padlen);
cmsg->cmsg_len += padlen;
bp += padlen;
/* copy the option */
if (typep[0] == IP6OPT_PAD1)
optlen = 1;
else
optlen = typep[1] + 2;
memcpy(bp, typep, optlen);
bp += optlen;
cmsg->cmsg_len += optlen;
/* calculate pad length after the option and insert the padding */
off = bp - (u_char *)eh;
padlen = ((off + 7) & ~7) - off;
inet6_insert_padopt(bp, padlen);
bp += padlen;
cmsg->cmsg_len += padlen;
/* update the length field of the ip6 option header */
eh->ip6e_len = ((bp - (u_char *)eh) >> 3) - 1;
return(0);
}
/*
* This function appends a Hop-by-Hop option or a Destination option
* into an ancillary data object that has been initialized by
* inet6_option_init(). This function returns a pointer to the 8-bit
* option type field that starts the option on success, or NULL on an
* error.
* The difference between this function and inet6_option_append() is
* that the latter copies the contents of a previously built option into
* the ancillary data object while the current function returns a
* pointer to the space in the data object where the option's TLV must
* then be built by the caller.
*
*/
u_int8_t *
inet6_option_alloc(cmsg, datalen, multx, plusy)
struct cmsghdr *cmsg;
int datalen;
int multx;
int plusy;
{
int padlen, off;
register u_int8_t *bp = (u_char *)cmsg + cmsg->cmsg_len;
u_int8_t *retval;
struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg);
/* argument validation */
if (multx != 1 && multx != 2 && multx != 4 && multx != 8)
return(NULL);
if (plusy < 0 || plusy > 7)
return(NULL);
/*
* If this is the first option, allocate space for the
* first 2 bytes(for next header and length fields) of
* the option header.
*/
if (bp == (u_char *)eh) {
bp += 2;
cmsg->cmsg_len += 2;
}
/* calculate pad length before the option. */
off = bp - (u_char *)eh;
padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
(off % multx);
padlen += plusy;
/* insert padding */
inet6_insert_padopt(bp, padlen);
cmsg->cmsg_len += padlen;
bp += padlen;
/* keep space to store specified length of data */
retval = bp;
bp += datalen;
cmsg->cmsg_len += datalen;
/* calculate pad length after the option and insert the padding */
off = bp - (u_char *)eh;
padlen = ((off + 7) & ~7) - off;
inet6_insert_padopt(bp, padlen);
bp += padlen;
cmsg->cmsg_len += padlen;
/* update the length field of the ip6 option header */
eh->ip6e_len = ((bp - (u_char *)eh) >> 3) - 1;
return(retval);
}
/*
* This function processes the next Hop-by-Hop option or Destination
* option in an ancillary data object. If another option remains to be
* processed, the return value of the function is 0 and *tptrp points to
* the 8-bit option type field (which is followed by the 8-bit option
* data length, followed by the option data). If no more options remain
* to be processed, the return value is -1 and *tptrp is NULL. If an
* error occurs, the return value is -1 and *tptrp is not NULL.
* (RFC 2292, 6.3.5)
*/
int
inet6_option_next(cmsg, tptrp)
const struct cmsghdr *cmsg;
u_int8_t **tptrp;
{
struct ip6_ext *ip6e;
int hdrlen, optlen;
u_int8_t *lim;
if (cmsg->cmsg_level != IPPROTO_IPV6 ||
(cmsg->cmsg_type != IPV6_HOPOPTS &&
cmsg->cmsg_type != IPV6_DSTOPTS))
return(-1);
/* message length validation */
if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext)))
return(-1);
ip6e = (struct ip6_ext *)CMSG_DATA(cmsg);
hdrlen = (ip6e->ip6e_len + 1) << 3;
if (cmsg->cmsg_len < CMSG_SPACE(hdrlen))
return(-1);
/*
* If the caller does not specify the starting point,
* simply return the 1st option.
* Otherwise, search the option list for the next option.
*/
lim = (u_int8_t *)ip6e + hdrlen;
if (*tptrp == NULL)
*tptrp = (u_int8_t *)(ip6e + 1);
else {
if ((optlen = ip6optlen(*tptrp, lim)) == 0)
return(-1);
*tptrp = *tptrp + optlen;
}
if (*tptrp >= lim) { /* there is no option */
*tptrp = NULL;
return(-1);
}
/*
* Finally, checks if the next option is safely stored in the
* cmsg data.
*/
if (ip6optlen(*tptrp, lim) == 0)
return(-1);
else
return(0);
}
/*
* This function is similar to the inet6_option_next() function,
* except this function lets the caller specify the option type to be
* searched for, instead of always returning the next option in the
* ancillary data object.
* Note: RFC 2292 says the type of tptrp is u_int8_t *, but we think
* it's a typo. The variable should be type of u_int8_t **.
*/
int
inet6_option_find(cmsg, tptrp, type)
const struct cmsghdr *cmsg;
u_int8_t **tptrp;
int type;
{
struct ip6_ext *ip6e;
int hdrlen, optlen;
u_int8_t *optp, *lim;
if (cmsg->cmsg_level != IPPROTO_IPV6 ||
(cmsg->cmsg_type != IPV6_HOPOPTS &&
cmsg->cmsg_type != IPV6_DSTOPTS))
return(-1);
/* message length validation */
if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext)))
return(-1);
ip6e = (struct ip6_ext *)CMSG_DATA(cmsg);
hdrlen = (ip6e->ip6e_len + 1) << 3;
if (cmsg->cmsg_len < CMSG_SPACE(hdrlen))
return(-1);
/*
* If the caller does not specify the starting point,
* search from the beginning of the option list.
* Otherwise, search from *the next option* of the specified point.
*/
lim = (u_int8_t *)ip6e + hdrlen;
if (*tptrp == NULL)
*tptrp = (u_int8_t *)(ip6e + 1);
else {
if ((optlen = ip6optlen(*tptrp, lim)) == 0)
return(-1);
*tptrp = *tptrp + optlen;
}
for (optp = *tptrp; optp < lim; optp += optlen) {
if (*optp == type) {
*tptrp = optp;
return(0);
}
if ((optlen = ip6optlen(optp, lim)) == 0)
return(-1);
}
/* search failed */
*tptrp = NULL;
return(-1);
}
/*
* Calculate the length of a given IPv6 option. Also checks
* if the option is safely stored in user's buffer according to the
* calculated length and the limitation of the buffer.
*/
static int
ip6optlen(opt, lim)
u_int8_t *opt, *lim;
{
int optlen;
if (*opt == IP6OPT_PAD1)
optlen = 1;
else {
/* is there enough space to store type and len? */
if (opt + 2 > lim)
return(0);
optlen = *(opt + 1) + 2;
}
if (opt + optlen <= lim)
return(optlen);
return(0);
}
static void
inet6_insert_padopt(u_char *p, int len)
{
switch(len) {
case 0:
return;
case 1:
p[0] = IP6OPT_PAD1;
return;
default:
p[0] = IP6OPT_PADN;
p[1] = len - 2;
memset(&p[2], 0, len - 2);
return;
}
}

296
lib/libc/net/rthdr.c Normal file
View File

@ -0,0 +1,296 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <string.h>
#include <stdio.h>
size_t
inet6_rthdr_space(type, seg)
int type, seg;
{
switch(type) {
case IPV6_RTHDR_TYPE_0:
if (seg < 1 || seg > 23)
return(0);
return(CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1)
+ sizeof(struct ip6_rthdr0)));
default:
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_space: unknown type(%d)\n", type);
#endif
return(0);
}
}
struct cmsghdr *
inet6_rthdr_init(bp, type)
void *bp;
int type;
{
register struct cmsghdr *ch = (struct cmsghdr *)bp;
register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(ch + 1);
ch->cmsg_level = IPPROTO_IPV6;
ch->cmsg_type = IPV6_RTHDR;
switch(type) {
case IPV6_RTHDR_TYPE_0:
ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) - sizeof(struct in6_addr));
bzero(rthdr, sizeof(struct ip6_rthdr0));
rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
return(ch);
default:
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_init: unknown type(%d)\n", type);
#endif
return(NULL);
}
}
int
inet6_rthdr_add(cmsg, addr, flags)
struct cmsghdr *cmsg;
const struct in6_addr *addr;
u_int flags;
{
register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(cmsg + 1);
switch(rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_add: unsupported flag(%d)\n", flags);
#endif
return(-1);
}
if (rt0->ip6r0_segleft == 23) {
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
#endif
return(-1);
}
if (flags == IPV6_RTHDR_STRICT) {
int c, b;
c = rt0->ip6r0_segleft / 8;
b = rt0->ip6r0_segleft % 8;
rt0->ip6r0_slmap[c] |= (1 << (7 - b));
}
rt0->ip6r0_segleft++;
bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3),
sizeof(struct in6_addr));
rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
break;
}
default:
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_add: unknown type(%d)\n",
rthdr->ip6r_type);
#endif
return(-1);
}
return(0);
}
int
inet6_rthdr_lasthop(cmsg, flags)
struct cmsghdr *cmsg;
unsigned int flags;
{
register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(cmsg + 1);
switch(rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT) {
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_lasthop: unsupported flag(%d)\n", flags);
#endif
return(-1);
}
if (rt0->ip6r0_segleft > 23) {
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_add: segment overflow\n");
#endif
return(-1);
}
if (flags == IPV6_RTHDR_STRICT) {
int c, b;
c = rt0->ip6r0_segleft / 8;
b = rt0->ip6r0_segleft % 8;
rt0->ip6r0_slmap[c] |= (1 << (7 - b));
}
break;
}
default:
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_lasthop: unknown type(%d)\n",
rthdr->ip6r_type);
#endif
return(-1);
}
return(0);
}
#if 0
int
inet6_rthdr_reverse(in, out)
const struct cmsghdr *in;
struct cmsghdr *out;
{
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_reverse: not implemented yet\n");
#endif
return -1;
}
#endif
int
inet6_rthdr_segments(cmsg)
const struct cmsghdr *cmsg;
{
register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(cmsg + 1);
switch(rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_segments: invalid size(%d)\n",
rt0->ip6r0_len);
#endif
return -1;
}
return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
}
default:
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_segments: unknown type(%d)\n",
rthdr->ip6r_type);
#endif
return -1;
}
}
struct in6_addr *
inet6_rthdr_getaddr(cmsg, index)
struct cmsghdr *cmsg;
int index;
{
register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(cmsg + 1);
switch(rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
int naddr;
if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_getaddr: invalid size(%d)\n",
rt0->ip6r0_len);
#endif
return NULL;
}
naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
if (index <= 0 || naddr < index) {
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_getaddr: invalid index(%d)\n", index);
#endif
return NULL;
}
return &rt0->ip6r0_addr[index - 1];
}
default:
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_getaddr: unknown type(%d)\n",
rthdr->ip6r_type);
#endif
return NULL;
}
}
int
inet6_rthdr_getflags(cmsg, index)
const struct cmsghdr *cmsg;
int index;
{
register struct ip6_rthdr *rthdr = (struct ip6_rthdr *)(cmsg + 1);
switch(rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
int naddr;
if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len) {
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_getflags: invalid size(%d)\n",
rt0->ip6r0_len);
#endif
return -1;
}
naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
if (index < 0 || naddr < index) {
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_getflags: invalid index(%d)\n", index);
#endif
return -1;
}
if (rt0->ip6r0_slmap[index / 8] & (0x80 >> (index % 8)))
return IPV6_RTHDR_STRICT;
else
return IPV6_RTHDR_LOOSE;
}
default:
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_getflags: unknown type(%d)\n",
rthdr->ip6r_type);
#endif
return -1;
}
}

40
lib/libc/net/vars6.c Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <netinet/in.h>
/*
* Definitions of some costant IPv6 addresses.
*/
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
const struct in6_addr in6addr_nodelocal_allnodes = IN6ADDR_NODELOCAL_ALLNODES_INIT;
const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;

View File

@ -1,5 +1,5 @@
# $NetBSD: shlib_version,v 1.71 1999/06/29 22:30:19 wrstuden Exp $
# $NetBSD: shlib_version,v 1.72 1999/07/01 18:23:53 itojun Exp $
# Remember to update distrib/sets/lists/base/shl.* when changing
#
major=12
minor=43
minor=44