Программно извлеките частный IP-адрес (IP-адреса)

Можно использовать должностное лицо как это наверху сценария:

exec > >(tee "$HOME/somefile.log") 2>&1

Например:

#!/bin/bash -

exec > >(tee "$HOME/somefile.log") 2>&1

echo "$HOME"
echo hi
date
date +%F
echo bye 1>&2

Дает мне вывод файлу $HOME/somefile.log и к терминалу как это:

/home/saml
hi
Sun Jan 20 13:54:17 EST 2013
2013-01-20
bye
7
13.04.2017, 15:36
4 ответа

Что-либо в частном пространстве IP будет всегда запускаться с одного из трех блоков IP-адреса.

  • 24-разрядный блок - 10. X.X.X
  • 20-разрядный блок - 172.16. X.X - 172.31. X.X
  • 16-разрядный блок - 192.168. X.X

Таким образом, просто grep для вышеупомянутых типов IP-адресов.

$ ifconfig | grep 'inet addr' | cut -d ':' -f 2 | awk '{ print $1 }' | \
      grep -E '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.)'
192.168.1.20

Подробнее

grep Я использую, использует регулярные выражения. В этом случае мы ищем следующие шаблоны:

  • 192.168
  • 10.
  • 172.1 [6789].
  • 172.2 [0-9].
  • 172.3 [01].

Дополнительно мы являемся явными только в соответствии числам, которые запускаются с одного из этих шаблонов. Привязка (^) предоставляет эту возможность нам.

Больше примеров

Если мы добавляем следующие строки к файлу только для тестирования grep .

$ cat afile 
192.168.0.1
10.11.15.3
1.23.3.4
172.16.2.4

Мы можем затем протестировать его как так:

$ cat afile | grep -E '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.)'
192.168.0.1
10.11.15.3
172.16.2.4
13
27.01.2020, 20:15
  • 1
    не всего один, он включает адреса от 172.16.0.0 до 172.31.255.255 –  Emyl 05.11.2013, 11:19
  • 2
    , Частные пробелы IP являются 10.0.0.0/8 (т.е. 10.0.0.0 => 10.255.255.255), 172.16.0.0/12 (т.е. 172.16.0.0 => 172.31.255.255) реклама 192.168.0.0/16 (т.е. 192.168.0.0 => 192.168.255.255), таким образом, Ваш regex не будет соответствовать каждому частному IP. –  ssssteffff 05.11.2013, 11:20
  • 3
    я знаю о Классе B, но никогда не имел потребность использовать его до сих пор, позволяют мне скорректировать regex. –  slm♦ 05.11.2013, 11:21
  • 4
    Посмотрите обновления, зафиксированный regex –  slm♦ 05.11.2013, 11:23
  • 5
    @slm, не называйте сети obselete именами классов. Сети Classful удерживались от использования назад в конце 90-х. –  Zoredache 05.11.2013, 19:34

IPv4 был создан в то время, когда 32-разрядные системы были распространены. Отмеченный точкой десятичный адрес IPv4 может быть сохранен в 32-разрядное целое число без знака, и битовые операции эффективно выполняются сетевым оборудованием. Битовая маска для 172.16.0.0/12 CIDR может быть сформирована из единственного сдвига влево и проверена по адресу с поразрядным синглом - и.

Существует три 'частных' диапазона сетевого адреса, определенные RFC 1918.

  • CIDR/8, (A) единственная большая сеть, (24-разрядный, 16M) диапазон адресов в 10.x.y.z/8
  • CIDR/12, (B) 16 непрерывных сетей (20-разрядный, 1M) диапазон адресов в 172.16+x.y.z/12, где x in [0..15]
  • CIDR/16, (C) 256 непрерывных сетей (16-разрядный, 64K) диапазон адресов в 192.168.y.z/16

Кроме того, для подразделения сети оператора,

  • CIDR/10, (A) единственная большая сеть, (24-разрядный, 16M) диапазон адресов в 100.64+x.y.z/10, где x in [0..63]

И для локальных для ссылки адресов,

  • CIDR/16, (B) единая сеть (16-разрядный, 64K) диапазон адресов в 169.254.y.z/16

С языком, который поддерживает битовые операции, можно преобразовать точечный десятичный адрес в целое число легко,

//assume x[0],x[1],x[2],x[3] are the parts of a dotted ip address
unsigned int ipv4 = (( (( (x[0]<<8) |x[1])<<8) |x[2])<<8) |x[3]

Предположим, что Вы определили константы для вышеупомянутых перечисленных адресов,

CIDR8 = (( (( (10<<8) |0xff)<<8) |0xff)<<8) |0xff
CIDR12 = (( (( (172<<8) |16 |0xf)<<8) |0xff)<<8) |0xff
CIDR16 = (( (( (192<<8) |168)<<8) |0xff)<<8) |0xff
CIDR10 = (( (( (100<<8) |64 |0x3f)<<8) |0xff)<<8) |0xff
CIDRLL = (( (( (169<<8) |254)<<8) |0xff)<<8) |0xff

Проверка, является ли Ваш адрес ipv4 одним из этих адресов, проста,

ipv4 == (ipv4 & CIDR8)  //10.0.0.0/8
ipv4 == (ipv4 & CIDR12) //172.16.0.0/12
ipv4 == (ipv4 & CIDR16) //192.168.0.0/16
ipv4 == (ipv4 & CIDR10) //100.64.0.0/10
ipv4 == (ipv4 & CIDRLL) //169.254.0.0/16

Вместо того, чтобы проверять на 16 различных 172.16.0.0/12 сетей, можно использовать вышеупомянутый подход битовой маски к непосредственно проверке, является ли адрес ipv4 частью одной из этих частных сетей (NAT). Выбор жемчуга (Python или рубин также работают), вместо оболочки или awk, и использование поразрядного сингла и операция значительно сокращают работу.

sub isprivate
{
    my($inet) = @_;
    if( $inet =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/ ) {
        if( $1==10 ) { return 10; }
        if( $1==172 && (($2 & 0x1f) == $2) ) { return 172; }
        if( $1==192 && ($2==168) ) { return 192; }
    }
    return 0;
};
sub iscarrier
{
    my($inet) = @_;
    if( $inet =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/ ) {
        if( $1==100 && (($2 & 0x7f) == $2) ) { return 100; }
    }
    return 0;
};
sub islinklocal
{
    my($inet) = @_;
    if( $inet =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/ ) {
        if( $1==169 && ($2==254) ) { return 169; }
    }
    return 0;
};

Как Вы хотите классифицировать адреса?

sub ipaddr
{
    my($inet) = @_;
    {
        if( isprivate($inet)>0 ) { $kind = "private"; }
        elsif( isloop($inet)>0 ) { $kind = "loopback"; }
        elsif( iscarrier($inet)>0 ) { $kind = "carrier"; }
        elsif( islinklocal($inet)>0 ) { $kind = "linklocal"; }
        else { $kind = ""; }
        print "$iface: $inet $netmask $broadcast ($flagsdesc) $kind\n";
    }
};

Выполненный ifconfig из сценария жемчуга,

$found = 0;
open($fh,"/sbin/ifconfig|");
while($line=<$fh>)
{
    chomp($line); $line =~ s/^\s+//;
    if( $line =~ /(\w+):\s+flags=(\d+)\s*\<(.*)\>\s+mtu\s+(\d+)\b/ ) {
        if( $found ) { ipaddr($inet); }
        $found = 1;
        ($iface,$flags,$flagsdesc,$mtu) = ($1,$2,$3,$4);
    }
    if( $line =~ /inet\s+(\d+\.\d+\.\d+\.\d+)\b/ ) {
        ($inet,$netmask,$broadcast) = ($1,"","");
        if( $line =~ /netmask\s+([\d+\.]+)\b/ ) { ($netmask) = ($1); }
        if( $line =~ /broadcast\s+([\d\.]+)\b/ ) { ($broadcast) = ($1); }
    }
}
if( $found ) { ipaddr($inet); }
1
27.01.2020, 20:15

Вывод (одна строка на IP) может быть фильтрован со следующим сценарием:

#!/bin/sh
PATTERN='^10\.' #  10.0.0.0/8
PATTERN+='|^192\.168\.'  # 192.168.0.0/16
PATTERN+='|^169\.254\.' # not strictly private range, but link local
for i in $(seq 16 31) ; do # 172.16.0.0/12
    PATTERN+="|^172\.$i\." 
done
egrep "$PATTERN"
exit 0

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

ifconfig | grep 'inet addr' | cut -d ':' -f 2 | awk '{ print $1 }' | ./filter_private_ips
0
27.01.2020, 20:15

Показать частные IP-адреса

ip -o addr show | \
  grep -v 'inet6' | \
  grep -v 'scope host' | \
  awk '{print $4}' | \
  cut -d '/' -f 1 | \
  grep -E '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.)'

Показать общедоступные IP-адреса

ip -o addr show | \
  grep -v 'inet6' | \
  grep -v 'scope host' | \
  awk '{print $4}' | \
  cut -d '/' -f 1 | \
  grep -vE '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.)'
1
27.01.2020, 20:15

Теги

Похожие вопросы