Formating nmap results to get http server - bash

I am trying to take a nmap scan result, determine the http ports (http, https, http-alt ...) and capture them ip and ports in order to automaticly perform web app scans.
I have my nmap results in grepable format. Using grep to delete any lines that do no contain the string "http". But I am now unsure how I can proceed.
Host: 127.0.0.1 (localhost) Ports: 3390/open/tcp//dsc///, 5901/open/tcp//vnc-1///, 8000/open/tcp//http-alt/// Ignored State: closed (65532)
This is my current result. From this I can get the IP of hosts with a http server open by using the cut command and getting the second field. which is the first part of my problem solved.
But now I am looking for a way to only get (from the above example)
8000/open/tcp//http-alt///
(NB: I'm not looking to get it just for the spefic case, using
cut -f 3 -d "," will work for this case, but if the http server was in the first field it would not work.)
after which i can use the cut command to get the port to then add it to a file with the ip, resulting in
127.0.0.1:8000
Could anyone advise a good way to do this?
Code of my simple bash script for doing a basic scan of all ports,the then doing a more advanced one based on the open ports found. Next step and objecive is to automaticly scan web apps with a directory scan and niktoo scan of identified web apps
#!/bin/bash
echo "Welcome to the quick lil tool. This runs a basic nmap scan, collects open ports and does a more advanced scan. reducing the time needed"
echo -e "\nUsage: ./getPorts.sh [Hosts]\n"
if [ $# -eq 0 ]
then
echo "No argument specified. Usage: ./getPorts.sh [Host or host file]"
exit 1
fi
if [[ "$EUID" -ne 0 ]]; then
echo "Not running as root"
exit 1
fi
nmap -iL $1 -p- -oA results
#Replace input file with gnmap scan, It will generate a list of all open ports
cat results.gnmap |awk -F'[/ ]' '{h=$2; for(i=1;i<=NF;i++){if($i=="open"){print h,":",$(i-1)}}}'| awk -F ':' '{print $2}' | sed -z 's/\n/,/g;s/,$/\n/' >> ports.list
#more advanced nmap scan
ports=$(cat ports.list)
echo $ports
nmap -p $ports -sC -sV -iL $1
EDIT: Found a way. Not sure why I was so focused on using the gnmap format for this, If I use the regular .nmap format. I can simple grep the line with http in and use cut to get the first field.
(cat results.nmap | grep 'http' | cut -d "/" -f 1)
EDIT2: I realised the method mentioned in my first edit is not optimal when processing multiple results as I then have a list of IP's from the .nmap, and a list of ports from the .gnmap. I have found a good solution to my problem using a single file. see below:
#!/bin/bash
httpalt=$(cat test.gnmap | awk '/\/http-alt\// {for(i=5;i<=NF;i++)if($i~"/open/.+/http-alt/"){sub("/.*","",$i); print "http://"$2":"$i}}')
if [ -z "$httpalt" ]
then
echo "No http-alt servers found"
else
echo "http-alt servers found"
echo $httpalt
printf "\n"
fi
http=$(cat test.gnmap | awk '/\/http\// {for(i=5;i<=NF;i++)if($i~"/open/.+/http/"){sub("/.*","",$i);print "http://"$2":"$i}}')
if [ -z "$http" ]
then
echo "No http servers found"
else
echo "http servers found"
echo $http
printf "\n"
fi
https=$(cat test.gnmap | awk '/\/https\// {for(i=5;i<=NF;i++)if($i~"/open/.+/https/"){sub("/.*","",$i); print "https://"$2":"$i}}')
if [ -z "$https" ]
then
echo "No http servers found"
else
echo "https servers found"
echo $https
printf "\n"
fi
echo ----
printf "All ip:webapps \n"
webserver=$(echo "$httpalt $http $https" | sed -e 's/\s\+/,/g'|sed -z 's/\n/,/g;s/,$/\n/')
if [[ ${webserver::1} == "," ]]
then
webserver="${webserver#?}"
else
echo 0; fi
for webservers in $webserver; do
echo $webservers
done
echo $https
https=$(echo "$https" | sed -e 's/\s\+/,/g'|sed -z 's/\n/,/g;s/,$/\n/')
echo $https
mkdir https
mkdir ./https/nikto/
mkdir ./https/dirb/
for onehttps in ${https//,/ }
do
echo "Performing Dirb and nikto for https"
dirb $onehttps > ./https/dirb/https_dirb
nikto -url $onehttps > ./https/nikto/https_nitko
done
mkdir http
mkdir ./http/nikto
mkdir ./http/dirb/
for onehttp in ${http//,/ }
do
echo $onehttp
echo "Performing Dirb for http"
dirb $onehttp >> ./http/dirb/http_dirb
nikto -url $onehttp >> ./http/nikto/http_nikto
done
mkdir httpalt
mkdir httpalt/nikto/
mkdir httpalt/dirb/
for onehttpalt in ${httpalt//,/ }
do
echo "Performing Dirb for http-alt"
dirb $onehttpalt >> ./httpalt/dirb/httpalt_dirb
nikto -url $onehttpalt >> ./httpalt/nikto/httpalt_nikto
done
This will check for any http, https, and http-alt servers, store them in a variable, check for duplicates and remove any trailing commas at the begining, It is far from perfect, but is a good solution for now!

Just want to share a brilliant open source tool on GitHub that can be used to easily parse NMAP XML files.
https://github.com/honze-net/nmap-query-xml
I use some of the python code to extract http/https URLs from the nmap xml file.
# pip3 install python-libnmap
from libnmap.parser import NmapParser
def extract_http_urls_from_nmap_xml(file):
    try:
        report = NmapParser.parse_fromfile(file)
        urls = []
    except IOError:
        print("Error: Nmap XML file %s not found. Quitting!" % file)
        sys.exit(1)
    for host in report.hosts:
        for service in host.services:
            filtered_services = "http,http-alt,http-mgmt,http-proxy,http-rpc-epmap,https,https-alt,https-wmap,http-wmap,httpx"
            if (service.state == "open") and (service.service in filtered_services.split(",")):
                line = "{service}{s}://{hostname}:{port}"
                line = line.replace("{xmlfile}", nmap_file)
                line = line.replace("{hostname}", host.address if not host.hostnames else host.hostnames[0]) # TODO: Fix naive code.
                line = line.replace("{hostnames}", host.address if not host.hostnames else ", ".join(list(set(host.hostnames)))) # TODO: Fix naive code.
                line = line.replace("{ip}", host.address)
                line = line.replace("{service}", service.service)
                line = line.replace("{s}", "s" if service.tunnel == "ssl" else "")
                line = line.replace("{protocol}", service.protocol)
                line = line.replace("{port}", str(service.port))
                line = line.replace("{state}", str(service.state))
                line = line.replace("-alt", "")
                line = line.replace("-mgmt", "")
                line = line.replace("-proxy", "")
                line = line.replace("-rpc-epmap", "")
                line = line.replace("-wmap", "")
                line = line.replace("httpx", "http")
                urls.append(line)
    return list(dict.fromkeys(urls))

printf "Host: 127.0.0.1 (localhost) Ports: 3390/open/tcp//dsc///, 5901/open/tcp//vnc-1///, 8000/open/tcp//http-alt/// Ignored State: closed (65532)" > file
cat file | tr -s ' ' | tr ',' '\n' | sed s'#^ ##g' > f2
string=$(sed -n '3p' f2 | cut -d' ' -f1)
It is only horizontal search which is difficult; vertical is easy. You can get any string out of any text you like, as long as you can get the string on its' own line, and then determine which line you need to print.
You only need complex regular expressions if you are relying exclusively on horizontal search. In almost all cases, as long as your substring is on its' own line, cut can take you the rest of the way.

Related

bash - using a command line argument (hostname) to run an external command

First time post, please forgive any missing information.
I have a script that is supposed to work with icinga. I need icinga to log into my Linux box and run a command like "script ". The script will then run a command to that hostname like sudo /etc/init.d/apache2 status then report back "running or unused" and an exit status of 0 or 2.
I'm wondering how I could add another command and have it one or the other run depending on what hostname it's given. Half of them need apache2 to be running and the other half need to have a process called dss to be running. I'd rather not have two separate scripts. Here is the working script and sorry it's sloppy but I haven't done any clean up and I'm not real good at bash yet.
so the user would run the script ./chkdss2 or
#!/bin/bash
ec=0
ec1=2
var3=run
var4=unused
for host in "$#"
do
var1=`ssh $host sudo /etc/init.d/dss status|awk '{print $6}'`
var2="$( echo $var1 | cut -c 3-5 )"
if [[ "$var2" == "$var3" ]]; then
echo "$host is running"
echo $ec
else
echo "$host is not running"
echo $ec1
fi
done
There are a couple ways to test if a particular hostname is for apache or dss. You only need to have a list of hostnames for each case, and check if the received hostnames are included in said lists.
Method 1: using arrays
#!/bin/bash
# Method 1, using array lists of hosts
apachehosts=('ap1' 'ap2' 'ap3')
dsshosts=('dss1' 'dss2' 'dss3')
for host in "$#"
do
if printf '%s\n' "${apachehosts[#]}" | grep -Fxq "$host"
then
echo "$host: APACHE HOST"
elif printf '%s\n' "${dsshosts[#]}" | grep -Fxq "$host"
then
echo "$host: DSS HOST"
else
echo "ERROR, $host: unknown host"
fi
done
To modify the lists of hosts, simply add or remove values in the declaration of arrays apachehosts and dsshosts.
Method 2: using case
#!/bin/bash
# Method 2, using case
for host in "$#"
do
case "$host" in
'ap1'|'ap2'|'ap3')
echo "CASE, $host: APACHE HOST"
;;
'dss1'|'dss2'|'dss3')
echo "CASE, $host: DSS HOST"
;;
*)
echo "ERROR CASE, $host: unknown host"
;;
esac
done
Here, you edit the patterns in each case.
Method 3: using if
#!/bin/bash
# Method 3, using if
for host in "$#"
do
if [[ "$host" == 'ap1' || "$host" == 'ap2' || "$host" == 'ap3' ]]
then
echo "IF, $host: APACHE HOST"
elif [[ "$host" == 'dss1' || "$host" == 'dss2' || "$host" == 'dss3' ]]
then
echo "IF, $host: DSS HOST"
else
echo "IF, $host: unknown host"
fi
done
Here you modify the if conditions. I prefer the other methods, since this one is more complicated to edit, it is not as clear, especially if your list of hosts is long.
Method 4: condition on the hostnames
If you are lucky, there is some pattern to your hostnames. Ex. all apache servers start with letters ap, all your dss servers include dss in the name, ...
You can then simply use 2 if statements to decide which is which.
#!/bin/bash
# Method 4, patterns
for host in "$#"
do
if [[ $(echo "$host" | grep -c -e "^ap") -ne 0 ]]
then
echo "PATTERNS, $host: APACHE HOST"
elif [[ $(echo "$host" | grep -c -e "dss") -ne 0 ]]
then
echo "PATTERNS, $host: DSS host"
else
echo "PATTERNS, $host: unknown host"
fi
done
Note: hostname apdss1 would come out as an Apache server here. Previous methods would respond "unknown host". You patterns must be strict enough to avoid mismatches.
I had a similar task to get few report items using single ssh request.
I had to retrieve in singel ssh command:
Full hostname (FQDN)
Linux version
IP address of its Docker host if exist, or "none"
I got my script to work in 3 stage.
1. Get multiple lines of information from remote host
ssh -q dudi-HP-Compaq-Elite-8300-MT <<< '
date +%F:%T # line 1: time stamp
hostname -f # line 2: hostname
awk "/DESCR/{print \$3}" /etc/lsb-release # line 3 : host linux distribution version
ip a | awk "/inet / && !/127.0.0.1/{sub(\"/.*\",\"\",\$2);printf(\"%s \", \$2)}" # line 4: list IP address to the host
'
Results:
2022-03-05:22:22:21
dudi-HP-Compaq-Elite-8300-MT
20
192.168.2.111 192.168.122.1 172.17.0.1
2. Process multiple lines of information from remote host
Read lines of information from remote host, into an array sshResultsArr.
readarray -t sshResultsArr < <(ssh -q dudi-HP-Compaq-Elite-8300-MT <<< '
date +%F:%T # line 1: time stamp
hostname -f # line 2: hostname
awk "/DESCR/{print \$3}" /etc/lsb-release # line 3 : host linux distribution version
ip a | awk "/inet / && !/127.0.0.1/{sub(\"/.*\",\"\",\$2);printf(\"%s \", \$2)}" # line 4: list IP address to the host
')
hostname=${sshResultsArr[1]}
osVersion=${sshResultsArr[2]}
hasDockerIp=$(grep -Eo "172(.[[:digit:]]{1,3}){3}" <<< "${sshResultsArr[3]}") # find IP starting with 172
hasDockerIp=${hasDockerIp:="none"} # if not found IP set to "NONE"
printf "%s \t OS version: %s \t has Docker IP: %s\n" "$hostname" "$osVersion" "$hasDockerIp"
Result:
dudi-HP-Compaq-Elite-8300-MT OS version: 20 has Docker IP: 172.17.0.1
3. Process each remote host in a loop
#!/bin/bash
for host in "$#"; do
readarray -t sshResultsArr < <(ssh -q $host <<< '
date +%F:%T # line 1: time stamp
hostname -f # line 2: hostname
awk "/DESCR/{print \$3}" /etc/lsb-release # line 3 : host linux distribution version
ip a | awk "/inet / && !/127.0.0.1/{sub(\"/.*\",\"\",\$2);printf(\"%s \", \$2)}" # line 4: list IP address to the host
')
hostname=${sshResultsArr[1]}
osVersion=${sshResultsArr[2]}
hasDockerIp=$(grep -Eo "172(.[[:digit:]]{1,3}){3}" <<< "${sshResultsArr[3]}") # find IP starting with 172
hasDockerIp=${hasDockerIp:="none"} # if not found IP set to "NONE"
printf "%s \t OS version: %s \t has Docker IP: %s\n" "$hostname" "$osVersion" "$hasDockerIp"
done
I was able to take a little bit from the answers I received and put together something that works well. Thank you all for your answers.
for host in "$#"
do
case "$host" in
('vho1uc1-primary'|'vho1uc2-backup'|'vho2uc1-primary'|'vho2uc2-backup'|'vho3uc1-primary'|'vho3uc2-backup'|'vho10uc1-primary')
var1=`ssh "$host" sudo /etc/init.d/apache2 status|awk '{print $4}'`
var2="$( echo $var1 | cut -c 3-5 )"
if [[ "$var2" == "$var3" ]]; then
echo "Apache2 on $host is running"
echo "0"
else
echo "Apache2 on $host is not running"
echo "2"
fi
;;
*)
esac
done

Concatenate String from inside an Array to another String in Bash

I have different .ovpn files with vpn configurations. I wrote a script, that checks the load of available servers and trys to connect with the one with the least load.
My problem is that the string variables who describe the Connection NetworkManager will choose, are not recognized by nmcli when they are called from an array within a script.
I concatenate and connect in this way in the script:
top="${TOP_TEN[$iters]}.tcp"
nmcli con up $top --ask
Here nmcli throws an unknown connection error. I tried echoing the $top variable before and tried to connect manually which works just fine. The variable in this example is "bg52.nordvpn.com.tcp".
Then i wrote another 4 liner to see if my concatenation messes something up:
TOP_TEN=(vpn1 vpn2 bg52.nordvpn.com vpn4)
echo ${TOP_TEN[2]}.tcp
top="${TOP_TEN[2]}.tcp"
nmcli con up $top --ask
Also here it also works just fine.
Does anybody understand why my ovpn connection is not recognized when passed as a string from a bash array?
Here is the complete script if it helps you better to understand the problem.
#!/usr/bin/bash
OVPN_FILES="/usr/lib/python3.10/site-packages/openpyn/files/ovpn_tcp"
COUNTRY_CODE=$1
TOP_TEN=()
function get_top_servers() {
TOP_TEN=()
while IFS= read -r server; do
TOP_TEN+=( $server )
done < <( nordvpn-server-find -n 10 -l $1 | tail -n 10 | tr -s " " | cut -d\ -f 1 )
}
function get_rand_ccode() {
rand_countr_code=`ls $OVPN_FILES | cut -c1-2 | uniq | shuf | head -n 1`
}
function old_con_down() {
ACTIVE_VPN=`nmcli c show --active | grep vpn | tr -s " " | cut -d\ -f 2`
if [ ! -z "$ACTIVE_VPN" ]; then
echo "Found active connection. Deactivating $ACTIVE_VPN ... "
nmcli con down $ACTIVE_VPN
# sleep 3
fi
}
if [ -z "$COUNTRY_CODE" ]; then
echo "set ccode"
COUNTRY_CODE=$(get_rand_ccode)
fi
echo "Get Top Servers for $COUNTRY_CODE"
get_top_servers $COUNTRY_CODE
iters=0
while [ 1 ]
do
if (( $iters > 9 )); then
COUNTRY_CODE=$(get_rand_ccode)
get_top_servers $COUNTRY_CODE
iters=0
fi
old_con_down
echo "Fastest Server is ..."
top="${TOP_TEN[$iters]}.tcp"
echo "${TOP_TEN[#]}"
nmcli con up $top --ask
if [ -z $? ]; then
exit 1
else
((iters++))
fi
done
The nordvpn-server-find i'm using inside the script was echoing also Control Sequences for bold and colored fonts. I had to strip them of, before feeding the output into nmcli.

for loop: commands start from begin every time

I have write the following bash script to check list of domains from domain.list and multiple directories from dir.list.
# is the first domain, it first tries to find file at
http://example.com
if success script finish and exit no problem.
if failed it go to check it at
https://example.com
if ok , script finish and exit,
if not
check for it at
http://example.com/$list of different directories.
If file found script finished and exit , if failed to find
then go to check it at
https://example.com/$list of different directories
But the problem , when the first check failed and second check failed , it goes to third check , but it keep looping , at third command and 4th command, tell it find file or list of directories finished.
I want the script when reach the 3rd command to run it and check for it at list of directories tell the list finish and not to go for the 4th command tell it finished
As at my script it keep checking for single domain at multiple directories and every time to check a new directory it start the whole script from the bagain and run the 1st command and 2nd command again from the begin and I do not need that, big loss of time
Thanks
#!/bin/bash
dirs=(`cat dir.list`)
doms=( `cat domain.list`)
for dom in "${doms[#]}"
do
for dir in "${dirs[#]}"
do
target1="http://${dom}"
target2="https://${dom}"
target3="http://${dom}/${dir}"
target4="https://${dom}/${dir}"
if curl -s --insecure -m2 ${target1}/test.txt | grep "success" > /dev/null ;then
echo ${target1} >> dir.result
break
elif curl -s --insecure -m2 ${target2}/test.txt | grep "success" > /dev/null;then
echo ${target2} >> dir.result
break
elif curl -s --insecure -m2 ${target3}/test.txt | grep "success" > /dev/null; then
echo ${target3} >> dir.result
break
elif curl -s --insecure -m2 ${target4}/test.txt | grep "success" > /dev/null ; then
echo ${target4} >> dir.result
break
fi
done
done
Your code is sub-optimal; if you have a list of 5 'dir' values, you check 5 times whether http://${domain}/test.txt exists — but the chances are that if it didn't exist the first time, it doesn't exist on the other times either.
You use dir to indicate a sub-directory name, but your code uses http://${dom}:${dir} rather than the more normal http://${dom}/${dir}. Technically, what follows the colon up to the first slash is a port number, not a directory. I'm going to assume this is a typo and the colon should be replaced by a slash.
Generally, do not use the back-tick notation; use $(…) instead. Avoid swathes of repeated code, too.
I think you can compress your script down to something like this:
#!/bin/bash
dirs=( $(cat dir.list) )
file=test.txt
fetch_file()
{
if curl -s --insecure -m2 "${1:?}/${file}" | grep "success" > /dev/null
then
echo "${1}"
return 0
else
return 1
fi
}
for dom in $(cat domain.list)
do
for proto in http https
do
fetch_file "${proto}://{$dom}" && break
for dir in "${dirs[#]}"
do
fetch_file "${proto}://${dom}/${dir}" && break 2
done
done
done > dir.result
If the domain list is massive, you could consider using while read dom; do …; done < domain.list instead of using the $(cat domain.list). It would be feasible, and possibly even sensible, to define variable site="${proto}://${dom}" and then use that in the invocations of fetch_file.
You can use this script:
while read dom; do
while read dir; do
target1="http://${dom}"
target2="https://${dom}"
target3="http://${dom}:${dir}"
target4="https://${dom}:${dir}"
if curl -s --insecure -m2 ${target1}/test.txt | grep -q "success"; then
echo ${target1} >> dir.result
break 2
elif curl -s --insecure -m2 ${target2}/test.txt | grep -q "success"; then
echo ${target2} >> dir.result
break 2
elif curl -s --insecure -m2 ${target3}/test.txt | grep -q "success"; then
echo ${target3} >> dir.result
break 2
elif curl -s --insecure -m2 ${target4}/test.txt | grep -q "success"; then
echo ${target4} >> dir.result
break 2
fi
done < dir.list
done < domain.list

Check URL and mail to webadmin Bash Script

Here is my code which will hit URL and check URL is working or not and will mail to respective webadmins
#!/bin/bash
curl -s --head http://myurl | head -n 1 | grep "HTTP/1.[01] [23].." > /dev/null
if [ $? -eq 0 ]
then
url1="myurl2 is working fine"
else
url1="myurl2 is not working"
fi
curl -s --head http://myurl2 | head -n 1 | grep "HTTP/1.[01] [23].." > /dev/null
if [ $? -eq 0 ]
then
url2="myurl is working fine"
else
url2="myurl is not working"
fi
exec 1<>/dev/tcp/127.0.0.1/25
a=$(cat <<"MAILEND"
HELO local.domain.name
MAIL FROM: <send#mydomain.com>
RCPT TO: <recieve#mail2.com>
DATA
From: send#mydomain.com
To: recieve#mail2.com
Subject: test
$url1 $url2.
.
QUIT
.
MAILEND
)
IFS='
'
declare -a b=($a)
for x in "${b[#]}"
do
echo $x
sleep 1
done
How ever in Mail I am getting $url1 $url2
This must be due to $url1 & $url2 is not getting substituted in line $a
Can Someone please help
let me mention one thing "mail" or "sendmail" mails get spamed in my domain so sending mails with above method only works fine
I am expecting "myurl is working" " myurl2 is not working"
as myurl2 httpd service I have already stopped
Thanks
Replace
cat <<"MAILEND"
with
cat <<MAILEND
Putting quotes around the identifier to a "here document" signals to the shell not to expand any variables. This is explained in the "Here Documents" section of man bash
This is intended as an aside, but since comments don't support code formatting, posting this refactoring here.
( cat <<____HERE
From: send#mydomain.com
To: recieve#mail2.com
Subject: test
____HERE
while read label url; do
if curl -s --head "$url" | head -n 1 | grep "HTTP/1.[01] [23].." > /dev/null
then
echo "$label is working fine"
else
echo "$label is broken"
fi
done <<____HERE |
myurl http://myurl2
myurl2 http://myurl
____HERE
) | sendmail -oi -t
I am assuming that the labels cross-matching each other's URLs is unintentional and/or incidental and/or beyond my limited comprehension.

Bind9 DNS Zone Transfer Script - Bash script to avoid duplicates

I created a bash script to transfer my zones between my primary and secondary DNS server.
It downloads my zone list from the primary and checks for any new zones and then downloads and inserts those zone files into the zone directory and into the .local file for bind.
The problem I have is that if the zone file does not exist, the script will enter the details into the .local regardless of if this config already exists or not.
Can someone help me out to distinguish between zones that already exist and simply download the zone file.
I have pasted my script below and if anyone has any queries on how it works, please feel free to ask.
(can someone wrap the code please, it never works properly for me in any browser I try!)
#!/bin/sh
NAMED="/etc/bind/named.conf.local"
TMPNAMED="/tmp/zns-441245.temp"
TMPZONEFILE="/tmp/zones.txt"
TMP="/tmp/zns-732.temp"
ZONELOCATION="/var/cache/bind"
IGNORE=`cat ignore.txt`
logger DNS Update script running...
echo -n "Checking for new named.conf... "
wget -q http://91.121.75.205:10801/named/named.conf -O $TMPNAMED
if [ -e $TMPNAMED ]
then
echo "done."
else
echo "no new data!"
exit
fi
echo -n "Generating zone names... "
grep "^zone" $TMPNAMED | cut -d " " -f "2" | cut -d "\"" -f 2 > $TMPZONEFILE
sed '1,5d' $TMPZONEFILE > $TMP
mv $TMP $TMPZONEFILE
echo "done. ("$TMPZONEFILE")"
echo "Generating zone info... "
grep -vf ignore.txt $TMPZONEFILE | while read ZONE; do
echo -n "Checking for $ZONELOCATION/$ZONE.db "
if [ -e $ZONELOCATION/$ZONE.db ]
then
echo "[ exists ]"
else
export updates="yes"
echo "[ doesn't exist ]"
echo "New zone available ($ZONE)... "
echo "zone \"$ZONE\" {
type slave;
file \"$ZONELOCATION/$ZONE.db\";
masters { 91.121.75.205; };
allow-notify { 91.121.75.205; };
};" >> $NAMED
fi
done
echo "Updating Bind configuration... "
/etc/init.d/bind9 restart
rm $TMPZONEFILE
rm $TMPNAMED
One problem may be that your wget creates a file regardless of whether there's a source file so checking for existence will always be true.
if [ -s $TMPNAMED ]
then
echo "done." # file exists AND has data
else
echo "no new data!"
exit
fi
will test to see if it's empty or non-existent and exit if so. This may be an issue with your if [ -e $ZONELOCATION/$ZONE.db ] as well.
sed or awk could do all of this in one line:
grep "^zone" $TMPNAMED | cut -d " " -f "2" | cut -d "\"" -f 2 > $TMPZONEFILE
sed '1,5d' $TMPZONEFILE > $TMP
but I would need to see some sample data to offer a solution.
Simplified quoting:
echo "done. ($TMPZONEFILE)"
You're not using the IGNORE variable or the updates variable. I don't see any reason to export it. Also, if you are relying on it elsewhere, its value won't survive once the while loop exits since piping something (grep in this case) into while sets up a subshell. It may be better to do one of these:
Bash:
while ...
do
...
done <(grep -vf ignore.txt $TMPZONEFILE)
sh:
grep -vf ignore.txt $TMPZONEFILE > tmp.out
while ...
do
...
done < tmp.out
I recommend using mktemp or tempfile to create temporary files, by the way.
This might be more readable and allows you to include quotes without having to escape them:
cat << EOF >> "$NAMED"
zone "$ZONE" {
type slave;
file "$ZONELOCATION/$ZONE.db";
masters { 91.121.75.205; };
allow-notify { 91.121.75.205; };
};
EOF
It's always a good habit to quote variables that contain filenames.
If you're going to all of that trouble to synchronise named.conf you might just as well rsync the whole config including the zone files, and not bother using zone transfers between primary and secondary.
It's by no means mandatory to use AXFR to slave servers. If you've got administrative control over all of the servers for a zone it's quite acceptable to treat them all as masters.

Resources