{"id":14235859,"url":"https://github.com/spf-tools/spf-tools","last_synced_at":"2026-04-12T17:00:44.133Z","repository":{"id":21356098,"uuid":"24673245","full_name":"spf-tools/spf-tools","owner":"spf-tools","description":"Shell scripts for taming the SPF (Sender Policy Framework) records in order to fight 10-maximum-DNS-look-ups limit.","archived":false,"fork":false,"pushed_at":"2024-07-17T04:27:42.000Z","size":312,"stargazers_count":179,"open_issues_count":5,"forks_count":68,"subscribers_count":27,"default_branch":"master","last_synced_at":"2024-08-21T21:27:50.226Z","etag":null,"topics":["continuous-integration","dns","posix-sh","sender-policy-framework","shell","spf","spf-records"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spf-tools.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-10-01T09:49:02.000Z","updated_at":"2024-08-14T09:26:45.000Z","dependencies_parsed_at":"2023-02-14T05:15:53.419Z","dependency_job_id":null,"html_url":"https://github.com/spf-tools/spf-tools","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spf-tools%2Fspf-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spf-tools%2Fspf-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spf-tools%2Fspf-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spf-tools%2Fspf-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spf-tools","download_url":"https://codeload.github.com/spf-tools/spf-tools/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229478740,"owners_count":18079376,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["continuous-integration","dns","posix-sh","sender-policy-framework","shell","spf","spf-records"],"created_at":"2024-08-20T21:02:25.671Z","updated_at":"2026-04-12T17:00:44.124Z","avatar_url":"https://github.com/spf-tools.png","language":"Shell","funding_links":[],"categories":["Shell"],"sub_categories":[],"readme":"                 _|       |               |      \n      __| __ \\  |         __|  _ \\   _ \\  |  __| \n    \\__ \\ |   | __|_____| |   (   | (   | |\\__ \\ \n    ____/ .__/ _|        \\__|\\___/ \\___/ _|____/ \n         _|\n\n\n# SPF-tools\n\n[![Join the chat at https://gitter.im/jsarenik/spf-tools][gitter-img]][gitter]\n\n## Debian package\n\nA `.deb` package is available via the [edmundlod apt repository](https://github.com/edmundlod/apt):\n\n```bash\nsudo apt install spf-tools\n```\n\nSee the [apt repo README](https://github.com/edmundlod/apt) for setup instructions.\n\n---\n\nSimple tools for keeping the SPF TXT records tidy in order to fight\n[10 maximum DNS look-ups](http://serverfault.com/questions/584708).\n\n## Release notes\n\n### 2019/10 - new domain spf-tools.eu.org\n\nDomain name spf-tools.eu.org is used for testing now.\n\n### 2016/11 - new records on output\n\nspf-tools since version spf-tools/spf-tools@f4f51f7 do not\noutput merely `ip4` and `ip6` records, but also keep original `ptr`\nand `exists` ones.\n\n\n## General Usage\n\nYour original TXT record which causes more than 10 DNS look-ups\nshould be saved as an otherwise unused subdomain TXT record\n(e.g. `spf-orig.spf-tools.eu.org`).\n\nCreate a configuration file:\n\n    cat \u003e ~/.spf-toolsrc \u003c\u003cEOF\n    DOMAIN=spf-tools.eu.org\n    ORIG_SPF=spf-orig.spf-tools.eu.org\n    DESPF_SKIP_DOMAINS=_spf.domain1.com:spf.domain2.org\n    DNS_TIMEOUT=5\n    DNS_SERVER=\n    EOF\n\nNow just call any of the scripts described below.\n\n\n## Tools Description\n\n### despf.sh\n\n```\nUsage: despf.sh [OPTION]... [DOMAIN]...\nDecompose SPF records of a DOMAIN. Optionally can\nsort and unique them.\nDOMAIN may be specified in an environment variable.\n\nAvailable options:\n  -s DOMAIN[:DOMAIN...]      skip domains, i.e. leave include\n                             without decomposition\n  -t N                       set DNS timeout to N seconds\n  -h                         display this help and exit\n```\n\n`despf.sh` is a tool that resolves all `ip4` and `ip6` blocks\nfound in any included SPF subdomain. It prints all these blocks\n`sort(1)`ed and `uniq(1)`ed to stdout, one per line.\nOther output (`Getting ...`) is on stderr.\n\nExample:\n\n    ./despf.sh google.com\n    Getting _spf.google.com\n    Getting _netblocks.google.com\n    Getting _netblocks2.google.com\n    Getting _netblocks3.google.com\n    ip4:173.194.0.0/16\n    ip4:74.125.0.0/16\n    ...\n    ip6:2a00:1450:4000::/36\n    ip6:2c0f:fb50:4000::/36\n\nThe `DNS_TIMEOUT` configuration variable sets number of seconds\nfor the `host -W SECS` command (the same as option `-t`, see\nhelp).\n\n\n### mkblocks.sh\n\n`mkblocks.sh` tool is meant to parse a list of blocks produced by\ndespf.sh and prepare content of TXT records that all fit into one\nUDP packet, splitting into more TXT records if needed.\n\nOne TXT record per line of standard output.\n\n    ./despf.sh | ./normalize.sh | ./simplify.sh | ./mkblocks.sh\n\n\n### compare.sh\n\nCurrent SPF records can be verified by running `compare.sh`.\nIf the TXT records need an update, it will automatically run\nthe other tools to print out or copy into pastebuffer the\nnew TXT records in reverse order.\n\nBest practice is to put those lines into DNS starting with the\nlast one. That's why `xsel.sh` reverses the input gathered from\n`mkblocks.sh`.\n\nThe last record to update is root domain's record which just\ncontains an include. It should be always updated as the last one\nand the prefix alternated between `spf` and `_spf` prefixes when\nchanging records, so the records are all consistent until the\nroot one is changed.\n\n\n### xsel.sh\n\nIn order to semi-automate the task of updating the records,\npipe the output of `mkblocks.sh` to `xsel.sh`.\n\n\n### normalize.sh\n\nThis script takes care of correct CIDR ranges. At the moment\nonly IPv4.\n\nExample:\n\n    $ ./normalize.sh \u003c\u003cEOF\n    \u003e ip4:207.68.169.173/30\n    \u003e ip4:207.68.169.175/30\n    \u003e ip4:65.55.238.129/26\n    \u003e EOF\n    ip4:207.68.169.172/30\n    ip4:207.68.169.172/30\n    ip4:65.55.238.128/26\n\n\n### simplify.sh\n\nThis script takes out individual IPv4 addresses which are already\ncontained in CIDR ranges.\n\n    $ ./simplify.sh \u003c\u003cEOF\n    \u003e ip4:192.168.0.1\n    \u003e ip4:192.168.0.0/24\n    \u003e EOF\n    ip4:192.168.0.0/24\n\n\n### cloudflare.sh\n\nDependencies: [jq](https://stedolan.github.io/jq/),\n[awk](https://www.gnu.org/software/gawk/),\n[sed](https://www.gnu.org/software/sed/),\n[grep](https://www.gnu.org/software/grep/)\n\nScript to update pre-existing TXT SPF records for a domain according\nto the input in DNS zone format using CloudFlare's API.\n\nTo use this script, file `.spf-toolsrc` in `$HOME` directory should\ncontain `TOKEN` variable definition which is then used\nto connect to CloudFlare API. The file should also contain `DOMAIN`\nand `ORIG_SPF` variables which stand for the target SPF domain\n(e.g. `spf-tools.eu.org`) and original SPF record with includes\n(e.g. `spf-orig.spf-tools.eu.org`) in order to use `runspftools.sh`\nwithout modifying the script.\n\nThe script is written against v4 of https://api.cloudflare.com/\n\nThe only needed permissions for a custom API token are:\n  - Zone.Zone: Read\n  - Zone.DNS: Edit\n\nUsage:\n\n    ./despf.sh | ./normalize.sh | ./simplify.sh | ./iprange.sh | ./cloudflare.sh\n\n### dnsimple.sh\n\nDependencies: [jq](https://stedolan.github.io/jq/)\n\nScript to create or update pre-existing TXT SPF records for\na domain according to the input in mkblocks format using\nDNSimple's API.\n\nTo use this script, file `.spf-toolsrc` in `$HOME` directory should\ncontain a `TOKEN` variable definition with an account token (not a user\ntoken) which is then used to connect to the DNSimple API. The file\nshould also contain `DOMAIN` and `ORIG_SPF` variables which \nstand for the target SPF domain (e.g. `spf-tools.eu.org`) and\noriginal SPF record with includes (e.g. `spf-orig.spf-tools.eu.org`) \nin order to use `runspftools.sh` without modifying the script.\n\nThe script is written against v2 running at https://api.dnsimple.com/v2/\n\nUsage:\n\n    ./despf.sh | ./normalize.sh | ./simplify.sh | ./iprange.sh | ./mkblocks.sh \\\n      ./dnsimple.sh spf-tools.eu.org\n\n### route53.sh\n\nDependencies: [jq](https://stedolan.github.io/jq/),\n[aws](https://aws.amazon.com/cli/),\n[awk](https://www.gnu.org/software/gawk/),\n[sed](https://www.gnu.org/software/sed/),\n[grep](https://www.gnu.org/software/grep/)\n\n```\n Usage: route53.sh [OPTION]... [HOSTED_ZONE_ID]\n  Script to update pre-existing TXT SPF records for\n  a domain according to the input in DNS zone format.\n\n  Available options:\n    -t TTL                     set Time To Live for DNS records\n    -a TXT RECORD              set aditional TXT record to domain (can be used multiple times)\n\n  Default values:\n    TTL = 300\n```\nScript to update pre-existing TXT SPF records for a domain according\nto the input in DNS zone format.\n\nThe AWS CLI can be configured using `~/.aws/credentials` or using\nenvironment variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`\n(find more details in [Configuring the AWS CLI](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-environment)\ndocumentation.\n\nExample:\n\n    ./despf.sh | ./simplify.sh | ./mkblocks.sh | \\\n      ./route53.sh -a \"google-site-verification=deadbeef\" DEADBEEF\n\n\n### iprange.sh\n\nExtra dependencies: [iprange](https://github.com/firehol/iprange)\n\nThis script optimizes the IPv4 address block output (similar to, but\nmore than `simplify.sh` because it can join multiple networks into\none bigger).\n\nUsage:\n\n    ./despf.sh | ./iprange.sh\n\nExample:\n\n    $ ./despf.sh cont.spf-tools.eu.org\n    ip4:13.111.0.0/24\n    ip4:13.111.1.0/24\n    ip4:13.111.2.0/24\n    ip4:13.111.3.0/24\n    $ ./despf.sh cont.spf-tools.eu.org | ./iprange.sh\n    ip4:13.111.0.0/22\n\n## Putting it all together\n\n    ./despf.sh | ./normalize.sh | ./simplify.sh | ./iprange.sh \\\n      | ./mkblocks.sh | ./xsel.sh\n\n## Free Ad\n\nAs we are successfully using a free eu.org domain, we are proud to\nspread the word: Free domains: http://www.eu.org/\n\n## Links\n\n * https://dmarcian.com/spf-survey/spf.spf-tools.eu.org\n * https://dmarcian.com/spf-survey/spf-orig.spf-tools.eu.org\n * http://www.kitterman.com/spf/validate.html\n * http://serverfault.com/questions/584708\n * http://www.openspf.org/SPF_Record_Syntax\n * http://tools.ietf.org/html/rfc7208#section-5.5\n * http://tools.ietf.org/html/rfc7208#section-14.1\n * https://space.dmarcian.com/too-many-dns-lookups/\n * https://nic.eu.org/\n\n\n## License\n\n    Copyright 2015-2019 spf-tools team (see AUTHORS)\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n\n[gitter-img]: https://badges.gitter.im/Join%20Chat.svg\n[gitter]: https://gitter.im/jsarenik/spf-tools\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspf-tools%2Fspf-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspf-tools%2Fspf-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspf-tools%2Fspf-tools/lists"}