diff options
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 01dc3b61e091..a00269e04bd1 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 e8c6d4fa912f..026909af40a8 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 000000000000..65af709eaf8a --- /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 000000000000..1289b11b3eef --- /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 a26e45d3b83d..2f5491849b0d 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 abfe34a93ad8..d7b0077f606e 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 ab495e32115f..c739824abb4d 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> |