Проверьте, принадлежит ли IP к CIDR

Вопрос или проблема

У нас есть список CIDR’ов

1.10.10.0/24
5.154.0.0/16
5.181.219.0/24
23.90.68.0/24
31.40.214.0/24

Я хочу проверить, принадлежит ли IP, например: 23.90.68.56 к любому из вышеперечисленных CIDR’ов. Если да, то мы получаем вывод этого CIDR.

Согласно приведенному выше примеру, вывод должен быть 23.90.68.0/24

Я пытался использовать grepcidr, но не знаю, как мы можем вывести этот конкретный CIDR.

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

Вероятно, у вас есть Python:

#!/usr/bin/env python3
import argparse
import ipaddress
import sys

parser = argparse.ArgumentParser()
parser.add_argument("address")
args = parser.parse_args()

addr = ipaddress.ip_address(args.address)

for line in sys.stdin:
    cidr = ipaddress.ip_network(line.strip())
    if addr in cidr:
        print(cidr)
        exit(0)

exit(1)

Вот мое решение, обновляющее решение Уолтера Вехоувена выше.

#!/bin/bash

function is_ip_in_cidr()
{
    local ip=$1
    local cidr=$2

    #Сначала обрабатываем CIDR
    local network=$(echo $cidr | cut -d/ -f1)
    local mask=$(echo $cidr | cut -d/ -f2)

    #Квадратная точечная нотация имеет 4 поля. Сдвигаем и добавляем, чтобы получить десятичное число
    local network_dec=$(echo $network | awk -F. '{printf("%d\n", (($1 * 256 +$2) * 256 + $3) * 256 + $4) }')
    #ТЕСТ echo "network_dec: $network_dec"

    #Сдвигаем битовую маску на правильное количество мест для заданной маски
    local mask_dec=$((0xffffffff << (32 - $mask)))

    #ТЕСТ local mask_dec=$((0x0000000f << (32 - $mask)))
    #ТЕСТ printf "mask_dec: %x\n", $mask_dec

    #Но ограничиваем битовую маску до 32 бит или 8 шестнадцатеричных разрядов.
    local mask_dec2=$((0xffffffff & $mask_dec))
    #ТЕСТ printf "mask_dec2: %x\n", $mask_dec2

    #Применяем маску к сетевому адресу, чтобы получить биты для проверки
    local net1=$(( $mask_dec2 & $network_dec ))
    #ТЕСТ printf "net1: %x\n", $net1

    #Обрабатываем IP-адрес. Снова Квадратная точечная нотация, сдвигаем и добавляем.
    local ip_dec=$(echo $ip | awk -F. '{printf("%d\n", (($1 * 256 +$2) * 256 + $3) * 256 + $4) }')
    #ТЕСТ echo "IP DEC: $ip_dec"

    #Применяем ту же маску к IP-адресу
    local net2=$(( $mask_dec2 & $ip_dec ))
    #ТЕСТ printf "net2: %x\n", $net2

    #Теперь два сетевых компонента могут быть сравнены
    if [[ $net1 == $net2 ]]; then
        return 0
    else
        return 1
    fi
}

# Тестируем функцию с примером IP-адреса и CIDR
ip="192.168.1.5"
cidr="192.168.1.0/24"

if $(is_ip_in_cidr $ip $cidr); then
    echo "ДА, $ip находится в $cidr"
else
    echo "НЕТ, $ip не находится в $cidr"
fi

echo ""

ip="192.168.1.5"
cidr="192.168.0.0/24"

if $(is_ip_in_cidr $ip $cidr); then
    echo "ДА, $ip находится в $cidr"
else
    echo "НЕТ, $ip не находится в $cidr"
fi

Возможный shell-скрипт:

#!/bin/bash

ip=$1
shift; shift

for net in "$@"
do
    nmap -sL -n $net | grep -q $ip && echo $net
done

Если вам нужен список CIDR'ов в файле, используйте ./название_скрипта ip_для_проверки $(cat имя_файла). Возможно, это бесполезное использование cat.

./cidr.sh 23.90.68.56 $(cat cidrs.txt)

в python это будет:

import socket

def is_ip_in_cidr(ip, cidr):
    network, mask = cidr.split("/")
    mask = int(mask)
    ip_int = int.from_bytes(socket.inet_aton(ip), "big")
    network_int = int.from_bytes(socket.inet_aton(network), "big")
    network_mask = (0xFFFFFFFF << (32 - mask)) & 0xFFFFFFFF
    return (ip_int & network_mask) == network_int

# Тестируем функцию с примером IP-адреса и CIDR
ip = "192.168.0.5"
cidr = "192.168.0.0/24"

if is_ip_in_cidr(ip, cidr):
    print(f"{ip} находится в {cidr}")
else:
    print(f"{ip} НЕ находится в {cidr}")

если вы можете использовать предоставленный список как фиксированный набор для проверки так:

import socket

def is_ip_in_cidr(ip, cidrs):
    for cidr in cidrs:
        network, mask = cidr.split("/")
        mask = int(mask)
        ip_int = int.from_bytes(socket.inet_aton(ip), "big")
        network_int = int.from_bytes(socket.inet_aton(network), "big")
        network_mask = (0xFFFFFFFF << (32 - mask)) & 0xFFFFFFFF
        if (ip_int & network_mask) == network_int:
            return True
    return False

# Тестируем функцию с примером IP-адреса и списком CIDR'ов
ip = "192.168.0.5"
cidrs = ["1.10.10.0/24", "5.154.0.0/16", "5.181.219.0/24", "23.90.68.0/24", "31.40.214.0/24"]

if is_ip_in_cidr(ip, cidrs):
    print(f"{ip} находится в одном из {cidrs}")
else:
    print(f"{ip} НЕ находится ни в одном из {cidrs}")

в bash

#!/bin/bash

function is_ip_in_cidr {
  local ip=$1
  local cidr=$2
  local network=$(echo $cidr | cut -d/ -f1)
  local mask=$(echo $cidr | cut -d/ -f2)
  local network_dec=$(echo $network | awk -F. '{printf("%d\n", ($1 * 256 + $2) * 256 + $3)}')
  local ip_dec=$(echo $ip | awk -F. '{printf("%d\n", ($1 * 256 + $2) * 256 + $3)}')
  local mask_dec=$((0xffffffff << (32 - $mask)))
  if [[ $((ip_dec & mask_dec)) -eq $((network_dec & mask_dec)) ]]; then
    echo "true"
  else
    echo "false"
  fi
}

# Тестируем функцию с примером IP-адреса и CIDR
ip="192.168.0.5"
cidr="192.168.0.0/24"

if $(is_ip_in_cidr $ip $cidr); then
  echo "$ip находится в $cidr"
else
  echo "$ip НЕ находится в $cidr"
fi

Я вижу, что некоторые из решений, предоставленных здесь, очень медленные, и никто не использует grepcidr.

Чтобы ответить на вопрос:

Я пытался использовать grepcidr, но не знаю, как мы можем вывести этот конкретный CIDR.

Вот как вы можете использовать grepcidr для обратного поиска:

cat << EOF > /tmp/list_of_CIDRs
5.154.0.0/16
5.181.219.0/24
23.90.68.0/24
31.40.214.0/24
EOF

cat << EOF > /tmp/list_of_IPs
1.1.1.1
5.181.219.42
23.90.68.56
23.90.68.98
EOF

cat /tmp/list_of_CIDRs | while read CIDR
do
 if MATCH=$(grepcidr $CIDR < /tmp/list_of_IPs)
 then
  echo $CIDR содержит $MATCH
 fi
done

Выход:

5.181.219.0/24 содержит 5.181.219.42
23.90.68.0/24 содержит 23.90.68.56 23.90.68.98

Ответ или решение

Проверка принадлежности IP-адреса к подсети в формате CIDR

Ситуация, когда необходимо проверить, принадлежит ли IP-адрес определенной подсети в формате CIDR (Classless Inter-Domain Routing), довольно распространена в области информационных технологий. В данной статье детально рассмотрим, как можно решить эту задачу с помощью bash-скрипта, Python и утилиты grepcidr.

Цели и предпосылки

Мы имеем список CIDR и желаем проверить, принадлежит ли указанный IP-адрес к какому-либо из них. В качестве примера, приведем следующие CIDR:

1.10.10.0/24
5.154.0.0/16
5.181.219.0/24
23.90.68.0/24
31.40.214.0/24

И мы хотим проверить IP-адрес 23.90.68.56. Ожидаемый результат: 23.90.68.0/24.

Использование Bash

Для проверки принадлежности IP-адреса к CIDR с помощью bash можно использовать следующий скрипт:

#!/bin/bash

function is_ip_in_cidr() {
    local ip=$1
    local cidr=$2

    local network=$(echo $cidr | cut -d/ -f1)
    local mask=$(echo $cidr | cut -d/ -f2)

    local network_dec=$(echo $network | awk -F. '{printf("%d\n", (($1 * 256 + $2) * 256 + $3) * 256 + $4))}')
    local mask_dec=$((0xffffffff << (32 - $mask)))

    local net1=$(( $network_dec & $mask_dec ))
    local ip_dec=$(echo $ip | awk -F. '{printf("%d\n", (($1 * 256 + $2) * 256 + $3) * 256 + $4))}')
    local net2=$(( $ip_dec & $mask_dec ))

    [[ $net1 == $net2 ]]
}

ip="23.90.68.56"

for cidr in 1.10.10.0/24 5.154.0.0/16 5.181.219.0/24 23.90.68.0/24 31.40.214.0/24; do
    if is_ip_in_cidr "$ip" "$cidr"; then
        echo "$ip принадлежит $cidr"
    fi
done

Эта функция проверяет, принадлежит ли IP-адрес к заданной подсети, используя побитовые операции.

Использование Python

Если предположить, что более удобно использовать Python, то следующим образом можно реализовать задачу:

import ipaddress

def is_ip_in_cidr(ip, cidrs):
    addr = ipaddress.ip_address(ip)
    for cidr in cidrs:
        if addr in ipaddress.ip_network(cidr):
            print(f"{ip} принадлежит {cidr}")
            return
    print(f"{ip} не принадлежит ни одной из подсетей")

ip_address = "23.90.68.56"
cidr_list = [
    "1.10.10.0/24",
    "5.154.0.0/16",
    "5.181.219.0/24",
    "23.90.68.0/24",
    "31.40.214.0/24",
]

is_ip_in_cidr(ip_address, cidr_list)

Использование grepcidr

Если вы хотите использовать утилиту grepcidr, чтобы упростить проверку, вы можете сделать следующее:

echo "23.90.68.56" | grepcidr -f <(printf "1.10.10.0/24\n5.154.0.0/16\n5.181.219.0/24\n23.90.68.0/24\n31.40.214.0/24")

Эта команда проверит, принадлежит ли IP-адрес к одной из предоставленных подсетей и выведет соответствующие CIDR.

Заключение

Таким образом, существует несколько способов проверки принадлежности IP-адреса к подсетям в формате CIDR. Используйте bash, Python или утилиты командной строки в зависимости от ваших предпочтений и условий работы. Каждый из этих методов позволяет эффективно проверять IP-адреса и может быть адаптирован под конкретные требования вашего проекта.

Оцените материал
Добавить комментарий

Капча загружается...