Идентификатор частного IP-адреса в регулярном выражении

Мне интересно, лучший ли это способ сопоставить строку, начинающуюся с частного IP-адреса (регулярное выражение в стиле Perl):

(^127\.0\.0\.1)|(^192\.168)|(^10\.)|(^172\.1[6-9])|(^172\.2[0-9])|(^172\.3[0-1])

Спасибо большое!


person caseyamcl    schedule 11.05.2010    source источник
comment
Во-первых, вы должны просмотреть RFC1918, чтобы получить правильный список. Во-вторых, я предполагаю, что решение, не использующее регулярные выражения, будет легче поддерживать. После преобразования IP-адреса в числовой его довольно легко сопоставить со списком диапазонов частных IP-адресов. Это также позволит вам легко использовать общедоступные списки богонов, которые содержат гораздо больше, чем RFC1918.   -  person derobert    schedule 12.05.2010
comment
@derobert верно, но для таких целей, как фильтр удаленных адресов Tomcat, вам нужно регулярное выражение.   -  person Raedwald    schedule 25.02.2013
comment
Распространенной ошибкой новичка является думать, что ^ означает не в этом контексте, поэтому стоит отметить: каждый ^ в вашем выражении просто привязывает совпадение к началу строки. В традиционном регулярном выражении нет простого способа сказать не эту строку, хотя Perl-совместимые/PCRE-выражения имеют отрицательный просмотр вперед с (?!...)   -  person tripleee    schedule 14.12.2017


Ответы (10)


Я предполагаю, что вы хотите сопоставить эти диапазоны:

127.  0.0.0 – 127.255.255.255     127.0.0.0 /8
 10.  0.0.0 –  10.255.255.255      10.0.0.0 /8
172. 16.0.0 – 172. 31.255.255    172.16.0.0 /12
192.168.0.0 – 192.168.255.255   192.168.0.0 /16

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

(^127\.)|
(^10\.)|
(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|
(^192\.168\.)

Также обратите внимание, что это предполагает, что IP-адреса уже проверены — он принимает такие вещи, как 10.foobar.

person Mark Byers    schedule 11.05.2010
comment
Если вы хотите исключить частные IP-адреса из отслеживания Google Analytics, используйте это: gist.github.com/1000402 - person Aron Woost; 31.05.2011
comment
Первая строка должна быть (^127\.)| - person Mark Rose; 07.06.2012
comment
Он не проверяет внутренние IP-адреса наших сетей: например: 10.131.43.84 Ваш 10-й блок нарушен. - person mfriis; 26.07.2013
comment
Версия Java: '(^127\\.0\\.0\\.1)|(^10\\.)|(^172\\.1[6-9]\\.)|(^172\\.2[0-9]\\.)|(^172\\.3[0-1]\\.)|(^192\\.168\\.)' - person Phani; 23.05.2015
comment
сложнее, но точнее: (^127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$)|(^10\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$)|(^172\.1[6-9]{1}[0-9]{0,1}\.[0-9]{1,3}\.[0-9]{1,3}$)|(^172\.2[0-9]{1}[0-9]{0,1}\.[0-9]{1,3}\.[0-9]{1,3}$)|(^172\.3[0-1]{1}[0-9]{0,1}\.[0-9]{1,3}\.[0-9]{1,3}$)|(^192\.168\.[0-9]{1,3}\.[0-9]{1,3}$) - person dr.dimitru; 15.01.2016
comment
Локальные частные адреса 169.254.*.* также должны быть в этом наборе. Написано компактно: ^(10|127|169\.254|172\.1[6-9]|172\.2[0-9]|172\.3[0-1]|192\.168)\. - person karmakaze; 28.03.2016
comment
@karmakaze Это все еще можно упростить / сократить до ^(10|127|169\.254|172\.(1[6-9]|2[0-9]|3[0-1])|192\.168)\. (или даже ^1(0|27|69\.254|72\.(1[6-9]|2[0-9]|3[0-1])|92\.168)\., но это может быть слишком далеко). - person Nicolas Melay; 12.10.2020

Это то же самое, что и правильный ответ Марка, но теперь включает частные адреса IPv6.

/(^127\.)|(^192\.168\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^::1$)|(^[fF][cCdD])/
person Edward    schedule 04.07.2012
comment
Плохо. Согласно Википедии (en.wikipedia.org/wiki/Unique_local_address), блок (fc00::/7) зарезервирован для уникальных локальных адресов. Это регулярное выражение только добавляет адрес локального хоста (:: 1) к принятому решению. - person dana; 14.03.2013
comment
Согласно github.com/rails/rails/pull/12651/files регулярное выражение для этого будет ^[fF][cCdD] - я соответствующим образом редактирую ответ. - person blueyed; 15.03.2015
comment
Символ / в начале и в конце сценария предполагает, что вы используете выражение на каком-то языке, таком как Javascript, но это недопустимо на других языках. Несмотря на это, более короткая версия (и без косых черт) ^(127\.)|(192\.168\.)|(10\.)|(172\.1[6-9]\.)|(172\.2[0-9]\.)|(172\.3[0-1]\.)|(::1$)|([fF][cCdD]) - person Mariano Ruiz; 28.06.2017
comment
@MarianoRuiz Я считаю, что вам нужна группа захвата вокруг всего этого, если у вас есть курсор в начале, иначе вы в конечном итоге сопоставите 127. в начале и остальные группы в любом месте строки. - person wmassingham; 19.08.2019

я сгенерировал это

REGEXP ДЛЯ СЕТЕЙ КЛАССА А:

(10)(\.([2]([0-5][0-5]|[01234][6-9])|[1][0-9][0-9]|[1-9][0-9]|[0-9])){3}

REGEXP ДЛЯ СЕТЕЙ КЛАССА B:

(172)\.(1[6-9]|2[0-9]|3[0-1])(\.(2[0-4][0-9]|25[0-5]|[1][0-9][0-9]|[1-9][0-9]|[0-9])){2}

REGEXP ДЛЯ СЕТЕЙ КЛАССА C:

(192)\.(168)(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])){2}

Дайте мне знать, если вы столкнетесь с какой-либо ошибкой

Если вы уверены в своем выводе (скажем, например, netstat) и вам не нужно проверять действительность IP-адреса, потому что это уже сделано, вы можете поймать частные IP-адреса с помощью этой формулы

grep -P "(10.|192.168|172.1[6-9].|172.2[0-9].|172.3[01].).* "

person user3177026    schedule 09.01.2014
comment
Просто используя [2][0-5][0-5] для диапазона от 200 до 255, такие числа, как 206 до 209 и 216 до 219 и т. д., не будут совпадать. Вам придется заменить это на ([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]). - person kielabokkie; 15.03.2014
comment
Для какого языка это используется? Я не могу заставить его работать, regex101.com/r/jdVmny/1 - person Justin; 07.06.2017

вот что я использую в питоне:

rfc1918 = re.compile('^(10(\.(25[0-5]|2[0-4][0-9]|1[0-9]{1,2}|[0-9]{1,2})){3}|((172\.(1[6-9]|2[0-9]|3[01]))|192\.168)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{1,2}|[0-9]{1,2})){2})$')

При желании вы можете удалить якоря ^ и/или $.

Я предпочитаю приведенное выше регулярное выражение, потому что оно отсеивает недопустимые октеты (все, что выше 255).

пример использования:

if rfc1918.match(ip):
    print "ip is private"
person Josh Worley    schedule 02.06.2017

Это на тот случай, если вы решите согласиться с моим комментарием, предлагающим не использовать регулярные выражения. Непроверено (но, вероятно, работает или, по крайней мере, близко) в Perl:

@private = (
    {network => inet_aton('127.0.0.0'),   mask => inet_aton('255.0.0.0')   },
    {network => inet_aton('192.168.0.0'), mask => inet_aton('255.255.0.0') },
    # ...
);

$ip = inet_aton($ip_text);
if (grep $ip & $_->{mask} == $_->{network}, @private) {
    # ip address is private
} else {
    # ip address is not private
}

Обратите внимание, что @private — это просто данные, которые вы можете легко изменить. Или загрузите на лету из справочника Cymru Bogon.

edit: мне приходит в голову, что запрос регулярного выражения Perl не означает, что вы знаете Perl, поэтому ключевая строка заключается в том, что есть «grep», который просто перебирает каждый диапазон частных адресов. Вы берете свой IP-адрес, побитовый и с сетевой маской, и сравниваете с сетевым адресом. Если равны, это часть этой частной сети.

person derobert    schedule 11.05.2010

Выглядит правильно. Лично я бы изменил первый на:

^127\.0 

При этом: (^127\.0\.0\.1) вы ищете все, что начинается с 127.0.0.1 и пропускает 127.0.0.2*, 127.0.2.*, 127.0.* и т. д.

person KM.    schedule 11.05.2010
comment
Я знаю, что это старо, но этот вопрос был первым или вторым в моем поиске Google. Я считаю, что весь блок 127.0.0.0/8 зарезервирован для обратной связи, так что 0 там даже не должно быть. - person Leagsaidh Gordon; 17.01.2014

на 10 лет позже. Кредиты Mark Byers, bramp, Edward, blueyed, user3177026, Justin, karmakaze, Ron Maupin.

Ответить на TLDR

Только начало

Пожалуйста, удалите разрывы строк - это просто для удобства чтения:

^(?:
127\.|
0?10\.|
172\.0?1[6-9]\.|
172\.0?2[0-9]\.|
172\.0?3[01]\.|
192\.168\.|
169\.254\.|
::1|
[fF][cCdD][0-9a-fA-F]{2}:|
[fF][eE][89aAbB][0-9a-fA-F]:
)

?: в начале круглой скобки означает, что эта круглая скобка не захватывается и может сделать ее немного быстрее.

Пожалуйста, будьте осторожны с обратной косой чертой. В Postgres, например. вы должны использовать строку E и должны экранировать обратную косую черту с помощью обратной косой черты - или просто используйте [.] вместо E'\\.'!

Весь IP (десятичный, начальные нули необязательны, максимум три цифры)

Пожалуйста, удалите разрывы строк - это просто для удобства чтения:

\b(
127\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|
0?10\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|
172\.0?1[6-9]\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|
172\.0?2[0-9]\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|
172\.0?3[01]\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|
192\.168\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|
169\.254\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|
::1|
[fF][cCdD][0-9a-fA-F]{2}(?:[:][0-9a-fA-F]{0,4}){0,7}|
[fF][eE][89aAbB][0-9a-fA-F](?:[:][0-9a-fA-F]{0,4}){0,7}
)
(?:\/([789]|1?[0-9]{2}))?
\b

https://regex101.com/r/JCLOZL/14 (Резервная копия: https://etherpad.wikimedia.org/p/JCLOZL)

Подробности

IPv4

  127.0.0.0 to 127.255.255.255 is   127.0.0.0/8   # localhost, loopback etc.
   10.0.0.0 to  10.255.255.255 is    10.0.0.0/8   # approximately/formerly class A
 172.16.0.0 to  172.31.255.255 is  172.16.0.0/12  # approximately/formerly class B
192.168.0.0 to 192.168.255.255 is 192.168.0.0/16  # approximately/formerly class C
169.254.0.0 to 169.254.255.255 is 169.254.0.0/16  # link-local addresses since 2005

Пример:

172.17.50.33 or more explicit:
172.17.50.33/32

Я не уверен, что часть за косой чертой может иметь начальные нули (маловероятно), но IP может иметь начальные нули.

IPv4 с ведущими нулями (десятичное число)

127.000.000.000 to 127.255.255.255 is 127.000.000.000/8   # localhost, loopback etc.
010.000.000.000 to 010.255.255.255 is 010.000.000.000/8   # approx/formerly class A
172.016.000.000 to 172.031.255.255 is 172.016.000.000/12  # approx/formerly class B
192.168.000.000 to 192.168.255.255 is 192.168.000.000/16  # approx/formerly class C
169.254.000.000 to 169.254.255.255 is 169.254.000.000/16  # link-local addresses

Пример:

172.017.050.033 or more explicit:
172.017.050.033/32

IPv4 с ведущими нулями (восьмеричный)

Не поддерживается в моем регулярном выражении. Чтобы сделать вашу программу идеальной, проверьте и предупредите пользователя о восьмеричных IP-адресах и/или более трех цифр!

0177.0000.0000.0000 to 0177.0377.0377.0377 is 0177.0000.0000.0000/8   # loopback
0012.0000.0000.0000 to 0012.0377.0377.0377 is 0012.0000.0000.0000/8   # A
0254.0020.0000.0000 to 0254.0037.0377.0377 is 0254.0020.0000.0000/12  # B
0300.0250.0000.0000 to 0300.0250.0377.0377 is 0300.0250.0000.0000/16  # C
0251.0376.0000.0000 to 0251.0376.0377.0377 is 0251.0376.0000.0000/16  # link-local

Пример:

0254.0021.0062.0041 or more explicit:
0254.0021.0062.0041/32

Да, 172.017.050.033 совпадает с 0254.0021.0062.0041 на разных инструментах. Протестировано с ping на macOS.

Конечно, в некоторых инструментах вы также можете смешивать десятичную (без нуля в начале) с восьмеричной (по крайней мере, с одним нулем в начале). :С

IPv6

fc00:0000:… to fdff:ffff:… is fc00::/7
fe80:0000:… to febf:ffff:… is fe80::/10  # link-local addresses

Это может быть не совсем то, что вы хотите, потому что:

Частные IPv4-адреса определены RFC 1918, Распределение адресов для частных интернетов, и адреса используются во многих сетях по всему миру. ULA-адреса IPv6 должны быть уникальными (U в ULA), чтобы их нельзя было повторно использовать в нескольких местах, поэтому они должны иметь 40 случайных битов в глобальном идентификаторе, что дает высокие ожидания уникальности.

Все адреса из публичного интернета будут в диапазоне от 2000:: до 3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff (2000::/3). Вам нужно правильно замаскировать адрес, чтобы увидеть, находится ли он в общедоступном диапазоне, а затем сделать то же самое для непубличных диапазонов в общедоступном диапазоне. Если он проходит тест общедоступного диапазона, он должен провалить закрытые диапазоны в общедоступном диапазоне. Если он проходит все это, это публичный адрес. Устройства IoT также получают глобальные (общедоступные) IPv6-адреса. Смысл IPv6 в том, что существует достаточно адресов, чтобы каждый интерфейс на каждом устройстве получил глобальный IPv6-адрес, восстанавливая способ, которым IP был изначально разработан (больше не нужно обходиться без NAT).

Некоторые внутренние адреса вашего веб-сервера будут адресами Link-Local (fe80::/10), и можно назначить адреса ULA (fc00::/7 из которых вы можете назначить из fd00::/8 с определенными ограничениями) для трафика, который никогда не будет разрешен в общедоступном Интернете.

Пример:

fdff:1234:abcd:5678:effe:9098:dcba:7654 or more explicit:
fdff:1234:abcd:5678:effe:9098:dcba:7654/128

Неполный список ссылок

Когда я пришел сюда, я не знал о:

person qräbnö    schedule 15.07.2020

Если вы ищете system.net defaultProxy и конфигурацию обхода прокси-серверов, которая использует прокси-сервер для внешних, но использует прямые подключения для внутренних хостов (можно сделать с некоторой поддержкой ipv6)...

<system.net>
  <defaultProxy enabled="true">
    <proxy proxyaddress="http://proxycluster.privatedomain.net:8080" bypassonlocal="True"  />
    <bypasslist>
      <!-- exclude local host -->
      <add address="^(http|https)://localhost$" />
      <!-- excludes *.privatedomain.net -->
      <add address="^(http|https)://.*\.privatedomain\.net$" />
      <!-- excludes simple host names -->
      <add address="^(http|https)://[a-z][a-z0-9\-_]*$" />
      <!-- exclude private network addresses 192.168, 172.16..31 through 31, 127.* etc. -->
      <add address="^(http|https)://((((127)|(10))\.[0-9]+\.[0-9]+\.[0-9]+)|(((172\.(1[6-9]|2[0-9]|3[0-1]))|(192\.168))\.[0-9]+\.[0-9]+))$"/>
    </bypasslist>
  </defaultProxy>
  <connectionManagement>
    <add address="*" maxconnection="10" />
  </connectionManagement>
</system.net>
person Mhano    schedule 13.03.2015

Вам нужен конечный разделитель, чтобы получить весь 4-й октет, если это более одной цифры.

^(10.([0-9][0-9]?|[0-1][0-9]?[0-9]?|2[0-4]?[0-9]?|25[0-5])|172.(1[6-9]|2[0-9]|3[0-1])|192.168).([0-9][0-9]?|[0-1][0-9]?[0-9]?|2[0-4]?[0-9]?|25[0-5]).([0-9][0-9]?|[0-1][0-9]?[0-9]?|2[0-4]?[0-9]?|25[0-5])$

person Vesselin Yanev    schedule 16.02.2021

FWIW этот шаблон был более чем на 10% быстрее при использовании pattern.matcher:

^1((0)|(92\\.168)|(72\\.((1[6-9])|(2[0-9])|(3[0-1])))|(27))\\.
person scott    schedule 05.01.2016
comment
Я сделал несколько тестов, но, похоже, это примерно на 100% медленнее. Можете ли вы предоставить некоторые тесты, подтверждающие это? - person Joseph Callaars; 09.11.2016