Switch Advanced Sockets API for IPv6 from RFC2292 to RFC3542

(aka RFC2292bis).  Though I believe this commit doesn't break
backward compatibility againt existing binaries, it breaks
backward compatibility of API.
Now, the applications which use Advanced Sockets API such as
telnet, ping6, mld6query and traceroute6 use RFC3542 API.

Obtained from:	KAME
This commit is contained in:
ume 2003-10-24 18:26:30 +00:00
parent 0b2009d038
commit 881c4fa391
32 changed files with 3107 additions and 1144 deletions

View File

@ -2846,7 +2846,7 @@ sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop,
struct sockaddr_in *_sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
struct cmsghdr *cmsg;
struct ip6_rthdr *rth;
#endif
struct addrinfo hints, *res;
int error;
@ -2889,11 +2889,13 @@ sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop,
#ifdef INET6
if (ai->ai_family == AF_INET6) {
cmsg = inet6_rthdr_init(*cpp, IPV6_RTHDR_TYPE_0);
if ((rth = inet6_rth_init((void *)*cpp, sizeof(buf),
IPV6_RTHDR_TYPE_0, 0)) == NULL)
return -1;
if (*cp != '@')
return -1;
*protop = IPPROTO_IPV6;
*optp = IPV6_PKTOPTIONS;
*optp = IPV6_RTHDR;
} else
#endif
{
@ -2965,8 +2967,8 @@ sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop,
#ifdef INET6
if (res->ai_family == AF_INET6) {
sin6 = (struct sockaddr_in6 *)res->ai_addr;
inet6_rthdr_add(cmsg, &sin6->sin6_addr,
IPV6_RTHDR_LOOSE);
if (inet6_rth_add((void *)rth, &sin6->sin6_addr) == -1)
return(0);
} else
#endif
{
@ -2981,23 +2983,14 @@ sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop,
/*
* Check to make sure there is space for next address
*/
#ifdef INET6
if (res->ai_family == AF_INET6) {
if (((char *)CMSG_DATA(cmsg) +
sizeof(struct ip6_rthdr) +
((inet6_rthdr_segments(cmsg) + 1) *
sizeof(struct in6_addr))) > ep)
return -1;
} else
#endif
if (lsrp + 4 > ep)
return -1;
freeaddrinfo(res);
}
#ifdef INET6
if (res->ai_family == AF_INET6) {
inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
*lenp = cmsg->cmsg_len;
rth->ip6r_len = rth->ip6r_segleft * 2;
*lenp = (rth->ip6r_len + 1) << 3;
} else
#endif
{

View File

@ -44,7 +44,8 @@ MAN+= addr2ascii.3 byteorder.3 ethers.3 getaddrinfo.3 gethostbyname.3 \
getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 hesiod.3 \
if_indextoname.3 \
inet.3 inet_net.3 \
inet6_option_space.3 inet6_rthdr_space.3 linkaddr.3 \
inet6_opt_init.3 inet6_option_space.3 inet6_rth_space.3 \
inet6_rthdr_space.3 linkaddr.3 \
nsdispatch.3 rcmd.3 rcmdsh.3 resolver.3 sockatmark.3
MLINKS+=addr2ascii.3 ascii2addr.3
@ -73,11 +74,22 @@ MLINKS+=inet.3 addr.3 inet.3 inet_addr.3 inet.3 inet_aton.3 \
inet.3 inet_ntop.3 inet.3 inet_pton.3 \
inet.3 network.3 inet.3 ntoa.3
MLINKS+=inet_net.3 inet_net_ntop.3 inet_net.3 inet_net_pton.3
MLINKS+=inet6_option_space.3 inet6_option_alloc.3 \
MLINKS+=inet6_opt_init.3 inet6_opt_append.3 \
inet6_opt_init.3 inet6_opt_find.3 \
inet6_opt_init.3 inet6_opt_finish.3 \
inet6_opt_init.3 inet6_opt_get_val.3 \
inet6_opt_init.3 inet6_opt_next.3 \
inet6_opt_init.3 inet6_opt_set_val.3 \
inet6_option_space.3 inet6_option_alloc.3 \
inet6_option_space.3 inet6_option_append.3 \
inet6_option_space.3 inet6_option_find.3 \
inet6_option_space.3 inet6_option_init.3 \
inet6_option_space.3 inet6_option_next.3 \
inet6_rth_space.3 inet6_rth_add.3 \
inet6_rth_space.3 inet6_rth_getaddr.3 \
inet6_rth_space.3 inet6_rth_init.3 \
inet6_rth_space.3 inet6_rth_reverse.3 \
inet6_rth_space.3 inet6_rth_segments.3 \
inet6_rthdr_space.3 inet6_rthdr_add.3 \
inet6_rthdr_space.3 inet6_rthdr_getaddr.3 \
inet6_rthdr_space.3 inet6_rthdr_getflags.3 \

View File

@ -1,4 +1,4 @@
/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */
/* $KAME: getaddrinfo.c,v 1.160 2003/05/17 01:30:42 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -37,6 +37,10 @@
* - Return values. There are nonstandard return values defined and used
* in the source code. This is because RFC2553 is silent about which error
* code must be returned for which situation.
* - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2
* says to use inet_aton() to convert IPv4 numeric to binary (allows
* classful form as a result).
* current code - disallow classful form for IPv4 (due to use of inet_pton).
* - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
* invalid. current code - SEGV on freeaddrinfo(NULL)
*
@ -71,11 +75,15 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#ifdef INET6
#include <sys/queue.h>
#include <net/if_var.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <netinet6/in6_var.h> /* XXX */
#endif /* INET6 */
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#include <netdb.h>
#include <pthread.h>
#include <resolv.h>
@ -153,23 +161,24 @@ struct explore {
#define WILD_AF(ex) ((ex)->e_wild & 0x01)
#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
#define WILD_ACTIVE(ex) ((ex)->e_wild & 0x08)
#define WILD_PASSIVE(ex) ((ex)->e_wild & 0x10)
};
static const struct explore explore[] = {
#if 0
{ PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
{ PF_LOCAL, ANY, ANY, NULL, 0x01 },
#endif
#ifdef INET6
{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
{ PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x1f },
{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x0f }, /* !PASSIVE */
{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x17 }, /* PASSIVE */
{ PF_INET6, SOCK_RAW, ANY, NULL, 0x1d },
#endif
{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
{ PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
{ PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
{ PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x1f },
{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x0f }, /* !PASSIVE */
{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x17 }, /* PASSIVE */
{ PF_INET, SOCK_RAW, ANY, NULL, 0x1d },
{ -1, 0, 0, NULL, 0 },
};
@ -179,6 +188,8 @@ static const struct explore explore[] = {
#define PTON_MAX 4
#endif
#define AIO_SRCFLAG_DEPRECATED 0x1
static const ns_src default_dns_files[] = {
{ NSSRC_FILES, NS_SUCCESS },
{ NSSRC_DNS, NS_SUCCESS },
@ -202,20 +213,23 @@ typedef union {
} querybuf;
static int str_isnumber(const char *);
static int explore_copy(const struct addrinfo *, const struct addrinfo *,
struct addrinfo **);
static int explore_null(const struct addrinfo *,
const char *, struct addrinfo **);
static int explore_numeric(const struct addrinfo *, const char *,
const char *, struct addrinfo **);
const char *, struct addrinfo **, const char *);
static int explore_numeric_scope(const struct addrinfo *, const char *,
const char *, struct addrinfo **);
static int get_canonname(const struct addrinfo *,
struct addrinfo *, const char *);
static struct addrinfo *get_ai(const struct addrinfo *,
const struct afd *, const char *);
static struct addrinfo *copy_ai(const struct addrinfo *);
static int get_portmatch(const struct addrinfo *, const char *);
static int get_port(struct addrinfo *, const char *, int);
static const struct afd *find_afd(int);
static int addrconfig(struct addrinfo *);
static int addrconfig(int);
#ifdef INET6
static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
#endif
@ -373,10 +387,20 @@ getaddrinfo(hostname, servname, hints, res)
struct addrinfo sentinel;
struct addrinfo *cur;
int error = 0;
struct addrinfo ai;
struct addrinfo ai0;
struct addrinfo ai, ai0, *afai;
struct addrinfo *pai;
const struct afd *afd;
const struct explore *ex;
struct addrinfo *afailist[sizeof(afdl)/sizeof(afdl[0])];
struct addrinfo *afai_unspec;
int found;
int numeric = 0;
/* ensure we return NULL on errors */
*res = NULL;
memset(afailist, 0, sizeof(afailist));
afai_unspec = NULL;
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
@ -417,20 +441,27 @@ getaddrinfo(hostname, servname, hints, res)
*/
if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
for (ex = explore; ex->e_af >= 0; ex++) {
if (pai->ai_family != ex->e_af)
if (!MATCH_FAMILY(pai->ai_family, ex->e_af,
WILD_AF(ex)))
continue;
if (ex->e_socktype == ANY)
if (!MATCH(pai->ai_socktype, ex->e_socktype,
WILD_SOCKTYPE(ex)))
continue;
if (ex->e_protocol == ANY)
if (!MATCH(pai->ai_protocol, ex->e_protocol,
WILD_PROTOCOL(ex)))
continue;
if (pai->ai_socktype == ex->e_socktype &&
pai->ai_protocol != ex->e_protocol) {
ERR(EAI_BADHINTS);
}
/* matched */
break;
}
if (ex->e_af < 0) {
ERR(EAI_BADHINTS);
}
}
}
#if defined(AI_ALL) && defined(AI_V4MAPPED)
/*
* post-2553: AI_ALL and AI_V4MAPPED are effective only against
* AF_INET6 query. They need to be ignored if specified in other
@ -451,6 +482,7 @@ getaddrinfo(hostname, servname, hints, res)
#endif
break;
}
#endif
/*
* check for special cases. (1) numeric servname is disallowed if
@ -459,7 +491,7 @@ getaddrinfo(hostname, servname, hints, res)
*/
if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
#ifdef PF_INET6
|| MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
|| MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
#endif
) {
ai0 = *pai; /* backup *pai */
@ -480,13 +512,63 @@ getaddrinfo(hostname, servname, hints, res)
ai0 = *pai;
/* NULL hostname, or numeric hostname */
/*
* NULL hostname, or numeric hostname.
* If numreic representation of AF1 can be interpreted as FQDN
* representation of AF2, we need to think again about the code below.
*/
found = 0;
for (afd = afdl; afd->a_af; afd++) {
*pai = ai0;
if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
continue;
if (pai->ai_family == PF_UNSPEC)
pai->ai_family = afd->a_af;
if (hostname == NULL) {
/*
* filter out AFs that are not supported by the kernel
* XXX errno?
*/
if (!addrconfig(pai->ai_family))
continue;
error = explore_null(pai, servname,
&afailist[afd - afdl]);
} else
error = explore_numeric_scope(pai, hostname, servname,
&afailist[afd - afdl]);
if (!error && afailist[afd - afdl])
found++;
}
if (found) {
numeric = 1;
goto globcopy;
}
if (hostname == NULL)
ERR(EAI_NONAME); /* used to be EAI_NODATA */
if (pai->ai_flags & AI_NUMERICHOST)
ERR(EAI_NONAME);
/*
* hostname as alphabetical name.
* first, try to query DNS for all possible address families.
*/
/*
* the operating systems support PF_UNSPEC lookup in explore_fqdn().
*/
*pai = ai0;
error = explore_fqdn(pai, hostname, servname, &afai_unspec);
globcopy:
for (ex = explore; ex->e_af >= 0; ex++) {
*pai = ai0;
/* PF_UNSPEC entries are prepared for DNS queries only */
if (ex->e_af == PF_UNSPEC)
continue;
if (pai->ai_family == PF_UNSPEC)
pai->ai_family = ex->e_af;
if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
continue;
@ -495,6 +577,23 @@ getaddrinfo(hostname, servname, hints, res)
if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
continue;
#ifdef AI_ADDRCONFIG
/*
* If AI_ADDRCONFIG is specified, check if we are
* expected to return the address family or not.
*/
if ((pai->ai_flags & AI_ADDRCONFIG) != 0 &&
!addrconfig(afd->a_af))
continue;
#endif
if ((pai->ai_flags & AI_PASSIVE) != 0 && WILD_PASSIVE(ex))
;
else if ((pai->ai_flags & AI_PASSIVE) == 0 && WILD_ACTIVE(ex))
;
else
continue;
if (pai->ai_family == PF_UNSPEC)
pai->ai_family = ex->e_af;
if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
@ -502,86 +601,93 @@ getaddrinfo(hostname, servname, hints, res)
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
pai->ai_protocol = ex->e_protocol;
if (hostname == NULL)
error = explore_null(pai, servname, &cur->ai_next);
else
error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
/*
* if the servname does not match socktype/protocol, ignore it.
*/
if (get_portmatch(pai, servname) != 0)
continue;
if (error)
goto free;
if (afai_unspec)
afai = afai_unspec;
else {
if ((afd = find_afd(pai->ai_family)) == NULL)
continue;
/* XXX assumes that afd points inside afdl[] */
afai = afailist[afd - afdl];
}
if (!afai)
continue;
error = explore_copy(pai, afai, &cur->ai_next);
while (cur && cur->ai_next)
cur = cur->ai_next;
}
/*
* XXX
* If numreic representation of AF1 can be interpreted as FQDN
* representation of AF2, we need to think again about the code below.
*/
if (sentinel.ai_next)
goto good;
if (hostname == NULL)
ERR(EAI_NONAME); /* used to be EAI_NODATA */
if (pai->ai_flags & AI_NUMERICHOST)
ERR(EAI_NONAME);
if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0))
ERR(EAI_FAIL);
/*
* hostname as alphabetical name.
* we would like to prefer AF_INET6 than AF_INET, so we'll make a
* outer loop by AFs.
*/
for (ex = explore; ex->e_af >= 0; ex++) {
*pai = ai0;
/* require exact match for family field */
if (pai->ai_family != ex->e_af)
continue;
if (!MATCH(pai->ai_socktype, ex->e_socktype,
WILD_SOCKTYPE(ex))) {
continue;
}
if (!MATCH(pai->ai_protocol, ex->e_protocol,
WILD_PROTOCOL(ex))) {
continue;
}
if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
pai->ai_socktype = ex->e_socktype;
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
pai->ai_protocol = ex->e_protocol;
error = explore_fqdn(pai, hostname, servname,
&cur->ai_next);
while (cur && cur->ai_next)
cur = cur->ai_next;
}
/* XXX */
/* XXX inhibit errors if we have the result */
if (sentinel.ai_next)
error = 0;
if (error)
goto free;
/*
* ensure we return either:
* - error == 0, non-NULL *res
* - error != 0, NULL *res
*/
if (error == 0) {
if (sentinel.ai_next) {
good:
*res = sentinel.ai_next;
return SUCCESS;
error = 0;
} else
error = EAI_FAIL;
}
free:
bad:
if (sentinel.ai_next)
freeaddrinfo(sentinel.ai_next);
*res = NULL;
bad:
if (afai_unspec)
freeaddrinfo(afai_unspec);
for (afd = afdl; afd->a_af; afd++) {
if (afailist[afd - afdl])
freeaddrinfo(afailist[afd - afdl]);
}
if (!*res)
if (sentinel.ai_next)
freeaddrinfo(sentinel.ai_next);
return error;
}
static int
explore_copy(pai, src0, res)
const struct addrinfo *pai; /* seed */
const struct addrinfo *src0; /* source */
struct addrinfo **res;
{
int error;
struct addrinfo sentinel, *cur;
const struct addrinfo *src;
error = 0;
sentinel.ai_next = NULL;
cur = &sentinel;
for (src = src0; src != NULL; src = src->ai_next) {
if (src->ai_family != pai->ai_family)
continue;
cur->ai_next = copy_ai(src);
if (!cur->ai_next) {
error = EAI_MEMORY;
goto fail;
}
cur->ai_next->ai_socktype = pai->ai_socktype;
cur->ai_next->ai_protocol = pai->ai_protocol;
cur = cur->ai_next;
}
*res = sentinel.ai_next;
return 0;
fail:
freeaddrinfo(sentinel.ai_next);
return error;
}
@ -596,7 +702,6 @@ explore_null(pai, servname, res)
const char *servname;
struct addrinfo **res;
{
int s;
const struct afd *afd;
struct addrinfo *cur;
struct addrinfo sentinel;
@ -606,17 +711,6 @@ explore_null(pai, servname, res)
sentinel.ai_next = NULL;
cur = &sentinel;
/*
* filter out AFs that are not supported by the kernel
* XXX errno?
*/
s = _socket(pai->ai_family, SOCK_DGRAM, 0);
if (s < 0) {
if (errno != EMFILE)
return 0;
} else
_close(s);
/*
* if the servname does not match socktype/protocol, ignore it.
*/
@ -655,11 +749,12 @@ explore_null(pai, servname, res)
* numeric hostname
*/
static int
explore_numeric(pai, hostname, servname, res)
explore_numeric(pai, hostname, servname, res, canonname)
const struct addrinfo *pai;
const char *hostname;
const char *servname;
struct addrinfo **res;
const char *canonname;
{
const struct afd *afd;
struct addrinfo *cur;
@ -671,12 +766,6 @@ explore_numeric(pai, hostname, servname, res)
sentinel.ai_next = NULL;
cur = &sentinel;
/*
* if the servname does not match socktype/protocol, ignore it.
*/
if (get_portmatch(pai, servname) != 0)
return 0;
afd = find_afd(pai->ai_family);
if (afd == NULL)
return 0;
@ -689,6 +778,14 @@ explore_numeric(pai, hostname, servname, res)
pai->ai_family == PF_UNSPEC /*?*/) {
GET_AI(cur->ai_next, afd, pton);
GET_PORT(cur->ai_next, servname);
if ((pai->ai_flags & AI_CANONNAME)) {
/*
* Set the numeric address itself as
* the canonical name, based on a
* clarification in rfc2553bis-03.
*/
GET_CANONNAME(cur->ai_next, canonname);
}
while (cur && cur->ai_next)
cur = cur->ai_next;
} else
@ -702,6 +799,14 @@ explore_numeric(pai, hostname, servname, res)
pai->ai_family == PF_UNSPEC /*?*/) {
GET_AI(cur->ai_next, afd, pton);
GET_PORT(cur->ai_next, servname);
if ((pai->ai_flags & AI_CANONNAME)) {
/*
* Set the numeric address itself as
* the canonical name, based on a
* clarification in rfc2553bis-03.
*/
GET_CANONNAME(cur->ai_next, canonname);
}
while (cur && cur->ai_next)
cur = cur->ai_next;
} else
@ -731,7 +836,7 @@ explore_numeric_scope(pai, hostname, servname, res)
struct addrinfo **res;
{
#if !defined(SCOPE_DELIMITER) || !defined(INET6)
return explore_numeric(pai, hostname, servname, res);
return explore_numeric(pai, hostname, servname, res, hostname);
#else
const struct afd *afd;
struct addrinfo *cur;
@ -739,22 +844,16 @@ explore_numeric_scope(pai, hostname, servname, res)
char *cp, *hostname2 = NULL, *scope, *addr;
struct sockaddr_in6 *sin6;
/*
* if the servname does not match socktype/protocol, ignore it.
*/
if (get_portmatch(pai, servname) != 0)
return 0;
afd = find_afd(pai->ai_family);
if (afd == NULL)
return 0;
if (!afd->a_scoped)
return explore_numeric(pai, hostname, servname, res);
return explore_numeric(pai, hostname, servname, res, hostname);
cp = strchr(hostname, SCOPE_DELIMITER);
if (cp == NULL)
return explore_numeric(pai, hostname, servname, res);
return explore_numeric(pai, hostname, servname, res, hostname);
/*
* Handle special case of <scoped_address><delimiter><scope id>
@ -767,7 +866,7 @@ explore_numeric_scope(pai, hostname, servname, res)
addr = hostname2;
scope = cp + 1;
error = explore_numeric(pai, addr, servname, res);
error = explore_numeric(pai, addr, servname, res, hostname);
if (error == 0) {
u_int32_t scopeid;
@ -777,6 +876,8 @@ explore_numeric_scope(pai, hostname, servname, res)
sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
free(hostname2);
freeaddrinfo(*res);
*res = NULL;
return(EAI_NONAME); /* XXX: is return OK? */
}
sin6->sin6_scope_id = scopeid;
@ -785,6 +886,10 @@ explore_numeric_scope(pai, hostname, servname, res)
free(hostname2);
if (error && *res) {
freeaddrinfo(*res);
*res = NULL;
}
return error;
#endif
}
@ -796,10 +901,9 @@ get_canonname(pai, ai, str)
const char *str;
{
if ((pai->ai_flags & AI_CANONNAME) != 0) {
ai->ai_canonname = (char *)malloc(strlen(str) + 1);
ai->ai_canonname = strdup(str);
if (ai->ai_canonname == NULL)
return EAI_MEMORY;
strlcpy(ai->ai_canonname, str, strlen(str) + 1);
}
return 0;
}
@ -875,6 +979,39 @@ get_ai(pai, afd, addr)
return ai;
}
/* XXX need to malloc() the same way we do from other functions! */
static struct addrinfo *
copy_ai(pai)
const struct addrinfo *pai;
{
struct addrinfo *ai;
size_t l;
l = sizeof(*ai) + pai->ai_addrlen;
if ((ai = (struct addrinfo *)malloc(l)) == NULL)
return NULL;
memset(ai, 0, l);
memcpy(ai, pai, sizeof(*ai));
ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen);
if (pai->ai_canonname) {
l = strlen(pai->ai_canonname) + 1;
if ((ai->ai_canonname = malloc(l)) == NULL) {
free(ai);
return NULL;
}
strlcpy(ai->ai_canonname, pai->ai_canonname, l);
} else {
/* just to make sure */
ai->ai_canonname = NULL;
}
ai->ai_next = NULL;
return ai;
}
static int
get_portmatch(ai, servname)
const struct addrinfo *ai;
@ -914,6 +1051,7 @@ get_port(ai, servname, matchonly)
return EAI_SERVICE;
case SOCK_DGRAM:
case SOCK_STREAM:
case SOCK_SEQPACKET:
allownumeric = 1;
break;
case ANY:
@ -931,11 +1069,11 @@ get_port(ai, servname, matchonly)
return EAI_SERVICE;
port = htons(port);
} else {
switch (ai->ai_socktype) {
case SOCK_DGRAM:
switch (ai->ai_protocol) {
case IPPROTO_UDP:
proto = "udp";
break;
case SOCK_STREAM:
case IPPROTO_TCP:
proto = "tcp";
break;
default:
@ -986,41 +1124,20 @@ find_afd(af)
* will take care of it.
* the semantics of AI_ADDRCONFIG is not defined well. we are not sure
* if the code is right or not.
*
* XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with
* _dns_getaddrinfo.
*/
static int
addrconfig(pai)
struct addrinfo *pai;
addrconfig(af)
int af;
{
int s, af;
int s;
/*
* TODO:
* Note that implementation dependent test for address
* configuration should be done everytime called
* (or apropriate interval),
* because addresses will be dynamically assigned or deleted.
*/
af = pai->ai_family;
if (af == AF_UNSPEC) {
if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
af = AF_INET;
else {
_close(s);
if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
af = AF_INET6;
else
_close(s);
}
}
if (af != AF_UNSPEC) {
if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
/* XXX errno */
s = socket(af, SOCK_DGRAM, 0);
if (s < 0) {
if (errno != EMFILE)
return 0;
_close(s);
}
pai->ai_family = af;
} else
close(s);
return 1;
}
@ -1033,16 +1150,15 @@ ip6_str2scopeid(scope, sin6, scopeid)
u_int32_t *scopeid;
{
u_long lscopeid;
struct in6_addr *a6;
struct in6_addr *a6 = &sin6->sin6_addr;
char *ep;
a6 = &sin6->sin6_addr;
/* empty scopeid portion is invalid */
if (*scope == '\0')
return -1;
if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
IN6_IS_ADDR_MC_NODELOCAL(a6)) {
/*
* We currently assume a one-to-one mapping between links
* and interfaces, so we simply use interface indices for
@ -1063,7 +1179,7 @@ ip6_str2scopeid(scope, sin6, scopeid)
goto trynumeric; /* global */
/* try to convert to a numeric id as a last resort */
trynumeric:
trynumeric:
errno = 0;
lscopeid = strtoul(scope, &ep, 10);
*scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
@ -1699,9 +1815,13 @@ _yphostent(line, pai)
*cp++ = '\0';
}
hints = *pai;
/* we should not glob socktype/protocol here */
memset(&hints, 0, sizeof(hints));
hints.ai_family = pai->ai_family;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_NUMERICHOST;
error = getaddrinfo(addr, NULL, &hints, &res0);
error = getaddrinfo(addr, "0", &hints, &res0);
if (error == 0) {
for (res = res0; res; res = res->ai_next) {
/* cover it up */

View File

@ -0,0 +1,291 @@
.\" $KAME: inet6_opt_init.3,v 1.5 2002/10/17 14:13:47 jinmei Exp $
.\"
.\" Copyright (C) 2000 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.
.\"
.\" $FreeBSD$
.\"
.Dd February 5, 2000
.Dt INET6_OPT_INIT 3
.Os
.\"
.Sh NAME
.Nm inet6_opt_init ,
.Nm inet6_opt_append ,
.Nm inet6_opt_finish ,
.Nm inet6_opt_set_val ,
.Nm inet6_opt_next ,
.Nm inet6_opt_find ,
.Nm inet6_opt_get_val
.Nd IPv6 Hop-by-Hop and Destination Options manipulation
.\"
.Sh SYNOPSIS
.In netinet/in.h
.Ft "int"
.Fn inet6_opt_init "void *extbuf" "socklen_t extlen"
.Ft "int"
.Fn inet6_opt_append "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t type" "socklen_t len" "u_int8_t align" "void **databufp"
.Ft "int"
.Fn inet6_opt_finish "void *extbuf" "socklen_t extlen" "int offset"
.Ft "int"
.Fn inet6_opt_set_val "void *databuf" "int offset" "void *val" "socklen_t vallen"
.Ft "int"
.Fn inet6_opt_next "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t *typep" "socklen_t *lenp" "void **databufp"
.Ft "int"
.Fn inet6_opt_find "void *extbuf" "socklen_t extlen" "int offset" "u_int8_t type" "socklen_t *lenp" "void **databufp"
.Ft "int"
.Fn inet6_opt_get_val "void *databuf" "socklen_t offset" "void *val" "socklen_t vallen"
.\"
.Sh DESCRIPTION
Building and parsing the Hop-by-Hop and Destination options is
complicated.
The advanced API therefore defines a set
of functions to help applications.
These functions assume the
formatting rules specified in Appendix B in RFC2460 i.e. that the
largest field is placed last in the option.
The function prototypes for
these functions are all in the
.Aq Li netinet/in.h
header.
.\"
.Ss inet6_opt_init
.Fn inet6_opt_init
returns the number of bytes needed for the empty
extension header i.e. without any options.
If
.Li extbuf
is not NULL it also initializes the extension header to have the correct length
field.
In that case if the
.Li extlen value is not a positive
.Po
i.e., non-zero
.Pc
multiple of 8 the function fails and returns -1.
.\"
.Ss inet6_opt_append
.Fn inet6_opt_append
returns the updated total length taking into account
adding an option with length
.Li len
and alignment
.Li align .
.Li Offset
should be the length returned by
.Fn inet6_opt_init
or a previous
.Fn inet6_opt_append .
If
.Li extbuf
is not NULL then, in addition to returning the length,
the function inserts any needed pad option, initializes the option
.Po
setting the type and length fields
.Pc
and returns a pointer to the location for the option content in
.Li databufp .
.Pp
.Li type
is the 8-bit option type.
.Li len
is the length of the option data
.Po
i.e. excluding the option type and option length fields.
.Pc
.Pp
Once
.Fn inet6_opt_append
has been called the application can use the
databuf directly, or use
.Fn inet6_opt_set_val
to specify the content of the option.
.Pp
The option type must have a value from 2 to 255, inclusive.
.Po
0 and 1 are reserved for the Pad1 and PadN options, respectively.
.Pc
.Pp
The option data length must have a value between 0 and 255,
inclusive, and is the length of the option data that follows.
.Pp
The
.Li align
parameter must have a value of 1, 2, 4, or 8.
The align value can not exceed the value of
.Li len .
.\"
.Ss inet6_opt_finish
.Fn inet6_opt_finish
returns the updated total length
taking into account the final padding of the extension header to make
it a multiple of 8 bytes.
.Li Offset
should be the length returned by
.Fn inet6_opt_init
or
.Fn inet6_opt_append .
If
.Li extbuf
is not NULL the function also
initializes the option by inserting a Pad1 or PadN option of the
proper length.
.Pp
If the necessary pad does not fit in the extension header buffer the
function returns -1.
.\"
.Ss inet6_opt_set_val
.Fn inet6_opt_set_val
inserts data items of various sizes in the data portion of the option.
.Li Databuf
should be a pointer returned by
.Fn inet6_opt_append .
.Li val
should point to the data to be
inserted.
.Li Offset
specifies where in the data portion of the option
the value should be inserted; the first byte after the option type
and length is accessed by specifying an offset of zero.
.Pp
The caller should ensure that each field is aligned on its natural
boundaries as described in Appendix B of RFC2460, but the function
must not rely on the caller's behavior.
Even when the alignment requirement is not satisfied,
the function should just copy the data as required.
.Pp
The function returns the offset for the next field
.Po
i.e.,
.Li offset
+
.Li vallen
.Pc
which can be used when composing option content with multiple fields.
.\"
.Ss inet6_opt_next
.Fn inet6_opt_next
parses received extension headers returning the next
option.
.Li Extbuf
and
.Li extlen
specifies the extension header.
.Li Offset
should either be zero (for the first option) or the length returned
by a previous call to
.Fn inet6_opt_next
or
.Fn inet6_opt_find .
It specifies the position where to continue scanning the extension
buffer.
The next option is returned by updating
.Li typep ,
.Li lenp ,
and
.Li databufp .
This function returns the updated
.Dq previous
length
computed by advancing past the option that was returned.
This returned
.Dq previous
length can then be passed to subsequent calls to
.Fn inet6_opt_next .
This function does not return any PAD1 or PADN options.
When there are no more options the return value is -1.
.\"
.Ss inet6_opt_get_val
.Fn inet6_opt_get_val
This function extracts data items of various sizes
in the data portion of the option.
.Li Databuf
should be a pointer returned by
.Fn inet6_opt_next
or
.Fn inet6_opt_find .
.Li Val
should point to the destination for the extracted data.
.Li Offset
specifies from where in the data portion of the option the value should be
extracted; the first byte after the option type and length is
accessed by specifying an offset of zero.
.Pp
It is expected that each field is aligned on its natural boundaries
as described in Appendix B of RFC2460, but the function must not
rely on the alignment.
.Pp
The function returns the offset for the next field
.Po
i.e.,
.Li offset
+
.Li vallen
.Pc
which can be used when extracting option content with
multiple fields.
Robust receivers might want to verify alignment before calling
this function.
.\"
.Sh DIAGNOSTICS
All the functions ruturn
.Li -1
on an error.
.\"
.Sh EXAMPLES
draft-ietf-ipngwg-rfc2292bis-08.txt
gives comprehensive examples in Section 23.
.Pp
KAME also provides examples in the advapitest directry of its kit.
.\"
.Sh SEE ALSO
.Rs
.%A W. Stevens
.%A M. Thomas
.%A E. Nordmark
.%A T. Jinmei
.%T "Advanced Sockets API for IPv6"
.%N draft-ietf-ipngwg-rfc2292bis-08
.%D October 2002
.Re
.Rs
.%A S. Deering
.%A R. Hinden
.%T "Internet Protocol, Version 6 (IPv6) Specification"
.%N RFC2460
.%D December 1998
.Re
.Sh HISTORY
The implementation first appeared in KAME advanced networking kit.
.Sh STANDARDS
The functions
are documented in
.Dq Advanced Sockets API for IPv6
.Pq draft-ietf-ipngwg-rfc2292bis-08.txt .
.\"
.Sh BUGS
The text was shamelessly copied from internet-drafts for RFC2292bis.

View File

@ -0,0 +1,254 @@
.\" $KAME: kame/kame/kame/libinet6/inet6_rth_space.3,v 1.4 2002/10/17 14:13:48 jinmei Exp $
.\" $FreeBSD$
.\"
.\" Copyright (C) 2000 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.
.\"
.\" $FreeBSD$
.\"
.Dd February 5, 2000
.Dt INET6_RTH_SPACE 3
.Os
.\"
.Sh NAME
.Nm inet6_rth_space
.Nm inet6_rth_init
.Nm inet6_rth_add
.Nm inet6_rth_reverse
.Nm inet6_rth_segments
.Nm inet6_rth_getaddr
.Nd IPv6 Routing Header Options manipulation
.\"
.Sh SYNOPSIS
.In netinet/in.h
.Ft socklen_t
.Fn inet6_rth_space "int" "int"
.Ft "void *"
.Fn inet6_rth_init "void *" "socklen_t" "int" "int"
.Ft int
.Fn inet6_rth_add "void *" "const struct in6_addr *"
.Ft int
.Fn inet6_rth_reverse "const void *" "void *"
.Ft int
.Fn inet6_rth_segments "const void *"
.Ft "struct in6_addr *"
.Fn inet6_rth_getaddr "const void *" "int"
.\"
.Sh DESCRIPTION
The IPv6 advanced API defines six
functions that the application calls to build and examine a Routing
header, and the ability to use sticky options or ancillary data to
communicate this information between the application and the kernel
using the IPV6_RTHDR option.
.Pp
Three functions build a Routing header:
.Bl -hang
.It Fn inet6_rth_space
returns #bytes required for Routing header
.It Fn inet6_rth_init
initializes buffer data for Routing header
.It Fn inet6_rth_add
adds one IPv6 address to the Routing header
.El
.Pp
Three functions deal with a returned Routing header:
.Bl -hang
.It Fn inet6_rth_reverse
reverses a Routing header
.It Fn inet6_rth_segments
returns #segments in a Routing header
.It Fn inet6_rth_getaddr
fetches one address from a Routing header
.El
.Pp
The function prototypes for these functions are defined as a result
of including the
.Aq Li netinet/in.h
header.
.\"
.Ss inet6_rth_space
.Fn inet6_rth_space
returns the number of bytes required to hold a Routing
header of the specified type containing the specified number of
.Li segments
.Po addresses.
.Pc
For an IPv6 Type 0 Routing header, the number
of
.Li segments
must be between 0 and 127, inclusive.
The return value is just the space for the Routing header.
When the application uses
ancillary data it must pass the returned length to
.Fn CMSG_LEN
to determine how much memory is needed for the ancillary data object
.Po
including the cmsghdr structure.
.Pc
.Pp
If the return value is 0, then either the type of the Routing header
is not supported by this implementation or the number of segments is
invalid for this type of Routing header.
.Pp
Note: This function returns the size but does not allocate the space
required for the ancillary data.
This allows an application to
allocate a larger buffer, if other ancillary data objects are
desired, since all the ancillary data objects must be specified to
.Fn sendmsg
as a single msg_control buffer.
.Ss inet6_rth_init
.Fn inet6_rth_init
initializes the buffer pointed to by
.Li bp
to contain a
Routing header of the specified type and sets ip6r_len based on the
.Li segments
parameter.
.Li bp_len
is only used to verify that the buffer is
large enough.
The ip6r_segleft field is set to zero;
.Fn inet6_rth_add
will increment it.
.Pp
When the application uses ancillary data the application must
initialize any cmsghdr fields.
.Pp
The caller must allocate the buffer and its size can be determined by
calling
.Fn inet6_rth_space .
.Pp
Upon success the return value is the pointer to the buffer
.Li bp ,
and this is then used as the first argument to the next two functions.
Upon an error the return value is NULL.
.\"
.Ss inet6_rth_add
.Fn inet6_rth_add
adds the IPv6 address pointed to by
.Li addr
to the end of the Routing header being constructed.
.Pp
If successful, the segleft member of the Routing Header is updated to
account for the new address in the Routing header and the return
value of the function is 0.
Upon an error the return value of the function is -1.
.\"
.Ss inet6_rth_reverse
.Fn inet6_rth_reverse
takes a Routing header extension header
.Po
pointed to by the first argument
.Li in
.Pc
and writes a new Routing header that sends
datagrams along the reverse of that route.
Both arguments are allowed to point to the same buffer
.Po
that is, the reversal can occur in place.
.Pc
.Pp
The return value of the function is 0 on success, or -1 upon an error.
.\"
.Ss inet6_rth_segments
.Fn inet6_rth_segments
returns the number of segments
.Po
addresses
.Pc
contained in the Routing header described by
.Li bp .
On success the return value is
zero or greater.
The return value of the function is -1 upon an error.
.\"
.Ss inet6_rth_getaddr
.Fn inet6_rth_getaddr
returns a pointer to the IPv6 address specified by
.Li index
.Po
which must have a value between 0 and one less than the value
returned by
.Fn inet6_rth_segments
.Pc
in the Routing header described by
.Li bp .
An application should first call
.Fn inet6_rth_segments
to obtain the number of segments in the Routing header.
.Pp
Upon an error the return value of the function is NULL.
.\"
.Sh DIAGNOSTICS
.Fn inet6_rth_space
and
.FN inet6_rth_getaddr
return 0 on errors.
.Pp
.Fn inet6_rthdr_init
returns
.Dv NULL
on error.
.Fn inet6_rth_add
and
.Fn inet6_rth_reverse
return0 on success, or -1 upon an error.
.\"
.Sh EXAMPLES
draft-ietf-ipngwg-rfc2292bis-08.txt
gives comprehensive examples in Section 22.
.Pp
KAME also provides examples in the advapitest directry of its kit.
.\"
.Sh SEE ALSO
.Rs
.%A W. Stevens
.%A M. Thomas
.%A E. Nordmark
.%A E. Jinmei
.%T "Advanced Sockets API for IPv6"
.%N draft-ietf-ipngwg-rfc2292bis-08
.%D October 2002
.Re
.Rs
.%A S. Deering
.%A R. Hinden
.%T "Internet Protocol, Version 6 (IPv6) Specification"
.%N RFC2460
.%D December 1998
.Re
.Sh HISTORY
The implementation first appeared in KAME advanced networking kit.
.Sh STANDARDS
The functions
are documented in
.Dq Advanced Sockets API for IPv6
.Pq draft-ietf-ipngwg-rfc2292bis-08.txt .
.\"
.Sh BUGS
The text was shamelessly copied from internet-drafts for RFC2292bis.

View File

@ -1,3 +1,5 @@
/* $KAME: ip6opt.c,v 1.13 2003/06/06 10:08:20 suz Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@ -111,6 +113,8 @@ inet6_option_append(cmsg, typep, multx, plusy)
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
@ -127,6 +131,7 @@ inet6_option_append(cmsg, typep, multx, plusy)
padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
(off % multx);
padlen += plusy;
padlen %= multx; /* keep the pad as short as possible */
/* insert padding */
inet6_insert_padopt(bp, padlen);
cmsg->cmsg_len += padlen;
@ -200,6 +205,7 @@ inet6_option_alloc(cmsg, datalen, multx, plusy)
padlen = (((off % multx) + (multx - 1)) & ~(multx - 1)) -
(off % multx);
padlen += plusy;
padlen %= multx; /* keep the pad as short as possible */
/* insert padding */
inet6_insert_padopt(bp, padlen);
cmsg->cmsg_len += padlen;
@ -383,3 +389,224 @@ inet6_insert_padopt(u_char *p, int len)
return;
}
}
/*
* The following functions are defined in a successor of RFC2292, aka
* rfc2292bis.
*/
int
inet6_opt_init(void *extbuf, socklen_t extlen)
{
struct ip6_ext *ext = (struct ip6_ext *)extbuf;
if (extlen < 0 || (extlen % 8))
return(-1);
if (ext) {
if (extlen == 0)
return(-1);
ext->ip6e_len = (extlen >> 3) - 1;
}
return(2); /* sizeof the next and the length fields */
}
int
inet6_opt_append(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
socklen_t len, u_int8_t align, void **databufp)
{
int currentlen = offset, padlen = 0;
/*
* The option type must have a value from 2 to 255, inclusive.
* (0 and 1 are reserved for the Pad1 and PadN options, respectively.)
*/
if (type < 2 || type > 255)
return(-1);
/*
* The option data length must have a value between 0 and 255,
* inclusive, and is the length of the option data that follows.
*/
if (len < 0 || len > 255)
return(-1);
/*
* The align parameter must have a value of 1, 2, 4, or 8.
* The align value can not exceed the value of len.
*/
if (align != 1 && align != 2 && align != 4 && align != 8)
return(-1);
if (align > len)
return(-1);
/* Calculate the padding length. */
currentlen += 2 + len; /* 2 means "type + len" */
if (currentlen % align)
padlen = align - (currentlen % align);
/* The option must fit in the extension header buffer. */
currentlen += padlen;
if (extlen && /* XXX: right? */
currentlen > extlen)
return(-1);
if (extbuf) {
u_int8_t *optp = (u_int8_t *)extbuf + offset;
if (padlen == 1) {
/* insert a Pad1 option */
*optp = IP6OPT_PAD1;
optp++;
}
else if (padlen > 0) {
/* insert a PadN option for alignment */
*optp++ = IP6OPT_PADN;
*optp++ = padlen - 2;
memset(optp, 0, padlen - 2);
optp += (padlen - 2);
}
*optp++ = type;
*optp++ = len;
*databufp = optp;
}
return(currentlen);
}
int
inet6_opt_finish(void *extbuf, socklen_t extlen, int offset)
{
int updatelen = offset > 0 ? (1 + ((offset - 1) | 7)) : 0;;
if (extbuf) {
u_int8_t *padp;
int padlen = updatelen - offset;
if (updatelen > extlen)
return(-1);
padp = (u_int8_t *)extbuf + offset;
if (padlen == 1)
*padp = IP6OPT_PAD1;
else if (padlen > 0) {
*padp++ = IP6OPT_PADN;
*padp++ = (padlen - 2);
memset(padp, 0, padlen - 2);
}
}
return(updatelen);
}
int
inet6_opt_set_val(void *databuf, int offset, void *val, socklen_t vallen)
{
memcpy((u_int8_t *)databuf + offset, val, vallen);
return(offset + vallen);
}
int
inet6_opt_next(void *extbuf, socklen_t extlen, int offset, u_int8_t *typep,
size_t *lenp, void **databufp)
{
u_int8_t *optp, *lim;
int optlen;
/* Validate extlen. XXX: is the variable really necessary?? */
if (extlen == 0 || (extlen % 8))
return(-1);
lim = (u_int8_t *)extbuf + extlen;
/*
* If this is the first time this function called for this options
* header, simply return the 1st option.
* Otherwise, search the option list for the next option.
*/
if (offset == 0) {
optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
}
else
optp = (u_int8_t *)extbuf + offset;
/* Find the next option skipping any padding options. */
while(optp < lim) {
switch(*optp) {
case IP6OPT_PAD1:
optp++;
break;
case IP6OPT_PADN:
if ((optlen = ip6optlen(optp, lim)) == 0)
goto optend;
optp += optlen;
break;
default: /* found */
if ((optlen = ip6optlen(optp, lim)) == 0)
goto optend;
*typep = *optp;
*lenp = optlen - 2;
*databufp = optp + 2;
return(optp + optlen - (u_int8_t *)extbuf);
}
}
optend:
*databufp = NULL; /* for safety */
return(-1);
}
int
inet6_opt_find(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
socklen_t *lenp, void **databufp)
{
u_int8_t *optp, *lim;
int optlen;
/* Validate extlen. XXX: is the variable really necessary?? */
if (extlen == 0 || (extlen % 8))
return(-1);
lim = (u_int8_t *)extbuf + extlen;
/*
* If this is the first time this function called for this options
* header, simply return the 1st option.
* Otherwise, search the option list for the next option.
*/
if (offset == 0) {
optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
}
else
optp = (u_int8_t *)extbuf + offset;
/* Find the specified option */
while(optp < lim) {
if ((optlen = ip6optlen(optp, lim)) == 0)
goto optend;
if (*optp == type) { /* found */
*lenp = optlen - 2;
*databufp = optp + 2;
return(optp + optlen - (u_int8_t *)extbuf);
}
optp += optlen;
}
optend:
*databufp = NULL; /* for safety */
return(-1);
}
int
inet6_opt_get_val(void *databuf, int offset, void *val, socklen_t vallen)
{
/* we can't assume alignment here */
memcpy(val, (u_int8_t *)databuf + offset, vallen);
return(offset + vallen);
}

View File

@ -1,4 +1,4 @@
/* $KAME: rthdr.c,v 1.8 2001/08/20 02:32:40 itojun Exp $ */
/* $KAME: rthdr.c,v 1.19 2003/06/06 10:48:51 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -42,272 +42,402 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <stdio.h>
/*
* RFC2292 API
*/
size_t
inet6_rthdr_space(type, seg)
int 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);
switch (type) {
case IPV6_RTHDR_TYPE_0:
if (seg < 1 || seg > 23)
return (0);
#ifdef COMPAT_RFC2292
return (CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) +
sizeof(struct ip6_rthdr0)));
#else
return (CMSG_SPACE(sizeof(struct in6_addr) * seg +
sizeof(struct ip6_rthdr0)));
#endif
return(0);
}
default:
return (0);
}
}
struct cmsghdr *
inet6_rthdr_init(bp, type)
void *bp;
int type;
void *bp;
int type;
{
struct cmsghdr *ch = (struct cmsghdr *)bp;
struct ip6_rthdr *rthdr;
struct cmsghdr *ch = (struct cmsghdr *)bp;
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
ch->cmsg_level = IPPROTO_IPV6;
ch->cmsg_type = IPV6_RTHDR;
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);
switch (type) {
case IPV6_RTHDR_TYPE_0:
#ifdef COMPAT_RFC2292
ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) -
sizeof(struct in6_addr));
#else
ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0));
#endif
return(NULL);
}
bzero(rthdr, sizeof(struct ip6_rthdr0));
rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
return (ch);
default:
return (NULL);
}
}
/* ARGSUSED */
int
inet6_rthdr_add(cmsg, addr, flags)
struct cmsghdr *cmsg;
const struct in6_addr *addr;
u_int flags;
struct cmsghdr *cmsg;
const struct in6_addr *addr;
u_int flags;
{
struct ip6_rthdr *rthdr;
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
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);
}
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)
return (-1);
if (rt0->ip6r0_segleft == 23)
return (-1);
return(0);
#ifdef COMPAT_RFC1883 /* XXX */
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));
}
#else
if (flags != IPV6_RTHDR_LOOSE)
return (-1);
#endif
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:
return (-1);
}
return (0);
}
/* ARGSUSED */
int
inet6_rthdr_lasthop(cmsg, flags)
struct cmsghdr *cmsg;
unsigned int flags;
struct cmsghdr *cmsg;
unsigned int flags;
{
struct ip6_rthdr *rthdr;
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
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);
}
switch (rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
#ifdef COMPAT_RFC1883 /* XXX */
if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
return (-1);
#endif /* COMPAT_RFC1883 */
if (rt0->ip6r0_segleft > 23)
return (-1);
#ifdef COMPAT_RFC1883 /* XXX */
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));
}
#else
if (flags != IPV6_RTHDR_LOOSE)
return (-1);
#endif /* COMPAT_RFC1883 */
break;
}
default:
return (-1);
}
return(0);
return (0);
}
#if 0
int
inet6_rthdr_reverse(in, out)
const struct cmsghdr *in;
struct cmsghdr *out;
const struct cmsghdr *in;
struct cmsghdr *out;
{
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_reverse: not implemented yet\n");
#endif
return -1;
return (-1);
}
#endif
int
inet6_rthdr_segments(cmsg)
const struct cmsghdr *cmsg;
const struct cmsghdr *cmsg;
{
struct ip6_rthdr *rthdr;
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
switch(rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
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;
if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
return (-1);
return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
}
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;
}
default:
return (-1);
}
}
struct in6_addr *
inet6_rthdr_getaddr(cmsg, idx)
struct cmsghdr *cmsg;
int idx;
struct cmsghdr *cmsg;
int idx;
{
struct ip6_rthdr *rthdr;
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
switch(rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
int naddr;
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;
if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
return NULL;
naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
if (idx <= 0 || naddr < idx)
return NULL;
#ifdef COMPAT_RFC2292
return (((struct in6_addr *)(rt0 + 1)) + idx - 1);
#else
return (((struct in6_addr *)(rt0 + 1)) + idx);
#endif
}
naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
if (idx <= 0 || naddr < idx) {
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_getaddr: invalid idx(%d)\n", idx);
#endif
return NULL;
}
return &rt0->ip6r0_addr[idx - 1];
}
default:
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_getaddr: unknown type(%d)\n",
rthdr->ip6r_type);
#endif
return NULL;
}
default:
return NULL;
}
}
int
inet6_rthdr_getflags(cmsg, idx)
const struct cmsghdr *cmsg;
int idx;
const struct cmsghdr *cmsg;
int idx;
{
struct ip6_rthdr *rthdr;
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
switch(rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
int naddr;
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;
if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
return (-1);
naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
if (idx < 0 || naddr < idx)
return (-1);
#ifdef COMPAT_RFC1883 /* XXX */
if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8)))
return IPV6_RTHDR_STRICT;
else
return IPV6_RTHDR_LOOSE;
#else
return IPV6_RTHDR_LOOSE;
#endif /* COMPAT_RFC1883 */
}
naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
if (idx < 0 || naddr < idx) {
#ifdef DEBUG
fprintf(stderr, "inet6_rthdr_getflags: invalid idx(%d)\n", idx);
#endif
return -1;
}
if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 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;
}
default:
return (-1);
}
}
/*
* RFC3542 (2292bis) API
*/
socklen_t
inet6_rth_space(int type, int segments)
{
switch (type) {
case IPV6_RTHDR_TYPE_0:
return (((segments * 2) + 1) << 3);
default:
return (0); /* type not suppported */
}
}
void *
inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
{
struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
struct ip6_rthdr0 *rth0;
switch (type) {
case IPV6_RTHDR_TYPE_0:
/* length validation */
if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments))
return (NULL);
memset(bp, 0, bp_len);
rth0 = (struct ip6_rthdr0 *)rth;
rth0->ip6r0_len = segments * 2;
rth0->ip6r0_type = IPV6_RTHDR_TYPE_0;
rth0->ip6r0_segleft = 0;
rth0->ip6r0_reserved = 0;
break;
default:
return (NULL); /* type not supported */
}
return (bp);
}
int
inet6_rth_add(void *bp, const struct in6_addr *addr)
{
struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
struct ip6_rthdr0 *rth0;
struct in6_addr *nextaddr;
switch (rth->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
rth0 = (struct ip6_rthdr0 *)rth;
nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft;
*nextaddr = *addr;
rth0->ip6r0_segleft++;
break;
default:
return (-1); /* type not supported */
}
return (0);
}
int
inet6_rth_reverse(const void *in, void *out)
{
struct ip6_rthdr *rth_in = (struct ip6_rthdr *)in;
struct ip6_rthdr0 *rth0_in, *rth0_out;
int i, segments;
switch (rth_in->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
rth0_in = (struct ip6_rthdr0 *)in;
rth0_out = (struct ip6_rthdr0 *)out;
/* parameter validation XXX too paranoid? */
if (rth0_in->ip6r0_len % 2)
return (-1);
segments = rth0_in->ip6r0_len / 2;
/* we can't use memcpy here, since in and out may overlap */
memmove((void *)rth0_out, (void *)rth0_in,
((rth0_in->ip6r0_len) + 1) << 3);
rth0_out->ip6r0_segleft = segments;
/* reverse the addresses */
for (i = 0; i < segments / 2; i++) {
struct in6_addr addr_tmp, *addr1, *addr2;
addr1 = (struct in6_addr *)(rth0_out + 1) + i;
addr2 = (struct in6_addr *)(rth0_out + 1) +
(segments - i - 1);
addr_tmp = *addr1;
*addr1 = *addr2;
*addr2 = addr_tmp;
}
break;
default:
return (-1); /* type not supported */
}
return (0);
}
int
inet6_rth_segments(const void *bp)
{
struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
struct ip6_rthdr0 *rh0;
int addrs;
switch (rh->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
rh0 = (struct ip6_rthdr0 *)bp;
/*
* Validation for a type-0 routing header.
* Is this too strict?
*/
if ((rh0->ip6r0_len % 2) != 0 ||
(addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
return (-1);
return (addrs);
default:
return (-1); /* unknown type */
}
}
struct in6_addr *
inet6_rth_getaddr(const void *bp, int idx)
{
struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
struct ip6_rthdr0 *rh0;
int rthlen, addrs;
switch (rh->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
rh0 = (struct ip6_rthdr0 *)bp;
rthlen = (rh0->ip6r0_len + 1) << 3;
/*
* Validation for a type-0 routing header.
* Is this too strict?
*/
if ((rthlen % 2) != 0 ||
(addrs = (rthlen >> 1)) < rh0->ip6r0_segleft)
return (NULL);
if (idx < 0 || addrs <= idx)
return (NULL);
return (((struct in6_addr *)(rh0 + 1)) + idx);
default:
return (NULL); /* unknown type */
break;
}
}

View File

@ -29,6 +29,7 @@
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>

View File

@ -3,7 +3,8 @@
PROG= ping6
MAN= ping6.8
CFLAGS+=-DINET6 -DIPSEC
CFLAGS+=-DINET6 -DIPSEC -DKAME_SCOPEID -DUSE_RFC2292BIS \
-DHAVE_POLL_H -DHAVE_ARC4RANDOM
WARNS= 0
BINOWN= root
@ -12,7 +13,4 @@ BINMODE=4555
LDADD= -lipsec -lm -lmd
DPADD= ${LIBIPSEC} ${LIBM} ${LIBMD}
# kame scopeid hack
CFLAGS+=-DKAME_SCOPEID
.include <bsd.prog.mk>

View File

@ -1,4 +1,4 @@
.\" $KAME: ping6.8,v 1.43 2001/06/28 06:54:29 suz Exp $
.\" $KAME: ping6.8,v 1.58 2003/06/20 12:00:22 itojun Exp $
.\"
.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
.\" All rights reserved.
@ -40,9 +40,9 @@ packets to network hosts
.Sh SYNOPSIS
.Nm
.\" without ipsec, or new ipsec
.Op Fl dfHnNqRtvwW
.Op Fl dfHmnNqtvwW
.\" old ipsec
.\" .Op Fl AdEfnNqRtvwW
.\" .Op Fl AdEfmnNqRtvwW
.Bk -words
.Op Fl a Ar addrtype
.Ek
@ -53,6 +53,9 @@ packets to network hosts
.Op Fl c Ar count
.Ek
.Bk -words
.Op Fl g Ar gateway
.Ek
.Bk -words
.Op Fl h Ar hoplimit
.Ek
.Bk -words
@ -78,7 +81,7 @@ packets to network hosts
.Op Fl s Ar packetsize
.Ek
.Bk -words
.Op Ar hops...\&
.Op Ar hops ...
.Ek
.Bk -words
.Ar host
@ -86,7 +89,7 @@ packets to network hosts
.Sh DESCRIPTION
The
.Nm
utility uses the
command uses the
.Tn ICMPv6
protocol's mandatory
.Tn ICMP6_ECHO_REQUEST
@ -103,14 +106,14 @@ The options are as follows:
.\" old ipsec
.\" .It Fl A
.\" Enables transport-mode IPsec authentication header
.\" (experimental).
.\" .Pq experimental .
.It Fl a Ar addrtype
Generate ICMPv6 Node Information Node Addresses query, rather than echo-request.
.Ar addrtype
must be a string constructed of the following characters.
.Bl -tag -width Ds -compact
.It Ic a
requests all the responder's unicast addresses.
requests unicast addresses from all of the responder's interfaces.
If the character is omitted,
only those addresses which belong to the interface which has the
responder's address are requests.
@ -134,7 +137,7 @@ This is an experimental option.
Set socket buffer size.
.It Fl c Ar count
Stop after sending
(and receiving)
.Pq and receiving
.Ar count
.Tn ECHO_RESPONSE
packets.
@ -144,7 +147,7 @@ Set the
option on the socket being used.
.\" .It Fl E
.\" Enables transport-mode IPsec encapsulated security payload
.\" (experimental).
.\" .Pq experimental .
.It Fl f
Flood ping.
Outputs packets as fast as they come back or one hundred times per second,
@ -152,7 +155,7 @@ whichever is more.
For every
.Tn ECHO_REQUEST
sent a period
.Dq .\&
.Dq \&.
is printed, while for every
.Tn ECHO_REPLY
received a backspace is printed.
@ -161,11 +164,16 @@ Only the super-user may use this option.
.Bf -emphasis
This can be very hard on a network and should be used with caution.
.Ef
.It Fl g Ar gateway
Specifies to use
.Ar gateway
as the next hop to the destination.
The gateway must be a neighbor of the sending node.
.It Fl H
Specifies to try reverse-lookup of IPv6 addresses.
The
.Nm
utility does not try reverse-lookup unless the option is specified.
command does not try reverse-lookup unless the option is specified.
.It Fl h Ar hoplimit
Set the IPv6 hoplimit.
.It Fl I Ar interface
@ -189,6 +197,16 @@ is specified,
sends that many packets as fast as possible before falling into its normal
mode of behavior.
Only the super-user may use this option.
.It Fl m
By default,
.Nm
asks the kernel to fragment packets to fit into the minimum IPv6 MTU.
.Fl m
will suppress the behavior in the following two levels:
when the option is specified once, the behavior will be disabled for
unicast packets.
When the option is more than once, it will be disabled for both
unicast and multicast packets.
.It Fl n
Numeric output only.
No attempt will be made to lookup symbolic names from addresses in the reply.
@ -197,12 +215,12 @@ Probe node information multicast group
.Pq Li ff02::2:xxxx:xxxx .
.Ar host
must be string hostname of the target
(must not be a numeric IPv6 address).
.Pq must not be a numeric IPv6 address .
Node information multicast group will be computed based on given
.Ar host ,
and will be used as the final destination.
Since node information multicast group is a link-local multicast group,
destination link needs to be specified by
outgoing interface needs to be specified by
.Fl I
option.
.It Fl p Ar pattern
@ -222,26 +240,10 @@ specifies IPsec policy to be used for the probe.
Quiet output.
Nothing is displayed except the summary lines at startup time and
when finished.
.It Fl R
Make the kernel believe that the target
.Ar host
(or the first
.Ar hop
if you specify
.Ar hops )
is reachable, by injecting upper-layer reachability confirmation hint.
The option is meaningful only if the target
.Ar host
(or the first hop)
is a neighbor.
.It Fl S Ar sourceaddr
Specifies the source address of request packets.
The source address must be one of the unicast addresses of the sending node.
If the outgoing interface is specified by the
.Fl I
option as well,
.Ar sourceaddr
needs to be an address assigned to the specified interface.
The source address must be one of the unicast addresses of the sending node,
and must be numeric.
.It Fl s Ar packetsize
Specifies the number of data bytes to be sent.
The default is 56, which translates into 64
@ -299,26 +301,13 @@ If duplicate packets are received, they are not included in the packet
loss calculation, although the round trip time of these packets is used
in calculating the round-trip time statistics.
When the specified number of packets have been sent
(and received)
.Pq and received
or if the program is terminated with a
.Dv SIGINT ,
a brief summary is displayed, showing the number of packets sent and
received, and the minimum, mean, maximum, and standard deviation of
received, and the minimum, maximum, mean, and standard deviation of
the round-trip times.
.Pp
If
.Nm
receives a
.Dv SIGINFO
(see the
.Cm status
argument for
.Xr stty 1 )
signal, the current number of packets sent and received, and the
minimum, mean, maximum, and standard deviation of the round-trip times
will be written to the standard output in the same format as the
standard completion message.
.Pp
This program is intended for use in network testing, measurement and
management.
Because of the load it can impose on the network, it is unwise to use
@ -335,14 +324,12 @@ during normal operations or from automated scripts.
.\" When a
.\" .Ar packetsize
.\" is given, this indicated the size of this extra piece of data
.\" (the default is 56).
.\" .Pq the default is 56 .
.\" Thus the amount of data received inside of an IP packet of type
.\" .Tn ICMP
.\" .Tn ECHO_REPLY
.\" will always be 8 bytes more than the requested data space
.\" (the
.\" .Tn ICMP
.\" header).
.\" .Pq the Tn ICMP header .
.\" .Pp
.\" If the data space is at least eight bytes large,
.\" .Nm
@ -353,12 +340,12 @@ during normal operations or from automated scripts.
.Sh DUPLICATE AND DAMAGED PACKETS
The
.Nm
utility will report duplicate and damaged packets.
command will report duplicate and damaged packets.
Duplicate packets should never occur when pinging a unicast address,
and seem to be caused by
inappropriate link-level retransmissions.
Duplicates may occur in many situations and are rarely
(if ever)
.Pq if ever
a good sign, although the presence of low levels of duplicates may not
always be cause for alarm.
Duplicates are expected when pinging a broadcast or multicast address,
@ -369,7 +356,7 @@ Damaged packets are obviously serious cause for alarm and often
indicate broken hardware somewhere in the
.Nm
packet's path
(in the network or in the hosts).
.Pq in the network or in the hosts .
.Sh TRYING DIFFERENT DATA PATTERNS
The
(inter)network
@ -398,11 +385,10 @@ You can then examine this file for repeated patterns that you can test
using the
.Fl p
option of
.Nm .
.Nm Ns .
.Sh RETURN VALUES
The
.Nm
utility returns 0 on success (the host is alive),
command returns 0 on success (the host is alive),
and non-zero if the arguments are incorrect or the host is not responding.
.Sh EXAMPLES
Normally,
@ -451,11 +437,28 @@ ping6 -a agl dst.foo.com
.Rs
.%A Matt Crawford
.%T "IPv6 Node Information Queries"
.%N draft-ietf-ipngwg-icmp-name-lookups-07.txt
.%D August 2000
.%N draft-ietf-ipngwg-icmp-name-lookups-09.txt
.%D May 2002
.%O work in progress material
.Re
.Sh HISTORY
The
.Xr ping 8
command appeared in
.Bx 4.3 .
The
.Nm
command with IPv6 support first appeared in the WIDE Hydrangea IPv6
protocol stack kit.
.Pp
IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack
was initially integrated into
.Fx 4.0
.Sh BUGS
.Nm
is intentionally separate from
.Xr ping 8 .
.Pp
There have been many discussions on why we separate
.Nm
and
@ -484,16 +487,3 @@ or
.Fl 4
option (or something like those) to specify the particular address family.
This essentially means that we have two different commands.
.Sh HISTORY
The
.Xr ping 8
command appeared in
.Bx 4.3 .
The
.Nm
utility with IPv6 support first appeared in WIDE Hydrangea IPv6 protocol stack
kit.
.Pp
IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack
was initially integrated into
.Fx 4.0

View File

@ -1,4 +1,4 @@
/* $KAME: ping6.c,v 1.126 2001/05/17 03:39:08 itojun Exp $ */
/* $KAME: ping6.c,v 1.169 2003/07/25 06:01:47 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -123,30 +123,32 @@ static const char rcsid[] =
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
#include <math.h>
#endif
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef IPSEC
#include <netinet6/ah.h>
#include <netinet6/ipsec.h>
#endif
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include <md5.h>
#else
#include "md5.h"
#endif
struct tv32 {
u_int32_t tv32_sec;
u_int32_t tv32_usec;
};
#define MAXPACKETLEN 131072
#define IP6LEN 40
#define ICMP6ECHOLEN 8 /* icmp echo header length excluding time */
#define ICMP6ECHOTMLEN sizeof(struct timeval)
#define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */
#define ICMP6ECHOTMLEN sizeof(struct tv32)
#define ICMP6_NIQLEN (ICMP6ECHOLEN + 8)
/* FQDN case, 64 bits of nonce + 32 bits ttl */
#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12)
@ -180,9 +182,6 @@ static const char rcsid[] =
#define F_FQDN 0x1000
#define F_INTERFACE 0x2000
#define F_SRCADDR 0x4000
#ifdef IPV6_REACHCONF
#define F_REACHCONF 0x8000
#endif
#define F_HOSTNAME 0x10000
#define F_FQDNOLD 0x20000
#define F_NIGROUP 0x40000
@ -209,6 +208,7 @@ char rcvd_tbl[MAX_DUP_CHK / 8];
struct addrinfo *res;
struct sockaddr_in6 dst; /* who to ping6 */
struct sockaddr_in6 src; /* src addr of this packet */
socklen_t srclen;
int datalen = DEFDATALEN;
int s; /* socket file descriptor */
u_char outpack[MAXPACKETLEN];
@ -217,7 +217,6 @@ char DOT = '.';
char *hostname;
int ident; /* process id to identify our packets */
u_int8_t nonce[8]; /* nonce field for node information */
struct in6_addr srcaddr;
int hoplimit = -1; /* hoplimit */
int pathmtu = 0; /* path MTU for the destination. 0 = unspec. */
@ -233,9 +232,7 @@ int timing; /* flag to do timing */
double tmin = 999999999.0; /* minimum round trip time */
double tmax = 0.0; /* maximum round trip time */
double tsum = 0.0; /* sum of all times, for doing average */
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
#endif
/* for node addresses */
u_short naflags;
@ -245,17 +242,16 @@ struct msghdr smsghdr;
struct iovec smsgiov;
char *scmsg = 0;
volatile int signo;
volatile sig_atomic_t seenalrm;
volatile sig_atomic_t seenint;
#ifdef SIGINFO
volatile sig_atomic_t seeninfo;
#endif
int main(int, char *[]);
void fill(char *, char *);
int get_hoplim(struct msghdr *);
int get_pathmtu(struct msghdr *);
void set_pathmtu(int);
struct in6_pktinfo *get_rcvpktinfo(struct msghdr *);
void onsignal(int);
void retransmit(void);
@ -270,7 +266,7 @@ void pr_nodeaddr(struct icmp6_nodeinfo *, int);
int myechoreply(const struct icmp6_hdr *);
int mynireply(const struct icmp6_nodeinfo *);
char *dnsdecode(const u_char **, const u_char *, const u_char *,
u_char *, size_t);
char *, size_t);
void pr_pack(u_char *, int, struct msghdr *);
void pr_exthdrs(struct msghdr *);
void pr_ip6opt(void *);
@ -290,17 +286,31 @@ main(argc, argv)
{
struct itimerval itimer;
struct sockaddr_in6 from;
#ifndef HAVE_ARC4RANDOM
struct timeval seed;
#endif
#ifdef HAVE_POLL_H
int timeout;
#else
struct timeval timeout, *tv;
#endif
struct addrinfo hints;
#ifdef HAVE_POLL_H
struct pollfd fdmaskp[1];
#else
fd_set *fdmaskp;
int fdmasks;
#endif
int cc, i;
int ch, fromlen, hold, packlen, preload, optval, ret_ga;
int ch, hold, packlen, preload, optval, ret_ga;
u_char *datap, *packet;
char *e, *target, *ifname = NULL;
char *e, *target, *ifname = NULL, *gateway = NULL;
int ip6optlen = 0;
struct cmsghdr *scmsgp = NULL;
#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
u_long lsockbufsize;
int sockbufsize = 0;
#endif
int usepktinfo = 0;
struct in6_pktinfo *pktinfo = NULL;
#ifdef USE_RFC2292BIS
@ -312,6 +322,9 @@ main(argc, argv)
#endif
double intval;
size_t rthlen;
#ifdef IPV6_USE_MIN_MTU
int mflag = 0;
#endif
/* just to be sure */
memset(&smsghdr, 0, sizeof(smsghdr));
@ -329,7 +342,7 @@ main(argc, argv)
#endif /*IPSEC_POLICY_IPSEC*/
#endif
while ((ch = getopt(argc, argv,
"a:b:c:dfHh:I:i:l:mnNp:qRS:s:tvwW" ADDOPTS)) != -1) {
"a:b:c:dfHg:h:I:i:l:mnNp:qS:s:tvwW" ADDOPTS)) != -1) {
#undef ADDOPTS
switch (ch) {
case 'a':
@ -377,7 +390,13 @@ main(argc, argv)
}
case 'b':
#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
sockbufsize = atoi(optarg);
errno = 0;
e = NULL;
lsockbufsize = strtoul(optarg, &e, 10);
sockbufsize = lsockbufsize;
if (errno || !*optarg || *e ||
sockbufsize != lsockbufsize)
errx(1, "invalid socket buffer size");
#else
errx(1,
"-b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported");
@ -393,16 +412,23 @@ main(argc, argv)
options |= F_SO_DEBUG;
break;
case 'f':
if (getuid())
errx(1, "must be superuser to flood ping");
if (getuid()) {
errno = EPERM;
errx(1, "Must be superuser to flood ping");
}
options |= F_FLOOD;
setbuf(stdout, (char *)NULL);
break;
case 'g':
gateway = optarg;
break;
case 'H':
options |= F_HOSTNAME;
break;
case 'h': /* hoplimit */
hoplimit = strtol(optarg, &e, 10);
if (*optarg == '\0' || *e != '\0')
errx(1, "illegal hoplimit %s", optarg);
if (255 < hoplimit || hoplimit < -1)
errx(1,
"illegal hoplimit -- %s", optarg);
@ -435,15 +461,17 @@ main(argc, argv)
options |= F_INTERVAL;
break;
case 'l':
if (getuid())
errx(1, "must be superuser to preload");
if (getuid()) {
errno = EPERM;
errx(1, "Must be superuser to preload");
}
preload = strtol(optarg, &e, 10);
if (preload < 0 || *optarg == '\0' || *e != '\0')
errx(1, "illegal preload value -- %s", optarg);
break;
case 'm':
#ifdef IPV6_USE_MIN_MTU
options |= F_NOMINMTU;
mflag++;
break;
#else
errx(1, "-%c is not supported on this platform", ch);
@ -462,19 +490,26 @@ main(argc, argv)
case 'q':
options |= F_QUIET;
break;
case 'R':
#ifdef IPV6_REACHCONF
options |= F_REACHCONF;
break;
#else
errx(1, "-R is not supported in this configuration");
#endif
case 'S':
/* XXX: use getaddrinfo? */
if (inet_pton(AF_INET6, optarg, (void *)&srcaddr) != 1)
errx(1, "invalid IPv6 address: %s", optarg);
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_flags = AI_NUMERICHOST; /* allow hostname? */
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_ICMPV6;
ret_ga = getaddrinfo(optarg, NULL, &hints, &res);
if (ret_ga) {
errx(1, "invalid source address: %s",
gai_strerror(ret_ga));
}
/*
* res->ai_family must be AF_INET6 and res->ai_addrlen
* must be sizeof(src).
*/
memcpy(&src, res->ai_addr, res->ai_addrlen);
srclen = res->ai_addrlen;
freeaddrinfo(res);
options |= F_SRCADDR;
usepktinfo++;
break;
case 's': /* size of packet to send */
datalen = strtol(optarg, &e, 10);
@ -528,6 +563,7 @@ main(argc, argv)
/*NOTREACHED*/
}
}
argc -= optind;
argv += optind;
@ -560,7 +596,7 @@ main(argc, argv)
target = argv[argc - 1];
/* getaddrinfo */
bzero(&hints, sizeof(struct addrinfo));
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_RAW;
@ -583,6 +619,38 @@ main(argc, argv)
res->ai_protocol)) < 0)
err(1, "socket");
/* set the source address if specified. */
if ((options & F_SRCADDR) &&
bind(s, (struct sockaddr *)&src, srclen) != 0) {
err(1, "bind");
}
/* set the gateway (next hop) if specified */
if (gateway) {
struct addrinfo ghints, *gres;
int error;
memset(&ghints, 0, sizeof(ghints));
ghints.ai_family = AF_INET6;
ghints.ai_socktype = SOCK_RAW;
ghints.ai_protocol = IPPROTO_ICMPV6;
error = getaddrinfo(gateway, NULL, &hints, &gres);
if (error) {
errx(1, "getaddrinfo for the gateway %s: %s",
gateway, gai_strerror(error));
}
if (gres->ai_next && (options & F_VERBOSE))
warnx("gateway resolves to multiple addresses");
if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP,
gres->ai_addr, gres->ai_addrlen)) {
err(1, "setsockopt(IPV6_NEXTHOP)");
}
freeaddrinfo(gres);
}
/*
* let the kerel pass extension headers of incoming packets,
* for privileged socket options
@ -619,11 +687,11 @@ main(argc, argv)
seteuid(getuid());
setuid(getuid());
if (options & F_FLOOD && options & F_INTERVAL)
if ((options & F_FLOOD) && (options & F_INTERVAL))
errx(1, "-f and -i incompatible options");
if ((options & F_NOUSERDATA) == 0) {
if (datalen >= sizeof(struct timeval)) {
if (datalen >= sizeof(struct tv32)) {
/* we can time transfer */
timing = 1;
} else
@ -641,15 +709,15 @@ main(argc, argv)
}
if (!(packet = (u_char *)malloc((u_int)packlen)))
errx(1, "unable to allocate packet");
err(1, "Unable to allocate packet");
if (!(options & F_PINGFILLED))
for (i = ICMP6ECHOLEN; i < packlen; ++i)
*datap++ = i;
ident = getpid() & 0xFFFF;
#ifndef __OpenBSD__
gettimeofday(&timeout, NULL);
srand((unsigned int)(timeout.tv_sec ^ timeout.tv_usec ^ (long)ident));
#ifndef HAVE_ARC4RANDOM
gettimeofday(&seed, NULL);
srand((unsigned int)(seed.tv_sec ^ seed.tv_usec ^ (long)ident));
memset(nonce, 0, sizeof(nonce));
for (i = 0; i < sizeof(nonce); i += sizeof(int))
*((int *)&nonce[i]) = rand();
@ -670,8 +738,9 @@ main(argc, argv)
&optval, sizeof(optval)) == -1)
err(1, "IPV6_MULTICAST_HOPS");
#ifdef IPV6_USE_MIN_MTU
if ((options & F_NOMINMTU) == 0) {
optval = 1;
if (mflag != 1) {
optval = mflag > 1 ? 0 : 1;
if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
&optval, sizeof(optval)) == -1)
err(1, "setsockopt(IPV6_USE_MIN_MTU)");
@ -765,11 +834,6 @@ main(argc, argv)
if (hoplimit != -1)
ip6optlen += CMSG_SPACE(sizeof(int));
#ifdef IPV6_REACHCONF
if (options & F_REACHCONF)
ip6optlen += CMSG_SPACE(0);
#endif
/* set IP6 packet options */
if (ip6optlen) {
if ((scmsg = (char *)malloc(ip6optlen)) == 0)
@ -798,10 +862,6 @@ main(argc, argv)
errx(1, "%s: invalid interface name", ifname);
#endif
}
/* set the source address */
if (options & F_SRCADDR)/* pktinfo must be valid */
pktinfo->ipi6_addr = srcaddr;
if (hoplimit != -1) {
scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
scmsgp->cmsg_level = IPPROTO_IPV6;
@ -810,15 +870,6 @@ main(argc, argv)
scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
}
#ifdef IPV6_REACHCONF
if (options & F_REACHCONF) {
scmsgp->cmsg_len = CMSG_LEN(0);
scmsgp->cmsg_level = IPPROTO_IPV6;
scmsgp->cmsg_type = IPV6_REACHCONF;
scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
}
#endif
if (argc > 1) { /* some intermediate addrs are specified */
int hops, error;
@ -873,11 +924,13 @@ main(argc, argv)
scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
}
{
if (!(options & F_SRCADDR)) {
/*
* source selection
* get the source address. XXX since we revoked the root
* privilege, we cannot use a raw socket for this.
*/
int dummy, len = sizeof(src);
int dummy;
socklen_t len = sizeof(src);
if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
err(1, "UDP socket");
@ -894,9 +947,14 @@ main(argc, argv)
err(1, "UDP setsockopt(IPV6_PKTINFO)");
if (hoplimit != -1 &&
setsockopt(dummy, IPPROTO_IPV6, IPV6_HOPLIMIT,
setsockopt(dummy, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
(void *)&hoplimit, sizeof(hoplimit)))
err(1, "UDP setsockopt(IPV6_HOPLIMIT)");
err(1, "UDP setsockopt(IPV6_UNICAST_HOPS)");
if (hoplimit != -1 &&
setsockopt(dummy, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
(void *)&hoplimit, sizeof(hoplimit)))
err(1, "UDP setsockopt(IPV6_MULTICAST_HOPS)");
if (rthdr &&
setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR,
@ -984,15 +1042,17 @@ main(argc, argv)
itimer.it_interval = interval;
itimer.it_value = interval;
(void)setitimer(ITIMER_REAL, &itimer, NULL);
if (ntransmitted == 0)
if (ntransmitted)
retransmit();
}
#ifndef HAVE_POLL_H
fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask);
if ((fdmaskp = malloc(fdmasks)) == NULL)
err(1, "malloc");
#endif
signo = seenalrm = seenint = 0;
seenalrm = seenint = 0;
#ifdef SIGINFO
seeninfo = 0;
#endif
@ -1024,24 +1084,42 @@ main(argc, argv)
if (options & F_FLOOD) {
(void)pinger();
#ifdef HAVE_POLL_H
timeout = 10;
#else
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
tv = &timeout;
} else
#endif
} else {
#ifdef HAVE_POLL_H
timeout = INFTIM;
#else
tv = NULL;
#endif
}
#ifdef HAVE_POLL_H
fdmaskp[0].fd = s;
fdmaskp[0].events = POLLIN;
cc = poll(fdmaskp, 1, timeout);
#else
memset(fdmaskp, 0, fdmasks);
FD_SET(s, fdmaskp);
cc = select(s + 1, fdmaskp, NULL, NULL, tv);
#endif
if (cc < 0) {
if (errno != EINTR) {
#ifdef HAVE_POLL_H
warn("poll");
#else
warn("select");
#endif
sleep(1);
}
continue;
} else if (cc == 0)
continue;
fromlen = sizeof(from);
m.msg_name = (caddr_t)&from;
m.msg_namelen = sizeof(from);
memset(&iov, 0, sizeof(iov));
@ -1073,7 +1151,6 @@ main(argc, argv)
printf("new path MTU (%d) is "
"notified\n", mtu);
}
set_pathmtu(mtu);
}
continue;
} else {
@ -1093,7 +1170,7 @@ void
onsignal(sig)
int sig;
{
signo = sig;
switch (sig) {
case SIGALRM:
seenalrm++;
@ -1245,9 +1322,14 @@ pinger()
icp->icmp6_code = 0;
icp->icmp6_id = htons(ident);
icp->icmp6_seq = ntohs(seq);
if (timing)
(void)gettimeofday((struct timeval *)
&outpack[ICMP6ECHOLEN], NULL);
if (timing) {
struct timeval tv;
struct tv32 *tv32;
(void)gettimeofday(&tv, NULL);
tv32 = (struct tv32 *)&outpack[ICMP6ECHOLEN];
tv32->tv32_sec = htonl(tv.tv_sec);
tv32->tv32_usec = htonl(tv.tv_usec);
}
cc = ICMP6ECHOLEN + datalen;
}
@ -1305,7 +1387,7 @@ dnsdecode(sp, ep, base, buf, bufsiz)
const u_char **sp;
const u_char *ep;
const u_char *base; /*base for compressed name*/
u_char *buf;
char *buf;
size_t bufsiz;
{
int i;
@ -1322,7 +1404,7 @@ dnsdecode(sp, ep, base, buf, bufsiz)
while (cp < ep) {
i = *cp;
if (i == 0 || cp != *sp) {
if (strlcat(buf, ".", bufsiz) >= bufsiz)
if (strlcat((char *)buf, ".", bufsiz) >= bufsiz)
return NULL; /*result overrun*/
}
if (i == 0)
@ -1347,7 +1429,7 @@ dnsdecode(sp, ep, base, buf, bufsiz)
while (i-- > 0 && cp < ep) {
l = snprintf(cresult, sizeof(cresult),
isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff);
if (l < 0 || l >= sizeof(cresult))
if (l >= sizeof(cresult) || l < 0)
return NULL;
if (strlcat(buf, cresult, bufsiz) >= bufsiz)
return NULL; /*result overrun*/
@ -1385,7 +1467,8 @@ pr_pack(buf, cc, mhdr)
int fromlen;
u_char *cp = NULL, *dp, *end = buf + cc;
struct in6_pktinfo *pktinfo = NULL;
struct timeval tv, *tp;
struct timeval tv, tp;
struct tv32 *tpp;
double triptime = 0;
int dupflag;
size_t off;
@ -1399,7 +1482,7 @@ pr_pack(buf, cc, mhdr)
mhdr->msg_namelen != sizeof(struct sockaddr_in6) ||
((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) {
if (options & F_VERBOSE)
warnx("invalid peername\n");
warnx("invalid peername");
return;
}
from = (struct sockaddr *)mhdr->msg_name;
@ -1427,14 +1510,14 @@ pr_pack(buf, cc, mhdr)
seq = ntohs(icp->icmp6_seq);
++nreceived;
if (timing) {
tp = (struct timeval *)(icp + 1);
tvsub(&tv, tp);
tpp = (struct tv32 *)(icp + 1);
tp.tv_sec = ntohl(tpp->tv32_sec);
tp.tv_usec = ntohl(tpp->tv32_usec);
tvsub(&tv, &tp);
triptime = ((double)tv.tv_sec) * 1000.0 +
((double)tv.tv_usec) / 1000.0;
tsum += triptime;
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
tsumsq += triptime * triptime;
#endif
if (triptime < tmin)
tmin = triptime;
if (triptime > tmax)
@ -1464,9 +1547,7 @@ pr_pack(buf, cc, mhdr)
memset(&dstsa, 0, sizeof(dstsa));
dstsa.sin6_family = AF_INET6;
#ifdef SIN6_LEN
dstsa.sin6_len = sizeof(dstsa);
#endif
dstsa.sin6_scope_id = pktinfo->ipi6_ifindex;
dstsa.sin6_addr = pktinfo->ipi6_addr;
(void)printf(" dst=%s",
@ -1767,7 +1848,7 @@ pr_rthdr(void *extbuf)
else {
if (!inet_ntop(AF_INET6, in6, ntopbuf,
sizeof(ntopbuf)))
strncpy(ntopbuf, "?", sizeof(ntopbuf));
strlcpy(ntopbuf, "?", sizeof(ntopbuf));
printf(" [%d]%s\n", i, ntopbuf);
}
}
@ -1787,9 +1868,9 @@ pr_rthdr(void *extbuf)
#endif /* USE_RFC2292BIS */
int
pr_bitrange(v, s, ii)
pr_bitrange(v, soff, ii)
u_int32_t v;
int s;
int soff;
int ii;
{
int off;
@ -1800,7 +1881,7 @@ pr_bitrange(v, s, ii)
/* shift till we have 0x01 */
if ((v & 0x01) == 0) {
if (ii > 1)
printf("-%u", s + off - 1);
printf("-%u", soff + off - 1);
ii = 0;
switch (v & 0x0f) {
case 0x00:
@ -1828,7 +1909,7 @@ pr_bitrange(v, s, ii)
break;
}
if (!ii)
printf(" %u", s + off);
printf(" %u", soff + off);
ii += i;
v >>= i; off += i;
}
@ -1949,7 +2030,7 @@ pr_nodeaddr(ni, nilen)
if (inet_ntop(AF_INET6, cp, ntop_buf, sizeof(ntop_buf)) ==
NULL)
strncpy(ntop_buf, "?", sizeof(ntop_buf));
strlcpy(ntop_buf, "?", sizeof(ntop_buf));
printf(" %s", ntop_buf);
if (withttl) {
if (ttl == 0xffffffff) {
@ -2065,60 +2146,6 @@ get_pathmtu(mhdr)
return(0);
}
void
set_pathmtu(mtu)
int mtu;
{
#ifdef IPV6_USE_MTU
static int firsttime = 1;
struct cmsghdr *cm;
if (firsttime) {
int oldlen = smsghdr.msg_controllen;
char *oldbuf = smsghdr.msg_control;
/* XXX: We need to enlarge control message buffer */
firsttime = 0; /* prevent further enlargement */
smsghdr.msg_controllen = oldlen + CMSG_SPACE(sizeof(int));
if ((smsghdr.msg_control =
(char *)malloc(smsghdr.msg_controllen)) == NULL)
err(1, "set_pathmtu: malloc");
cm = (struct cmsghdr *)CMSG_FIRSTHDR(&smsghdr);
cm->cmsg_len = CMSG_LEN(sizeof(int));
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_USE_MTU;
cm = (struct cmsghdr *)CMSG_NXTHDR(&smsghdr, cm);
if (oldlen)
memcpy((void *)cm, (void *)oldbuf, oldlen);
free(oldbuf);
}
/*
* look for a cmsgptr that points MTU structure.
* XXX: this procedure seems redundant at this moment, but we'd better
* keep the code generic enough for future extensions.
*/
for (cm = CMSG_FIRSTHDR(&smsghdr); cm;
cm = (struct cmsghdr *)CMSG_NXTHDR(&smsghdr, cm)) {
if (cm->cmsg_len == 0) /* XXX: paranoid check */
errx(1, "set_pathmtu: internal error");
if (cm->cmsg_level == IPPROTO_IPV6 &&
cm->cmsg_type == IPV6_USE_MTU &&
cm->cmsg_len == CMSG_LEN(sizeof(int)))
break;
}
if (cm == NULL)
errx(1, "set_pathmtu: internal error: no space for path MTU");
*(int *)CMSG_DATA(cm) = mtu;
#endif
}
/*
* tvsub --
* Subtract 2 timeval structs: out = out - in. Out is assumed to
@ -2144,12 +2171,13 @@ void
onint(notused)
int notused;
{
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGALRM, SIG_IGN);
summary();
exit(nreceived == 0);
(void)signal(SIGINT, SIG_DFL);
(void)kill(getpid(), SIGINT);
/* NOTREACHED */
exit(1);
}
/*
@ -2167,10 +2195,10 @@ summary()
(void)printf("+%ld duplicates, ", nrepeats);
if (ntransmitted) {
if (nreceived > ntransmitted)
(void)printf("-- somebody's printing up packets!");
(void)printf("-- somebody's duplicating packets!");
else
(void)printf("%d%% packet loss",
(int) (((ntransmitted - nreceived) * 100) /
(void)printf("%.1f%% packet loss",
((((double)ntransmitted - nreceived) * 100.0) /
ntransmitted));
}
(void)putchar('\n');
@ -2178,30 +2206,24 @@ summary()
/* Only display average to microseconds */
double num = nreceived + nrepeats;
double avg = tsum / num;
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
double dev = sqrt(tsumsq / num - avg * avg);
(void)printf(
"round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n",
tmin, avg, tmax, dev);
#else
(void)printf(
"round-trip min/avg/max = %.3f/%.3f/%.3f ms\n",
tmin, avg, tmax);
#endif
(void)fflush(stdout);
}
(void)fflush(stdout);
}
/*subject type*/
static char *niqcode[] = {
static const char *niqcode[] = {
"IPv6 address",
"DNS label", /*or empty*/
"IPv4 address",
};
/*result code*/
static char *nircode[] = {
static const char *nircode[] = {
"Success", "Refused", "Unknown",
};
@ -2323,11 +2345,11 @@ pr_icmph(icp, end)
(void)printf("Redirect\n");
if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf,
sizeof(ntop_buf)))
strncpy(ntop_buf, "?", sizeof(ntop_buf));
strlcpy(ntop_buf, "?", sizeof(ntop_buf));
(void)printf("Destination: %s", ntop_buf);
if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf,
sizeof(ntop_buf)))
strncpy(ntop_buf, "?", sizeof(ntop_buf));
strlcpy(ntop_buf, "?", sizeof(ntop_buf));
(void)printf(" New Target: %s", ntop_buf);
break;
case ICMP6_NI_QUERY:
@ -2459,10 +2481,10 @@ pr_iph(ip6)
(ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow),
ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim);
if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf)))
strncpy(ntop_buf, "?", sizeof(ntop_buf));
strlcpy(ntop_buf, "?", sizeof(ntop_buf));
printf("%s->", ntop_buf);
if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf)))
strncpy(ntop_buf, "?", sizeof(ntop_buf));
strlcpy(ntop_buf, "?", sizeof(ntop_buf));
printf("%s\n", ntop_buf);
}
@ -2594,7 +2616,7 @@ fill(bp, patp)
/* xxx */
if (ii > 0)
for (kk = 0;
kk <= MAXDATALEN - (8 + sizeof(struct timeval) + ii);
kk <= MAXDATALEN - (8 + sizeof(struct tv32) + ii);
kk += ii)
for (jj = 0; jj < ii; ++jj)
bp[jj + kk] = pat[jj];
@ -2623,7 +2645,7 @@ setpolicy(so, policy)
errx(1, "%s", ipsec_strerror());
if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf,
ipsec_get_policylen(buf)) < 0)
warnx("unable to set IPSec policy");
warnx("Unable to set IPsec policy");
free(buf);
return 0;
@ -2636,7 +2658,7 @@ nigroup(name)
char *name;
{
char *p;
unsigned char *q;
char *q;
MD5_CTX ctxt;
u_int8_t digest[16];
u_int8_t c;
@ -2654,16 +2676,16 @@ nigroup(name)
hbuf[(int)l] = '\0';
for (q = name; *q; q++) {
if (isupper(*q))
*q = tolower(*q);
if (isupper(*(unsigned char *)q))
*q = tolower(*(unsigned char *)q);
}
/* generate 8 bytes of pseudo-random value. */
bzero(&ctxt, sizeof(ctxt));
memset(&ctxt, 0, sizeof(ctxt));
MD5Init(&ctxt);
c = l & 0xff;
MD5Update(&ctxt, &c, sizeof(c));
MD5Update(&ctxt, name, l);
MD5Update(&ctxt, (unsigned char *)name, l);
MD5Final(digest, &ctxt);
if (inet_pton(AF_INET6, "ff02::2:0000:0000", &in6) != 1)
@ -2685,9 +2707,6 @@ usage()
"m"
#endif
"nNqtvwW"
#ifdef IPV6_REACHCONF
"R"
#endif
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
"] [-P policy"
@ -2695,9 +2714,9 @@ usage()
"AE"
#endif
#endif
"] [-a [aAclsg]] [-b sockbufsiz] [-c count]\n"
"] [-a [aAclsg]] [-b sockbufsiz] [-c count] \n"
"\t[-I interface] [-i wait] [-l preload] [-p pattern] "
"[-S sourceaddr]\n"
"\t[-s packetsize] [-h hoplimit] [hops...] host\n");
"\t[-s packetsize] [-h hoplimit] [hops...] [-g gateway] host\n");
exit(1);
}

View File

@ -80,7 +80,7 @@ struct icmp6_hdr {
u_int16_t icmp6_un_data16[2]; /* type-specific field */
u_int8_t icmp6_un_data8[4]; /* type-specific field */
} icmp6_dataun;
} __packed;
} __attribute__((__packed__));
#define icmp6_data32 icmp6_dataun.icmp6_un_data32
#define icmp6_data16 icmp6_dataun.icmp6_un_data16
@ -98,13 +98,15 @@ struct icmp6_hdr {
#define ICMP6_ECHO_REQUEST 128 /* echo service */
#define ICMP6_ECHO_REPLY 129 /* echo reply */
#define ICMP6_MEMBERSHIP_QUERY 130 /* group membership query */
#define MLD_LISTENER_QUERY 130 /* multicast listener query */
#define ICMP6_MEMBERSHIP_REPORT 131 /* group membership report */
#define MLD_LISTENER_REPORT 131 /* multicast listener report */
#define ICMP6_MEMBERSHIP_REDUCTION 132 /* group membership termination */
#define MLD_LISTENER_DONE 132 /* multicast listener done */
/* RFC2292 decls */
#define ICMP6_MEMBERSHIP_QUERY 130 /* group membership query */
#define ICMP6_MEMBERSHIP_REPORT 131 /* group membership report */
#define ICMP6_MEMBERSHIP_REDUCTION 132 /* group membership termination */
#ifndef _KERNEL
/* the followings are for backward compatibility to old KAME apps. */
#define MLD6_LISTENER_QUERY MLD_LISTENER_QUERY
@ -131,15 +133,12 @@ struct icmp6_hdr {
#define MLD_MTRACE_RESP 200 /* mtrace resp (to sender) */
#define MLD_MTRACE 201 /* mtrace messages */
#define ICMP6_HADISCOV_REQUEST 202 /* XXX To be defined */
#define ICMP6_HADISCOV_REPLY 203 /* XXX To be defined */
#ifndef _KERNEL
#define MLD6_MTRACE_RESP MLD_MTRACE_RESP
#define MLD6_MTRACE MLD_MTRACE
#endif
#define ICMP6_MAXTYPE 203
#define ICMP6_MAXTYPE 201
#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */
#define ICMP6_DST_UNREACH_ADMIN 1 /* administratively prohibited */
@ -179,7 +178,7 @@ struct icmp6_hdr {
struct mld_hdr {
struct icmp6_hdr mld_icmp6_hdr;
struct in6_addr mld_addr; /* multicast address */
} __packed;
} __attribute__((__packed__));
/* definitions to provide backward compatibility to old KAME applications */
#ifndef _KERNEL
@ -206,7 +205,7 @@ struct mld_hdr {
struct nd_router_solicit { /* router solicitation */
struct icmp6_hdr nd_rs_hdr;
/* could be followed by options */
} __packed;
} __attribute__((__packed__));
#define nd_rs_type nd_rs_hdr.icmp6_type
#define nd_rs_code nd_rs_hdr.icmp6_code
@ -218,7 +217,7 @@ struct nd_router_advert { /* router advertisement */
u_int32_t nd_ra_reachable; /* reachable time */
u_int32_t nd_ra_retransmit; /* retransmit timer */
/* could be followed by options */
} __packed;
} __attribute__((__packed__));
#define nd_ra_type nd_ra_hdr.icmp6_type
#define nd_ra_code nd_ra_hdr.icmp6_code
@ -246,7 +245,7 @@ struct nd_neighbor_solicit { /* neighbor solicitation */
struct icmp6_hdr nd_ns_hdr;
struct in6_addr nd_ns_target; /*target address */
/* could be followed by options */
} __packed;
} __attribute__((__packed__));
#define nd_ns_type nd_ns_hdr.icmp6_type
#define nd_ns_code nd_ns_hdr.icmp6_code
@ -257,7 +256,7 @@ struct nd_neighbor_advert { /* neighbor advertisement */
struct icmp6_hdr nd_na_hdr;
struct in6_addr nd_na_target; /* target address */
/* could be followed by options */
} __packed;
} __attribute__((__packed__));
#define nd_na_type nd_na_hdr.icmp6_type
#define nd_na_code nd_na_hdr.icmp6_code
@ -280,7 +279,7 @@ struct nd_redirect { /* redirect */
struct in6_addr nd_rd_target; /* target address */
struct in6_addr nd_rd_dst; /* destination address */
/* could be followed by options */
} __packed;
} __attribute__((__packed__));
#define nd_rd_type nd_rd_hdr.icmp6_type
#define nd_rd_code nd_rd_hdr.icmp6_code
@ -291,7 +290,7 @@ struct nd_opt_hdr { /* Neighbor discovery option header */
u_int8_t nd_opt_type;
u_int8_t nd_opt_len;
/* followed by option specific data*/
} __packed;
} __attribute__((__packed__));
#define ND_OPT_SOURCE_LINKADDR 1
#define ND_OPT_TARGET_LINKADDR 2
@ -310,7 +309,7 @@ struct nd_opt_prefix_info { /* prefix information */
u_int32_t nd_opt_pi_preferred_time;
u_int32_t nd_opt_pi_reserved2;
struct in6_addr nd_opt_pi_prefix;
} __packed;
} __attribute__((__packed__));
#define ND_OPT_PI_FLAG_ONLINK 0x80
#define ND_OPT_PI_FLAG_AUTO 0x40
@ -321,14 +320,14 @@ struct nd_opt_rd_hdr { /* redirected header */
u_int16_t nd_opt_rh_reserved1;
u_int32_t nd_opt_rh_reserved2;
/* followed by IP header and data */
} __packed;
} __attribute__((__packed__));
struct nd_opt_mtu { /* MTU option */
u_int8_t nd_opt_mtu_type;
u_int8_t nd_opt_mtu_len;
u_int16_t nd_opt_mtu_reserved;
u_int32_t nd_opt_mtu_mtu;
} __packed;
} __attribute__((__packed__));
struct nd_opt_route_info { /* route info */
u_int8_t nd_opt_rti_type;
@ -337,7 +336,7 @@ struct nd_opt_route_info { /* route info */
u_int8_t nd_opt_rti_flags;
u_int32_t nd_opt_rti_lifetime;
/* prefix follows */
} __packed;
} __attribute__((__packed__));
/*
* icmp6 namelookup
@ -352,7 +351,7 @@ struct icmp6_namelookup {
u_int8_t icmp6_nl_name[3];
#endif
/* could be followed by options */
} __packed;
} __attribute__((__packed__));
/*
* icmp6 node information
@ -361,7 +360,7 @@ struct icmp6_nodeinfo {
struct icmp6_hdr icmp6_ni_hdr;
u_int8_t icmp6_ni_nonce[8];
/* could be followed by reply data */
} __packed;
} __attribute__((__packed__));
#define ni_type icmp6_ni_hdr.icmp6_type
#define ni_code icmp6_ni_hdr.icmp6_code
@ -424,7 +423,7 @@ struct ni_reply_fqdn {
u_int32_t ni_fqdn_ttl; /* TTL */
u_int8_t ni_fqdn_namelen; /* length in octets of the FQDN */
u_int8_t ni_fqdn_name[3]; /* XXX: alignment */
} __packed;
} __attribute__((__packed__));
/*
* Router Renumbering. as router-renum-08.txt
@ -435,7 +434,7 @@ struct icmp6_router_renum { /* router renumbering header */
u_int8_t rr_flags;
u_int16_t rr_maxdelay;
u_int32_t rr_reserved;
} __packed;
} __attribute__((__packed__));
#define ICMP6_RR_FLAGS_TEST 0x80
#define ICMP6_RR_FLAGS_REQRESULT 0x40
@ -457,7 +456,7 @@ struct rr_pco_match { /* match prefix part */
u_int8_t rpm_maxlen;
u_int16_t rpm_reserved;
struct in6_addr rpm_prefix;
} __packed;
} __attribute__((__packed__));
#define RPM_PCO_ADD 1
#define RPM_PCO_CHANGE 2
@ -473,7 +472,7 @@ struct rr_pco_use { /* use prefix part */
u_int32_t rpu_pltime;
u_int32_t rpu_flags;
struct in6_addr rpu_prefix;
} __packed;
} __attribute__((__packed__));
#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x80
#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x40
@ -491,7 +490,7 @@ struct rr_result { /* router renumbering result message */
u_int8_t rrr_matchedlen;
u_int32_t rrr_ifid;
struct in6_addr rrr_prefix;
} __packed;
} __attribute__((__packed__));
#if BYTE_ORDER == BIG_ENDIAN
#define ICMP6_RR_RESULT_FLAGS_OOB 0x0002
#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0001

View File

@ -39,6 +39,7 @@
#include <sys/cdefs.h>
#include <sys/_types.h>
#include <sys/socket.h>
#include <machine/endian.h>
/* Protocols common to RFC 1700, POSIX, and X/Open. */

View File

@ -173,7 +173,6 @@ struct inpcb {
int inp6_cksum;
u_short inp6_ifindex;
short inp6_hops;
u_int8_t inp6_hlim;
} inp_depend6;
LIST_ENTRY(inpcb) inp_portlist;
struct inpcbport *inp_phd; /* head of this list */
@ -183,7 +182,6 @@ struct inpcb {
#define in6p_faddr inp_inc.inc6_faddr
#define in6p_laddr inp_inc.inc6_laddr
#define in6p_route inp_inc.inc6_route
#define in6p_ip6_hlim inp_depend6.inp6_hlim
#define in6p_hops inp_depend6.inp6_hops /* default hop limit */
#define in6p_ip6_nxt inp_ip_p
#define in6p_flowinfo inp_flow
@ -286,16 +284,20 @@ struct inpcbinfo { /* XXX documentation, prefixes */
#define IN6P_HOPOPTS 0x040000 /* receive hop-by-hop options */
#define IN6P_DSTOPTS 0x080000 /* receive dst options after rthdr */
#define IN6P_RTHDR 0x100000 /* receive routing header */
#define IN6P_TCLASS 0x400000 /* receive traffic class value */
#define IN6P_RTHDRDSTOPTS 0x200000 /* receive dstoptions before rthdr */
#define IN6P_AUTOFLOWLABEL 0x800000 /* attach flowlabel automatically */
#define IN6P_RFC2292 0x40000000 /* used RFC2292 API on the socket */
#define IN6P_MTU 0x80000000 /* receive path MTU */
#define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\
INP_RECVIF|INP_RECVTTL|\
IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\
IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS|\
IN6P_AUTOFLOWLABEL)
IN6P_TCLASS|IN6P_AUTOFLOWLABEL|IN6P_RFC2292|\
IN6P_MTU)
#define INP_UNMAPPABLEOPTS (IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR|\
IN6P_AUTOFLOWLABEL)
IN6P_TCLASS|IN6P_AUTOFLOWLABEL)
/* for KAME src sync over BSD*'s */
#define IN6P_HIGHPORT INP_HIGHPORT

View File

@ -85,7 +85,7 @@ struct ip6_hdr {
} ip6_ctlun;
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
} __packed;
} __attribute__((__packed__));
#define ip6_vfc ip6_ctlun.ip6_un2_vfc
#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
@ -119,7 +119,7 @@ struct ip6_hdr {
struct ip6_ext {
u_int8_t ip6e_nxt;
u_int8_t ip6e_len;
} __packed;
} __attribute__((__packed__));
/* Hop-by-Hop options header */
/* XXX should we pad it to force alignment on an 8-byte boundary? */
@ -127,7 +127,7 @@ struct ip6_hbh {
u_int8_t ip6h_nxt; /* next header */
u_int8_t ip6h_len; /* length in units of 8 octets */
/* followed by options */
} __packed;
} __attribute__((__packed__));
/* Destination options header */
/* XXX should we pad it to force alignment on an 8-byte boundary? */
@ -135,7 +135,7 @@ struct ip6_dest {
u_int8_t ip6d_nxt; /* next header */
u_int8_t ip6d_len; /* length in units of 8 octets */
/* followed by options */
} __packed;
} __attribute__((__packed__));
/* Option types and related macros */
#define IP6OPT_PAD1 0x00 /* 00 0 00000 */
@ -143,7 +143,10 @@ struct ip6_dest {
#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */
#define IP6OPT_NSAP_ADDR 0xC3 /* 11 0 00011 */
#define IP6OPT_TUNNEL_LIMIT 0x04 /* 00 0 00100 */
#ifndef _KERNEL
#define IP6OPT_RTALERT 0x05 /* 00 0 00101 (KAME definition) */
#endif
#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 (2292bis, recommended) */
#define IP6OPT_RTALERT_LEN 4
#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */
@ -151,10 +154,6 @@ struct ip6_dest {
#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */
#define IP6OPT_MINLEN 2
#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */
#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */
#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */
#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */
#define IP6OPT_EID 0x8a /* 10 0 01010 */
#define IP6OPT_TYPE(o) ((o) & 0xC0)
@ -174,7 +173,7 @@ struct ip6_rthdr {
u_int8_t ip6r_type; /* routing type */
u_int8_t ip6r_segleft; /* segments left */
/* followed by routing type specific data */
} __packed;
} __attribute__((__packed__));
/* Type 0 Routing header */
struct ip6_rthdr0 {
@ -185,7 +184,7 @@ struct ip6_rthdr0 {
u_int8_t ip6r0_reserved; /* reserved field */
u_int8_t ip6r0_slmap[3]; /* strict/loose bit map */
struct in6_addr ip6r0_addr[1]; /* up to 23 addresses */
} __packed;
} __attribute__((__packed__));
/* Fragment header */
struct ip6_frag {
@ -193,7 +192,7 @@ struct ip6_frag {
u_int8_t ip6f_reserved; /* reserved field */
u_int16_t ip6f_offlg; /* offset, reserved, and flag */
u_int32_t ip6f_ident; /* identification */
} __packed;
} __attribute__((__packed__));
#if BYTE_ORDER == BIG_ENDIAN
#define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */

View File

@ -245,9 +245,15 @@ icmp6_error(m, type, code, param)
oip6 = mtod(m, struct ip6_hdr *);
/*
* Multicast destination check. For unrecognized option errors,
* this check has already done in ip6_unknown_opt(), so we can
* check only for other errors.
* If the destination address of the erroneous packet is a multicast
* address, or the packet was sent using link-layer multicast,
* we should basically suppress sending an error (RFC 2463, Section
* 2.4).
* We have two exceptions (the item e.2 in that section):
* - the Pakcet Too Big message can be sent for path MTU discovery.
* - the Parameter Problem Message that can be allowed an icmp6 error
* in the option type field. This check has been done in
* ip6_unknown_opt(), so we can just check the type and code.
*/
if ((m->m_flags & (M_BCAST|M_MCAST) ||
IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
@ -256,7 +262,10 @@ icmp6_error(m, type, code, param)
code != ICMP6_PARAMPROB_OPTION)))
goto freeit;
/* Source address check. XXX: the case of anycast source? */
/*
* RFC 2463, 2.4 (e.5): source address check.
* XXX: the case of anycast source?
*/
if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
goto freeit;
@ -1100,6 +1109,26 @@ icmp6_mtudisc_update(ip6cp, validated)
struct rtentry *rt = NULL;
struct sockaddr_in6 sin6;
#if 0
/*
* RFC2460 section 5, last paragraph.
* even though minimum link MTU for IPv6 is IPV6_MMTU,
* we may see ICMPv6 too big with mtu < IPV6_MMTU
* due to packet translator in the middle.
* see ip6_output() and ip6_getpmtu() "alwaysfrag" case for
* special handling.
*/
if (mtu < IPV6_MMTU)
return;
#endif
/*
* we reject ICMPv6 too big with abnormally small value.
* XXX what is the good definition of "abnormally small"?
*/
if (mtu < sizeof(struct ip6_hdr) + sizeof(struct ip6_frag) + 8)
return;
if (!validated)
return;
@ -2122,7 +2151,9 @@ icmp6_reflect(m, off)
ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_nxt = IPPROTO_ICMPV6;
if (m->m_pkthdr.rcvif) {
if (outif)
ip6->ip6_hlim = ND_IFINFO(outif)->chlim;
else if (m->m_pkthdr.rcvif) {
/* XXX: This may not be the outgoing interface */
ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim;
} else

View File

@ -407,15 +407,6 @@ struct route_in6 {
* Options for use with [gs]etsockopt at the IPV6 level.
* First word of comment is data type; bool is stored in int.
*/
#define IPV6_JOIN_GROUP 12 /* ip6_mreq; join a group membership */
#define IPV6_LEAVE_GROUP 13 /* ip6_mreq; leave a group membership */
#define IPV6_MULTICAST_HOPS 10 /* int; set/get IP6 multicast hops */
#define IPV6_MULTICAST_IF 9 /* u_int; set/get IP6 multicast i/f */
#define IPV6_MULTICAST_LOOP 11 /* u_int; set/get IP6 multicast loopback */
#define IPV6_UNICAST_HOPS 4 /* int; IP6 hops */
#define IPV6_V6ONLY 27 /* bool; only bind INET6 at wildcard bind */
#if __BSD_VISIBLE
/* no hdrincl */
#if 0 /* the followings are relic in IPv4 and hence are disabled */
#define IPV6_OPTIONS 1 /* buf/ip6_opts; set/get IP6 options */
@ -425,18 +416,27 @@ struct route_in6 {
#define IPV6_RETOPTS 8 /* ip6_opts; set/get IP6 options */
#endif
#define IPV6_SOCKOPT_RESERVED1 3 /* reserved for future use */
#define IPV6_UNICAST_HOPS 4 /* int; IP6 hops */
#define IPV6_MULTICAST_IF 9 /* u_int; set/get IP6 multicast i/f */
#define IPV6_MULTICAST_HOPS 10 /* int; set/get IP6 multicast hops */
#define IPV6_MULTICAST_LOOP 11 /* u_int; set/get IP6 multicast loopback */
#define IPV6_JOIN_GROUP 12 /* ip6_mreq; join a group membership */
#define IPV6_LEAVE_GROUP 13 /* ip6_mreq; leave a group membership */
#define IPV6_PORTRANGE 14 /* int; range to choose for unspec port */
#define ICMP6_FILTER 18 /* icmp6_filter; icmp6 filter */
/* RFC2292 options */
#define IPV6_PKTINFO 19 /* bool; send/recv if, src/dst addr */
#define IPV6_HOPLIMIT 20 /* bool; hop limit */
#define IPV6_NEXTHOP 21 /* bool; next hop addr */
#define IPV6_HOPOPTS 22 /* bool; hop-by-hop option */
#define IPV6_DSTOPTS 23 /* bool; destination option */
#define IPV6_RTHDR 24 /* bool; routing header */
#define IPV6_PKTOPTIONS 25 /* buf/cmsghdr; set/get IPv6 options */
#ifdef _KERNEL
#define IPV6_2292PKTINFO 19 /* bool; send/recv if, src/dst addr */
#define IPV6_2292HOPLIMIT 20 /* bool; hop limit */
#define IPV6_2292NEXTHOP 21 /* bool; next hop addr */
#define IPV6_2292HOPOPTS 22 /* bool; hop-by-hop option */
#define IPV6_2292DSTOPTS 23 /* bool; destinaion option */
#define IPV6_2292RTHDR 24 /* bool; routing header */
#define IPV6_2292PKTOPTIONS 25 /* buf/cmsghdr; set/get IPv6 options */
#endif
#define IPV6_CHECKSUM 26 /* int; checksum offset for raw socket */
#define IPV6_V6ONLY 27 /* bool; make AF_INET6 sockets v6 only */
#ifndef _KERNEL
#define IPV6_BINDV6ONLY IPV6_V6ONLY
#endif
@ -454,6 +454,51 @@ struct route_in6 {
#define IPV6_FW_GET 34 /* get entire firewall rule chain */
#endif
/* new socket options introduced in RFC2292bis */
#define IPV6_RTHDRDSTOPTS 35 /* ip6_dest; send dst option before rthdr */
#define IPV6_RECVPKTINFO 36 /* bool; recv if, dst addr */
#define IPV6_RECVHOPLIMIT 37 /* bool; recv hop limit */
#define IPV6_RECVRTHDR 38 /* bool; recv routing header */
#define IPV6_RECVHOPOPTS 39 /* bool; recv hop-by-hop option */
#define IPV6_RECVDSTOPTS 40 /* bool; recv dst option after rthdr */
#ifdef _KERNEL
#define IPV6_RECVRTHDRDSTOPTS 41 /* bool; recv dst option before rthdr */
#endif
#define IPV6_USE_MIN_MTU 42 /* bool; send packets at the minimum MTU */
#define IPV6_RECVPATHMTU 43 /* bool; notify an according MTU */
#define IPV6_PATHMTU 44 /* mtuinfo; get the current path MTU (sopt),
4 bytes int; MTU notification (cmsg) */
#if 0 /*obsoleted during 2292bis -> 3542*/
#define IPV6_REACHCONF 45 /* no data; ND reachability confirm
(cmsg only/not in of RFC3542) */
#endif
/* more new socket options introduced in RFC2292bis */
#define IPV6_PKTINFO 46 /* in6_pktinfo; send if, src addr */
#define IPV6_HOPLIMIT 47 /* int; send hop limit */
#define IPV6_NEXTHOP 48 /* sockaddr; next hop addr */
#define IPV6_HOPOPTS 49 /* ip6_hbh; send hop-by-hop option */
#define IPV6_DSTOPTS 50 /* ip6_dest; send dst option befor rthdr */
#define IPV6_RTHDR 51 /* ip6_rthdr; send routing header */
#if 0
#define IPV6_PKTOPTIONS 52 /* buf/cmsghdr; set/get IPv6 options */
/* obsoleted by 2292bis */
#endif
#define IPV6_RECVTCLASS 57 /* bool; recv traffic class values */
#define IPV6_AUTOFLOWLABEL 59 /* bool; attach flowlabel automagically */
#define IPV6_TCLASS 61 /* int; send traffic class value */
#define IPV6_DONTFRAG 62 /* bool; disable IPv6 fragmentation */
#define IPV6_PREFER_TEMPADDR 63 /* int; prefer temporary addresses as
* the source address.
*/
/* to define items, should talk with KAME guys first, for *BSD compatibility */
#define IPV6_RTHDR_LOOSE 0 /* this hop need not be a neighbor. XXX old spec */
@ -482,6 +527,14 @@ struct in6_pktinfo {
unsigned int ipi6_ifindex; /* send/recv interface index */
};
/*
* Control structure for IPV6_RECVPATHMTU socket option.
*/
struct ip6_mtuinfo {
struct sockaddr_in6 ip6m_addr; /* or sockaddr_storage? */
u_int32_t ip6m_mtu;
};
/*
* Argument for IPV6_PORTRANGE:
* - which range to search when port is unspecified at bind() or connect()
@ -490,6 +543,7 @@ struct in6_pktinfo {
#define IPV6_PORTRANGE_HIGH 1 /* "high" - request firewall bypass */
#define IPV6_PORTRANGE_LOW 2 /* "low" - vouchsafe security */
#if __BSD_VISIBLE
/*
* Definitions for inet6 sysctl operations.
*
@ -544,6 +598,7 @@ struct in6_pktinfo {
/* New entries should be added here from current IPV6CTL_MAXID value. */
/* to define items, should talk with KAME guys first, for *BSD compatibility */
#define IPV6CTL_MAXID 42
#endif /* __BSD_VISIBLE */
/*
* Redefinition of mbuf flags
@ -584,6 +639,8 @@ typedef __size_t size_t;
#define _SIZE_T_DECLARED
#endif
#if __BSD_VISIBLE
__BEGIN_DECLS
struct cmsghdr;
@ -591,14 +648,14 @@ extern int inet6_option_space __P((int));
extern int inet6_option_init __P((void *, struct cmsghdr **, int));
extern int inet6_option_append __P((struct cmsghdr *, const uint8_t *,
int, int));
extern uint8_t *inet6_option_alloc __P((struct cmsghdr *, int, int, int));
extern int inet6_option_next __P((const struct cmsghdr *, uint8_t **));
extern int inet6_option_find __P((const struct cmsghdr *, uint8_t **, int));
extern u_int8_t *inet6_option_alloc __P((struct cmsghdr *, int, int, int));
extern int inet6_option_next __P((const struct cmsghdr *, u_int8_t **));
extern int inet6_option_find __P((const struct cmsghdr *, u_int8_t **, int));
extern size_t inet6_rthdr_space __P((int, int));
extern struct cmsghdr *inet6_rthdr_init __P((void *, int));
extern int inet6_rthdr_add __P((struct cmsghdr *, const struct in6_addr *,
unsigned int));
unsigned int));
extern int inet6_rthdr_lasthop __P((struct cmsghdr *, unsigned int));
#if 0 /* not implemented yet */
extern int inet6_rthdr_reverse __P((const struct cmsghdr *, struct cmsghdr *));
@ -607,19 +664,19 @@ extern int inet6_rthdr_segments __P((const struct cmsghdr *));
extern struct in6_addr *inet6_rthdr_getaddr __P((struct cmsghdr *, int));
extern int inet6_rthdr_getflags __P((const struct cmsghdr *, int));
extern int inet6_opt_init __P((void *, size_t));
extern int inet6_opt_append __P((void *, size_t, int, uint8_t,
size_t, uint8_t, void **));
extern int inet6_opt_finish __P((void *, size_t, int));
extern int inet6_opt_set_val __P((void *, size_t, void *, int));
extern int inet6_opt_init __P((void *, socklen_t));
extern int inet6_opt_append __P((void *, socklen_t, int, u_int8_t, socklen_t,
u_int8_t, void **));
extern int inet6_opt_finish __P((void *, socklen_t, int));
extern int inet6_opt_set_val __P((void *, int, void *, socklen_t));
extern int inet6_opt_next __P((void *, size_t, int, uint8_t *,
size_t *, void **));
extern int inet6_opt_find __P((void *, size_t, int, uint8_t,
size_t *, void **));
extern int inet6_opt_get_val __P((void *, size_t, void *, int));
extern size_t inet6_rth_space __P((int, int));
extern void *inet6_rth_init __P((void *, int, int, int));
extern int inet6_opt_next __P((void *, socklen_t, int, u_int8_t *, socklen_t *,
void **));
extern int inet6_opt_find __P((void *, socklen_t, int, u_int8_t, socklen_t *,
void **));
extern int inet6_opt_get_val __P((void *, int, void *, socklen_t));
extern socklen_t inet6_rth_space __P((int, int));
extern void *inet6_rth_init __P((void *, socklen_t, int, int));
extern int inet6_rth_add __P((void *, const struct in6_addr *));
extern int inet6_rth_reverse __P((const void *, void *));
extern int inet6_rth_segments __P((const void *));

View File

@ -444,8 +444,7 @@ in6_pcbdetach(inp)
so->so_pcb = NULL;
sotryfree(so);
}
if (inp->in6p_options)
m_freem(inp->in6p_options);
ip6_freepcbopts(inp->in6p_outputopts);
ip6_freemoptions(inp->in6p_moptions);
if (inp->in6p_route.ro_rt)

View File

@ -391,7 +391,10 @@ struct in6_rrenumreq {
#define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq)
#define SIOCGDRLST_IN6 _IOWR('i', 74, struct in6_drlist)
#define SIOCGPRLST_IN6 _IOWR('i', 75, struct in6_prlist)
#ifdef _KERNEL
/* XXX: SIOCGPRLST_IN6 is exposed in KAME but in6_oprlist is not. */
#define SIOCGPRLST_IN6 _IOWR('i', 75, struct in6_oprlist)
#endif
#ifdef _KERNEL
#define OSIOCGIFINFO_IN6 _IOWR('i', 76, struct in6_ondireq)
#endif

View File

@ -916,7 +916,7 @@ ip6_process_hopopts(m, opthead, hbhlen, rtalertp, plenp)
}
optlen = *(opt + 1) + 2;
break;
case IP6OPT_RTALERT:
case IP6OPT_ROUTER_ALERT:
/* XXX may need check for alignment */
if (hbhlen < IP6OPT_RTALERT_LEN) {
ip6stat.ip6s_toosmall++;
@ -1077,14 +1077,9 @@ ip6_savecontrol(in6p, mp, ip6, m)
struct ip6_hdr *ip6;
struct mbuf *m;
{
#if __FreeBSD_version >= 500000
#define IS2292(x, y) ((in6p->in6p_flags & IN6P_RFC2292) ? (x) : (y))
struct thread *td = curthread; /* XXX */
#else
struct proc *td = curproc; /* XXX */
#endif
int privileged = 0;
int rthdr_exist = 0;
if (td && !suser(td))
privileged++;
@ -1096,9 +1091,8 @@ ip6_savecontrol(in6p, mp, ip6, m)
microtime(&tv);
*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
SCM_TIMESTAMP, SOL_SOCKET);
if (*mp) {
if (*mp)
mp = &(*mp)->m_next;
}
}
#endif
@ -1113,20 +1107,32 @@ ip6_savecontrol(in6p, mp, ip6, m)
*mp = sbcreatecontrol((caddr_t) &pi6,
sizeof(struct in6_pktinfo),
IPV6_PKTINFO, IPPROTO_IPV6);
if (*mp) {
IS2292(IPV6_2292PKTINFO, IPV6_PKTINFO), IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
}
}
if ((in6p->in6p_flags & IN6P_HOPLIMIT) != 0) {
int hlim = ip6->ip6_hlim & 0xff;
*mp = sbcreatecontrol((caddr_t) &hlim, sizeof(int),
IPV6_HOPLIMIT, IPPROTO_IPV6);
if (*mp) {
IS2292(IPV6_2292HOPLIMIT, IPV6_HOPLIMIT), IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
}
if ((in6p->in6p_flags & IN6P_TCLASS) != 0) {
u_int32_t flowinfo;
int tclass;
flowinfo = (u_int32_t)ntohl(ip6->ip6_flow & IPV6_FLOWINFO_MASK);
flowinfo >>= 20;
tclass = flowinfo & 0xff;
*mp = sbcreatecontrol((caddr_t) &tclass, sizeof(tclass),
IPV6_TCLASS, IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
}
}
/*
@ -1135,7 +1141,11 @@ ip6_savecontrol(in6p, mp, ip6, m)
* be some hop-by-hop options which can be returned to normal user.
* See RFC 2292 section 6.
*/
if ((in6p->in6p_flags & IN6P_HOPOPTS) != 0 && privileged) {
if ((in6p->in6p_flags & IN6P_HOPOPTS) != 0) {
#ifdef DIAGNOSTIC
if (!privileged)
panic("IN6P_HOPOPTS is set for unprivileged socket");
#endif
/*
* Check if a hop-by-hop options header is contatined in the
* received packet, and if so, store the options as ancillary
@ -1143,7 +1153,6 @@ ip6_savecontrol(in6p, mp, ip6, m)
* just after the IPv6 header, which is assured through the
* IPv6 input processing.
*/
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
struct ip6_hbh *hbh;
int hbhlen = 0;
@ -1178,50 +1187,17 @@ ip6_savecontrol(in6p, mp, ip6, m)
* Note: this constraint is removed in 2292bis.
*/
*mp = sbcreatecontrol((caddr_t)hbh, hbhlen,
IPV6_HOPOPTS, IPPROTO_IPV6);
if (*mp) {
IS2292(IPV6_2292HOPOPTS, IPV6_HOPOPTS),
IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
}
#ifdef PULLDOWN_TEST
m_freem(ext);
#endif
}
}
/* IPV6_DSTOPTS and IPV6_RTHDR socket options */
if ((in6p->in6p_flags & (IN6P_DSTOPTS | IN6P_RTHDRDSTOPTS)) != 0) {
int proto, off, nxt;
/*
* go through the header chain to see if a routing header is
* contained in the packet. We need this information to store
* destination options headers (if any) properly.
* XXX: performance issue. We should record this info when
* processing extension headers in incoming routine.
* (todo) use m_aux?
*/
proto = IPPROTO_IPV6;
off = 0;
nxt = -1;
while (1) {
int newoff;
newoff = ip6_nexthdr(m, off, proto, &nxt);
if (newoff < 0)
break;
if (newoff < off) /* invalid, check for safety */
break;
if ((proto = nxt) == IPPROTO_ROUTING) {
rthdr_exist = 1;
break;
}
off = newoff;
}
}
if ((in6p->in6p_flags &
(IN6P_RTHDR | IN6P_DSTOPTS | IN6P_RTHDRDSTOPTS)) != 0) {
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
if ((in6p->in6p_flags & (IN6P_RTHDR | IN6P_DSTOPTS)) != 0) {
int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr);
/*
@ -1293,7 +1269,7 @@ ip6_savecontrol(in6p, mp, ip6, m)
break;
*mp = sbcreatecontrol((caddr_t)ip6e, elen,
IPV6_DSTOPTS,
IS2292(IPV6_2292DSTOPTS, IPV6_DSTOPTS),
IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
@ -1303,7 +1279,7 @@ ip6_savecontrol(in6p, mp, ip6, m)
break;
*mp = sbcreatecontrol((caddr_t)ip6e, elen,
IPV6_RTHDR,
IS2292(IPV6_2292RTHDR, IPV6_RTHDR),
IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
@ -1339,6 +1315,7 @@ ip6_savecontrol(in6p, mp, ip6, m)
;
}
#undef IS2292
}
#ifdef PULLDOWN_TEST

File diff suppressed because it is too large Load Diff

View File

@ -128,6 +128,14 @@ struct ip6po_rhinfo {
#define ip6po_rthdr ip6po_rhinfo.ip6po_rhi_rthdr
#define ip6po_route ip6po_rhinfo.ip6po_rhi_route
/* Nexthop related info */
struct ip6po_nhinfo {
struct sockaddr *ip6po_nhi_nexthop;
struct route_in6 ip6po_nhi_route; /* Route to the nexthop */
};
#define ip6po_nexthop ip6po_nhinfo.ip6po_nhi_nexthop
#define ip6po_nextroute ip6po_nhinfo.ip6po_nhi_route
struct ip6_pktopts {
struct mbuf *ip6po_m; /* Pointer to mbuf storing the data */
int ip6po_hlim; /* Hoplimit for outgoing packets */
@ -135,8 +143,9 @@ struct ip6_pktopts {
/* Outgoing IF/address information */
struct in6_pktinfo *ip6po_pktinfo;
struct sockaddr *ip6po_nexthop; /* Next-hop address */
/* Next-hop address information */
struct ip6po_nhinfo ip6po_nhinfo;
struct ip6_hbh *ip6po_hbh; /* Hop-by-Hop options header */
/* Destination options header (before a routing header) */
@ -147,6 +156,29 @@ struct ip6_pktopts {
/* Destination options header (after a routing header) */
struct ip6_dest *ip6po_dest2;
int ip6po_tclass; /* traffic class */
int ip6po_minmtu; /* fragment vs PMTU discovery policy */
#define IP6PO_MINMTU_MCASTONLY -1 /* default; send at min MTU for multicast*/
#define IP6PO_MINMTU_DISABLE 0 /* always perform pmtu disc */
#define IP6PO_MINMTU_ALL 1 /* always send at min MTU */
int ip6po_prefer_tempaddr; /* whether temporary addresses are
preferred as source address */
#define IP6PO_TEMPADDR_SYSTEM -1 /* follow the system default */
#define IP6PO_TEMPADDR_NOTPREFER 0 /* not prefer temporary address */
#define IP6PO_TEMPADDR_PREFER 1 /* prefer temporary address */
int ip6po_flags;
#if 0 /* parameters in this block is obsolete. do not reuse the values. */
#define IP6PO_REACHCONF 0x01 /* upper-layer reachability confirmation. */
#define IP6PO_MINMTU 0x02 /* use minimum MTU (IPV6_USE_MIN_MTU) */
#endif
#define IP6PO_DONTFRAG 0x04 /* disable fragmentation (IPV6_DONTFRAG) */
#define IP6PO_USECOA 0x08 /* use care of address */
int needfree; /* members dynamically allocated */
};
/*
@ -336,8 +368,9 @@ int ip6_output __P((struct mbuf *, struct ip6_pktopts *,
struct inpcb *));
int ip6_ctloutput __P((struct socket *, struct sockopt *));
void init_ip6pktopts __P((struct ip6_pktopts *));
int ip6_setpktoptions __P((struct mbuf *, struct ip6_pktopts *, int, int));
void ip6_clearpktopts __P((struct ip6_pktopts *, int, int));
int ip6_setpktoptions __P((struct mbuf *, struct ip6_pktopts *,
struct ip6_pktopts *, int, int, int));
void ip6_clearpktopts __P((struct ip6_pktopts *, int));
struct ip6_pktopts *ip6_copypktopts __P((struct ip6_pktopts *, int));
int ip6_optlen __P((struct inpcb *));

View File

@ -125,7 +125,7 @@ mld6_init()
/* XXX: grotty hard coding... */
hbh_buf[2] = IP6OPT_PADN; /* 2 byte padding */
hbh_buf[3] = 0;
hbh_buf[4] = IP6OPT_RTALERT;
hbh_buf[4] = IP6OPT_ROUTER_ALERT;
hbh_buf[5] = IP6OPT_RTALERT_LEN - 2;
bcopy((caddr_t)&rtalert_code, &hbh_buf[6], sizeof(u_int16_t));

View File

@ -1323,7 +1323,7 @@ nd6_ioctl(cmd, data, ifp)
struct ifnet *ifp;
{
struct in6_drlist *drl = (struct in6_drlist *)data;
struct in6_prlist *prl = (struct in6_prlist *)data;
struct in6_oprlist *oprl = (struct in6_oprlist *)data;
struct in6_ndireq *ndi = (struct in6_ndireq *)data;
struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data;
struct in6_ndifreq *ndif = (struct in6_ndifreq *)data;
@ -1343,14 +1343,7 @@ nd6_ioctl(cmd, data, ifp)
dr = TAILQ_FIRST(&nd_defrouter);
while (dr && i < DRLSTSIZ) {
drl->defrouter[i].rtaddr = dr->rtaddr;
if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) {
/* XXX: need to this hack for KAME stack */
drl->defrouter[i].rtaddr.s6_addr16[1] = 0;
} else
log(LOG_ERR,
"default router list contains a "
"non-linklocal address(%s)\n",
ip6_sprintf(&drl->defrouter[i].rtaddr));
in6_clearscope(&drl->defrouter[i].rtaddr);
drl->defrouter[i].flags = dr->flags;
drl->defrouter[i].rtlifetime = dr->rtlifetime;
@ -1364,50 +1357,46 @@ nd6_ioctl(cmd, data, ifp)
case SIOCGPRLST_IN6:
/*
* obsolete API, use sysctl under net.inet6.icmp6
*
* XXX the structure in6_prlist was changed in backward-
* incompatible manner. in6_oprlist is used for SIOCGPRLST_IN6,
* in6_prlist is used for nd6_sysctl() - fill_prlist().
*/
/*
* XXX meaning of fields, especialy "raflags", is very
* differnet between RA prefix list and RR/static prefix list.
* how about separating ioctls into two?
*/
bzero(prl, sizeof(*prl));
bzero(oprl, sizeof(*oprl));
s = splnet();
pr = nd_prefix.lh_first;
while (pr && i < PRLSTSIZ) {
struct nd_pfxrouter *pfr;
int j;
(void)in6_embedscope(&prl->prefix[i].prefix,
(void)in6_embedscope(&oprl->prefix[i].prefix,
&pr->ndpr_prefix, NULL, NULL);
prl->prefix[i].raflags = pr->ndpr_raf;
prl->prefix[i].prefixlen = pr->ndpr_plen;
prl->prefix[i].vltime = pr->ndpr_vltime;
prl->prefix[i].pltime = pr->ndpr_pltime;
prl->prefix[i].if_index = pr->ndpr_ifp->if_index;
prl->prefix[i].expire = pr->ndpr_expire;
oprl->prefix[i].raflags = pr->ndpr_raf;
oprl->prefix[i].prefixlen = pr->ndpr_plen;
oprl->prefix[i].vltime = pr->ndpr_vltime;
oprl->prefix[i].pltime = pr->ndpr_pltime;
oprl->prefix[i].if_index = pr->ndpr_ifp->if_index;
oprl->prefix[i].expire = pr->ndpr_expire;
pfr = pr->ndpr_advrtrs.lh_first;
j = 0;
while (pfr) {
if (j < DRLSTSIZ) {
#define RTRADDR prl->prefix[i].advrtr[j]
#define RTRADDR oprl->prefix[i].advrtr[j]
RTRADDR = pfr->router->rtaddr;
if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) {
/* XXX: hack for KAME */
RTRADDR.s6_addr16[1] = 0;
} else
log(LOG_ERR,
"a router(%s) advertises "
"a prefix with "
"non-link local address\n",
ip6_sprintf(&RTRADDR));
in6_clearscope(&RTRADDR);
#undef RTRADDR
}
j++;
pfr = pfr->pfr_next;
}
prl->prefix[i].advrtrs = j;
prl->prefix[i].origin = PR_ORIG_RA;
oprl->prefix[i].advrtrs = j;
oprl->prefix[i].origin = PR_ORIG_RA;
i++;
pr = pr->ndpr_next;
@ -1419,16 +1408,16 @@ nd6_ioctl(cmd, data, ifp)
rpp = LIST_NEXT(rpp, rp_entry)) {
if (i >= PRLSTSIZ)
break;
(void)in6_embedscope(&prl->prefix[i].prefix,
(void)in6_embedscope(&oprl->prefix[i].prefix,
&pr->ndpr_prefix, NULL, NULL);
prl->prefix[i].raflags = rpp->rp_raf;
prl->prefix[i].prefixlen = rpp->rp_plen;
prl->prefix[i].vltime = rpp->rp_vltime;
prl->prefix[i].pltime = rpp->rp_pltime;
prl->prefix[i].if_index = rpp->rp_ifp->if_index;
prl->prefix[i].expire = rpp->rp_expire;
prl->prefix[i].advrtrs = 0;
prl->prefix[i].origin = rpp->rp_origin;
oprl->prefix[i].raflags = rpp->rp_raf;
oprl->prefix[i].prefixlen = rpp->rp_plen;
oprl->prefix[i].vltime = rpp->rp_vltime;
oprl->prefix[i].pltime = rpp->rp_pltime;
oprl->prefix[i].if_index = rpp->rp_ifp->if_index;
oprl->prefix[i].expire = rpp->rp_expire;
oprl->prefix[i].advrtrs = 0;
oprl->prefix[i].origin = rpp->rp_origin;
i++;
}
}

View File

@ -129,6 +129,24 @@ struct in6_defrouter {
u_short if_index;
};
#ifdef _KERNEL
struct in6_oprlist {
char ifname[IFNAMSIZ];
struct {
struct in6_addr prefix;
struct prf_ra raflags;
u_char prefixlen;
u_char origin;
u_long vltime;
u_long pltime;
u_long expire;
u_short if_index;
u_short advrtrs; /* number of advertisement routers */
struct in6_addr advrtr[DRLSTSIZ]; /* XXX: explicit limit */
} prefix[PRLSTSIZ];
};
#endif
struct in6_prlist {
char ifname[IFNAMSIZ];
struct {
@ -150,9 +168,9 @@ struct in6_prefix {
struct prf_ra raflags;
u_char prefixlen;
u_char origin;
u_long vltime;
u_long pltime;
u_long expire;
u_int32_t vltime;
u_int32_t pltime;
time_t expire;
u_int32_t flags;
int refcnt;
u_short if_index;
@ -220,9 +238,6 @@ struct nd_defrouter {
u_char flags; /* flags on RA message */
u_short rtlifetime;
u_long expire;
u_long advint; /* Mobile IPv6 addition (milliseconds) */
u_long advint_expire; /* Mobile IPv6 addition */
int advints_lost; /* Mobile IPv6 addition */
struct ifnet *ifp;
};
@ -319,7 +334,7 @@ extern u_int32_t ip6_temp_valid_lifetime; /* seconds */
extern int ip6_temp_regen_advance; /* seconds */
union nd_opts {
struct nd_opt_hdr *nd_opt_array[9]; /* max = home agent info */
struct nd_opt_hdr *nd_opt_array[13]; /* max = target address list */
struct {
struct nd_opt_hdr *zero;
struct nd_opt_hdr *src_lladdr;
@ -328,8 +343,10 @@ union nd_opts {
struct nd_opt_rd_hdr *rh;
struct nd_opt_mtu *mtu;
struct nd_opt_hdr *six;
struct nd_opt_advint *adv;
struct nd_opt_hai *hai;
struct nd_opt_advinterval *adv;
struct nd_opt_homeagent_info *hai;
struct nd_opt_hdr *src_addrlist;
struct nd_opt_hdr *tgt_addrlist;
struct nd_opt_hdr *search; /* multiple opts */
struct nd_opt_hdr *last; /* multiple opts */
int done;
@ -344,6 +361,8 @@ union nd_opts {
#define nd_opts_mtu nd_opt_each.mtu
#define nd_opts_adv nd_opt_each.adv
#define nd_opts_hai nd_opt_each.hai
#define nd_opts_src_addrlist nd_opt_each.src_addrlist
#define nd_opts_tgt_addrlist nd_opt_each.tgt_addrlist
#define nd_opts_search nd_opt_each.search
#define nd_opts_last nd_opt_each.last
#define nd_opts_done nd_opt_each.done

View File

@ -269,9 +269,6 @@ nd6_ra_input(m, off, icmp6len)
dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
dr0.expire = time_second + dr0.rtlifetime;
dr0.ifp = ifp;
dr0.advint = 0; /* Mobile IPv6 */
dr0.advint_expire = 0; /* Mobile IPv6 */
dr0.advints_lost = 0; /* Mobile IPv6 */
/* unspecified or not? (RFC 2461 6.3.4) */
if (advreachable) {
advreachable = ntohl(advreachable);

View File

@ -331,10 +331,11 @@ rip6_output(m, va_alist)
struct inpcb *in6p;
u_int plen = m->m_pkthdr.len;
int error = 0;
struct ip6_pktopts opt, *optp = 0;
struct ip6_pktopts opt, *stickyopt = NULL;
struct ifnet *oifp = NULL;
int type = 0, code = 0; /* for ICMPv6 output statistics only */
int priv = 0;
struct in6_addr *in6a;
va_list ap;
va_start(ap, m);
@ -344,17 +345,21 @@ rip6_output(m, va_alist)
va_end(ap);
in6p = sotoin6pcb(so);
stickyopt = in6p->in6p_outputopts;
priv = 0;
if (so->so_cred->cr_uid == 0)
priv = 1;
dst = &dstsock->sin6_addr;
if (control) {
if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0)
if ((error = ip6_setpktoptions(control, &opt,
stickyopt, priv, 0,
so->so_proto->pr_protocol))
!= 0) {
goto bad;
optp = &opt;
} else
optp = in6p->in6p_outputopts;
}
in6p->in6p_outputopts = &opt;
}
/*
* For an ICMPv6 packet, we should know its type and code
@ -393,7 +398,9 @@ rip6_output(m, va_alist)
* XXX Boundary check is assumed to be already done in
* ip6_setpktoptions().
*/
if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) {
if (in6p->in6p_outputopts &&
(pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
pi->ipi6_ifindex) {
ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex);
oifp = ifnet_byindex(pi->ipi6_ifindex);
} else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
@ -416,19 +423,16 @@ rip6_output(m, va_alist)
/*
* Source address selection.
*/
{
struct in6_addr *in6a;
if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions,
&in6p->in6p_route, &in6p->in6p_laddr, &error)) == 0) {
if (error == 0)
error = EADDRNOTAVAIL;
goto bad;
}
ip6->ip6_src = *in6a;
if (in6p->in6p_route.ro_rt)
oifp = ifnet_byindex(in6p->in6p_route.ro_rt->rt_ifp->if_index);
if ((in6a = in6_selectsrc(dstsock, in6p->in6p_outputopts,
in6p->in6p_moptions, &in6p->in6p_route, &in6p->in6p_laddr,
&error)) == 0) {
if (error == 0)
error = EADDRNOTAVAIL;
goto bad;
}
ip6->ip6_src = *in6a;
if (in6p->in6p_route.ro_rt)
oifp = ifnet_byindex(in6p->in6p_route.ro_rt->rt_ifp->if_index);
ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
(in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);
ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
@ -466,7 +470,7 @@ rip6_output(m, va_alist)
*p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
}
error = ip6_output(m, optp, &in6p->in6p_route, 0,
error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, 0,
in6p->in6p_moptions, &oifp, in6p);
if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
if (oifp)
@ -482,11 +486,9 @@ rip6_output(m, va_alist)
m_freem(m);
freectl:
if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt)
RTFREE(optp->ip6po_route.ro_rt);
if (control) {
if (optp == &opt)
ip6_clearpktopts(optp, 0, -1);
ip6_clearpktopts(in6p->in6p_outputopts, -1);
in6p->in6p_outputopts = stickyopt;
m_freem(control);
}
return (error);

View File

@ -172,8 +172,7 @@ ip6_rthdr0(m, ip6, rh0)
index = addrs - rh0->ip6r0_segleft;
rh0->ip6r0_segleft--;
/* note that ip6r0_addr does not exist in RFC2292bis */
nextaddr = rh0->ip6r0_addr + index;
nextaddr = ((struct in6_addr *)(rh0 + 1)) + index;
/*
* reject invalid addresses. be proactive about malicious use of

View File

@ -143,7 +143,8 @@ udp6_output(in6p, m, addr6, control, td)
if (td && !suser(td))
priv = 1;
if (control) {
if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0)
if ((error = ip6_setpktoptions(control, &opt, stickyopt, priv,
0, IPPROTO_UDP)) != 0)
goto release;
in6p->in6p_outputopts = &opt;
}
@ -304,7 +305,7 @@ udp6_output(in6p, m, addr6, control, td)
releaseopt:
if (control) {
ip6_clearpktopts(in6p->in6p_outputopts, 0, -1);
ip6_clearpktopts(in6p->in6p_outputopts, -1);
in6p->in6p_outputopts = stickyopt;
m_freem(control);
}

View File

@ -18,6 +18,6 @@ PROG= mld6query
MAN= mld6query.8
SRCS= mld6.c
CFLAGS+= -DINET6 -DIPSEC
CFLAGS+= -DINET6 -DIPSEC -DUSE_RFC2292BIS
.include <bsd.prog.mk>

View File

@ -1,4 +1,4 @@
/* $KAME: mld6.c,v 1.11 2001/05/13 15:45:07 suz Exp $ */
/* $KAME: mld6.c,v 1.15 2003/04/02 11:29:54 suz Exp $ */
/* $FreeBSD$ */
/*
@ -34,6 +34,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <ifaddrs.h>
#include <unistd.h>
#include <signal.h>
@ -51,9 +52,28 @@
#include <string.h>
#include <err.h>
/* portability with older KAME headers */
#ifndef MLD_LISTENER_QUERY
#define MLD_LISTENER_QUERY MLD6_LISTENER_QUERY
#define MLD_LISTENER_REPORT MLD6_LISTENER_REPORT
#define MLD_LISTENER_DONE MLD6_LISTENER_DONE
#define MLD_MTRACE_RESP MLD6_MTRACE_RESP
#define MLD_MTRACE MLD6_MTRACE
#define mld_hdr mld6_hdr
#define mld_type mld6_type
#define mld_code mld6_code
#define mld_cksum mld6_cksum
#define mld_maxdelay mld6_maxdelay
#define mld_reserved mld6_reserved
#define mld_addr mld6_addr
#endif
#ifndef IP6OPT_ROUTER_ALERT
#define IP6OPT_ROUTER_ALERT IP6OPT_RTALERT
#endif
struct msghdr m;
struct sockaddr_in6 dst;
struct mld6_hdr mldh;
struct mld_hdr mldh;
struct in6_addr maddr = IN6ADDR_ANY_INIT, any = IN6ADDR_ANY_INIT;
struct ipv6_mreq mreq;
u_short ifindex;
@ -77,14 +97,14 @@ main(int argc, char *argv[])
u_int type;
int ch;
type = MLD6_LISTENER_QUERY;
type = MLD_LISTENER_QUERY;
while ((ch = getopt(argc, argv, "dr")) != -1) {
switch (ch) {
case 'd':
type = MLD6_LISTENER_DONE;
type = MLD_LISTENER_DONE;
break;
case 'r':
type = MLD6_LISTENER_REPORT;
type = MLD_LISTENER_REPORT;
break;
default:
usage();
@ -139,6 +159,8 @@ main(int argc, char *argv[])
(void)setitimer(ITIMER_REAL, &itimer, NULL);
FD_ZERO(&fdset);
if (s >= FD_SETSIZE)
errx(1, "descriptor too big");
for (;;) {
FD_SET(s, &fdset);
if ((i = select(s + 1, &fdset, NULL, NULL, NULL)) < 0)
@ -156,10 +178,17 @@ make_msg(int index, struct in6_addr *addr, u_int type)
static struct iovec iov[2];
static u_char *cmsgbuf;
int cmsglen, hbhlen = 0;
#ifdef USE_RFC2292BIS
void *hbhbuf = NULL, *optp = NULL;
int currentlen;
#else
u_int8_t raopt[IP6OPT_RTALERT_LEN];
#endif
struct in6_pktinfo *pi;
struct cmsghdr *cmsgp;
u_short rtalert_code = htons(IP6OPT_RTALERT_MLD);
struct ifaddrs *ifa, *ifap;
struct in6_addr src;
dst.sin6_len = sizeof(dst);
dst.sin6_family = AF_INET6;
@ -177,13 +206,47 @@ make_msg(int index, struct in6_addr *addr, u_int type)
m.msg_iovlen = 1;
bzero(&mldh, sizeof(mldh));
mldh.mld6_type = type & 0xff;
mldh.mld6_maxdelay = htons(QUERY_RESPONSE_INTERVAL);
mldh.mld6_addr = *addr;
mldh.mld_type = type & 0xff;
mldh.mld_maxdelay = htons(QUERY_RESPONSE_INTERVAL);
mldh.mld_addr = *addr;
/* MLD packet should be advertised from linklocal address */
getifaddrs(&ifa);
for (ifap = ifa; ifap; ifap = ifap->ifa_next) {
if (index != if_nametoindex(ifap->ifa_name))
continue;
if (ifap->ifa_addr->sa_family != AF_INET6)
continue;
if (!IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)
ifap->ifa_addr)->sin6_addr))
continue;
break;
}
if (ifap == NULL)
errx(1, "no linkocal address is available");
memcpy(&src, &((struct sockaddr_in6 *)ifap->ifa_addr)->sin6_addr,
sizeof(src));
freeifaddrs(ifa);
#ifdef __KAME__
/* remove embedded ifindex */
src.s6_addr[2] = src.s6_addr[3] = 0;
#endif
#ifdef USE_RFC2292BIS
if ((hbhlen = inet6_opt_init(NULL, 0)) == -1)
errx(1, "inet6_opt_init(0) failed");
if ((hbhlen = inet6_opt_append(NULL, 0, hbhlen, IP6OPT_ROUTER_ALERT, 2,
2, NULL)) == -1)
errx(1, "inet6_opt_append(0) failed");
if ((hbhlen = inet6_opt_finish(NULL, 0, hbhlen)) == -1)
errx(1, "inet6_opt_finish(0) failed");
cmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(hbhlen);
#else
hbhlen = sizeof(raopt);
cmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
inet6_option_space(hbhlen);
#endif
if ((cmsgbuf = malloc(cmsglen)) == NULL)
errx(1, "can't allocate enough memory for cmsg");
@ -196,23 +259,40 @@ make_msg(int index, struct in6_addr *addr, u_int type)
cmsgp->cmsg_type = IPV6_PKTINFO;
pi = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
pi->ipi6_ifindex = index;
memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));
memcpy(&pi->ipi6_addr, &src, sizeof(pi->ipi6_addr));
/* specifiy to insert router alert option in a hop-by-hop opt hdr. */
cmsgp = CMSG_NXTHDR(&m, cmsgp);
#ifdef USE_RFC2292BIS
cmsgp->cmsg_len = CMSG_LEN(hbhlen);
cmsgp->cmsg_level = IPPROTO_IPV6;
cmsgp->cmsg_type = IPV6_HOPOPTS;
hbhbuf = CMSG_DATA(cmsgp);
if ((currentlen = inet6_opt_init(hbhbuf, hbhlen)) == -1)
errx(1, "inet6_opt_init(len = %d) failed", hbhlen);
if ((currentlen = inet6_opt_append(hbhbuf, hbhlen, currentlen,
IP6OPT_ROUTER_ALERT, 2,
2, &optp)) == -1)
errx(1, "inet6_opt_append(currentlen = %d, hbhlen = %d) failed",
currentlen, hbhlen);
(void)inet6_opt_set_val(optp, 0, &rtalert_code, sizeof(rtalert_code));
if ((currentlen = inet6_opt_finish(hbhbuf, hbhlen, currentlen)) == -1)
errx(1, "inet6_opt_finish(buf) failed");
#else /* old advanced API */
if (inet6_option_init((void *)cmsgp, &cmsgp, IPV6_HOPOPTS))
errx(1, "inet6_option_init failed\n");
raopt[0] = IP6OPT_RTALERT;
raopt[0] = IP6OPT_ROUTER_ALERT;
raopt[1] = IP6OPT_RTALERT_LEN - 2;
memcpy(&raopt[2], (caddr_t)&rtalert_code, sizeof(u_short));
if (inet6_option_append(cmsgp, raopt, 4, 0))
errx(1, "inet6_option_append failed\n");
#endif
}
void
dump(int s)
{
int i;
struct mld6_hdr *mld;
struct mld_hdr *mld;
u_char buf[1024];
struct sockaddr_in6 from;
int from_len = sizeof(from);
@ -223,17 +303,17 @@ dump(int s)
&from_len)) < 0)
return;
if (i < sizeof(struct mld6_hdr)) {
if (i < sizeof(struct mld_hdr)) {
printf("too short!\n");
return;
}
mld = (struct mld6_hdr *)buf;
mld = (struct mld_hdr *)buf;
printf("from %s, ", inet_ntop(AF_INET6, &from.sin6_addr,
ntop_buf, sizeof(ntop_buf)));
switch (mld->mld6_type) {
switch (mld->mld_type) {
case ICMP6_MEMBERSHIP_QUERY:
printf("type=Multicast Listener Query, ");
break;
@ -244,7 +324,7 @@ dump(int s)
printf("type=Multicast Listener Done, ");
break;
}
printf("addr=%s\n", inet_ntop(AF_INET6, &mld->mld6_addr,
printf("addr=%s\n", inet_ntop(AF_INET6, &mld->mld_addr,
ntop_buf, sizeof(ntop_buf)));
fflush(stdout);
@ -252,7 +332,8 @@ dump(int s)
/* ARGSUSED */
void
quit(int signum) {
quit(int signum)
{
mreq.ipv6mr_multiaddr = any;
mreq.ipv6mr_interface = ifindex;
if (setsockopt(s, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq,

View File

@ -18,7 +18,7 @@ MAN= traceroute6.8
BINOWN= root
BINMODE= 4555
CFLAGS+= -DINET6 -DIPSEC -DHAVE_POLL
CFLAGS+= -DINET6 -DIPSEC -DUSE_RFC2292BIS -DHAVE_POLL
DPADD= ${LIBIPSEC}
LDADD= -lipsec