18

Разбор скрипта для командной строки Linux. Часть 2

В прошлой части разбора нам удалось сократить и сделать код более читабельным. В этой части, мы попробуем изучить используемые в скрипте инструменты и сделать код ещё лучше.


Хоть скрипт теоретически был рассчитан на любые доменные имена. На деле, проверка на доменной имя pikabu.ru, дала следующий результат:

91.228.152.0 - 91.228.155.255
MNT-FIRSTCOLO
91.228.152.0/22

Как видим, 2-я строчка тут явно лишняя. Из этого делаем вывод, что скрипт не работает правильно для всех доменов. В вопросе нахождения сетей, которые принадлежат домену, я увы недостаточно компетентен. Поэтому моей целью будет лишь добиться схожего результата и разобрать общие проблемы, которые актуальны для большинства скриптов.

И так, код который мы получили в конце первой части:

#!/bin/bash

####PART 1####

if [[ -z "$1" ]]; then
echo "Error: missing argument" 1>&2 ; exit 1
fi

f_out="$(mktemp)"

f_tmp="$(mktemp)"

trap "rm -f $f_out $f_tmp" EXIT

####PART 2####

echo "*********************************************"
echo "Get A records from DNS:"
# Octet regex
o_re="(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
# IP regex
ip_re="$o_re\.$o_re\.$o_re\.$o_re"

dig $1 A | grep "^$1" | grep -o -E "$ip_re" | tee "$f_out"

dig $1 A | grep "^www.$1" | grep -o -E "$ip_re" | tee -a "$f_out"

####PART 3####

echo "*********************************************"
echo "Get NS records from DNS:"
dig $1 NS | grep "^$1" | awk {'print $NF}' | while read nsserv
do
nsname=${nsserv:0:${#nsserv}-1}
echo "=================================="
echo "NS: $nsname"
dig @$nsname $1 A | grep "^$1" | grep -o -E "$ip_re" | tee -a $f_out
done
####PART 4####
echo "*********************************************"
echo "Resolve ip range from whois service:"
sort -h $f_out | uniq > $f_tmp
rm $f_out
cat $f_tmp | while read ip
do
echo "Get ip range for $ip"
whois $ip | grep -E -i "inetnum|route|netrange|cidr" >> $f_out
done


####PART 5####

echo "*********************************************"

echo "Result"
echo "*********************************************"
sort $f_out | uniq | while read range
do
echo "${range:16}"
done

Плюс ко всему, код был разделён на 5 частей, для лучшей навигации.

Для начала, вернемся ко 2-ой части кода. А конкретно к этим строкам:

dig $1 A | grep "^$1" | grep -o -E "$ip_re" | tee "$f_out"
dig $1 A | grep "^www.$1" | grep -o -E "$ip_re" | tee -a "$f_out"

Лишь на данном моменте тут была замечена ошибка. Предположительно, автор хотел получить данные как по доменному имени vk.com, так и www.vk.com, однако забыл дописать это программе dig. Внесем правки:

dig $1 A | grep "^$1" | grep -o -E "$ip_re" | tee "$f_out"
dig www.$1 A | grep "^www.$1" | grep -o -E "$ip_re" | tee -a "$f_out"

Далее было замечено, что программа dig умеет принимать множество доменных имен, воспользуемся этим:

dig {www.,}$1 A | grep -E "^(www.|)$1" | grep -o -E "$ip_re" | tee "$f_out"

Уже лучше, вместо 2-ух строк, теперь лишь одна.


Программа dig выписывает множество лишней информации:

; <<>> DiG 9.9.5-9+deb8u6-Debian <<>> vk.com A
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10732
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1280
;; QUESTION SECTION:
;vk.com. IN A
;; ANSWER SECTION:
vk.com. 33 IN A 87.240.131.118
vk.com. 33 IN A 87.240.131.117
vk.com. 33 IN A 87.240.131.120
;; Query time: 0 msec
;; SERVER: 192.168.3.1#53(192.168.3.1)
;; WHEN: Fri Jun 24 16:27:13 CEST 2016
;; MSG SIZE rcvd: 83

Автор дальнейшими действиями извлекает из этого вывода ip адреса. Но если посмотреть мануал к программе dig, то мы увидим что есть опция +short, которая выписывает лишь ip адреса, без лишней информации. Так, мы можем сократить команду, всего до:

dig +short {www.,}$1 A | tee "$f_out"

И как следствие, мы получаем нужный нам результат, без лишних команд и регулярных выражений. Поэтому обычно советую, перед тем как писать сложные конструкции, сначала изучите инструмент с которым вы работаете.

Теперь можем перейти к 3-ей части, начнем с первых команд:

dig $1 NS | grep "^$1" | awk {'print $NF}'

Снова используя параметр +short, получится:

dig +short $1 NS

Далее, результат с этой команды посылается в цикл while:

dig +short $1 NS | while read nsserv
do
nsname=${nsserv:0:${#nsserv}-1}
echo "=================================="
echo "NS: $nsname"
dig @$nsname $1 A | grep "^$1" | grep -o -E "$ip_re" | tee -a $f_out
done

Думаю сразу видно, что к последней команде в цикле можно применить опцию +short:

dig +short @$nsname $1 A | tee -a $f_out

Так мы опять избавились от лишних действий.


Но вернемся к перемененной nsname, тут автор хочет удалить точку на конце переменной. В коде это было сделано без внешних программ(sed,awk,...), что очень хорошо, но можно ещё проще:

nsname=${nsserv:0:-1}

Подробнее о всех возможностях работы со значениями переменных, можете прочитать на bash-hackers.org.

В 4-ой части кода, есть не очень красивые решения, которые связаны с временными файлами, мы исправим это во время избавления от временных файлов. Так же не понятно, зачем в sort был использован параметр -h(human-numeric-sort). Т.к. sort использован только для дальнейшего uniq, то можно использовать sort  без параметров. Но мы будем использовать более правильную сортировку ip адресов:

sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 $f_out | uniq > $f_tmp

В данном случае, ip адреса будут отсортированы по числовым значениям каждого столбца.

5-я часть кода, это только вывод результата, возможно я бы по другому выписал сети, т.к. выписывание после 16 символа, это не самый лучший вариант, но это не столь важно.


Переменные o_re и ip_re, нам уже ни к чему, поэтому можем их удалить.


После всех правок код выглядит следующим образом:

#!/bin/bash


####PART 1####

if [[ -z "$1" ]]; then

echo "Error: missing argument" 1>&2 ; exit 1

fi


f_out="$(mktemp)"

f_tmp="$(mktemp)"


trap "rm -f $f_out $f_tmp" EXIT


####PART 2####

echo "*********************************************"

echo "Get A records from DNS:"


dig +short {www.,}$1 A | tee "$f_out"


####PART 3####

echo "*********************************************"

echo "Get NS records from DNS:"

dig +short $1 NS | while read nsserv

do

nsname=${nsserv:0:-1}

echo "=================================="

echo "NS: $nsname"

dig +short @$nsname $1 A | tee -a $f_out

done


####PART 4####

echo "*********************************************"

echo "Resolve ip range from whois service:"

sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 $f_out | uniq > $f_tmp

rm $f_out

cat $f_tmp | while read ip

do

echo "Get ip range for $ip"

whois $ip | grep -E -i "inetnum|route|netrange|cidr" >> $f_out

done


####PART 5####

echo "*********************************************"

echo "Result"

echo "*********************************************"

sort $f_out | uniq | while read range

do

echo "${range:16}"

done


В следующей(заключительной) части, мы избавимся от временных файлов и немного поработаем с выводом. А пока подумайте, почему лучше не использовать echo в скриптах? И ради примера, есть задачка на echo в комментариях.


Спасибо за внимание, надеюсь данный пост окажется для вас полезным.


P.s. если был непонятен как-то шаг или конструкция в коде, то жду ваших вопросов в комментариях.

GNU/Linux

1.2K постов15.6K подписчиков

Правила сообщества

Все дистрибутивы хороши.

Будьте людьми.

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества

Недвижимость и ремонт

Теги

Популярные авторы

Сообщества