Skip to content


Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time



firewall - enables filtering of queries and responses based on expressions.


The firewall plugin defines a list of rules that trigger a workflow action on a DNS query and its response. A rule list is an ordered set of rules that are evaluated in sequence. Rules can be an expression rule, or a policy engine rule. An expression rule has two parts: an action and an expression. When the rule is evaluated, first the expression is evaluated.

  • If the expression evaluates to true the action is performed on the query and the rule list evaluation ceases.
  • If the expression does not evaluates to true then next rule in sequence is evaluated.

The firewall plugin can also refer to other policy engines to determine the action to take.


firewall DIRECTION {
  • DIRECTION indicates if the rule list will be applied to queries or responses. It can be query or response.

  • ACTION defines the workflow action to take if the EXPRESSION evaluates to true. If no actions are defined for the query DIRECTION, the default action is to block. Available actions:

    • allow : continue the DNS resolution process (i.e., continue to the next plugin in the chain)
    • refuse : interrupt the DNS resolution, reply with REFUSED response code
    • block : interrupt the DNS resolution, reply with NXDOMAIN response code
    • drop : interrupt the DNS resolution, do not reply (client will time out)

    An action must be followed by an EXPRESSION, which defines the boolean expression for the rule. See Expressions section below.

  • POLICY-PLUGIN : is the name of another plugin that implements a firewall policy engine. ENGINE-NAME is the name of an engine defined in your Corefile. Requests/responses will be evaluated by that plugin policy engine to determine the action.


Expressions follow a c-like expression format where the variables are either the metadata of CoreDNS or the fields of a DNS query/response. Common operators apply.

Expression Examples:

  • client_ip == ''
  • type == 'AAAA'
  • type IN ('AAAA', 'A', 'TXT')
  • type IN ('AAAA', 'A') && name =~ ''
  • [mac/address] =~ '.*:FF:.*'

NOTE: because of the / separator included in a label of metadata, those labels must be enclosed in brackets [...].

Expression Variables

The following variables are supported for querying information in expressions. All values are strings (see atoi function below for arithmetic operations).

  • type: type of the request (A, AAAA, TXT, ...)
  • name: name of the request (the domain name requested)
  • class: class of the request (IN, CH, ...)
  • proto: protocol used (tcp or udp)
  • client_ip: client's IP address, for IPv6 addresses these are enclosed in brackets: [::1]
  • size: request size in bytes
  • port: client's port
  • rcode: response CODE (NOERROR, NXDOMAIN, SERVFAIL, ...)
  • rsize: raw (uncompressed), response size (a client may receive a smaller response)
  • >rflags: response flags, each set flag will be displayed, e.g., "aa, tc". This includes the qr bit as well
  • >bufsize: the EDNS0 buffer size advertised in the query
  • >do: the EDNS0 DO (DNSSEC OK) bit set in the query
  • >id: query ID
  • >opcode: query OPCODE
  • server_ip: server's IP address; for IPv6 addresses these are enclosed in brackets: [::1]
  • server_port : client's port
  • response_ip : the IP address returned in the first A or AAAA record of the Answer section

Expression Functions

  • atoi(string): convert a string to a numeric value.
  • incidr(ip, cidr): returns true if ip is in the subnet defined by cidr.
  • random(): returns a random floating point number in the range [0.0, 1.0).

Policy Engine Plugins

In addition to using the built-in action/expression syntax, the firewall plugin can use a policy engine plugin to evaluate policy.

To use a policy engine plugin, you'll need to compile the plugin into CoreDNS, then declare the plugin in your Corefile, and reference the plugin as an action of a firewall rule. See the "Using a Policy Engine Plugin" example below.

When authoring a new policy engine plugin, the plugin must implement the Engineer interface defined in firewall/policy.

This repository includes two Policy Engine Plugins:

  • themis - enables Infoblox's Themis policy engine to be used as a CoreDNS firewall policy engine
  • opa - enables OPA to be used as a CoreDNS firewall policy engine.

External Plugin

Firewall and other associated policy plugins in this repository are external plugins, which means they are not included in CoreDNS releases. To use the plugins in this repository, you'll need to build a CoreDNS image with the plugins you want to add included in the plugin list. In a nutshell you'll need to:

  • Clone release, e.g., git clone -b v1.6.9 --depth 1 .
  • Add this plugin (, and any desired policy engines to plugin.cfg per instructions therein. Order in this file is important, as it dictates the order of plugin execution when processing a query. The firewall plugin should execute before plugins that generate responses.
  • make -f Makefile.release DOCKER=your-docker-repo release
  • make -f Makefile.release DOCKER=your-docker-repo docker
  • make -f Makefile.release DOCKER=your-docker-repo docker-push


Client IP ACL

This example shows how to use firewall to create a basic client IP address-based ACL. Here is expressly REFUSED. Other clients in and are allowed. All other clients are not responded to.

. {
   firewall query {
      refuse client_ip == ''
      allow client_ip =~ '10\.120\.0\..*'
      allow client_ip =~ '10\.120\.1\..*'
      drop true

Domain Name Policy

Allow all queries for Allow A and AAAA queries for NXDOMAIN all other queries.

. {
   firewall query {
      allow name =~ ''
      allow name =~ '' && (type == 'A' || type == 'AAAA')
      block true

Response Policy

Allow all queries, but block all responses that contain an IP matching 10.120.1.* in the first record of the Answer section.

. {
   firewall query {
      allow true
   firewall response {
      block response_ip  =~ '10\.120\.1\..*'

EDNS0 Metadata Policy

This example uses the metadata_edns0 plugin to define labels group_id and client_id with values extracted from EDNS0. The firewall rules use those metadata to REFUSE any query without a group_id of 123456789 or client_id of ABCDEF. {
   metadata_edns0 {
      group_id edns0 0xffed bytes
      client_id edns0 0xffee bytes
   firewall query {
      refuse [metadata_edns0/client_id] != 'ABCDEF'
      refuse [metadata_edns0/group_id] != '123456789'
      allow true

Kubernetes Metadata Multi-Tenancy Policy

This example shows how firewall could be useful in a Kubernetes-based multi-tenancy application. It uses the kubernetes plugin metadata to prevent Pods in certain Namespaces from looking up Services in other Namespaces. Specifically, if the requesting Pod is in a Namespace beginning with 'tenant-', it permits only lookups to Services that are in the same Namespace or in the 'default' Namespace. Note here that pods verified is required in the kubernetes plugin to enable the use of the [kubernetes/client-namespace] metadata variable. Also note that this is at the DNS level only, and does not prevent network access between tenant Namespaces, e.g., if Service IPs are known.

cluster.local {
   kubernetes {
      pods verified
   firewall query {
      allow [kubernetes/client-namespace] !~ '^tenant-'
      allow [kubernetes/namespace] == [kubernetes/client-namespace]
      allow [kubernetes/namespace] == 'default'
      block true

Using a Policy Engine Plugin

The following example illustrates how the a policy engine plugin (themis in this example) can be used by the firewall plugin.

. {
  firewall query {
    themis myengine
  themis myengine {


CoreDNS external plugin to provide in-process policies as well as external policy services







No releases published


No packages published