diff options
author | ume <ume@FreeBSD.org> | 2003-10-24 18:26:30 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2003-10-24 18:26:30 +0000 |
commit | 881c4fa39150df7d0de2dae7ae808f6a73cb199a (patch) | |
tree | 6ce05cb7459c9a9be90d670c12bfddbbbcb6946d /lib | |
parent | 0b2009d038122fd790a91ca95c5d9044ff2715c0 (diff) | |
download | FreeBSD-src-881c4fa39150df7d0de2dae7ae808f6a73cb199a.zip FreeBSD-src-881c4fa39150df7d0de2dae7ae808f6a73cb199a.tar.gz |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/net/Makefile.inc | 16 | ||||
-rw-r--r-- | lib/libc/net/getaddrinfo.c | 430 | ||||
-rw-r--r-- | lib/libc/net/inet6_opt_init.3 | 291 | ||||
-rw-r--r-- | lib/libc/net/inet6_rth_space.3 | 254 | ||||
-rw-r--r-- | lib/libc/net/ip6opt.c | 227 | ||||
-rw-r--r-- | lib/libc/net/rthdr.c | 548 | ||||
-rw-r--r-- | lib/libsdp/search.c | 1 |
7 files changed, 1401 insertions, 366 deletions
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc index 01dc3b61..a00269e 100644 --- a/lib/libc/net/Makefile.inc +++ b/lib/libc/net/Makefile.inc @@ -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 \ diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c index e8c6d4f..026909a 100644 --- a/lib/libc/net/getaddrinfo.c +++ b/lib/libc/net/getaddrinfo.c @@ -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,108 +512,182 @@ getaddrinfo(hostname, servname, hints, res) ai0 = *pai; - /* NULL hostname, or numeric hostname */ - for (ex = explore; ex->e_af >= 0; ex++) { + /* + * 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; - /* PF_UNSPEC entries are prepared for DNS queries only */ - if (ex->e_af == PF_UNSPEC) - continue; - - if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) - continue; - if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) - continue; - if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) + if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) continue; if (pai->ai_family == PF_UNSPEC) - pai->ai_family = ex->e_af; - 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; + pai->ai_family = afd->a_af; - if (hostname == NULL) - error = explore_null(pai, servname, &cur->ai_next); - else - error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); - - if (error) - goto free; + 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]); - while (cur && cur->ai_next) - cur = cur->ai_next; + if (!error && afailist[afd - afdl]) + found++; + } + if (found) { + numeric = 1; + goto globcopy; } - - /* - * 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. + * 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; - /* require exact match for family field */ - if (pai->ai_family != ex->e_af) + 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; + 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 (!MATCH(pai->ai_socktype, ex->e_socktype, - WILD_SOCKTYPE(ex))) { +#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; - } - if (!MATCH(pai->ai_protocol, ex->e_protocol, - WILD_PROTOCOL(ex))) { +#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) 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); + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + continue; + + 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 */ + /* 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; @@ -607,17 +712,6 @@ explore_null(pai, servname, res) 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. */ if (get_portmatch(pai, servname) != 0) @@ -655,11 +749,12 @@ free: * 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 @@ nextline: *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 */ diff --git a/lib/libc/net/inet6_opt_init.3 b/lib/libc/net/inet6_opt_init.3 new file mode 100644 index 0000000..65af709 --- /dev/null +++ b/lib/libc/net/inet6_opt_init.3 @@ -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. diff --git a/lib/libc/net/inet6_rth_space.3 b/lib/libc/net/inet6_rth_space.3 new file mode 100644 index 0000000..1289b11 --- /dev/null +++ b/lib/libc/net/inet6_rth_space.3 @@ -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. diff --git a/lib/libc/net/ip6opt.c b/lib/libc/net/ip6opt.c index a26e45d..2f54918 100644 --- a/lib/libc/net/ip6opt.c +++ b/lib/libc/net/ip6opt.c @@ -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); +} diff --git a/lib/libc/net/rthdr.c b/lib/libc/net/rthdr.c index abfe34a..d7b0077 100644 --- a/lib/libc/net/rthdr.c +++ b/lib/libc/net/rthdr.c @@ -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; - - rthdr = (struct ip6_rthdr *)CMSG_DATA(ch); - - 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); + struct cmsghdr *ch = (struct cmsghdr *)bp; + struct ip6_rthdr *rthdr; + + rthdr = (struct ip6_rthdr *)CMSG_DATA(ch); + + ch->cmsg_level = IPPROTO_IPV6; + ch->cmsg_type = IPV6_RTHDR; + + 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; - - 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); + struct ip6_rthdr *rthdr; + + 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) + return (-1); + 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 - return(-1); - } + 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); + 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; - - 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); - } + struct ip6_rthdr *rthdr; + + rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); + + 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); + + 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) + 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 + } - rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); + default: + return NULL; + } +} - switch(rthdr->ip6r_type) { - case IPV6_RTHDR_TYPE_0: - { - struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; - int naddr; +int +inet6_rthdr_getflags(cmsg, idx) + const struct cmsghdr *cmsg; + int idx; +{ + struct ip6_rthdr *rthdr; + + 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; + + 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 */ + } - 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; + default: + return (-1); } - 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; +} + +/* + * 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 */ } - return &rt0->ip6r0_addr[idx - 1]; - } +} - default: -#ifdef DEBUG - fprintf(stderr, "inet6_rthdr_getaddr: unknown type(%d)\n", - rthdr->ip6r_type); -#endif - return NULL; - } +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_rthdr_getflags(cmsg, idx) - const struct cmsghdr *cmsg; - int idx; +inet6_rth_add(void *bp, const struct in6_addr *addr) { - struct ip6_rthdr *rthdr; + 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); +} - rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg); +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 */ + } - switch(rthdr->ip6r_type) { - case IPV6_RTHDR_TYPE_0: - { - struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr; - int naddr; + return (0); +} - 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; +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 */ } - 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; +} + +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; } - 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; - } } diff --git a/lib/libsdp/search.c b/lib/libsdp/search.c index ab495e3..c739824 100644 --- a/lib/libsdp/search.c +++ b/lib/libsdp/search.c @@ -29,6 +29,7 @@ * $FreeBSD$ */ +#include <sys/types.h> #include <sys/uio.h> #include <netinet/in.h> #include <arpa/inet.h> |