From 73eff3822baf06526fddfaa26e8e81ab27540742 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 19 Feb 2020 14:59:06 +0000 Subject: [PATCH] added PTR parsing. added string to skad conversion functions --- mio/bin/t01.c | 14 +- mio/lib/dns.c | 43 +++-- mio/lib/mio-dns.h | 3 +- mio/lib/mio-skad.h | 38 +++++ mio/lib/skad.c | 410 ++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 455 insertions(+), 53 deletions(-) diff --git a/mio/bin/t01.c b/mio/bin/t01.c index a51129b..df03cd1 100644 --- a/mio/bin/t01.c +++ b/mio/bin/t01.c @@ -608,7 +608,6 @@ static void on_dnc_resolve(mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio_errnum { mio_dns_pkt_info_t* pi = MIO_NULL; - if (data) // status == MIO_ENOERR { mio_uint32_t i; @@ -660,7 +659,7 @@ static void on_dnc_resolve(mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio_errnum { no_valid_reply: if (status == MIO_ETMOUT) printf ("XXXXXXXXXXXXXXXX TIMED OUT XXXXXXXXXXXXXXXXX\n"); - else printf ("XXXXXXXXXXXXXXXXx NO REPLY XXXXXXXXXXXXXXXXXXXXXXXXX\n"); + else printf ("XXXXXXXXXXXXXXXXx NO VALID REPLY XXXXXXXXXXXXXXXXXXXXXXXXX\n"); } done: @@ -698,6 +697,10 @@ static void on_dnc_resolve_brief (mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio { printf ("^^^ SIMPLE -> NS [%s] %d\n", brr->dptr, (int)brr->dlen); } + else if (brr->rrtype == MIO_DNS_RRT_PTR) + { + printf ("^^^ SIMPLE -> PTR [%s] %d\n", brr->dptr, (int)brr->dlen); + } else if (brr->rrtype == MIO_DNS_RRT_SOA) { mio_dns_brrd_soa_t* soa = brr->dptr; @@ -711,7 +714,7 @@ static void on_dnc_resolve_brief (mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio else { if (status == MIO_ETMOUT) printf ("QQQQQQQQQQQQQQQQQQQ TIMED OUT QQQQQQQQQQQQQQQQQ\n"); - else printf ("QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ NO REPLY QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQq\n"); + else printf ("QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ NO VALID REPLY QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQq - %d\n", mio_geterrnum(mio_svc_dnc_getmio(dnc))); } } @@ -1014,6 +1017,11 @@ if (!mio_svc_dnc_resolve(dnc, "code.miflux.com", MIO_DNS_RRT_A, MIO_SVC_DNC_RESO printf ("resolve attempt failure ---> code.miflux.com\n"); } +if (!mio_svc_dnc_resolve(dnc, "1.1.1.1.in-addr.arpa", MIO_DNS_RRT_PTR, MIO_SVC_DNC_RESOLVE_FLAG_BRIEF, on_dnc_resolve_brief, 0)) +{ + printf ("resolve attempt failure ---> 1.1.1.1.in-addr.arpa\n"); +} + //if (!mio_svc_dnc_resolve(dnc, "ipv6.google.com", MIO_DNS_RRT_AAAA, MIO_SVC_DNC_RESOLVE_FLAG_BRIEF, on_dnc_resolve_brief, 0)) if (!mio_svc_dnc_resolve(dnc, "google.com", MIO_DNS_RRT_SOA, MIO_SVC_DNC_RESOLVE_FLAG_BRIEF, on_dnc_resolve_brief, 0)) //if (!mio_svc_dnc_resolve(dnc, "google.com", MIO_DNS_RRT_NS, MIO_SVC_DNC_RESOLVE_FLAG_BRIEF, on_dnc_resolve_brief, 0)) diff --git a/mio/lib/dns.c b/mio/lib/dns.c index 1f0e946..6da7e1d 100644 --- a/mio/lib/dns.c +++ b/mio/lib/dns.c @@ -221,7 +221,7 @@ static int dnc_on_read (mio_dev_sck_t* dev, const void* data, mio_iolen_t dlen, mio_dns_msg_t* reqmsg; mio_uint16_t id; - if (dlen < MIO_SIZEOF(*pkt)) + if (MIO_UNLIKELY(dlen < MIO_SIZEOF(*pkt))) { MIO_DEBUG0 (mio, "dns packet too small from ....\n"); /* TODO: add source packet */ return 0; /* drop */ @@ -450,21 +450,6 @@ mio_dns_msg_t* mio_svc_dnc_sendmsg (mio_svc_dnc_t* dnc, mio_dns_bhdr_t* bdns, mi return msg; } -#if 0 -mio_dns_msg_t* mio_svc_dnc_resendmsg (mio_svc_dnc_t* dnc, mio_dns_msg_t* msg) -{ - if (mio_dev_sck_write(dnc->sck, mio_dns_msg_to_pkt(msg), msg->pktlen, msg, &dnc->serveraddr) <= -1) - { - release_dns_msg (dnc, msg); - return MIO_NULL; - } - - msg->no_release = 1; ???? - return msg; -} -#endif - - mio_dns_msg_t* mio_svc_dnc_sendreq (mio_svc_dnc_t* dnc, mio_dns_bhdr_t* bdns, mio_dns_bqr_t* qr, mio_dns_bedns_t* edns, mio_svc_dnc_on_reply_t on_reply, mio_oow_t xtnsize) { /* send a request without resource records */ @@ -497,9 +482,17 @@ typedef struct dnc_dns_msg_resolve_xtn_t dnc_dns_msg_resolve_xtn_t; static void on_dnc_resolve (mio_svc_dnc_t* dnc, mio_dns_msg_t* reqmsg, mio_errnum_t status, const void* data, mio_oow_t dlen) { mio_t* mio = mio_svc_dnc_getmio(dnc); + mio_dns_pkt_t* pkt; mio_dns_pkt_info_t* pi = MIO_NULL; dnc_dns_msg_resolve_xtn_t* reqmsgxtn = dnc_dns_msg_resolve_getxtn(reqmsg); + MIO_ASSERT (mio, dlen >= MIO_SIZEOF(*pkt)); /* this is guaranteed by the dnc_on_read() */ + pkt = (mio_dns_pkt_t*)data; + if (pkt->tc && (reqmsgxtn->flags & MIO_SVC_DNC_RESOLVE_FLAG_TCP_IF_TC)) /* truncated */ + { + /* TODO: */ + } + if (!(reqmsgxtn->flags & MIO_SVC_DNC_RESOLVE_FLAG_BRIEF)) { /* the full reply packet is requested. no transformation is required */ @@ -799,11 +792,12 @@ static int parse_answer_rr (mio_t* mio, mio_dns_rr_part_t rr_part, mio_oow_t pos case MIO_DNS_RRT_CNAME: case MIO_DNS_RRT_NS: + case MIO_DNS_RRT_PTR: { #if !defined(MIO_BUILD_RELEASE) mio_uint8_t* xptr = pi->_ptr; #endif - if (parse_domain_name(mio, pi) <= -1) return -1; + if (parse_domain_name(mio, pi) <= -1) goto oops; MIO_ASSERT (mio, pi->_ptr == xptr + dlen); break; } @@ -822,10 +816,10 @@ static int parse_answer_rr (mio_t* mio, mio_dns_rr_part_t rr_part, mio_oow_t pos pi->_rrdptr += MIO_SIZEOF(*soa); soa->mname = (mio_bch_t*)pi->_rrdptr; - if (parse_domain_name(mio, pi) <= -1) return -1; + if (parse_domain_name(mio, pi) <= -1) goto oops; soa->rname = (mio_bch_t*)pi->_rrdptr; - if (parse_domain_name(mio, pi) <= -1) return -1; + if (parse_domain_name(mio, pi) <= -1) goto oops; MIO_MEMCPY (&soa->serial, pi->_ptr, 20); soa->serial = mio_ntoh32(soa->serial); @@ -836,9 +830,10 @@ static int parse_answer_rr (mio_t* mio, mio_dns_rr_part_t rr_part, mio_oow_t pos } else { - if (parse_domain_name(mio, pi) <= -1) return -1; - if (parse_domain_name(mio, pi) <= -1) return -1; + if (parse_domain_name(mio, pi) <= -1) goto oops; + if (parse_domain_name(mio, pi) <= -1) goto oops; } + if (MIO_UNLIKELY(pi->_end - pi->_ptr) < 20) goto oops; pi->_ptr += 20; MIO_ASSERT (mio, pi->_ptr == xptr + dlen); @@ -966,14 +961,13 @@ void mio_dns_free_packet_info (mio_t* mio, mio_dns_pkt_info_t* pi) /* ----------------------------------------------------------------------- */ -static mio_oow_t encode_rdata_in_dns_msg (mio_t* mio, const mio_dns_brr_t* rr, mio_dns_rrtr_t* rrtr) +static mio_oow_t encode_rrdata_in_dns_msg (mio_t* mio, const mio_dns_brr_t* rr, mio_dns_rrtr_t* rrtr) { switch (rr->rrtype) { case MIO_DNS_RRT_A: break; case MIO_DNS_RRT_AAAA: - break; /* @@ -993,6 +987,7 @@ static mio_oow_t encode_rdata_in_dns_msg (mio_t* mio, const mio_dns_brr_t* rr, m case MIO_DNS_RRT_NS: case MIO_DNS_RRT_PTR: /* just a normal domain name */ + /* TODO: take a null-terminated string and encode it using to_dn() */ break; #if 0 @@ -1130,7 +1125,7 @@ mio_dns_msg_t* mio_dns_make_msg (mio_t* mio, mio_dns_bhdr_t* bhdr, mio_dns_bqr_t rrtr->rrclass = mio_hton16(rr[i].rrclass); rrtr->ttl = mio_hton32(rr[i].ttl); - rdata_len = encode_rdata_in_dns_msg(mio, &rr[i], rrtr); + rdata_len = encode_rrdata_in_dns_msg(mio, &rr[i], rrtr); dn = (mio_uint8_t*)(rrtr + 1) + rdata_len; match_count++; diff --git a/mio/lib/mio-dns.h b/mio/lib/mio-dns.h index 86caeeb..1ff2afc 100644 --- a/mio/lib/mio-dns.h +++ b/mio/lib/mio-dns.h @@ -391,7 +391,8 @@ typedef void (*mio_svc_dnc_on_resolve_t) ( enum mio_svc_dnc_resolve_flag_t { - MIO_SVC_DNC_RESOLVE_FLAG_BRIEF = (1 << 0) + MIO_SVC_DNC_RESOLVE_FLAG_BRIEF = (1 << 0), + MIO_SVC_DNC_RESOLVE_FLAG_TCP_IF_TC = (1 << 1) }; typedef enum mio_svc_dnc_resolve_flag_t mio_svc_dnc_resolve_flag_t; diff --git a/mio/lib/mio-skad.h b/mio/lib/mio-skad.h index 1f6c0ec..dc10c2e 100644 --- a/mio/lib/mio-skad.h +++ b/mio/lib/mio-skad.h @@ -67,6 +67,44 @@ typedef struct mio_skad_t mio_skad_t; extern "C" { #endif +MIO_EXPORT int mio_ucharstoskad ( + mio_t* mio, + const mio_uch_t* str, + mio_oow_t len, + mio_skad_t* skad +); + +MIO_EXPORT int mio_bcharstoskad ( + mio_t* mio, + const mio_bch_t* str, + mio_oow_t len, + mio_skad_t* skad +); + +MIO_EXPORT mio_oow_t mio_skadtoucstr ( + mio_t* mio, + const mio_skad_t* skad, + mio_uch_t* buf, + mio_oow_t len, + int flags +); + +MIO_EXPORT mio_oow_t mio_skadtobcstr ( + mio_t* mio, + const mio_skad_t* skad, + mio_bch_t* buf, + mio_oow_t len, + int flags +); + +#if defined(MIO_OOCH_IS_UCH) +# define mio_oocharstoskad mio_ucharstoskad +# define mio_skadtooocstr mio_skadtoucstr +#else +# define mio_oocharstoskad mio_bcharstoskad +# define mio_skadtooocstr mio_skadtobcstr +#endif + MIO_EXPORT int mio_skad_family ( const mio_skad_t* skad ); diff --git a/mio/lib/skad.c b/mio/lib/skad.c index 571a8b8..5cc387b 100644 --- a/mio/lib/skad.c +++ b/mio/lib/skad.c @@ -62,12 +62,54 @@ union mio_skad_alt_t typedef union mio_skad_alt_t mio_skad_alt_t; -static int str_to_ipv4 (const mio_ooch_t* str, mio_oow_t len, struct in_addr* inaddr) +static int uchars_to_ipv4 (const mio_uch_t* str, mio_oow_t len, struct in_addr* inaddr) { - const mio_ooch_t* end; + const mio_uch_t* end; int dots = 0, digits = 0; mio_uint32_t acc = 0, addr = 0; - mio_ooch_t c; + mio_uch_t c; + + end = str + len; + + do + { + if (str >= end) + { + if (dots < 3 || digits == 0) return -1; + addr = (addr << 8) | acc; + break; + } + + c = *str++; + + if (c >= '0' && c <= '9') + { + if (digits > 0 && acc == 0) return -1; + acc = acc * 10 + (c - '0'); + if (acc > 255) return -1; + digits++; + } + else if (c == '.') + { + if (dots >= 3 || digits == 0) return -1; + addr = (addr << 8) | acc; + dots++; acc = 0; digits = 0; + } + else return -1; + } + while (1); + + inaddr->s_addr = mio_hton32(addr); + return 0; + +} + +static int bchars_to_ipv4 (const mio_bch_t* str, mio_oow_t len, struct in_addr* inaddr) +{ + const mio_bch_t* end; + int dots = 0, digits = 0; + mio_uint32_t acc = 0, addr = 0; + mio_bch_t c; end = str + len; @@ -105,14 +147,14 @@ static int str_to_ipv4 (const mio_ooch_t* str, mio_oow_t len, struct in_addr* in } #if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) -static int str_to_ipv6 (const mio_ooch_t* src, mio_oow_t len, struct in6_addr* inaddr) +static int uchars_to_ipv6 (const mio_uch_t* src, mio_oow_t len, struct in6_addr* inaddr) { mio_uint8_t* tp, * endp, * colonp; - const mio_ooch_t* curtok; - mio_ooch_t ch; + const mio_uch_t* curtok; + mio_uch_t ch; int saw_xdigit; unsigned int val; - const mio_ooch_t* src_end; + const mio_uch_t* src_end; src_end = src + len; @@ -177,7 +219,117 @@ static int str_to_ipv6 (const mio_ooch_t* src, mio_oow_t len, struct in6_addr* i } if (ch == '.' && ((tp + MIO_SIZEOF(struct in_addr)) <= endp) && - str_to_ipv4(curtok, src_end - curtok, (struct in_addr*)tp) == 0) + uchars_to_ipv4(curtok, src_end - curtok, (struct in_addr*)tp) == 0) + { + tp += MIO_SIZEOF(struct in_addr*); + saw_xdigit = 0; + break; + } + + return -1; + } + + if (saw_xdigit) + { + if (tp + MIO_SIZEOF(mio_uint16_t) > endp) return -1; + *tp++ = (mio_uint8_t)(val >> 8) & 0xff; + *tp++ = (mio_uint8_t)val & 0xff; + } + if (colonp != MIO_NULL) + { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + mio_oow_t n = tp - colonp; + mio_oow_t i; + + for (i = 1; i <= n; i++) + { + endp[-i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + + if (tp != endp) return -1; + + return 0; +} + +static int bchars_to_ipv6 (const mio_bch_t* src, mio_oow_t len, struct in6_addr* inaddr) +{ + mio_uint8_t* tp, * endp, * colonp; + const mio_bch_t* curtok; + mio_bch_t ch; + int saw_xdigit; + unsigned int val; + const mio_bch_t* src_end; + + src_end = src + len; + + MIO_MEMSET (inaddr, 0, MIO_SIZEOF(*inaddr)); + tp = &inaddr->s6_addr[0]; + endp = &inaddr->s6_addr[MIO_COUNTOF(inaddr->s6_addr)]; + colonp = MIO_NULL; + + /* Leading :: requires some special handling. */ + if (src < src_end && *src == ':') + { + src++; + if (src >= src_end || *src != ':') return -1; + } + + curtok = src; + saw_xdigit = 0; + val = 0; + + while (src < src_end) + { + int v1; + + ch = *src++; + + if (ch >= '0' && ch <= '9') + v1 = ch - '0'; + else if (ch >= 'A' && ch <= 'F') + v1 = ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + v1 = ch - 'a' + 10; + else v1 = -1; + if (v1 >= 0) + { + val <<= 4; + val |= v1; + if (val > 0xffff) return -1; + saw_xdigit = 1; + continue; + } + + if (ch == ':') + { + curtok = src; + if (!saw_xdigit) + { + if (colonp) return -1; + colonp = tp; + continue; + } + else if (src >= src_end) + { + /* a colon can't be the last character */ + return -1; + } + + *tp++ = (mio_uint8_t)(val >> 8) & 0xff; + *tp++ = (mio_uint8_t)val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + + if (ch == '.' && ((tp + MIO_SIZEOF(struct in_addr)) <= endp) && + bchars_to_ipv4(curtok, src_end - curtok, (struct in_addr*)tp) == 0) { tp += MIO_SIZEOF(struct in_addr*); saw_xdigit = 0; @@ -216,12 +368,14 @@ static int str_to_ipv6 (const mio_ooch_t* src, mio_oow_t len, struct in6_addr* i } #endif -int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_skad_t* _skad) +/* ---------------------------------------------------------- */ + +int mio_ucharstoskad (mio_t* mio, const mio_uch_t* str, mio_oow_t len, mio_skad_t* _skad) { mio_skad_alt_t* skad = (mio_skad_alt_t*)_skad; - const mio_ooch_t* p; - const mio_ooch_t* end; - mio_oocs_t tmp; + const mio_uch_t* p; + const mio_uch_t* end; + mio_ucs_t tmp; p = str; end = str + len; @@ -237,14 +391,10 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska #if defined(AF_UNIX) if (*p == '/' && len >= 2) { - #if defined(MIO_OOCH_IS_BCH) - mio_copy_bcstr (skad->un.sun_path, MIO_COUNTOF(skad->un.sun_path), str); - #else mio_oow_t dstlen; dstlen = MIO_COUNTOF(skad->un.sun_path) - 1; if (mio_convutobchars(mio, p, &len, skad->un.sun_path, &dstlen) <= -1) return -1; skad->un.sun_path[dstlen] = '\0'; - #endif skad->un.sun_family = AF_UNIX; return 0; } @@ -254,7 +404,7 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska if (*p == '[') { /* IPv6 address */ - tmp.ptr = (mio_ooch_t*)++p; /* skip [ and remember the position */ + tmp.ptr = (mio_uch_t*)++p; /* skip [ and remember the position */ while (p < end && *p != '%' && *p != ']') p++; if (p >= end) goto no_rbrack; @@ -294,7 +444,7 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska else { /* interface name as a scope id? */ - const mio_ooch_t* stmp = p; + const mio_uch_t* stmp = p; unsigned int index; do p++; while (p < end && *p != ']'); if (mio_ucharstoifindex(mio, stmp, p - stmp, &index) <= -1) return -1; @@ -305,18 +455,18 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska } p++; /* skip ] */ - if (str_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog; + if (uchars_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog; skad->in6.sin6_family = AF_INET6; } else { #endif /* IPv4 address */ - tmp.ptr = (mio_ooch_t*)p; + tmp.ptr = (mio_uch_t*)p; while (p < end && *p != ':') p++; tmp.len = p - tmp.ptr; - if (str_to_ipv4(tmp.ptr, tmp.len, &skad->in4.sin_addr) <= -1) + if (uchars_to_ipv4(tmp.ptr, tmp.len, &skad->in4.sin_addr) <= -1) { #if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) /* check if it is an IPv6 address not enclosed in []. @@ -327,11 +477,10 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska goto unrecog; } - while (p < end && *p != '%') p++; tmp.len = p - tmp.ptr; - if (str_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog; + if (uchars_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog; if (p < end && *p == '%') { @@ -367,7 +516,7 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska else { /* interface name as a scope id? */ - const mio_ooch_t* stmp = p; + const mio_uch_t* stmp = p; unsigned int index; do p++; while (p < end); if (mio_ucharstoifindex(mio, stmp, p - stmp, &index) <= -1) return -1; @@ -396,7 +545,218 @@ int mio_oocharstoskad (mio_t* mio, const mio_ooch_t* str, mio_oow_t len, mio_ska p++; /* skip : */ - tmp.ptr = (mio_ooch_t*)p; + tmp.ptr = (mio_uch_t*)p; + while (p < end && *p >= '0' && *p <= '9') + { + port = port * 10 + (*p - '0'); + p++; + } + + tmp.len = p - tmp.ptr; + if (tmp.len <= 0 || tmp.len >= 6 || + port > MIO_TYPE_MAX(mio_uint16_t)) + { + mio_seterrbfmt (mio, MIO_EINVAL, "port number blank or too large"); + return -1; + } + + #if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + if (skad->in4.sin_family == AF_INET) + skad->in4.sin_port = mio_hton16(port); + else + skad->in6.sin6_port = mio_hton16(port); + #else + skad->in4.sin_port = mio_hton16(port); + #endif + } + + return 0; + +unrecog: + mio_seterrbfmt (mio, MIO_EINVAL, "unrecognized address"); + return -1; + +no_rbrack: + mio_seterrbfmt (mio, MIO_EINVAL, "missing right bracket"); + return -1; +} + +/* ---------------------------------------------------------- */ + +int mio_bcharstoskad (mio_t* mio, const mio_bch_t* str, mio_oow_t len, mio_skad_t* _skad) +{ + mio_skad_alt_t* skad = (mio_skad_alt_t*)_skad; + const mio_bch_t* p; + const mio_bch_t* end; + mio_bcs_t tmp; + + p = str; + end = str + len; + + if (p >= end) + { + mio_seterrbfmt (mio, MIO_EINVAL, "blank address"); + return -1; + } + + MIO_MEMSET (skad, 0, MIO_SIZEOF(*skad)); + +#if defined(AF_UNIX) + if (*p == '/' && len >= 2) + { + mio_copy_bcstr (skad->un.sun_path, MIO_COUNTOF(skad->un.sun_path), str); + skad->un.sun_family = AF_UNIX; + return 0; + } +#endif + +#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + if (*p == '[') + { + /* IPv6 address */ + tmp.ptr = (mio_bch_t*)++p; /* skip [ and remember the position */ + while (p < end && *p != '%' && *p != ']') p++; + + if (p >= end) goto no_rbrack; + + tmp.len = p - tmp.ptr; + if (*p == '%') + { + /* handle scope id */ + mio_uint32_t x; + + p++; /* skip % */ + + if (p >= end) + { + /* premature end */ + mio_seterrbfmt (mio, MIO_EINVAL, "scope id blank"); + return -1; + } + + if (*p >= '0' && *p <= '9') + { + /* numeric scope id */ + skad->in6.sin6_scope_id = 0; + do + { + x = skad->in6.sin6_scope_id * 10 + (*p - '0'); + if (x < skad->in6.sin6_scope_id) + { + mio_seterrbfmt (mio, MIO_EINVAL, "scope id too large"); + return -1; /* overflow */ + } + skad->in6.sin6_scope_id = x; + p++; + } + while (p < end && *p >= '0' && *p <= '9'); + } + else + { + /* interface name as a scope id? */ + const mio_bch_t* stmp = p; + unsigned int index; + do p++; while (p < end && *p != ']'); + if (mio_bcharstoifindex(mio, stmp, p - stmp, &index) <= -1) return -1; + skad->in6.sin6_scope_id = index; + } + + if (p >= end || *p != ']') goto no_rbrack; + } + p++; /* skip ] */ + + if (bchars_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog; + skad->in6.sin6_family = AF_INET6; + } + else + { +#endif + /* IPv4 address */ + tmp.ptr = (mio_bch_t*)p; + while (p < end && *p != ':') p++; + tmp.len = p - tmp.ptr; + + if (bchars_to_ipv4(tmp.ptr, tmp.len, &skad->in4.sin_addr) <= -1) + { + #if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + /* check if it is an IPv6 address not enclosed in []. + * the port number can't be specified in this format. */ + if (p >= end || *p != ':') + { + /* without :, it can't be an ipv6 address */ + goto unrecog; + } + + + while (p < end && *p != '%') p++; + tmp.len = p - tmp.ptr; + + if (bchars_to_ipv6(tmp.ptr, tmp.len, &skad->in6.sin6_addr) <= -1) goto unrecog; + + if (p < end && *p == '%') + { + /* handle scope id */ + mio_uint32_t x; + + p++; /* skip % */ + + if (p >= end) + { + /* premature end */ + mio_seterrbfmt (mio, MIO_EINVAL, "scope id blank"); + return -1; + } + + if (*p >= '0' && *p <= '9') + { + /* numeric scope id */ + skad->in6.sin6_scope_id = 0; + do + { + x = skad->in6.sin6_scope_id * 10 + (*p - '0'); + if (x < skad->in6.sin6_scope_id) + { + mio_seterrbfmt (mio, MIO_EINVAL, "scope id too large"); + return -1; /* overflow */ + } + skad->in6.sin6_scope_id = x; + p++; + } + while (p < end && *p >= '0' && *p <= '9'); + } + else + { + /* interface name as a scope id? */ + const mio_bch_t* stmp = p; + unsigned int index; + do p++; while (p < end); + if (mio_bcharstoifindex(mio, stmp, p - stmp, &index) <= -1) return -1; + skad->in6.sin6_scope_id = index; + } + } + + if (p < end) goto unrecog; /* some gargage after the end? */ + + skad->in6.sin6_family = AF_INET6; + return 0; + #else + goto unrecog; + #endif + } + + skad->in4.sin_family = AF_INET; +#if (MIO_SIZEOF_STRUCT_SOCKADDR_IN6 > 0) + } +#endif + + if (p < end && *p == ':') + { + /* port number */ + mio_uint32_t port = 0; + + p++; /* skip : */ + + tmp.ptr = (mio_bch_t*)p; while (p < end && *p >= '0' && *p <= '9') { port = port * 10 + (*p - '0');