Bash script, чтобы перечислить все IP-адреса в префиксе
Я пытаюсь создать script, чтобы я мог ввести набор префиксов, которые затем будут перечислять все IP-адреса в префиксах (включая сеть/хост/широковещание).
Пример:
./convert-prefix-to-IPs.sh 192.168.0.0/23 203.20.0.0/16
192.168.0.0
192.168.0.1
...
192.168.0.255
192.168.1.0
..
192.168.1.255
203.20.0.0
..
203.20.255.255
Есть несколько сценариев python/perl, которые могут это сделать, но я надеюсь иметь простой bash script, поскольку он может использоваться в системах без perl/python (да.. я знаю.. )
Ответы
Ответ 1
Вот что я использую для генерации всех IP-адресов в данном блоке CIDR
nmap -sL 10.10.64.0/27 | awk '/Nmap scan report/{print $NF}'
Просто так просто
Приведенная выше команда выводит это
10.10.64.0
10.10.64.1
10.10.64.2
10.10.64.3
10.10.64.4
10.10.64.5
10.10.64.6
10.10.64.7
10.10.64.8
10.10.64.9
10.10.64.10
10.10.64.11
10.10.64.12
10.10.64.13
10.10.64.14
10.10.64.15
10.10.64.16
10.10.64.17
10.10.64.18
10.10.64.19
10.10.64.20
10.10.64.21
10.10.64.22
10.10.64.23
10.10.64.24
10.10.64.25
10.10.64.26
10.10.64.27
10.10.64.28
10.10.64.29
10.10.64.30
10.10.64.31
Ответ 2
Я тоже искал это решение и обнаружил, что @scherand script отлично работает. Я также добавил к этому script, чтобы предоставить вам больше возможностей. Файл справки ниже.
ЭТО script РАСШИРЯЕТ АДРЕС CIDR.
СИНТАКСИС
./cidr-to-ip.sh [OPTION(only one)] [STRING/FILENAME]
ОПИСАНИЕ
-h Отображает этот экран справки
-f Задает проверку границы сети при задании STRING (s)
-i Будет считываться из входного файла (файл должен содержать один CIDR для каждой строки) (без проверки границ сети)
-b Будет делать то же самое, что и -i, но с проверкой границ сети
Примеры
./cidr-to-ip.sh 192.168.0.1/24
./cidr-to-ip.sh 192.168.0.1/24 10.10.0.0/28
./cidr-to-ip.sh -f 192.168.0.0/16
./cidr-to-ip.sh -i inputfile.txt
./cidr-to-ip.sh -b inputfile.txt
#!/bin/bash
############################
## Methods
############################
prefix_to_bit_netmask() {
prefix=$1;
shift=$(( 32 - prefix ));
bitmask=""
for (( i=0; i < 32; i++ )); do
num=0
if [ $i -lt $prefix ]; then
num=1
fi
space=
if [ $(( i % 8 )) -eq 0 ]; then
space=" ";
fi
bitmask="${bitmask}${space}${num}"
done
echo $bitmask
}
bit_netmask_to_wildcard_netmask() {
bitmask=$1;
wildcard_mask=
for octet in $bitmask; do
wildcard_mask="${wildcard_mask} $(( 255 - 2#$octet ))"
done
echo $wildcard_mask;
}
check_net_boundary() {
net=$1;
wildcard_mask=$2;
is_correct=1;
for (( i = 1; i <= 4; i++ )); do
net_octet=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
if [ $(( $net_octet&$mask_octet )) -ne 0 ]; then
is_correct=0;
fi
fi
done
echo $is_correct;
}
#######################
## MAIN
#######################
OPTIND=1;
getopts "fibh" force;
shift $((OPTIND-1))
if [ $force = 'h' ]; then
echo ""
echo -e "THIS SCRIPT WILL EXPAND A CIDR ADDRESS.\n\nSYNOPSIS\n ./cidr-to-ip.sh [OPTION(only one)] [STRING/FILENAME]\nDESCRIPTION\n -h Displays this help screen\n -f Forces a check for network boundary when given a STRING(s)\n -i Will read from an Input file (no network boundary check)\n -b Will do the same as –i but with network boundary check\n\nEXAMPLES\n ./cidr-to-ip.sh 192.168.0.1/24\n ./cidr-to-ip.sh 192.168.0.1/24 10.10.0.0/28\n ./cidr-to-ip.sh -f 192.168.0.0/16\n ./cidr-to-ip.sh -i inputfile.txt\n ./cidr-to-ip.sh -b inputfile.txt\n"
exit
fi
if [ $force = 'i' ] || [ $force = 'b' ]; then
old_IPS=$IPS
IPS=$'\n'
lines=($(cat $1)) # array
IPS=$old_IPS
else
[email protected]
fi
for ip in ${lines[@]}; do
net=$(echo $ip | cut -d '/' -f 1);
prefix=$(echo $ip | cut -d '/' -f 2);
do_processing=1;
bit_netmask=$(prefix_to_bit_netmask $prefix);
wildcard_mask=$(bit_netmask_to_wildcard_netmask "$bit_netmask");
is_net_boundary=$(check_net_boundary $net "$wildcard_mask");
if [ $force = 'f' ] && [ $is_net_boundary -ne 1 ] || [ $force = 'b' ] && [ $is_net_boundary -ne 1 ] ; then
read -p "Not a network boundary! Continue anyway (y/N)? " -n 1 -r
echo ## move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_processing=1;
else
do_processing=0;
fi
fi
if [ $do_processing -eq 1 ]; then
str=
for (( i = 1; i <= 4; i++ )); do
range=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
range="{$range..$(( $range | $mask_octet ))}";
fi
str="${str} $range"
done
ips=$(echo $str | sed "s, ,\\.,g"); ## replace spaces with periods, a join...
eval echo $ips | tr ' ' '\n'
else
exit
fi
done
Ответ 3
Этот короткий скрипт напечатает все IP-адреса в диапазоне CIDR в несколько строк Bash. (Я назвал его prips
честь команды Ubuntu с тем же именем. Очевидно, что если эта команда доступна, используйте ее.)
prips() {
local cidr=$1 ; local lo hi a b c d e f g h
# range is bounded by network (-n) & broadcast (-b) addresses.
lo=$(ipcalc -n "$cidr" | cut -f2 -d=)
hi=$(ipcalc -b "$cidr" | cut -f2 -d=)
IFS=. read -r a b c d <<< "$lo"
IFS=. read -r e f g h <<< "$hi"
eval "echo {$a..$e}.{$b..$f}.{$c..$g}.{$d..$h}"
}
Обратите внимание, что я предполагаю версию ipcalc
RedHat Linux (Erik Troan, Preston Brown), а не версию Krischan Jodies, установленную на некоторых платформах (например, Mac OS X).
Примеры:
$ prips 10.0.0.128/27
10.0.0.128 10.0.0.129 10.0.0.130 10.0.0.131 10.0.0.132 10.0.0.133 10.0.0.134 10.0.0.135 10.0.0.136 10.0.0.137 10.0.0.138 10.0.0.139 10.0.0.140 10.0.0.141 10.0.0.142 10.0.0.143 10.0.0.144 10.0.0.145 10.0.0.146 10.0.0.147 10.0.0.148 10.0.0.149 10.0.0.150 10.0.0.151 10.0.0.152 10.0.0.153 10.0.0.154 10.0.0.155 10.0.0.156 10.0.0.157 10.0.0.158 10.0.0.159
Вычисляет правильное количество адресов в /23 сетях:
$ prips 10.0.0.0/23 | wc -w
512
Проверка нескольких из этих адресов с помощью cut:
$ prips 10.0.0.0/23 | cut -f1-10,256-266 -d' '
10.0.0.0 10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4 10.0.0.5 10.0.0.6 10.0.0.7 10.0.0.8 10.0.0.9 10.0.0.255 10.0.1.0 10.0.1.1 10.0.1.2 10.0.1.3 10.0.1.4 10.0.1.5 10.0.1.6 10.0.1.7 10.0.1.8 10.0.1.9
И, возможно, слишком медленно, но также правильно генерирует 16 миллионов адресов в сети /8:
$ date ; prips 10.0.0.0/8 | wc -w ; date
Sat May 20 18:06:00 AEST 2017
16777216
Sat May 20 18:06:41 AEST 2017
Ответ 4
nmap
полезен, но перебор.
Вместо этого вы можете использовать prips
. Избавляет вас от необходимости извлекать дополнительный вывод из nmap
и использовать awk
.
Вызов prips 192.168.0.0/23
напечатает то, что вам нужно.
Я использую следующее, чтобы пропустить сетевой адрес и трансляцию: prips "$subnet" | sed -e '1d; $d'
Припс также имеет другие полезные опции, например, возможность выборки каждого n-го IP-адреса.
Доступно через apt
, brew
, rpm
и как tar.gz
.
Ответ 5
Недавно я написал функцию для создания всех IP-адресов с заданного сетевого адреса. Функция принимает сетевой адрес в качестве аргумента и принимает маски CIDR и подсети. Затем script сохраняет все IP-адреса в переменной массива $ips.
код
function network_address_to_ips() {
# define empty array to hold the ip addresses
ips=()
# create array containing network address and subnet
network=(${1//\// })
# split network address by dot
iparr=(${network[0]//./ })
# check for subnet mask or create subnet mask from CIDR notation
if [[ ${network[1]} =~ '.' ]]; then
netmaskarr=(${network[1]//./ })
else
if [[ $((8-${network[1]})) -gt 0 ]]; then
netmaskarr=($((256-2**(8-${network[1]}))) 0 0 0)
elif [[ $((16-${network[1]})) -gt 0 ]]; then
netmaskarr=(255 $((256-2**(16-${network[1]}))) 0 0)
elif [[ $((24-${network[1]})) -gt 0 ]]; then
netmaskarr=(255 255 $((256-2**(24-${network[1]}))) 0)
elif [[ $((32-${network[1]})) -gt 0 ]]; then
netmaskarr=(255 255 255 $((256-2**(32-${network[1]}))))
fi
fi
# correct wrong subnet masks (e.g. 240.192.255.0 to 255.255.255.0)
[[ ${netmaskarr[2]} == 255 ]] && netmaskarr[1]=255
[[ ${netmaskarr[1]} == 255 ]] && netmaskarr[0]=255
# generate list of ip addresses
for i in $(seq 0 $((255-${netmaskarr[0]}))); do
for j in $(seq 0 $((255-${netmaskarr[1]}))); do
for k in $(seq 0 $((255-${netmaskarr[2]}))); do
for l in $(seq 1 $((255-${netmaskarr[3]}))); do
ips+=( $(( $i+$(( ${iparr[0]} & ${netmaskarr[0]})) ))"."$(( $j+$(( ${iparr[1]} & ${netmaskarr[1]})) ))"."$(($k+$(( ${iparr[2]} & ${netmaskarr[2]})) ))"."$(($l+$((${iparr[3]} & ${netmaskarr[3]})) )) )
done
done
done
done
}
Пример
network_address_to_ips 10.0.1.0/255.255.255.240
echo ${ips[@]}
network_address_to_ips 10.1.0.0/24
echo ${ips[@]}
Ответ 6
Я думаю, что этот маленький script, который я взломал, делает трюк. Если нет, это определенно отправная точка! Удачи.
#!/bin/bash
############################
## Methods
############################
prefix_to_bit_netmask() {
prefix=$1;
shift=$(( 32 - prefix ));
bitmask=""
for (( i=0; i < 32; i++ )); do
num=0
if [ $i -lt $prefix ]; then
num=1
fi
space=
if [ $(( i % 8 )) -eq 0 ]; then
space=" ";
fi
bitmask="${bitmask}${space}${num}"
done
echo $bitmask
}
bit_netmask_to_wildcard_netmask() {
bitmask=$1;
wildcard_mask=
for octet in $bitmask; do
wildcard_mask="${wildcard_mask} $(( 255 - 2#$octet ))"
done
echo $wildcard_mask;
}
#######################
## MAIN
#######################
for ip in [email protected]; do
net=$(echo $ip | cut -d '/' -f 1);
prefix=$(echo $ip | cut -d '/' -f 2);
bit_netmask=$(prefix_to_bit_netmask $prefix);
wildcard_mask=$(bit_netmask_to_wildcard_netmask "$bit_netmask");
str=
for (( i = 1; i <= 4; i++ )); do
range=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
range="{0..$mask_octet}";
fi
str="${str} $range"
done
ips=$(echo $str | sed "s, ,\\.,g"); ## replace spaces with periods, a join...
eval echo $ips | tr ' ' '\012'
done
Ответ 7
Я немного расширил @rberg script.
- проверьте, действительно ли сеть, которую вы предоставляете, является сетью (используйте
-f
, чтобы пропустить проверку)
- обрабатывать сетевые маски больше
/24
Возможно, это кому-то полезно.
#!/bin/bash
############################
## Methods
############################
prefix_to_bit_netmask() {
prefix=$1;
shift=$(( 32 - prefix ));
bitmask=""
for (( i=0; i < 32; i++ )); do
num=0
if [ $i -lt $prefix ]; then
num=1
fi
space=
if [ $(( i % 8 )) -eq 0 ]; then
space=" ";
fi
bitmask="${bitmask}${space}${num}"
done
echo $bitmask
}
bit_netmask_to_wildcard_netmask() {
bitmask=$1;
wildcard_mask=
for octet in $bitmask; do
wildcard_mask="${wildcard_mask} $(( 255 - 2#$octet ))"
done
echo $wildcard_mask;
}
check_net_boundary() {
net=$1;
wildcard_mask=$2;
is_correct=1;
for (( i = 1; i <= 4; i++ )); do
net_octet=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
if [ $(( $net_octet&$mask_octet )) -ne 0 ]; then
is_correct=0;
fi
fi
done
echo $is_correct;
}
#######################
## MAIN
#######################
OPTIND=1;
getopts "f" force;
shift $(( OPTIND-1 ));
for ip in [email protected]; do
net=$(echo $ip | cut -d '/' -f 1);
prefix=$(echo $ip | cut -d '/' -f 2);
do_processing=1;
bit_netmask=$(prefix_to_bit_netmask $prefix);
wildcard_mask=$(bit_netmask_to_wildcard_netmask "$bit_netmask");
is_net_boundary=$(check_net_boundary $net "$wildcard_mask");
if [ $force != 'f' ] && [ $is_net_boundary -ne 1 ]; then
read -p "Not a network boundary! Continue anyway (y/N)? " -n 1 -r
echo ## move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_processing=1;
else
do_processing=0;
fi
fi
if [ $do_processing -eq 1 ]; then
str=
for (( i = 1; i <= 4; i++ )); do
range=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
range="{$range..$(( $range | $mask_octet ))}";
fi
str="${str} $range"
done
ips=$(echo $str | sed "s, ,\\.,g"); ## replace spaces with periods, a join...
eval echo $ips | tr ' ' '\012'
fi
done
Ответ 8
Хотел прокомментировать ответ выше, но пока не имею представителя.
Используя верхнее решение с NMAP, я добавил это в свой .bashrc
expand-ip() {
nmap -sL -n -iL "$1" | awk '/Nmap scan report/{print $NF}'
}
Теперь я могу использовать это только с expand-ip targs
.
Ответ 9
Вы можете использовать этот script
(вам необходимо установить" bc "в вашей системе):
for ip in [email protected] ;do
net=$(echo $ip | cut -d '/' -f 1);
prefix=$(echo $ip | cut -d '/' -f 2);
o1=$(echo $net | cut -d '.' -f4);
o2=$(echo $net | cut -d '.' -f3);
o3=$(echo $net | cut -d '.' -f2);
o4=$(echo $net | cut -d '.' -f1);
len=$(echo "2^(32 - $prefix)"|bc);
for i in `seq $len`;do
echo "$o4.$o3.$o2.$o1";
o1=$(echo "$o1+1"|bc);
if [ $o1 -eq 256 ]; then
o1=0;
o2=$(echo "$o2+1"|bc);
if [ $o2 -eq 256 ]; then
o2=0;
o3=$(echo "$o3+1"|bc);
if [ $o3 -eq 256 ]; then
o3=0;
o4=$(echo "$o4+1"|bc);
fi
fi
fi
done
done
Ответ 10
fping -Aaqgr 1 10.1.1.0/24
Простота работает лучше всего
Ответ 11
Этот скрипт должен делать. Это (почти) чистый Bash. Часть seq
может быть заменена, если требуется полностью чистая обработка.
Поскольку Bash, по-видимому, использует 4-байтовые целые числа из двух дополнений со знаком, сценарий ограничен максимумом /8 маски. Я обнаружил, что диапазоны больше /16 непрактичны, так что это меня совсем не беспокоит. Если кто-то знает простой способ преодолеть это, пожалуйста, поделитесь :)
#!/usr/bin/env bash
base=${1%/*}
masksize=${1#*/}
[ $masksize -lt 8 ] && { echo "Max range is /8."; exit 1;}
mask=$(( 0xFFFFFFFF << (32 - $masksize) ))
IFS=. read a b c d <<< $base
ip=$(( ($b << 16) + ($c << 8) + $d ))
ipstart=$(( $ip & $mask ))
ipend=$(( ($ipstart | ~$mask ) & 0x7FFFFFFF ))
seq $ipstart $ipend | while read i; do
echo $a.$(( ($i & 0xFF0000) >> 16 )).$(( ($i & 0xFF00) >> 8 )).$(( $i & 0x00FF ))
done
Использование:
./script.sh 192.168.13.55/22
Протестировано с Bash версии 4.4.23. YMMV.
Ответ 12
Это лучший способ подсчета IP-адресов в подсети:
cat SUBNETFILE | paste -sd+ - | bc