github.com/teknogeek/dnscontrol/v2@v2.10.1-0.20200227202244-ae299b55ba42/docs/spf-optimizer.md (about)

     1  ---
     2  layout: default
     3  title: SPF Optimizer
     4  ---
     5  
     6  # SPF Optimizer
     7  
     8  dnscontrol can optimize the SPF settings on a domain by flattening
     9  (inlining) includes and removing duplicates.  dnscontrol also makes
    10  it easier to document your SPF configuration.
    11  
    12  **Warning:** Flattening SPF includes is risky.  Only flatten an SPF
    13  setting if it is absolutely needed to bring the number of "lookups"
    14  to be less than 10. In fact, it is debatable whether or not ISPs
    15  enforce the "10 lookup rule".
    16  
    17  
    18  ## The old way
    19  
    20  Here is an example of how SPF settings are normally done:
    21  
    22  ```
    23  D("example.tld", REG, DNS, ...
    24    TXT("v=spf1 ip4:198.252.206.0/24 ip4:192.111.0.0/24 include:_spf.google.com include:mailgun.org include:spf-basic.fogcreek.com include:mail.zendesk.com include:servers.mcsv.net include:sendgrid.net include:450622.spf05.hubspotemail.net ~all")
    25  )
    26  ```
    27  
    28  This has a few problems:
    29  
    30  * No comments. It is difficult to add a comment. In particular, we want to be able to list which ticket requested each item in the SPF setting so that history is retained.
    31  * Ugly diffs.  If you add an element to the SPF setting, the diff will show the entire line changed, which is difficult to read.
    32  * Too many lookups. The SPF RFC says that SPF settings should not require more than 10 DNS lookups. If we manually flatten (i.e. "inline") an include, we have to remember to check back to see if the settings have changed. Humans are not good at that kind of thing.
    33  
    34  ## The dnscontrol way
    35  
    36  ```
    37  D("example.tld", REG, DSP, ...
    38    A("@", "10.2.2.2"),
    39    MX("@", "example.tld."),
    40    SPF_BUILDER({
    41      label: "@",
    42      overflow: "_spf%d",
    43      raw: "_rawspf",
    44      ttl: "5m",
    45      parts: [
    46        "v=spf1",
    47        "ip4:198.252.206.0/24", // ny-mail*
    48        "ip4:192.111.0.0/24", // co-mail*
    49        "include:_spf.google.com", // GSuite
    50        "include:mailgun.org", // Greenhouse.io
    51        "include:spf-basic.fogcreek.com", // Fogbugz
    52        "include:mail.zendesk.com", // Zenddesk
    53        "include:servers.mcsv.net", // MailChimp
    54        "include:sendgrid.net", // SendGrid
    55        "include:450622.spf05.hubspotemail.net", // Hubspot (Ticket# SREREQ-107)
    56        "~all"
    57      ],
    58      flatten: [
    59        "spf-basic.fogcreek.com", // Rational: Being deprecated. Low risk if it breaks.
    60        "450622.spf05.hubspotemail.net" // Rational: Unlikely to change without warning.
    61      ]
    62    }),
    63  );
    64  ```
    65  
    66  By using the `SPF_BUILDER()` we gain many benefits:
    67  
    68  * Comments can appear next to the element they refer to.
    69  * Diffs will be shorter and more specific; therefore easier to read.
    70  * Automatic flattening.  We can specify which includes should be flattened and dnscontrol will do the work. It will even warn us if the includes change.
    71  
    72  ## Syntax
    73  
    74  When you want to specify SPF settings for a domain, use the
    75  `SPF_BUILDER()` function.
    76  
    77  ```
    78  D("example.tld", REG, DSP, ...
    79    ...
    80    ...
    81    ...
    82    SPF_BUILDER({
    83      label: "@",
    84      overflow: "_spf%d",  // Delete this line if you don't want big strings split.
    85      raw: "_rawspf",  // Delete this line if the default is sufficient.
    86      parts: [
    87        "v=spf1",
    88        // fill in your SPF items here
    89        "~all"
    90      ],
    91      flatten: [
    92        // fill in any domains to inline.
    93      ]
    94    }),
    95    ...
    96    ...
    97  );
    98  ```
    99  
   100  The parameters are:
   101  
   102  * `label:` The label of the first TXT record. (Optional. Default: `"@"`)
   103  * `overflow:` If set, SPF strings longer than 255 chars will be split into multiple TXT records. The value of this setting determines the template for what the additional labels will be named. If not set, no splitting will occur and dnscontrol may generate TXT strings that are too long.
   104  * `raw:` The label of the unaltered SPF settings. (Optional. Default: `"_rawspf"`)
   105  * `ttl:` This allows setting a specific TTL on this SPF record. (Optional. Default: using default record TTL)
   106  * `parts:` The individual parts of the SPF settings.
   107  * `flatten:` Which includes should be inlined. For safety purposes the flattening is done on an opt-in basis. If `"*"` is listed, all includes will be flattened... this might create more problems than is solves due to length limitations.
   108  
   109  `SPR_BUILDER()` returns multiple `TXT()` records:
   110  
   111    * `TXT("@", "v=spf1 .... ~all")`
   112      *  This is the optimized configuration.
   113    * `TXT("_spf1", "...")`
   114      * If the optimizer needs to split a long string across multiple TXT records, the additional TXT records will have labels `_spf1`, `_spf2`, `_spf3`, etc.
   115    * `TXT("_rawspf", "v=spf1 .... ~all")`
   116      * This is the unaltered SPF configuration. This is purely for debugging purposes and is not used by any email or anti-spam system.  It is only generated if flattening is requested.
   117  
   118  
   119  We recommend first using this without any flattening. Make sure
   120  `dnscontrol preview` works as expected. Once that is done, add the
   121  flattening required to reduce the number of lookups to 10 or less.
   122  
   123  To count the number of lookups, you can use our interactive SPF
   124  debugger at [https://stackexchange.github.io/dnscontrol/flattener/index.html](https://stackexchange.github.io/dnscontrol/flattener/index.html)
   125  
   126  
   127  ## Notes about the DNS Cache
   128  
   129  dnscontrol keeps a cache of the DNS lookups performed during
   130  optimization.  The cache is maintained so that the optimizer does
   131  not produce different results depending on the ups and downs of
   132  other people's DNS servers. This makes it possible to do `dnscontrol
   133  push` even if your or third-party DNS servers are down.
   134  
   135  The DNS cache is kept in a file called `spfcache.json`. If it needs
   136  to be updated, the proper data will be written to a file called
   137  `spfcache.updated.json` and instructions such as the ones below
   138  will be output telling you exactly what to do:
   139  
   140  ```
   141  $ dnscontrol preview
   142  1 Validation errors:
   143  WARNING: 2 spf record lookups are out of date with cache (_spf.google.com,_netblocks3.google.com).
   144  Wrote changes to spfcache.updated.json. Please rename and commit:
   145      $ mv spfcache.updated.json spfcache.json
   146      $ git commit spfcache.json
   147  ```
   148  
   149  In this case, you are being asked to replace `spfcache.json` with
   150  the newly generated data in `spfcache.updated.json`.
   151  
   152  Needing to do this kind of update is considered a validation error
   153  and will block `dnscontrol push` from running.
   154  
   155  Note: The instructions are hardcoded strings. The filenames will
   156  not change.
   157  
   158  Note: The instructions assume you use git. If you use something
   159  else, please do the appropriate equivalent command.
   160  
   161  ## Caveats:
   162  
   163  1. Dnscontrol 'gives up' if it sees SPF records it can't understand.
   164  This includes: syntax errors, features that our spflib doesn't know
   165  about, overly complex SPF settings, and anything else that we we
   166  didn't feel like implementing.
   167  
   168  2. The TXT record that is generated may exceed DNS limits.  dnscontrol
   169  will not generate a single TXT record that exceeds DNS limits, but
   170  it ignores the fact that there may be other TXT records on the same
   171  label.  For example, suppose it generates a TXT record on the bare
   172  domain (stackoverflow.com) that is 250 bytes long. That's fine and
   173  doesn't require a continuation record.  However if there is another
   174  TXT record (not an SPF record, perhaps a TXT record used to verify
   175  domain ownership), the total packet size of all the TXT records
   176  could exceed 512 bytes, and will require EDNS or a TCP request.
   177  
   178  3. Dnscontrol does not warn if the number of lookups exceeds 10.
   179  We hope to implement this some day.
   180  
   181  4. The `redirect=` directive is only partially implemented.  We only
   182  handle the case where redirect is the last item in the SPF record.
   183  In which case, it is equivalent to `include:`.
   184  
   185  
   186  ## Advanced Technique: Interactive SPF Debugger
   187  
   188  dnscontrol includes an experimental system for viewing
   189  SPF settings:
   190  
   191  [https://stackexchange.github.io/dnscontrol/flattener/index.html](https://stackexchange.github.io/dnscontrol/flattener/index.html)
   192  
   193  You can also run this locally (it is self-contained) by opening
   194  `dnscontrol/docs/flattener/index.html` in your browser.
   195  
   196  You can use this to determine the minimal number of domains you
   197  need to flatten to have fewer than 10 lookups.
   198  
   199  The output is as follows:
   200  
   201  1. The top part lists the domain as it current is configured, how
   202  many lookups it requires, and includes a checkbox for each item
   203  that could be flattened.
   204  
   205  2. Fully flattened: This section shows the SPF configuration if you
   206  fully flatten it. i.e. This is what it would look like if all the
   207  checkboxes were checked. Note that this result is likely to be
   208  longer than 255 bytes, the limit for a single TXT string.
   209  
   210  3. Fully flattened split: This takes the "fully flattened" result
   211  and splits it into multiple DNS records.  To continue to the next
   212  record an include is added.
   213  
   214  
   215  ## Advanced Technique: Define once, use many
   216  
   217  In some situations we define an SPF setting once and want to re-use
   218  it on many domains. Here's how to do this:
   219  
   220  ```
   221  var SPF_MYSETTINGS = SPF_BUILDER({
   222    label: "@",
   223    overflow: "_spf%d",
   224    raw: "_rawspf",
   225    parts: [
   226      "v=spf1",
   227      ...
   228      "~all"
   229    ],
   230    flatten: [
   231      ...
   232    ]
   233  });
   234  
   235  D("example.tld", REG, DSP, ...
   236      SPF_MYSETTINGS
   237  );
   238  
   239  D("example2.tld", REG, DSP, ...
   240       SPF_MYSETTINGS
   241  );
   242  ```