Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dnsdist: SpoofRaw with comma creates malformed packets #10456

Closed
wojas opened this issue May 28, 2021 · 14 comments · Fixed by #10532
Closed

dnsdist: SpoofRaw with comma creates malformed packets #10456

wojas opened this issue May 28, 2021 · 14 comments · Fixed by #10532
Assignees
Milestone

Comments

@wojas
Copy link
Member

wojas commented May 28, 2021

  • Program: dnsdist
  • Issue type: Bug report

Short description

SpoofRaw creates malformed packets when TXT records include a comma.

Environment

Master as of yesterday (b67e520) and same on 1.6.0.

Steps to reproduce

newServer{address='8.8.8.8'}
function spoof_raw_txt(dq)
    local content = '\001,' -- the comma causes an issue
    return DNSAction.SpoofRaw, content
end
addAction(AllRule(), LuaAction(spoof_raw_txt))

The same happens when using the FFI interface.

Expected behaviour

dig -t txt returns a TXT record with only a comma.

Actual behaviour

;; Warning: Message parser reports malformed message packet.

; <<>> DiG 9.16.15 <<>> -p 7899 @localhost -t txt example.com
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46310
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: Message has 1 extra bytes at end

;; QUESTION SECTION:
;example.com.			IN	TXT

Other information

No other characters cause this issue:

newServer{address='8.8.8.8'}
function spoof_raw_txt(dq)
    local s = ''
    for i = 0, 255 do
        local ch = string.char(i)
        if ch ~= ',' then
            s = s .. ch
        end
    end
    local content = string.char(#s) .. s
    return DNSAction.SpoofRaw, content
end
addAction(AllRule(), LuaAction(spoof_raw_txt))
example.com.		60	IN	TXT	"\000\001\002\003\004\005\006\007\008\009\010\011\012\013\014\015\016\017\018\019\020\021\022\023\024\025\026\027\028\029\030\031 !\"#$%&'()*+-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\127\128\129\130\131\132\133\134\135\136\137\138\139\140\141\142\143\144\145\146\147\148\149\150\151\152\153\154\155\156\157\158\159\160\161\162\163\164\165\166\167\168\169\170\171\172\173\174\175\176\177\178\179\180\181\182\183\184\185\186\187\188\189\190\191\192\193\194\195\196\197\198\199\200\201\202\203\204\205\206\207\208\209\210\211\212\213\214\215\216\217\218\219\220\221\222\223\224\225\226\227\228\229\230\231\232\233\234\235\236\237\238\239\240\241\242\243\244\245\246\247\248\249\250\251\252\253\254\255"
@wojas wojas added the dnsdist label May 28, 2021
@rgacogne rgacogne added this to the dnsdist-1.6.x milestone May 28, 2021
@rgacogne
Copy link
Member

Looks like we might need some form of escaping now that we handle multiple values separated by commas..

@Habbie
Copy link
Member

Habbie commented May 28, 2021

Just to be sure, I checked, and indeed #10063 introduces this.

@Habbie
Copy link
Member

Habbie commented May 28, 2021

Looks like we might need some form of escaping now that we handle multiple values separated by commas..

Or add support for returning tables?

@Habbie
Copy link
Member

Habbie commented May 28, 2021

Or add support for returning tables?

Oh, not that easy, because of the DNSAction prototype.

@wojas
Copy link
Member Author

wojas commented May 31, 2021

One possible solution would be to add a SpoofRawMulti action where every record value would be prefixed by two length bytes. A convenience function could be provided to convert a table of strings to the right length-prefixed string.

This would be a bit ugly. We could hide the ugliness with a pure Lua wrapper around the callback that converts SpoofRaw, {...} into SpoofRawMulti, spoofRawMultiFromTable({...}).

@Habbie
Copy link
Member

Habbie commented May 31, 2021

One possible solution would be to add a SpoofRawMulti action where every record value would be prefixed by two length bytes.

I had the exact same idea. Must be a good idea then!

@rgacogne rgacogne self-assigned this Jun 16, 2021
@rgacogne
Copy link
Member

Oh, not that easy, because of the DNSAction prototype.

I just tried to turn the return value of LuaAction from a std::tuple<int, boost::optional<string>> into std::tuple<int, boost::optional<boost::variant<string, std::vector<std::pair<int, std::string>>>>> but there is a 10% penalty for very small functions, so unfortunately that does not look like a viable option.

@rgacogne
Copy link
Member

I'm pondering adding Lua bindings to store a table into the DNSQuestion object instead. We would then check if that table has been set when we receive a DNSAction.SpoofRaw result, and fall back to the string instead. Any thoughts?

@Habbie
Copy link
Member

Habbie commented Jun 16, 2021

I think that makes sense. Sounds like it would keep the interface cheap -usually-, and not terribly hard to use even for the special cases. We should include some actual full examples in the docs if we do this, I think.

@wojas
Copy link
Member Author

wojas commented Jun 16, 2021

That would work fine for plain Lua. The FFI interface would need an alternative way to set this.

@rgacogne
Copy link
Member

Sure, we would add a setter function in the FFI interface :)

@rgacogne
Copy link
Member

It turns out that there is already a non-FFI way to do this via DNSQuestion.spoof(): https://dnsdist.org/reference/dq.html?#DNSQuestion:spoof
I'm going to add the necessary bits to have a FFI counterpart.

@mdavids
Copy link

mdavids commented Dec 19, 2022

@rgacogne
Copy link
Member

Could this be related?

https://mailman.powerdns.com/pipermail/dnsdist/2022-December/001267.html

Very likely, yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants