Skip to content

Instantly share code, notes, and snippets.

@grepwood
Created December 2, 2014 08:38

Revisions

  1. Michael Dec created this gist Dec 2, 2014.
    289 changes: 289 additions & 0 deletions setup_pdns.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,289 @@
    #!/bin/bash
    # Before running this script
    RUNLEVELS="235"
    HAVE_PASS=0
    FEEDED_KEY=""
    ROLE=""
    JOB_PID=$$
    NAN=1
    NUMREGEX='^[0-9]+$'
    DEPS=""
    DEBUG=0

    # Before you begin, you have to set these variables:
    NS1_INET="0"
    SOLUS_MANAGER="0"

    # If there are any commented out lines, that means they are for MySQL 5.1
    # The script has been refactored to work with MariaDB 5.5, which is a non-Oracle implementation of MySQL 5.5

    if [ "$NS1_INET" == "0" ] || [ "$SOLUS_MANAGER" == "0" ]; then
    echo "Before you begin to set up your host, you must edit the following variables:"
    echo "NS1_INET located at line 14"
    echo "SOLUS_MANAGER located at line 15"
    echo "They need to be IPv4 addresses of your nameserver 1 and your VM manager"
    exit
    fi

    if [ "$#" -gt "0" ]; then
    if [ "$#" -eq "1" ] || [ "$#" -eq "2" ]; then
    if [[ $1 =~ ^([mM][aA][sS][tT][eE][rR])$ ]]; then
    ROLE="Master"
    elif [[ $1 =~ ^([sS][lL][aA][vV][eE])$ ]]; then
    ROLE="Slave"
    else
    echo "First argument is either slave or master."
    exit
    fi
    fi
    if [ "$#" -eq "2" ]; then
    FEEDED_KEY="$2"
    HAVE_PASS=1
    fi
    if [ "$#" -gt "3" ]; then
    echo "This program accepts only 2 argument"
    exit
    fi
    else
    echo "Usage: setup_pdns.sh role (pass)"
    echo "role is either master or slave"
    echo "pass is optional"
    exit
    fi

    CONFLICT=`netstat -lnpu | tail -n+3 | awk '{print $4}' | sed 's/.*://' | grep ^53$ | wc -l`
    if [ "$CONFLICT" -eq "1" ]; then
    COLUMNS=`netstat -lnpu | tail -n+3 | awk 'BEGIN {FS=" "} ; END{print NF}'`
    CONFLICT_NAME=`netstat -lnpu | tail -n+3 | awk '{print $"$COLUMNS"}'`
    echo "$CONFLICT_NAME is hogging port 53. Kill it."
    exit
    elif [ "$CONFLICT" -gt "1" ]; then
    echo "There are programs fighting for port 53! Kill them before continuing."
    exit
    fi

    mkdir -p /var/lib/mysql

    HAVE_EPEL=`rpm -qa epel-release | wc -l`
    if [ "$HAVE_EPEL" -eq "0" ]; then
    rpm -U http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm 2>/dev/null
    fi

    if [ ! -f "/etc/yum.repos.d/mariadb.repo" ] || [ `md5sum /etc/yum.repos.d/mariadb.repo 2>/dev/null | awk '{print $1}'` != "02fdd192719bcc8bf621db927a1c3de4" ]; then
    printf "Adding MariaDB repo... "
    echo "[mariadb]" > /etc/yum.repos.d/mariadb.repo
    echo "name = MariaDB" >> /etc/yum.repos.d/mariadb.repo
    echo "baseurl = http://yum.mariadb.org/5.5/centos6-amd64" >> /etc/yum.repos.d/mariadb.repo
    echo "gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB" >> /etc/yum.repos.d/mariadb.repo
    echo "gpgcheck=1" >> /etc/yum.repos.d/mariadb.repo
    rpm --import https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
    echo "done!"
    fi

    printf "Installing MariaDB and PDNS... "
    if [ "`rpm -qa pdns pdns-backend-mysql MariaDB-server | wc -l`" -lt "3" ]; then
    HAVE_PDNS=`rpm -qa pdns | wc -l`
    HAVE_BACKEND=`rpm -qa pdns-backend-mysql | wc -l`
    HAVE_MARIA=`rpm -qa MariaDB-server | wc -l`
    if [ "$HAVE_PDNS" -eq "0" ]; then
    DEPS="$DEPS pdns"
    fi
    if [ "$HAVE_BACKEND" -eq "0" ]; then
    DEPS="$DEPS pdns-backend-mysql"
    fi
    if [ "$HAVE_MARIA" -eq "0" ]; then
    DEPS="$DEPS MariaDB-server"
    fi
    yum install $DEPS --enablerepo=epel,mariadb -y -q 2>/dev/null 1>/dev/null
    echo "done!"
    else
    echo "it wasn't necessary"
    fi

    printf "Adding MySQLd and PDNS to runlevels: $RUNLEVELS... "
    chkconfig --levels $RUNLEVELS mysql on
    chkconfig --levels $RUNLEVELS pdns on
    echo "done!"

    service mysql start

    INTERJECT=`cat -n /etc/my.cnf.d/server.cnf | grep "\[mysqld\]" | awk '{print $1}'`

    if [ "$HAVE_PASS" -eq "1" ]; then
    mysqladmin -u root password $FEEDED_KEY
    else
    read -r -s -p "What should be the root MySQL pass? " FEEDED_KEY
    echo ""
    HAVE_PASS=1
    mysqladmin -u root password $FEEDED_KEY
    fi

    printf "Fetching PDNS SQL database... "
    curl http://files.soluslabs.com/solusvm/pdns/pdns.sql 2>/dev/null > pdns.sql.$JOB_PID
    sed 's/type=InnoDB;/ENGINE\ =\ InnoDB;/' pdns.sql.$JOB_PID > pdns.sql
    rm -f pdns.sql.$JOB_PID
    echo "done!"
    printf "Merging PDNS database into our MySQL... "
    mysql -u root --password=$FEEDED_KEY < pdns.sql
    rm -f pdns.sql
    echo "done!"

    printf "Altering PDNS config... "
    sed 's/^launch=bind$/launch=gmysql/' /etc/pdns/pdns.conf > pdns.conf.$JOB_PID
    mv pdns.conf.$JOB_PID /etc/pdns/pdns.conf
    echo "gmysql-host=127.0.0.1" >> /etc/pdns/pdns.conf
    echo "gmysql-user=root" >> /etc/pdns/pdns.conf
    echo "gmysql-password=$FEEDED_KEY" >> /etc/pdns/pdns.conf
    echo "gmysql-dbname=powerdns" >> /etc/pdns/pdns.conf
    echo "done!"

    service pdns start

    printf "Altering iptables rules... "
    IPT_RULE_NO=`iptables -L INPUT --line-number | tail -n+3 | tail -n-1 | awk '{print $1}'`
    for ((IPT_COUNTER=IPT_RULE_NO; IPT_COUNTER > 0; IPT_COUNTER--)); do
    IPT_RULE=`iptables -L INPUT | tail -n+3 | head -n$IPT_RULE_NO | tail -n1`
    echo $IPT_RULE > ipt.$JOB_PID
    IPT_RULE=`cat ipt.$JOB_PID`
    rm -f ipt.$JOB_PID
    if [ "$IPT_RULE" == "REJECT all -- anywhere anywhere reject-with icmp-host-prohibited" ]; then
    iptables -D INPUT $IPT_COUNTER
    fi
    done
    SSH_DUPES=`iptables -L INPUT | grep -E '22|ssh' | grep -v SSH | wc -l`
    if [ "$SSH_DUPES" -ne "0" ]; then
    for ((SSH_COUNTER=1; SSH_COUNTER <= $SSH_DUPES; SSH_COUNTER++)); do
    iptables -D INPUT `iptables -L INPUT --line-number | grep -E '22|ssh' | grep -v SSH | head -n$SSH_COUNTER | tail -n1 | awk '{print $1}'`
    done
    fi
    if ! iptables -L INPUT | grep -qE '53|domain'; then
    iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT
    fi
    if [ `iptables -L INPUT --line-number | grep SSH | wc -l` -eq "0" ]; then
    iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name SSH --rsource
    iptables -A INPUT -p tcp -m tcp --dport 22 -m recent --rcheck --seconds 30 --hitcount 4 --rttl --name SSH --rsource -j REJECT --reject-with tcp-reset
    iptables -A INPUT -p tcp -m tcp --dport 22 -m recent --rcheck --seconds 30 --hitcount 3 --rttl --name SSH --rsource -j LOG --log-prefix "SSH brute force "
    iptables -A INPUT -p tcp -m tcp --dport 22 -m recent --update --seconds 30 --hitcount 3 --rttl --name SSH --rsource -j REJECT --reject-with tcp-reset
    fi
    iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT

    if [ "$ROLE" == "Master" ]; then
    if ! iptables -L INPUT | grep -qE '3306|mysql'; then
    iptables -A INPUT -p tcp -m tcp --dport 3306 -j ACCEPT
    fi
    iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited
    echo "done!"

    printf "Granting permission to users to connect to master... "
    echo "GRANT ALL ON powerdns.* TO 'root'@'$NS1_INET' IDENTIFIED BY '$FEEDED_KEY';" > mysql.cmd.$JOB_PID
    printf "grant all privileges on *.* to 'root'@'$SOLUS_MANAGER' identified by '$FEEDED_KEY';" >> mysql.cmd.$JOB_PID
    mysql -u root --password=$FEEDED_KEY < mysql.cmd.$JOB_PID
    rm -f mysql.cmd.$JOB_PID
    echo "done!"

    printf "Editing /etc/my.cnf.d/server.cnf... "
    head -n$INTERJECT /etc/my.cnf.d/server.cnf > server.cnf.$JOB_PID
    echo "server-id=1" >> server.cnf.$JOB_PID
    echo "log-bin=mariadb-bin" >> server.cnf.$JOB_PID
    echo "log-bin-index=mariadb-bin.index" >> server.cnf.$JOB_PID
    echo "expire-logs-days=10" >> server.cnf.$JOB_PID
    echo "max-binlog-size=100M" >> server.cnf.$JOB_PID
    echo "binlog-do-db=powerdns" >> server.cnf.$JOB_PID
    tail -n+`expr $INTERJECT + 1` /etc/my.cnf.d/server.cnf >> server.cnf.$JOB_PID
    mv server.cnf.$JOB_PID /etc/my.cnf.d/server.cnf
    echo "done!"

    read -r -s -p "Enter slave password: " USER_PASS
    echo ""
    printf "Preparing MySQL master setup command... "
    echo "create user pdnsslave;" > mysql.cmd.$JOB_PID
    echo "create user 'pdnsslave'@'*';" >> mysql.cmd.$JOB_PID
    echo "grant replication slave on *.* to pdnsslave identified by '$USER_PASS';" >> mysql.cmd.$JOB_PID
    printf "flush privileges;" >> mysql.cmd.$JOB_PID
    echo "done!"

    printf "Executing said command... "
    mysql -u root --password=$FEEDED_KEY < mysql.cmd.$JOB_PID
    echo "done!"

    service pdns stop
    service mysql stop
    service mysql start
    service pdns start

    printf "Altering iptables rules... "
    IPT_RULE_NO=`iptables -L INPUT --line-number | tail -n+3 | tail -n-1 | awk '{print $1}'`
    for ((IPT_COUNTER=$IPT_RULE_NO; IPT_COUNTER > 0; IPT_COUNTER--)); do
    IPT_RULE=`iptables -L INPUT | tail -n+3 | head -n$IPT_RULE_NO | tail -n1`
    echo $IPT_RULE > ipt.$JOB_PID
    IPT_RULE=`cat ipt.$JOB_PID`
    rm -f ipt.$JOB_PID
    if [ "$IPT_RULE" == "REJECT all -- anywhere anywhere reject-with icmp-host-prohibited" ]; then
    iptables -D INPUT $IPT_COUNTER
    fi
    done
    SSH_DUPES=`iptables -L INPUT | grep -E '22|ssh' | grep -v SSH | wc -l`
    if [ "$SSH_DUPES" -ne "0" ]; then
    for ((SSH_COUNTER=1; SSH_COUNTER <= $SSH_DUPES; SSH_COUNTER++)); do
    iptables -D INPUT `iptables -L INPUT --line-number | grep -E '22|ssh' | grep -v SSH | head -n$SSH_COUNTER | tail -n1 | awk '{print $1}'`
    done
    fi
    if ! iptables -L INPUT | grep -qE '3306|mysql'; then
    iptables -A INPUT -p tcp -m tcp --dport 3306 -j ACCEPT
    fi
    if ! iptables -L INPUT | grep -qE '53|domain'; then
    iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT
    fi
    if [ `iptables -L INPUT --line-number | grep SSH | wc -l` -eq "0" ]; then
    iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name SSH --rsource
    iptables -A INPUT -p tcp -m tcp --dport 22 -m recent --rcheck --seconds 30 --hitcount 4 --rttl --name SSH --rsource -j REJECT --reject-with tcp-reset
    iptables -A INPUT -p tcp -m tcp --dport 22 -m recent --rcheck --seconds 30 --hitcount 3 --rttl --name SSH --rsource -j LOG --log-prefix "SSH brute force "
    iptables -A INPUT -p tcp -m tcp --dport 22 -m recent --update --seconds 30 --hitcount 3 --rttl --name SSH --rsource -j REJECT --reject-with tcp-reset
    fi
    iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
    iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited
    echo "done!"
    service iptables save

    mysql -u root --password=$FEEDED_KEY -e "show master status \G"
    elif [ "$ROLE" == "Slave" ]; then
    iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited
    echo "done!"
    while [ "$NAN" -eq "1" ]; do
    read -r -p "What server ID should this host have? [2 or greater] " SLAVE_ID
    if [[ $SLAVE_ID =~ $NUMREGEX ]] && [ $SLAVE_ID -gt 1 ]; then
    NAN=0
    printf "Thanks! Now, configuring my.cnf for slave... "
    else
    echo "This is not a valid number greater than 2"
    fi
    done
    head -n$INTERJECT /etc/my.cnf.d/server.cnf > server.cnf.$JOB_PID
    echo "server-id=$SLAVE_ID" >> server.cnf.$JOB_PID
    echo "relay-log=slave-relay-bin" >> server.cnf.$JOB_PID
    echo "relay-log-index=slave-relay-bin.index" >> server.cnf.$JOB_PID
    echo "replicate-do-db=powerdns" >> server.cnf.$JOB_PID
    tail -n+`expr $INTERJECT + 1` /etc/my.cnf.d/server.cnf >> server.cnf.$JOB_PID
    mv server.cnf.$JOB_PID /etc/my.cnf.d/server.cnf
    echo "done!"

    service mysql restart

    echo "Continue only if you have configured your master PDNS correctly!"
    read -r -p "What was the file number? mariadb-bin." INDEX
    read -r -p "And what was the position? " POSITION
    read -r -s -p "Enter slave password: " USER_PASS
    echo ""
    echo "change master to master_host='$NS1_INET', master_user='pdnsslave', master_password='$USER_PASS', master_log_file='mariadb-bin.$INDEX', master_log_pos=$POSITION, master_connect_retry=60;" > mysql.cmd.$JOB_PID
    printf "Preparing SQL command... "
    echo "change master to master_host='$NS1_INET', master_user='pdnsslave', master_password='$USER_PASS', master_log_file='mariadb-bin.$INDEX', master_log_pos=$POSITION, master_connect_retry=60;" > mysql.cmd.$JOB_PID
    printf "start slave;" >> mysql.cmd.$JOB_PID
    echo "done!"

    mysql -u root --password=$FEEDED_KEY < mysql.cmd.$JOB_PID
    mysql -u root --password=$FEEDED_KEY -e "show slave status \G"

    rm -f mysql.cmd.$JOB_PID
    else
    echo "Congratulations. You somehow tricked bash."
    fi