Verifique se o IP está no intervalo da Matriz de Whitelist

2
#!/bin/bash

MAXCDN_ARRAY="108.161.176.0/20 94.46.144.0/20 146.88.128.0/20 198.232.124.0/22 23.111.8.0/22 217.22.28.0/22 64.125.76.64/27 64.125.76.96/27 64.125.78.96/27 64.125.78.192/27 64.125.78.224/27 64.125.102.32/27 64.125.102.64/27 64.125.102.96/27 94.31.27.64/27 94.31.33.128/27 94.31.33.160/27 94.31.33.192/27 94.31.56.160/27 177.54.148.0/24 185.18.207.65/26 50.31.249.224/27 50.31.251.32/28 119.81.42.192/27 119.81.104.96/28 119.81.67.8/29 119.81.0.104/30 119.81.1.144/30 27.50.77.226/32 27.50.79.130/32 119.81.131.130/32 119.81.131.131/32 216.12.211.59/32 216.12.211.60/32 37.58.110.67/32 37.58.110.68/32 158.85.206.228/32 158.85.206.231/32 174.36.204.195/32 174.36.204.196/32"

$IP = 108.161.184.123

if [ $IP in $MAXCDN_ARRAY ];
    then:
        echo "$IP is in MAXCDN range"
    else:
        echo "$IP is not in MAXCDN range"
fi 

Eu tenho uma lista de IPs em MAXCDN_ARRAY para ser usada como whitelist. Quero verificar se um endereço IP específico está no intervalo nessa matriz.

Como posso estruturar o código para que ele possa comparar todos os IPs no array e dizer o IP específico no intervalo dessa lista ou não?

    
por NecNecco 05.04.2016 / 05:17

3 respostas

6

Você pode usar grepcidr para verificar se um endereço IP está em uma lista de redes CIDR.

#! /bin/bash

NETWORKS="108.161.176.0/20 94.46.144.0/20 146.88.128.0/20 198.232.124.0/22
          23.111.8.0/22 217.22.28.0/22 64.125.76.64/27 64.125.76.96/27
          64.125.78.96/27 64.125.78.192/27 64.125.78.224/27 64.125.102.32/27
          64.125.102.64/27 64.125.102.96/27 94.31.27.64/27 94.31.33.128/27
          94.31.33.160/27 94.31.33.192/27 94.31.56.160/27 177.54.148.0/24
          185.18.207.65/26 50.31.249.224/27 50.31.251.32/28 119.81.42.192/27
          119.81.104.96/28 119.81.67.8/29 119.81.0.104/30 119.81.1.144/30
          27.50.77.226/32 27.50.79.130/32 119.81.131.130/32 119.81.131.131/32
          216.12.211.59/32 216.12.211.60/32 37.58.110.67/32 37.58.110.68/32
          158.85.206.228/32 158.85.206.231/32 174.36.204.195/32
          174.36.204.196/32"

for IP in 108.161.184.123 108.161.176.123 192.168.0.1 172.16.21.99; do
    grepcidr "$NETWORKS" <(echo "$IP") >/dev/null && \
        echo "$IP is in MAXCDN range" || \
        echo "$IP is not in MAXCDN range"
done

NOTA: grepcidr espera que o (s) endereço (s) IP correspondente seja em um arquivo, não apenas um argumento na linha de comando. É por isso que tive que usar <(echo "$IP") acima.

Saída:

108.161.184.123 is in MAXCDN range
108.161.176.123 is in MAXCDN range
192.168.0.1 is not in MAXCDN range
172.16.21.99 is not in MAXCDN range

grepcidr está disponível pré-empacotado para várias distros, incluindo Debian:

Package: grepcidr
Version: 2.0-1
Description-en: Filter IP addresses matching IPv4 CIDR/network specification
 grepcidr can be used to filter a list of IP addresses against one or
 more Classless Inter-Domain Routing (CIDR) specifications, or
 arbitrary networks specified by an address range. As with grep, there
 are options to invert matching and load patterns from a file.
 grepcidr is capable of comparing thousands or even millions of IPs
 to networks with little memory usage and in reasonable computation
 time.
 .
 grepcidr has endless uses in network software, including: mail
 filtering and processing, network security, log analysis, and many
 custom applications.
 Homepage: http://www.pc-tools.net/unix/grepcidr/

Caso contrário, a fonte está disponível no link acima.

Outra alternativa é escrever um script perl ou python usando uma das muitas bibliotecas / módulos para manipular e verificar endereços IPv4 com esses idiomas.

Por exemplo, o perl module Data::Validate::IP tem uma função is_innet_ipv4($ip, $network) ; Net::CIDR::Lite tem um método $cidr->find($ip); muito semelhante; e Net::IPv4Addr tem uma função ipv4_in_network() .

python tem bibliotecas comparáveis, incluindo ipy , ipaddr e ipcalc , entre outras.

    
por 05.04.2016 / 08:35
2

Sei que isso é mais antigo e já tem uma resposta aceita, mas essa solução utiliza uma função que escrevi para portabilidade em vários servidores em um ambiente em que grepcidr não era um pacote padrão em todos os servidores.

Os comentários devem esclarecer o que está fazendo.

#! /bin/bash

# Set DEBUG=1, in order to see it iterate through the calculations.
#DEBUG=1

MAXCDN_ARRAY="108.161.176.0/20 94.46.144.0/20 146.88.128.0/20 198.232.124.0/22 23.111.8.0/22 217.22.28.0/22 64.125.76.64/27 64.125.76.96/27 64.125.78.96/27 64.125.78.192/27 64.125.78.224/27 64.125.102.32/27 64.125.102.64/27 64.125.102.96/27 94.31.27.64/27 94.31.33.128/27 94.31.33.160/27 94.31.33.192/27 94.31.56.160/27 177.54.148.0/24 185.18.207.65/26 50.31.249.224/27 50.31.251.32/28 119.81.42.192/27 119.81.104.96/28 119.81.67.8/29 119.81.0.104/30 119.81.1.144/30 27.50.77.226/32 27.50.79.130/32 119.81.131.130/32 119.81.131.131/32 216.12.211.59/32 216.12.211.60/32 37.58.110.67/32 37.58.110.68/32 158.85.206.228/32 158.85.206.231/32 174.36.204.195/32 174.36.204.196/32"

IP=108.161.184.123

function in_subnet {
    # Determine whether IP address is in the specified subnet.
    #
    # Args:
    #   sub: Subnet, in CIDR notation.
    #   ip: IP address to check.
    #
    # Returns:
    #   1|0
    #
    local ip ip_a mask netmask sub sub_ip rval start end

    # Define bitmask.
    local readonly BITMASK=0xFFFFFFFF

    # Set DEBUG status if not already defined in the script.
    [[ "${DEBUG}" == "" ]] && DEBUG=0

    # Read arguments.
    IFS=/ read sub mask <<< "${1}"
    IFS=. read -a sub_ip <<< "${sub}"
    IFS=. read -a ip_a <<< "${2}"

    # Calculate netmask.
    netmask=$(($BITMASK<<$((32-$mask)) & $BITMASK))

    # Determine address range.
    start=0
    for o in "${sub_ip[@]}"
    do
        start=$(($start<<8 | $o))
    done

    start=$(($start & $netmask))
    end=$(($start | ~$netmask & $BITMASK))

    # Convert IP address to 32-bit number.
    ip=0
    for o in "${ip_a[@]}"
    do
        ip=$(($ip<<8 | $o))
    done

    # Determine if IP in range.
    (( $ip >= $start )) && (( $ip <= $end )) && rval=1 || rval=0

    (( $DEBUG )) &&
        printf "ip=0x%08X; start=0x%08X; end=0x%08X; in_subnet=%u\n" $ip $start $end $rval 1>&2

    echo "${rval}"
}

for subnet in $MAXCDN_ARRAY
do
    (( $(in_subnet $subnet $IP) )) &&
        echo "${IP} is in ${subnet}" && break
done
    
por 28.08.2018 / 21:55
0
# SETUP CIDR ARRAY DATA
cidrs=(10.10.10.0/24 20.20.20.0/24)
cidrarr=()
for cidr in "${cidrs[@]}"; do
    mask=$(echo $cidr | cut -d/ -f2)
    ip=$(echo $cidr | cut -d/ -f1)
    cidrdec=0;maskdec=0;p=0
    for i in {1..4}; do
        e=$((2**$((8*(4-$i)))))
        o=$(echo $ip | cut -d. -f$i)
        cidrdec=$(($cidrdec+$o*$e))
    done
    for ((i=1; i<=$mask; i++)); do
        maskdec=$(($maskdec+2**(32-$i)))
    done
    cidrarr+=($cidr)
    cidrarr+=($cidrdec)
    cidrarr+=($maskdec)
done
# END SETUP CIDR ARRAY DATA

cidrtest() {
    ipdec=0
    for i in {1..4}; do
        e=$((2**$((8*(4-$i)))))
        o=$(echo $1 | cut -d. -f$i)
        ipdec=$(($ipdec+$o*$e))
    done
    for i in ${!cidrarr[@]}; do
        [ $((i%3)) -ne 0 ] && continue
        t=${cidrarr[i+1]}
        m=${cidrarr[i+2]}
        ipm=$(($ipdec & $m))
        [[ $ipm -eq $t ]] && echo "$1 is within ${cidrarr[i]}"
    done
}

cidrtest 10.10.0.1
    
por 03.08.2018 / 11:02