Suricata DNS IPS rule

Hi,

I want to create a DNS rule in suricata, which allows a DNS response packet only if there was a query before for that packet. Can I define such a rule in suricata?

If it’s within the same flow, you can set a flowbit in the first part and use that flowbit in a second signature, see 6.10. Flow Keywords — Suricata 6.0.3 documentation

I want to keep track of outgoing DNS requests from the home network, and when I get any DNS response, I want to check if I requested this in the past. I am thinking lua script might help me in writing such a rule, but I am not sure if I can store outgoing DNS requests flows, and then later match with DNS responses.

I remember that in the past there was an ‘unsolicited response’ event that could be caught in an alert to detect this. Unfortunately this seems to have been removed in more recent versions (possibly with the move of the DNS parser to Rust). Does someone from the team know why this is no longer there?

Do we have the unsolicited response feature still in suricata? I was not able to find much on it.

A change in the implementation. The old DNS parser was transactional, it held onto the request until a response was seen. This caused issues with logging requests that never got a response, plus made it easy to flood the parser and cause issues, even with protections in place.

I also think that a purely unsolicited response was never logged properly, as a request was required to setup the transaction. You would get an unsolicited response if you had a request, reply, then a reply all on the same session though.

The Rust parser is unidirectional and does not match requests up with responses which did fix a lot of issues, also makes this check harder to do. There is a small bounded cache of previous requests per state when config rules are used, so its possible such a feature could come back I suppose, would need to look at performance impact, etc.

2 Likes

Is it possible in suricata to have my own custom lua scripts that logs an outgoing DNS request, and when I see a DNS response , it sees if an existing DNS request exists, if not then drops the response?

A Lua rule might get you there.

I’m not actually sure what you are after.

If you just want to drop unsolicited responses, as in a DNS response where there is no matching request, you can probably just use flowbits, or better yet, blocking incoming DNS responses with no session at the firewall.

If you really do want to look at the rrname in the responses to match them up to requests you will have use a Lua rule, and keep some global state of seen hostnames. This test case might help a little (but doesn’t do what you are after): suricata-verify/tests/dns-lua-rules at master · OISF/suricata-verify · GitHub.

I was hoping datasets might help, but we don’t expose enough of the DNS response to the rule language unfortunately.