And from an actual implementation.

enum encoding {
        sbpr_text,
        sbpr_port,
        sbpr_ipv4s,
        sbpr_ipv6s,
        sbpr_base64
};

static const struct {
        const char *    name;
        unsigned int    value;
        enum encoding   encoding;
        bool            initial;
} sbpr[] = {
        { "key0=", 0, sbpr_text, true },
        { "alpn=", 1, sbpr_text, true },
        { "port=", 2, sbpr_port, true },
        { "esnikeys=", 3, sbpr_base64, true },
        { "ipv4hint=", 4, sbpr_ipv4s, true },
        { "ipv6hint=", 6, sbpr_ipv6s, true },
};

                switch (sbpr[i].encoding) {
                case sbpr_text:
                        RETERR(multitxt_fromtext(region, target));
                        break;
                case sbpr_port:
                        ul = strtoul(region->base, &e, 10);
                        if (*e != '\0') {
                                return (DNS_R_SYNTAX);
                        }
                        if (ul > 0xffff) {
                                return (ISC_R_RANGE);
                        }
                        RETERR(uint16_tobuffer(ul, target));
                        break;
                case sbpr_ipv4s:
                        do {
                                snprintf(tbuf, sizeof(tbuf), "%*s",
                                         (int)(region->length), region->base);
                                e = strchr(tbuf, ',');
                                if (e != NULL) {
                                        *e++ = 0;
                                        isc_textregion_consume(region,
                                                               e - tbuf);
                                }
                                if (inet_pton(AF_INET, tbuf, abuf) != 1) {
                                        return (DNS_R_SYNTAX);
                                }
                                mem_tobuffer(target, abuf, 4);
                        } while (e != NULL);
                        break;
                case sbpr_ipv6s:
                        do {
                                snprintf(tbuf, sizeof(tbuf), "%*s",
                                         (int)(region->length), region->base);
                                e = strchr(tbuf, ',');
                                if (e != NULL) {
                                        *e++ = 0;
                                        isc_textregion_consume(region,
                                                               e - tbuf);
                                }
                                if (inet_pton(AF_INET6, tbuf, abuf) != 1) {
                                        return (DNS_R_SYNTAX);
                                }
                                mem_tobuffer(target, abuf, 16);
                        } while (e != NULL);
                        break;
                case sbpr_base64:
                        RETERR(isc_base64_decodestring(region->base,
                                                       target));
                        break;
                default:
                        INSIST(0);
                        ISC_UNREACHABLE();
                }


                switch(encoding) {
                case sbpr_text:
                        RETERR(multitxt_totext(&r, target));
                        break;
                case sbpr_port:
                        num = uint16_fromregion(&r);
                        n = snprintf(buf, sizeof(buf), "%u", num);
                        INSIST(n > 0 && (unsigned)n < sizeof(buf));
                        RETERR(str_totext(buf, target));
                        break;
                case sbpr_ipv4s:
                        while (r.length > 0U) {
                                INSIST(r.length >= 4U);
                                inet_ntop(AF_INET, r.base, buf, sizeof(buf));
                                RETERR(str_totext(buf, target));
                                isc_region_consume(&r, 4);
                                if (r.length != 0U) {
                                        RETERR(str_totext(",", target));
                                }
                        }
                        break;
                case sbpr_ipv6s:
                        while (r.length > 0U) {
                                INSIST(r.length >= 16U);
                                inet_ntop(AF_INET6, r.base, buf, sizeof(buf));
                                RETERR(str_totext(buf, target));
                                isc_region_consume(&r, 16);
                                if (r.length != 0U) {
                                        RETERR(str_totext(",", target));
                                }
                        }
                        break;
                case sbpr_base64:
                        RETERR(isc_base64_totext(&r, 0, "", target));
                        break;
                default:
                        INSIST(0);
                        ISC_UNREACHABLE();
                }


> On 27 Sep 2019, at 9:31 am, Mark Andrews <[email protected]> wrote:
> 
> Implementing the encoder isn’t hard but it needs to be clearer that there are 
> specific encodings. It is easy to miss this. I did initially.
> 
> -- 
> Mark Andrews
> 
>> On 26 Sep 2019, at 20:41, Vladimír Čunát <[email protected]> wrote:
>> 
>> 
>> On 9/26/19 12:30 PM, Jan Včelák wrote:
>>>> The current draft attempts to minimize complexity for implementers by 
>>>> offering a fully generic encoding for unknown key types.  For example, 
>>>> "alpn=h3" can also be expressed as "key1=h3", and "port=8003" can also be 
>>>> expressed as "key2=\031\067".  This encoding may not be convenient, but 
>>>> hopefully it will reduce the burden of supporting new parameter types.
>>>> 
>>> I agree we need generic encoding. There is a way to express unknown
>>> record types (
>>> https://tools.ietf.org/html/rfc3597#section-5
>>> ) and the
>>> syntax used there is more compact than what you propose. It uses hex
>>> strings instead of escaped decimal values. However its clumsy to work
>>> with records in that syntax and you proposal is better in that sense.
>>> 
>> I'm curious, Is there much motivation for a bit more compactness of the 
>> *presentation* format?  I consider its design primarily meant for humans.
>> 
>> 
>>> I think this may become the most complex record type we have in DNS so
>>> far. None of the existing registered record types contain a list of
>>> key-value pairs of arbitrary length. Given that there is also a
>>> registry for key types involved it will be fun to implement the
>>> encoder/decoder. But we will have to deal with it. I'm interested in
>>> what others in this working group think.
>>> 
>> I think we should get "implementation experience" from multiple parties at 
>> least before publishing the RFC (though that's a point far ahead, I suppose).
>> --Vladimir
>> 
>> _______________________________________________
>> DNSOP mailing list
>> [email protected]
>> https://www.ietf.org/mailman/listinfo/dnsop
> _______________________________________________
> DNSOP mailing list
> [email protected]
> https://www.ietf.org/mailman/listinfo/dnsop

-- 
Mark Andrews, ISC
1 Seymour St., Dundas Valley, NSW 2117, Australia
PHONE: +61 2 9871 4742              INTERNET: [email protected]

_______________________________________________
DNSOP mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/dnsop

Reply via email to