Bash проверка правильности адреса CIDR - PullRequest
0 голосов
/ 29 апреля 2018

Я просто не могу обернуться вокруг этого. У меня есть регулярное выражение, которое проверяет, содержит ли строка действительный адрес записи CIDR.

(((?:25[012345]|2[0-4]\d|1?\d\d?)\.){3}(?:25[012345]|2[0-4]\d|1?\d\d?))(?:\/([1-9]|[1-2][0-9]|3[0-2]))(?![.\d])

Эта штука работает на Perl, PHP, Javascript и соответствует от x.x.x.x/8 до y.y.y.y/32.

Я пытался изменить эти \d на [[:digit:]] и \\d Ничего: (

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

#!/bin/bash

if [ "$1" = "" ]
then
    echo "Usage: $( basename $0) 123.456.789.0/12"
    exit
fi
REGEX1='(((?:25[012345]|2[0-4]\d|1?\d\d?)\.){3}(?:25[012345]|2[0-4]\d|1?\d\d?))(?:\/([1-9]|[1-2][0-9]|3[0-2]))(?![.\d])'
REGEX2='(((?:25[012345]|2[0-4]\\d|1?\\d\\d?)\.){3}(?:25[012345]|2[0-4]\\d|1?\\d\\d?))(?:\\/([1-9]|[1-2][0-9]|3[0-2]))(?![.\\d])'
REGEX3='(((?:25[012345]|2[0-4][[:digit:]]|1?[[:digit:]][[:digit:]]?)\\.){3}(?:25[012345]|2[0-4][[:digit:]]|1?[[:digit:]][[:digit:]]?))(?:\\/([1-9]|[1-2][0-9]|3[0-2]))(?![.[[:digit:]]])'

REGEX=$REGEX3

if [[ $1 =~ $REGEX ]]
then
    echo "$1 OK!"
else
    echo "$1 Not OK! $REGEX"
fi

Есть идеи, куда идти отсюда?

Обновлен. Добавлен рабочий скрипт:

#!/bin/bash

if [ "$1" = "" ]
then
    echo "Usage: $( basename $0) 123.456.789.0/12"
    exit
fi

REGEX='(((25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?))(\/([8-9]|[1-2][0-9]|3[0-2]))([^0-9.]|$)'

if [[ $1 =~ $REGEX ]]
then
    echo "$1 OK!"
else
    echo "$1 Not OK!"
fi

if echo $1 | grep -Pq $REGEX
then
    echo "grep $1 OK!"
else
    echo "grep $1 Not OK!"
fi

Ответы [ 2 ]

0 голосов
/ 07 мая 2018

Решение Саймона элегантно. :)

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

valid_cidr_network() {
  local ip="${1%/*}"    # strip bits to leave ip address
  local bits="${1#*/}"  # strip ip address to leave bits
  local IFS=.; local -a a=($ip)

  # Sanity checks (only simple regexes)
  [[ $ip =~ ^[0-9]+(\.[0-9]+){3}$ ]] || return 1
  [[ $bits =~ ^[0-9]+$ ]] || return 1
  [[ $bits -gt 32 ]] || return 1

  # Create an array of 8-digit binary numbers from 0 to 255
  local -a binary=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})
  local binip=""

  # Test and append values of quads
  for quad in {0..3}; do
    [[ "${a[$quad]}" -gt 255 ]] && return 1
    printf -v binip '%s%s' "$binip" "${binary[${a[$quad]}]}"
  done

  # Fail if any bits are set in the host portion
  [[ ${binip:$bits} = *1* ]] && return 1

  return 0
}

Эта функция собирает IP-адрес в двоичном формате, а затем завершается ошибкой, если в части хоста IP-адреса установлены какие-либо "1".

0 голосов
/ 29 апреля 2018

Кратчайший путь к успеху - GNU grep, который также поддерживает PCRE:

if echo $CIDR | grep -qP "$REGEX"
then
  echo "$CIDR OK!"
  exit 0
else
  echo "$CIDR NOT OK!"
  exit 1
fi

grep's -q отключает его и использует код выхода для определения успеха. -P - это PCRE.

Но я должен отметить, что ваше регулярное выражение не полностью соответствует тому, что что-то является допустимым диапазоном CIDR; скорее, вы соответствуете действительному IP-адресу, за которым следует косая черта и число n ∈ 1-32. Дополнительное требование к диапазонам CIDR состоит в том, что младшие биты 32-n адреса равны нулю, например ::

IFS="./" read -r ip1 ip2 ip3 ip4 N <<< $CIDR
ip=$(($ip1 * 256 ** 3 + $ip2 * 256 ** 2 + $ip3 * 256 + $ip4))

if [ $(($ip % 2**(32-$N))) = 0 ]
then
  echo "$CIDR OK!"
  exit 0
else
  echo "$CIDR NOT OK!"
  exit 1
fi

Проверьте это, например, с помощью 127.0.0.0/24, 127.1.0.0, 127.1.1.0/24.

Или более странные диапазоны: 10.10.10.8/29, 127.0.0.0/8, 127.3.0.0/10, 192.168.248.0/21.

...