Re: IPv6 address parsing

Michael Powell <[email protected]>
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <CAMEoF_E3n98-yWUzmqZ8-ZDkvsc5ZCa5EN1Pcm1WL7UQt7mfFg@mail.gmail.com>
On Sat, Dec 16, 2017 at 1:08 PM, Michael Powell <[email protected]> wrote:
> On Fri, Dec 15, 2017 at 1:59 PM, Michael Powell <[email protected]> wrote:
>> On Fri, Dec 15, 2017 at 12:22 PM, Michael Powell <[email protected]> wrote:
>>> On Fri, Dec 15, 2017 at 11:31 AM, Michael Powell <[email protected]> wrote:
>>>> On Thu, Dec 7, 2017 at 1:21 PM, Michael Powell <[email protected]> wrote:
>>>>> Again, I am moving beyond IPv4 into IPv6. Do I need to re-post that
>>>>> grammar attempt? Maybe I do at this point.
>>>>>
>>>>> _dot = ".";
>>>>> _col = char_(':');
>>>>> _col_x2 = _col >> _col;
>>>>>
>>>>> // _dec_octet = uint_parser<std::uint8_t, 10, 1, 3>();
>>>>>
>>>>> qi::rule<Iterator> _dec_octet = ... ; // Approach TBD; probably
>>>>> running with the IPv4 proposal discussed in earlier thread(s).
>>>>>
>>>>> qi::rule<Iterator> _ipv4_addr = _dec_octet >> repeat(3)[_dot >> _dec_octet];
>>>>> // or, qi::rule<Iterator> _ipv4_addr = raw[_dec_octet >> _dot >>
>>>>> _dec_octet >> _dot >> _dec_octet >> _dot >> _dec_octet];
>>>>>
>>>>> qi::rule<Iterator> _h16 = raw[repeat(1, 4)[hex]];
>>>>> // Or (?): _h16 = hex >> -(hex >> -(hex >> -hex));
>>>>> qi::rule<Iterator> _h16_col = _h16 >> _col;
>>>>> qi::rule<Iterator> _ls32 = _h16_col >> _h16 | _ipv4_addr;
>>>>>
>>>>> qi::rule<Iterator, std::string()> _ipv6_addr
>>>>>     = repeat(6)[_h16_col] >> _ls32
>>>>>     | _col_x2 >> repeat(5)[_h16_col] >> _ls32
>>>>>     | -(_h16) >> _col_x2 >> repeat(4)[_h16_col] >> _ls32
>>>>>     | -(_h16_col >> _h16) >> _col_x2 >> repeat(3)[_h16_col] >> _ls32
>>>>>     | -(repeat(1, 2)[_h16_col] >> _h16) >> _col_x2 >>
>>>>> repeat(2)[_h16_col] >> _ls32
>>>>>     | -(repeat(1, 3)[_h16_col] >> _h16) >> _col_x2 >> _h16_col >> _ls32
>>>>>     | -(repeat(1, 4)[_h16_col] >> _h16) >> _col_x2 >> _ls32
>>>>>     | -(repeat(1, 5)[_h16_col] >> _h16) >> _col_x2 >> _h16
>>>>>     | -(repeat(1, 6)[_h16_col] >> _h16) >> _col_x2
>>>>>     ;
>>>>
>>>> I am testing the grammar now, and it seems like to me that the
>>>> optional and/or repeat are not working correctly.
>>>>
>>>> For test case: prefix = pf_max_4|pf_count_1, suffix = pf_none,
>>>> appendix = bo_hex_2, which yields address: "6a80:9024::c7e3:4150".
>>>>
>>>> Should be matching the alternative, from the RFC grammar:
>>>>   / [*4(h16 ":") h16] "::"            ls32
>>>>
>>>> Or from the Qi grammar:
>>>>      | -(repeat(1, 4)[_h16_col] >> _h16) >> _col_x2 >> _ls32
>>>>
>>>> But gets rejected. Did not parse, or rejected the entire string.
>>>>
>>>> Perhaps repeat does not work quite as advertised?
>>>>
>>>> Thoughts? Suggestions?
>>>
>>>
>>> qi::rule<Iterator, std::string()> _ipv6_addr
>>>     = repeat(6)[_h16_col] >> _ls32
>>>     | _col_x2 >> repeat(5)[_h16_col] >> _ls32
>>>     | -(-_h16) >> _col_x2 >> repeat(4)[_h16_col] >> _ls32
>>>     | -(-_h16_col >> _h16) >> _col_x2 >> repeat(3)[_h16_col] >> _ls32
>>>     | -(-repeat(1, 2)[_h16_col] >> _h16) >> _col_x2 >>
>>> repeat(2)[_h16_col] >> _ls32
>>>     | -(-repeat(1, 3)[_h16_col] >> _h16) >> _col_x2 >> _h16_col >> _ls32
>>>     | -(-repeat(1, 4)[_h16_col] >> _h16) >> _col_x2 >> _ls32
>>>     | -(-repeat(1, 5)[_h16_col] >> _h16) >> _col_x2 >> _h16
>>>     | -(-repeat(1, 6)[_h16_col] >> _h16) >> _col_x2
>>>     ;
>>>
>>> I did identify that possibly the prefix phrase needs to be built from
>>> optional elements within itself.
>>>
>>> However, still not parsing.
>>>
>>> I am concerned that either Qi optional, repeat, etc, perhaps even
>>> alternatives, are not working quite right in this instance.
>>>
>>> Do I need to separate the alternatives here into "micro" grammars
>>> within themselves for this to possibly work?
>>
>> Thus far, separating the more complex grammar into micro-grammars
>> seems to be the correct answer, the one that will work.
>
> I removed the repeats, and I think I've isolated an issue that nested
> optional operators do not work. i.e. -(-(-(...) ...) ...) >> ...
>
> Which does not match the phrase I expect it to.

Moving on, a little...

I now have a test case "8d5d:5be71c85:7c0e:d86f:540b:d0ec:f177:2316"
which should not be valid. I expect it to be invalid and rejected.
However, the grammar

_col = char_(':');

_h16 = raw[
  hex >> hex >> hex >> hex
    | hex >> hex >> hex
    | hex >> hex
    | hex
  ];
//// I was using repeat(...), but I have concerns whether REPEAT
(and/or OPTIONAL) are working properly, not least of all in this
context, never mind concerns over nested repeat, optional, etc.
//_h16 = repeat(1, 4)[hex];

_h16_col = _h16 >> _col;

_ls32 = _h16_col >> _h16;

_ipv6_addr = lexeme[
    _h16_col >> _h16_col >> _h16_col >> _h16_col >> _h16_col >>
_h16_col >> _ls32
];

_start = _ipv6_addr >> eoi;

Which leads me to believe that boost::spirit::hex
(boost::spirit::hex_type) is excessively greedy. Would it be more
appropriate if I simply said this: char_("0123456789abcdef"),
notwithstanding case?

I am also chewing on the test case parameters, whether I should drive
the test data to yield "8d5d:5be7::1c85:7c0e:d86f:540b:d0ec:f177:2316"
instead, but this is beyond the scope of my grammar concerns.

Any thoughts? Insights?

Thanks!

>> Not sure why the broader parent grammar doesn't work, however. Apart
>> from "greediness" suspicions, that is; the grammar is what it is, no?
>>
>>>> Thank you!
>>>>
>>>>> qi::rule<Iterator> _start = _ipv6_addr >> eoi;
>>>>>
>>>>> Q: Notwithstanding concern over raw IPv4, does the overall Qi-based
>>>>> IPv6 grammar look reasonable? If not, why not?
>>>>>
>>>>> I'd like to land in a Fusion data structure something like (string >>
>>>>> uint16_t >> eoi), but if I can land here, that's acceptable, too:
>>>>> (string >> -(uint8_t >> uint8_t >>
>>>>> uint8_t >> uint8_t) >> uint16_t >> eoi).
>>>>>
>>>>> From what I can determine, then, raw[...] is the difference between
>>>>> parsed types like uint8_t and string?
>>>>>
>>>>> ref: http://www.ietf.org/rfc/rfc5954.txt, section 4.1 Resolution for
>>>>> Extra Colon in IPv4-Mapped IPv6 Address
>>>>>
>>>>> Constructive feedback appreciated.
>>>>>
>>>>> Untested ATM, to be fair.
>>>>>
>>>>> On Thu, Dec 7, 2017 at 1:09 PM, Seth <[email protected]> wrote:
>>>>>> On 07-12-17 18:21, Michael Powell wrote:
>>>>>>> Well, you remembered incorrectly.
>>>>>>
>>>>>> I was asking.
>>>>>>
>>>>>>> If there's a doable intermediate step of parsed individual octets, so
>>>>>>> be it; no problem.
>>>>>>
>>>>>> Please per-use all the parts of my answer.
>>>>>>
>>>>>> On 07-12-17 17:13, Seth wrote:
>>>>>>> Maybe you'll be more convinced when it's demonstrated (I think I did
>>>>>>> this before):
>>>>>>>
>>>>>>> https://wandbox.org/permlink/M12U5PEYcB8vnxIs
>>>>>>>
>>>>>>> It's really just ~3 lines of code changed:
>>>>>>>
>>>>>>>     using ipv4_address = std::string; // much less useful representation
>>>>>>>     // ....
>>>>>>>     addr_  = raw[ octet_ >> '.' >> octet_ >> '.' >> octet_ >> '.' >>
>>>>>>> octet_ ];
>>>>>>>
>>>>>>> Note now that test fails:
>>>>>>
>>>>>> It's all there.
>>>>>>

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.