On Mon Oct 20 15:09:55 2014, rwfranks@acm.org wrote:
Show quoted text> On Mon Oct 20 13:32:51 2014, tlhackque wrote:
> > Another walk produced a simplification that you might consider.
> >
> > By always computing the MAC in receive, it's not necessary to save
> > the
> > wire data for verify().
>
> Not so fast!
>
> The decoder _cannot_ compute the MAC on a response packet because that
> part of the code does not know anything about the query which produced
> the response, or the previous packet in a multi-packet response.
>
I said 'receive', not 'decode' for computing the MAC. Meaning the caller of decode after decode returns. Actually, the caller of Packet->(new, create -- I don't have the code handy.) The wire data is still there; the decoded version lets you determine if there's a SIG/error.
All the decoder needs to do is save/return the offset of the last record it decodes. It doesn't need to know what that record is, or even what section it is in - the caller just needs the offset so if *it* decides to 'remove' the last record, it knows where that record starts in the undecoded bytestream. This suffices because *if* the record will be 'removed' (by length or substr) for the MAC computation, it MUST be the last record. It's just the end marker for the wire data going into MAC.
The logic to use the offset/compute the MAC can be a call into xSIG:: that provides the wire data buffer, decoded packet & last record decoded offset.
Those classes do know what goes into their MAC, and can keep whatever context they need in private data attached to their record and/or stashed in the resolver by the caller. E.g. xSIG::process_transaction always gets called if the last decoded record is an xSIG. The TSIG/SIG class can easily figure out if the MAC is needed using the decoded Packet & compute it using the wire data, saving the results for verify. (Including checking that arcount >1 & error status, etc.)
It is true that the request packet is required.
But I'll try not to think more about it on my next walk and leave the fix in your hands. I've probably reached the point of offering diminishing returns.
Show quoted text> Computing the MAC requires knowledge of the request MAC or prior MAC.
> If you look how the axfr() routine does the validation, you will note
> that the required state information is carried forward by creating a
> clone of the TSIG which is returned by verify() and fed to the next
> verify() call.
>
> This code was not so much written as evolved in response to discussion
> and bug reports.
That does tend to happen with long-lived software. It's unfortunate that any approach to this bug requires re-architecting the receive/verification paths. Of course, less re-architecting can patch it together at the price of efficiency and maintainability. My observation was that saving/copying the wire data can be avoided with the right architecture. Since axfr() data can be (very) large, and other queries very frequent it seemed worth thinking about.
As you're doing the work, it's your call. I hope that my comments have been useful.
Show quoted text> There is a trail of abject failure going back years.
Sigh. I didn't pay attention to this until axfr() broke. I'm just a user.
Aside from learning from the failures, then only thing to do is to stay positive and look forward. Hopefully your current pass will be the one that finally succeeds!
Show quoted text>
> I have just read RFC2931 again, and it seems to me SIG(0) ought to
> follow a similar pattern. Not least because Packet has no need to know
> if it verifies TSIG or SIG(0)
Agree on both counts.
Thanks again for plugging away at this. I'll stop meddling and look forward to a release with whatever fix you decide upon.