initial script import
This commit is contained in:
parent
ad512eb6d1
commit
4e140cfb5f
56
bin/pdns-audit.sh
Executable file
56
bin/pdns-audit.sh
Executable file
|
@ -0,0 +1,56 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# powerdns-tools
|
||||||
|
# https://git.stack-source.com/msb/powerdns-tools
|
||||||
|
# MIT License Copyright (c) 2022 Matthew Saunders Brown
|
||||||
|
#
|
||||||
|
# Basic PowerDNS audit tool. Gets list of zones from pdns database
|
||||||
|
# and does DNS lookups on their nameservers to see if the zone uses
|
||||||
|
# your nameservers or not (as listed in the authoritative() array below).
|
||||||
|
# This tool does not check for mismatched NS records, for example what
|
||||||
|
# is listed with the domain registrar is not what's configured in DNS.
|
||||||
|
# This tool should be run as root or another user that has access to
|
||||||
|
# the pdns database without having to specify connection info. For
|
||||||
|
# example a fully configured .my.cnf user file can provide this.
|
||||||
|
# For domains that are found to be using other nameservers than yours
|
||||||
|
# the A & MX records are listed, the idea being you can check against
|
||||||
|
# that to determine if the domains are using your hosting services.
|
||||||
|
# No action is taken, this just provides a report that can be reviewed.
|
||||||
|
|
||||||
|
# set array of our nameservers
|
||||||
|
authoritative=(ns1.example.com. ns2.example.com. ns3.example.com.)
|
||||||
|
|
||||||
|
# create array of domains from pdns database:
|
||||||
|
domains=(`mysql -s -e "SELECT LOWER(name) FROM pdns.domains"`)
|
||||||
|
|
||||||
|
# cycle through each domain
|
||||||
|
for domain in "${domains[@]}"; do
|
||||||
|
# get nameservers for domain
|
||||||
|
nameservers=(`/usr/bin/dig $domain ns +short`)
|
||||||
|
# check number of nameservers returned
|
||||||
|
if [[ ${#nameservers[@]} = 0 ]]; then
|
||||||
|
# domain returns zero nameservers (either unregistered, or registered but no NS entries configured in DNS)
|
||||||
|
echo ZERO: $domain
|
||||||
|
elif [[ ${#nameservers[@]} -gt 0 ]]; then
|
||||||
|
usesours=FALSE
|
||||||
|
for nameserver in "${nameservers[@]}"; do
|
||||||
|
if [[ " ${authoritative[*]} " =~ " ${nameserver} " ]]; then
|
||||||
|
usesours=TRUE
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ $usesours = FALSE ]]; then
|
||||||
|
# domain uses other nameservers than ours
|
||||||
|
unset arecord
|
||||||
|
unset mxrecord
|
||||||
|
arecord=`/usr/bin/dig $domain +short`
|
||||||
|
mxrecord=`/usr/bin/dig $domain mx +short`
|
||||||
|
echo OTHER: $domain - $arecord - $mxrecord
|
||||||
|
else
|
||||||
|
# domain uses our nameservers
|
||||||
|
echo VERIFIED: $domain
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# error getting nameservers
|
||||||
|
echo ERROR: $domain
|
||||||
|
fi
|
||||||
|
done
|
82
bin/pdns-record-del.sh
Executable file
82
bin/pdns-record-del.sh
Executable file
|
@ -0,0 +1,82 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# pdns-tools
|
||||||
|
# https://git.stack-source.com/msb/pdns-tools
|
||||||
|
# MIT License Copyright (c) 2022 Matthew Saunders Brown
|
||||||
|
|
||||||
|
# load include file
|
||||||
|
source $(dirname $0)/pdns.sh
|
||||||
|
|
||||||
|
help()
|
||||||
|
{
|
||||||
|
thisfilename=$(basename -- "$0")
|
||||||
|
echo "$thisfilename"
|
||||||
|
echo "Delete Resource Record set in zone."
|
||||||
|
echo ""
|
||||||
|
echo "usage: $thisfilename -z <zone> -n <name> -t <type> [-h]"
|
||||||
|
echo ""
|
||||||
|
echo " -h Print this help."
|
||||||
|
echo " -z <zone> Zone (domain name) to modify."
|
||||||
|
echo " -n <name> Hostname for the record(s) to delete."
|
||||||
|
echo " -t <type> Type of record(s) to del (A, CNAME, TXT, etc.)."
|
||||||
|
echo
|
||||||
|
echo " Record Sets are matched against zone, name & type. This tool deletes all records"
|
||||||
|
echo " that match the specified name & type for the given zone."
|
||||||
|
echo " <name> Can be a FQDN, or just the subdomain part (zone will be appended) or @ which will be replaced by the zone."
|
||||||
|
}
|
||||||
|
|
||||||
|
pdns:getoptions "$@"
|
||||||
|
|
||||||
|
# check for zone, make sure it ends with a .
|
||||||
|
if [[ -z $zone ]]; then
|
||||||
|
echo "zone is required"
|
||||||
|
exit
|
||||||
|
elif [[ $zone != *\. ]]; then
|
||||||
|
zone="$zone."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check for name, make sure it ends with a .
|
||||||
|
if [[ -z $name ]]; then
|
||||||
|
echo "name is required"
|
||||||
|
exit
|
||||||
|
elif [[ $name = "@" ]]; then
|
||||||
|
name=$zone
|
||||||
|
elif [[ $name != *\. ]]; then
|
||||||
|
name="$name."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# make sure name is equal to or part of zone
|
||||||
|
if [[ $name != $zone ]] && [[ $name != *\.$zone ]]; then
|
||||||
|
name="$name$zone"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check for type
|
||||||
|
if [[ -z $type ]]; then
|
||||||
|
echo "type is required"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# first query to see if zone already exists
|
||||||
|
zone_status=$(/usr/bin/curl --silent --output /tmp/$zone --write-out "%{http_code}" -H "X-API-Key: $api_key" "$api_base_url/zones/$zone")
|
||||||
|
|
||||||
|
if [[ $zone_status = 200 ]]; then
|
||||||
|
# verified zone exists, delete record
|
||||||
|
|
||||||
|
data="{\"rrsets\":[{\"name\":\"$name\",\"type\":\"$type\",\"changetype\":\"DELETE\",\"records\":[]}]}"
|
||||||
|
|
||||||
|
# delete record(s)
|
||||||
|
zone_status=$(/usr/bin/curl --silent --request PATCH --output "/tmp/$zone" --write-out "%{http_code}" --header "X-API-Key: $api_key" --data "$data" "$api_base_url/zones/$zone")
|
||||||
|
|
||||||
|
if [[ $zone_status = 204 ]]; then
|
||||||
|
echo "Success. Record(s) for $zone deleted."
|
||||||
|
else
|
||||||
|
echo "Error. http response deleting record(s) for $zone was: $zone_status"
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [[ $zone_status = 404 ]]; then
|
||||||
|
echo "Zone $zone does not exist, can't delete record."
|
||||||
|
else
|
||||||
|
echo "Unexpected http response checking for Zone $zone: $zone_status"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm /tmp/$zone
|
150
bin/pdns-record-rep.sh
Executable file
150
bin/pdns-record-rep.sh
Executable file
|
@ -0,0 +1,150 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# pdns-tools
|
||||||
|
# https://git.stack-source.com/msb/pdns-tools
|
||||||
|
# MIT License Copyright (c) 2022 Matthew Saunders Brown
|
||||||
|
|
||||||
|
# load include file
|
||||||
|
source $(dirname $0)/pdns.sh
|
||||||
|
|
||||||
|
help()
|
||||||
|
{
|
||||||
|
thisfilename=$(basename -- "$0")
|
||||||
|
echo "$thisfilename"
|
||||||
|
echo "Replace Resource Record set in zone."
|
||||||
|
echo ""
|
||||||
|
echo "usage: $thisfilename -z <zone> -n <name> -t <type> -c <content> [-l <ttl>] [-s <status>] [-h]"
|
||||||
|
echo ""
|
||||||
|
echo " -h Print this help."
|
||||||
|
echo " -z <zone> Zone (domain name) to modify records."
|
||||||
|
echo " -n <name> Hostname for this record."
|
||||||
|
echo " -t <type> Type of record to modify (A, CNAME, TXT, etc.)."
|
||||||
|
echo " -c <content> Resource record content (data / values)."
|
||||||
|
echo " -l <ttl> TTL, optional, defaults to $zone_defaults_ttl."
|
||||||
|
echo " -s <0|1> Status, optional. O (default) for active or 1 for disabled."
|
||||||
|
echo
|
||||||
|
echo " If record(s) do not exist they are created, if they already exist they are replaced."
|
||||||
|
echo " Record Sets are matched against zone, name & type. This tool updates/replaces all records"
|
||||||
|
echo " that match the specified name & type. <content> is the data for the record and can be multiple"
|
||||||
|
echo " records with each record separated by a pipe (|). In the case where you have multiple records"
|
||||||
|
echo " that match the specified name & type you must specify *all* of the records. If for example"
|
||||||
|
echo " you want to add a third NS record to a domain that already has a two NS records you must"
|
||||||
|
echo " specify all 3 NS records in the <content>, otherwise the 2 existing records will be deleted"
|
||||||
|
echo " and the single new record will be added from the <content>".
|
||||||
|
echo " When adding MX or SRV records specify the Priority as part of the record. e.g. -c \"10 mail.example.com\""
|
||||||
|
echo " Only MX & SRV records use Priority, leave Priority off all other records."
|
||||||
|
echo " <name> Can be a FQDN, or just the subdomain part (zone will be appended) or @ which will be replaced by the zone."
|
||||||
|
}
|
||||||
|
|
||||||
|
pdns:getoptions "$@"
|
||||||
|
|
||||||
|
# check for zone, make sure it ends with a .
|
||||||
|
if [[ -z $zone ]]; then
|
||||||
|
echo "zone is required"
|
||||||
|
exit
|
||||||
|
elif [[ $zone != *\. ]]; then
|
||||||
|
zone="$zone."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check for name, make sure it ends with a .
|
||||||
|
if [[ -z $name ]]; then
|
||||||
|
echo "name is required"
|
||||||
|
exit
|
||||||
|
elif [[ $name = "@" ]]; then
|
||||||
|
name=$zone
|
||||||
|
elif [[ $name != *\. ]]; then
|
||||||
|
name="$name."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# make sure name is equal to or part of zone
|
||||||
|
if [[ $name != $zone ]] && [[ $name != *\.$zone ]]; then
|
||||||
|
name="$name$zone"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check for type
|
||||||
|
if [[ -z $type ]]; then
|
||||||
|
echo "type is required"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check for content
|
||||||
|
if [[ -z $content ]]; then
|
||||||
|
echo "content is required"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check for ttl
|
||||||
|
if [[ -z $ttl ]]; then
|
||||||
|
ttl=$zone_defaults_ttl
|
||||||
|
fi
|
||||||
|
|
||||||
|
# first query to see if zone already exists
|
||||||
|
zone_status=$(/usr/bin/curl --silent --output /tmp/$zone --write-out "%{http_code}" -H "X-API-Key: $api_key" "$api_base_url/zones/$zone")
|
||||||
|
|
||||||
|
if [[ $zone_status = 200 ]]; then
|
||||||
|
# verified zone exists, add record(s)
|
||||||
|
|
||||||
|
data="{\"rrsets\":[{\"name\":\"$name\",\"type\":\"$type\",\"ttl\":$ttl,\"changetype\":\"REPLACE\",\"records\":["
|
||||||
|
|
||||||
|
# turn content in to array of records
|
||||||
|
orig_ifs="$IFS"
|
||||||
|
IFS='|'
|
||||||
|
read -r -a resourcerecords <<< "$content"
|
||||||
|
IFS="$orig_ifs"
|
||||||
|
|
||||||
|
# get number of records in set
|
||||||
|
resourcerecords_records_count=${#resourcerecords[@]}
|
||||||
|
records_count=0
|
||||||
|
|
||||||
|
for resourcerecord in "${resourcerecords[@]}"; do
|
||||||
|
|
||||||
|
records_count=$((records_count+1))
|
||||||
|
|
||||||
|
# make sure hostnames end in a .
|
||||||
|
declare -a types_that_require_dot=("CNAME MX NS PTR SRV")
|
||||||
|
if [[ " ${types_that_require_dot[*]} " =~ " ${type} " ]]; then
|
||||||
|
if [[ $resourcerecord != *\. ]]; then
|
||||||
|
resourcerecord="$resourcerecord."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# quote TXT records
|
||||||
|
if [[ $type = "TXT" ]]; then
|
||||||
|
resourcerecord="\\\"$resourcerecord\\\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set disabled status
|
||||||
|
if [[ $status = 1 ]]; then
|
||||||
|
disabled=true
|
||||||
|
else
|
||||||
|
disabled=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
data="$data{\"content\":\"$resourcerecord\",\"disabled\":$disabled}"
|
||||||
|
|
||||||
|
if [[ $records_count < $resourcerecords_records_count ]]; then
|
||||||
|
data="$data,"
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
data="$data]}]}"
|
||||||
|
|
||||||
|
# add record(s)
|
||||||
|
zone_status=$(/usr/bin/curl --silent --request PATCH --output "/tmp/$zone" --write-out "%{http_code}" --header "X-API-Key: $api_key" --data "$data" "$api_base_url/zones/$zone")
|
||||||
|
|
||||||
|
if [[ $zone_status = 204 ]]; then
|
||||||
|
echo "Success. Record(s) for $zone created/updated."
|
||||||
|
else
|
||||||
|
echo "Error. http response updating record(s) for $zone was: $zone_status"
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [[ $zone_status = 404 ]]; then
|
||||||
|
|
||||||
|
echo "Zone $zone does not exist, can't update records."
|
||||||
|
|
||||||
|
else
|
||||||
|
echo "Unexpected http response checking for Zone $zone: $zone_status"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm /tmp/$zone
|
160
bin/pdns-zone-add.sh
Executable file
160
bin/pdns-zone-add.sh
Executable file
|
@ -0,0 +1,160 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# pdns-tools
|
||||||
|
# https://git.stack-source.com/msb/pdns-tools
|
||||||
|
# MIT License Copyright (c) 2022 Matthew Saunders Brown
|
||||||
|
|
||||||
|
# load include file
|
||||||
|
source $(dirname $0)/pdns.sh
|
||||||
|
|
||||||
|
help()
|
||||||
|
{
|
||||||
|
thisfilename=$(basename -- "$0")
|
||||||
|
echo "$thisfilename"
|
||||||
|
echo "Add new zone to DNS"
|
||||||
|
echo ""
|
||||||
|
echo "usage: $thisfilename -z <zone> [-m <master>] [-t <type>] [-a <account>] [-b] [-h]"
|
||||||
|
echo ""
|
||||||
|
echo " -h Print this help."
|
||||||
|
echo " -z <zone> Zone (domain name) to add."
|
||||||
|
echo " -m <master> IP address of master, if this zone is of type SLAVE."
|
||||||
|
echo " -t <type> Defaults to NATIVE. Can also be MASTER or SLAVE. If type is SLAVE be sure to set master IP."
|
||||||
|
echo " -a <account> The account that controls this zones. For tying in to Control Panel or other custom admins."
|
||||||
|
echo " -b Bare - create zone without any Resource Records. Normally a default set of RR are created."
|
||||||
|
}
|
||||||
|
|
||||||
|
pdns:getoptions "$@"
|
||||||
|
|
||||||
|
# check for zone
|
||||||
|
if [[ -z $zone ]]; then
|
||||||
|
echo "zone is required"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# first query to see if zone already exists
|
||||||
|
zone_status=$(/usr/bin/curl --silent --output /tmp/$zone.output --write-out "%{http_code}" -H "X-API-Key: $api_key" "$api_base_url/zones/$zone")
|
||||||
|
|
||||||
|
if [[ $zone_status = 200 ]]; then
|
||||||
|
echo Zone $zone already exists.
|
||||||
|
elif [[ $zone_status = 404 ]]; then
|
||||||
|
|
||||||
|
# zone does not exist, create new zone now
|
||||||
|
|
||||||
|
# generate serial
|
||||||
|
serial=$(date +%Y%m%d00)
|
||||||
|
|
||||||
|
# set type (kind). NATIVE (default), MASTER or SLAVE
|
||||||
|
if [[ -n $type ]]; then
|
||||||
|
kind=$type
|
||||||
|
else
|
||||||
|
kind="NATIVE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# zone
|
||||||
|
data='{'
|
||||||
|
|
||||||
|
if [[ -n $account ]]; then
|
||||||
|
data="$data\"account\":\"$account\","
|
||||||
|
fi
|
||||||
|
data="$data\"name\":\"$zone.\","
|
||||||
|
data="$data\"kind\":\"$kind\","
|
||||||
|
if [[ -n $master ]]; then
|
||||||
|
data="$data\"masters\":[\"$master\"],"
|
||||||
|
fi
|
||||||
|
data="$data\"serial\":\"$serial\","
|
||||||
|
data="$data\"nameservers\":[],"
|
||||||
|
data="$data\"rrsets\":["
|
||||||
|
|
||||||
|
# create SOA
|
||||||
|
data="$data{"
|
||||||
|
data="$data\"name\":\"${zone}.\","
|
||||||
|
data="$data\"type\":\"SOA\","
|
||||||
|
data="$data\"ttl\":${zone_defaults_ttl},"
|
||||||
|
data="$data\"records\":["
|
||||||
|
data="$data{"
|
||||||
|
data="$data\"content\":\"$zone_default_ns. $zone_defaults_mbox. $serial $zone_defaults_refresh $zone_defaults_retry $zone_defaults_expire $zone_defaults_minimum\"",
|
||||||
|
data="$data\"disabled\":false"
|
||||||
|
data="$data}"
|
||||||
|
data="$data]"
|
||||||
|
|
||||||
|
|
||||||
|
if [[ -n $bare ]]; then
|
||||||
|
# do not add default records
|
||||||
|
data="$data}"
|
||||||
|
else
|
||||||
|
# add default records
|
||||||
|
data="$data},"
|
||||||
|
|
||||||
|
# get number of default records to add
|
||||||
|
default_records_count=${#default_records[@]}
|
||||||
|
records_count=0
|
||||||
|
|
||||||
|
# add default records
|
||||||
|
for record in "${default_records[@]}"; do
|
||||||
|
|
||||||
|
records_count=$((records_count+1))
|
||||||
|
|
||||||
|
# replace @ with zone
|
||||||
|
record=$(echo ${record} | sed -e "s/@/$zone/g")
|
||||||
|
|
||||||
|
# turn record row info in to array
|
||||||
|
orig_ifs="$IFS"
|
||||||
|
IFS='|'
|
||||||
|
read -r -a recordArray <<< "$record"
|
||||||
|
IFS="$orig_ifs"
|
||||||
|
|
||||||
|
# extract record info from array
|
||||||
|
rr_name=${recordArray[0]}
|
||||||
|
rr_type=${recordArray[1]}
|
||||||
|
rr_content=${recordArray[2]}
|
||||||
|
|
||||||
|
# munge data as needed
|
||||||
|
if vmail::validate_domain $rr_content; then
|
||||||
|
rr_content="$rr_content."
|
||||||
|
fi
|
||||||
|
if [[ $rr_type = TXT ]]; then
|
||||||
|
rr_content="\\\"$rr_content\\\""
|
||||||
|
fi
|
||||||
|
if [[ $rr_type = MX ]]; then
|
||||||
|
rr_content="$rr_content."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# add record
|
||||||
|
data="$data{"
|
||||||
|
data="$data\"name\":\"${rr_name}.\","
|
||||||
|
data="$data\"type\":\"${rr_type}\","
|
||||||
|
data="$data\"ttl\":${zone_defaults_ttl},"
|
||||||
|
data="$data\"records\":["
|
||||||
|
data="$data{"
|
||||||
|
data="$data\"content\":\"${rr_content}\"",
|
||||||
|
data="$data\"disabled\":false"
|
||||||
|
data="$data}"
|
||||||
|
data="$data]"
|
||||||
|
|
||||||
|
if [[ $records_count = $default_records_count ]]; then
|
||||||
|
data="$data}"
|
||||||
|
else
|
||||||
|
data="$data},"
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# close out data
|
||||||
|
data="$data]}"
|
||||||
|
|
||||||
|
# add zone
|
||||||
|
zone_status=$(/usr/bin/curl --silent --request POST --output "/tmp/$zone.output" --write-out "%{http_code}" --header "X-API-Key: $api_key" --data "$data" "$api_base_url/zones")
|
||||||
|
|
||||||
|
if [[ $zone_status = 201 ]]; then
|
||||||
|
echo Success. Zone $zone created.
|
||||||
|
else
|
||||||
|
echo Error. http response adding zone $zone was: $zone_status
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
echo Unexpected http response checking for Zone $zone: $zone_status
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm /tmp/$zone.output
|
43
bin/pdns-zone-del.sh
Executable file
43
bin/pdns-zone-del.sh
Executable file
|
@ -0,0 +1,43 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# pdns-tools
|
||||||
|
# https://git.stack-source.com/msb/pdns-tools
|
||||||
|
# MIT License Copyright (c) 2022 Matthew Saunders Brown
|
||||||
|
|
||||||
|
# load include file
|
||||||
|
source $(dirname $0)/pdns.sh
|
||||||
|
|
||||||
|
help()
|
||||||
|
{
|
||||||
|
thisfilename=$(basename -- "$0")
|
||||||
|
echo "$thisfilename"
|
||||||
|
echo "Delete a zone and all of it's records."
|
||||||
|
echo ""
|
||||||
|
echo "usage: $thisfilename -z <zone> [-x] [-h]"
|
||||||
|
echo ""
|
||||||
|
echo " -h Print this help."
|
||||||
|
echo " -z <zone> Zone (domain name) to delete."
|
||||||
|
echo " -x Execute (force) - don't prompt for confirmation."
|
||||||
|
}
|
||||||
|
|
||||||
|
pdns:getoptions "$@"
|
||||||
|
|
||||||
|
# check for zone
|
||||||
|
if [[ -z $zone ]]; then
|
||||||
|
echo "zone is required"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n $execute ]] || pdns::yesno "Delete $zone now?"; then
|
||||||
|
echo
|
||||||
|
zone_status=$(/usr/bin/curl --silent --output /tmp/$zone --write-out "%{http_code}" --request DELETE --header "X-API-Key: $api_key" $api_base_url/zones/$zone)
|
||||||
|
rm /tmp/$zone
|
||||||
|
|
||||||
|
if [[ $zone_status = 204 ]]; then
|
||||||
|
echo Zone $zone deleted.
|
||||||
|
elif [[ $zone_status = 404 ]]; then
|
||||||
|
echo Zone $zone does not exist.
|
||||||
|
else
|
||||||
|
echo Error. http response deleting zone $zone was: $zone_status
|
||||||
|
fi
|
||||||
|
fi
|
47
bin/pdns-zone-export.sh
Executable file
47
bin/pdns-zone-export.sh
Executable file
|
@ -0,0 +1,47 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# pdns-tools
|
||||||
|
# https://git.stack-source.com/msb/pdns-tools
|
||||||
|
# MIT License Copyright (c) 2022 Matthew Saunders Brown
|
||||||
|
|
||||||
|
# load include file
|
||||||
|
source $(dirname $0)/pdns.sh
|
||||||
|
|
||||||
|
help()
|
||||||
|
{
|
||||||
|
thisfilename=$(basename -- "$0")
|
||||||
|
echo "$thisfilename"
|
||||||
|
echo "Export full DNS zone"
|
||||||
|
echo ""
|
||||||
|
echo "usage: $thisfilename -z <zone> [-h]"
|
||||||
|
echo ""
|
||||||
|
echo " -h Print this help."
|
||||||
|
echo " -z <zone> Zone to get."
|
||||||
|
}
|
||||||
|
|
||||||
|
pdns:getoptions "$@"
|
||||||
|
|
||||||
|
# check for zone
|
||||||
|
if [[ -z $zone ]]; then
|
||||||
|
echo "zone is required"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMPDIR=$(mktemp -d -p /tmp)
|
||||||
|
|
||||||
|
# export zone and check http status
|
||||||
|
zone_status=$(/usr/bin/curl --silent --output "$TMPDIR/$zone" --write-out "%{http_code}" -H "X-API-Key: $api_key" $api_base_url/zones/$zone/export)
|
||||||
|
|
||||||
|
if [[ $zone_status = 200 ]]; then
|
||||||
|
# return zone level records
|
||||||
|
sed -e 's/\t/|/g' $TMPDIR/$zone|column -t -s \| |grep ^$zone.
|
||||||
|
# return subdomain records
|
||||||
|
sed -e 's/\t/|/g' $TMPDIR/$zone|column -t -s \| |grep -v ^$zone.
|
||||||
|
elif [[ $zone_status = 404 ]]; then
|
||||||
|
echo 404 Not Found, $zone does not exist
|
||||||
|
else
|
||||||
|
echo Unexecpted http response checking for existence of zone $zone: $zone_status
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm $TMPDIR/$zone
|
||||||
|
rmdir $TMPDIR
|
176
bin/pdns.sh
Executable file
176
bin/pdns.sh
Executable file
|
@ -0,0 +1,176 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# powerdns-tools
|
||||||
|
# https://git.stack-source.com/msb/powerdns-tools
|
||||||
|
# MIT License Copyright (c) 2022 Matthew Saunders Brown
|
||||||
|
#
|
||||||
|
# powerdns-tools include file, used by other powerdns-tools bash scripts
|
||||||
|
|
||||||
|
# Must be root, attempt sudo if need be. root is not actually required for the API commands, but we want to restrict access.
|
||||||
|
if [ "${EUID}" -ne 0 ]; then
|
||||||
|
exec sudo -u root --shell /bin/bash $0 $@
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Load local config
|
||||||
|
# Two variables, api_key & dns_domain, are only set in the local config
|
||||||
|
# Any of the other constants below can be overriden in the local config
|
||||||
|
if [[ -f /usr/local/etc/pdns.conf ]]; then
|
||||||
|
source /usr/local/etc/pdns.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
# constants
|
||||||
|
|
||||||
|
# API URL. Consider putting this behind a proxy with https on the front.
|
||||||
|
[[ -z $api_base_url ]] && api_base_url=http://127.0.0.1:8081/api/v1/servers/localhost
|
||||||
|
|
||||||
|
# Default IP address to use for new zone records
|
||||||
|
# Defaults to IP of server script is run from
|
||||||
|
[[ -z $default_ip ]] && default_ip=$(hostname --ip-address)
|
||||||
|
|
||||||
|
# Array of allowed Resource Record Types
|
||||||
|
[[ -z $rr_types ]] && declare -a rr_types=(A AAAA CNAME MX NS PTR SRV TXT)
|
||||||
|
|
||||||
|
# Minimum/maximum values for SOA and RR records
|
||||||
|
[[ -z $min_ttl ]] && min_ttl=300
|
||||||
|
[[ -z $max_ttl ]] && max_ttl=2419200
|
||||||
|
[[ -z $min_refresh ]] && min_refresh=300
|
||||||
|
[[ -z $min_retry ]] && min_retry=300
|
||||||
|
[[ -z $min_expire ]] && min_expire=86400
|
||||||
|
|
||||||
|
# Default values for new zones.
|
||||||
|
[[ -z $zone_default_ns ]] && zone_default_ns="ns1.$dns_domain"
|
||||||
|
[[ -z $zone_defaults_mbox ]] && zone_defaults_mbox="hostmaster.$dns_domain"
|
||||||
|
[[ -z $zone_defaults_ttl ]] && zone_defaults_ttl='3600'
|
||||||
|
[[ -z $zone_defaults_refresh ]] && zone_defaults_refresh='86400'
|
||||||
|
[[ -z $zone_defaults_retry ]] && zone_defaults_retry='7200'
|
||||||
|
[[ -z $zone_defaults_expire ]] && zone_defaults_expire='1209600'
|
||||||
|
[[ -z $zone_defaults_minimum ]] && zone_defaults_minimum='3600'
|
||||||
|
readonly zone_defaults_pri='0'
|
||||||
|
# zone_defaults_pri must be 0, do not change
|
||||||
|
|
||||||
|
# The following array specifies default records for new zone records.
|
||||||
|
# These get inserted automatically whenever a zone is created.
|
||||||
|
# The format of each record is (name|type|content). TTL is taken from defaults above.
|
||||||
|
# @ will be replace with the zone (domain name)
|
||||||
|
# TXT records will get quoted (don't add quotes around the content field here)
|
||||||
|
# Only MX & SRV records use priority, and it should be specified as part of the content/data field.
|
||||||
|
|
||||||
|
[[ -z $default_records ]] && declare -a default_records=("@|A|$default_ip"
|
||||||
|
"@|MX|10 mail.@"
|
||||||
|
"@|NS|ns1.$dns_domain"
|
||||||
|
"@|NS|ns2.$dns_domain"
|
||||||
|
"@|NS|ns3.$dns_domain"
|
||||||
|
"@|TXT|v=spf1 a mx -all"
|
||||||
|
"mail.@|A|$default_ip"
|
||||||
|
"www.@|CNAME|@")
|
||||||
|
|
||||||
|
# functions
|
||||||
|
|
||||||
|
# crude but good enough domain name format validation
|
||||||
|
function vmail::validate_domain () {
|
||||||
|
local my_domain=$1
|
||||||
|
if [[ $my_domain =~ ^(([a-zA-Z0-9](-?[a-zA-Z0-9])*)\.)+[a-zA-Z]{2,}\.?$ ]] ; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# yesno prompt
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# loop until y or n: if vmail::yesno "Continue?"; then
|
||||||
|
# default y: if vmail::yesno "Continue?" Y; then
|
||||||
|
# default n: if vmail::yesno "Continue?" N; then
|
||||||
|
function pdns::yesno() {
|
||||||
|
|
||||||
|
local prompt default reply
|
||||||
|
|
||||||
|
if [ "${2:-}" = "Y" ]; then
|
||||||
|
prompt="Y/n"
|
||||||
|
default=Y
|
||||||
|
elif [ "${2:-}" = "N" ]; then
|
||||||
|
prompt="y/N"
|
||||||
|
default=N
|
||||||
|
else
|
||||||
|
prompt="y/n"
|
||||||
|
default=
|
||||||
|
fi
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
|
||||||
|
read -p "$1 [$prompt] " -n 1 -r reply
|
||||||
|
|
||||||
|
# Default?
|
||||||
|
if [ -z "$reply" ]; then
|
||||||
|
reply=$default
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the reply is valid
|
||||||
|
case "$reply" in
|
||||||
|
Y*|y*) return 0 ;;
|
||||||
|
N*|n*) return 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function pdns:getoptions () {
|
||||||
|
local OPTIND
|
||||||
|
while getopts "hbz:m:t:a:n:c:l:s:x" opt ; do
|
||||||
|
case "${opt}" in
|
||||||
|
h ) # display help and exit
|
||||||
|
help
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
b ) # bare - create empty zone, do not any default records
|
||||||
|
bare=true
|
||||||
|
;;
|
||||||
|
z ) # zone
|
||||||
|
zone=${OPTARG,,}
|
||||||
|
# pdns stores zone name without trailing dot, remove if found
|
||||||
|
if [[ ${zone: -1} = '.' ]]; then
|
||||||
|
zone=${zone::-1}
|
||||||
|
fi
|
||||||
|
if ! vmail::validate_domain $zone; then
|
||||||
|
echo "ERROR: $zone is not a valid domain name."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
m ) # master - IP of master if this is a slave zone
|
||||||
|
master=${OPTARG}
|
||||||
|
;;
|
||||||
|
t ) # type
|
||||||
|
type=${OPTARG^^}
|
||||||
|
;;
|
||||||
|
a ) # account
|
||||||
|
account=${OPTARG}
|
||||||
|
;;
|
||||||
|
n ) # name - hostname for this record
|
||||||
|
name=${OPTARG,,}
|
||||||
|
;;
|
||||||
|
c ) # content - record data
|
||||||
|
content=${OPTARG}
|
||||||
|
;;
|
||||||
|
l ) # ttl - Time To Live
|
||||||
|
ttl=${OPTARG}
|
||||||
|
;;
|
||||||
|
s ) # status - disabled status, 0 for active 1 for inactive, default 0
|
||||||
|
status=${OPTARG}
|
||||||
|
;;
|
||||||
|
x ) # eXecute - don't prompt for confirmation
|
||||||
|
execute=true
|
||||||
|
;;
|
||||||
|
\? )
|
||||||
|
echo "Invalid option: $OPTARG"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
: )
|
||||||
|
echo "Invalid option: $OPTARG requires an argument"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND-1))
|
||||||
|
}
|
3
etc/pdns.conf
Normal file
3
etc/pdns.conf
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# API key
|
||||||
|
api_key=changeme
|
||||||
|
dns_domain=example.com
|
10
install.sh
Executable file
10
install.sh
Executable file
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
chmod 755 bin/*
|
||||||
|
cp bin/* /usr/local/bin/
|
||||||
|
|
||||||
|
if [[ ! -f /usr/local/etc/pdns.conf ]]; then
|
||||||
|
chmod 640 etc/pdns.conf
|
||||||
|
cp etc/pdns.conf /usr/local/etc/pdns.conf
|
||||||
|
echo "Install complete, but sure to update /usr/local/etc/pdns.conf with your settings."
|
||||||
|
fi
|
Loading…
Reference in New Issue
Block a user