프로그래밍 방식으로 개인 IP 주소 추출

프로그래밍 방식으로 개인 IP 주소 추출

프로그래밍 방식으로 추출하는 쉬운 방법을 찾고 있습니다.사적인컴퓨터의 IPv4 주소입니다.

비슷한 것이 문제, 그러나 개인 IP에만 해당됩니다.

예를 들어, 다음을 추출할 수 있습니다.모두다음 명령을 사용하십시오.

ifconfig | grep 'inet addr' | cut -d ':' -f 2 | awk '{ print $1 }'

출력 예:

6.11.71.78
10.0.2.15
127.0.0.1

비슷한 방식으로 개인 주소 공간의 IP만 가져오고 싶습니다. 따라서 동일한 예를 참조하면 출력은 다음과 같아야 합니다.

10.0.2.15

답변1

거기에 아무것도 없어요비공개 IP 공간항상 세 개의 IP 주소 블록 중 하나로 시작하십시오.

  • 24비트 블록 - 10.XXX
  • 20비트 블록 - 172.16.XX - 172.31.XX
  • 16비트 블록 - 192.168.XX

따라서 위 유형의 IP 주소를 찾으려면 grep을 사용하십시오.

$ 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].

또한 이러한 패턴 중 하나로 시작하는 숫자만 명시적으로 일치시킵니다. Anchor( ^)는 우리에게 이러한 능력을 제공하고 있습니다.

더 많은 예시

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

답변2

비공개 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]\.)'

답변3

IPv4는 32비트 시스템이 널리 보급되던 시기에 만들어졌습니다. IPv4 점으로 구분된 10진수 주소는 32비트 부호 없는 정수로 저장될 수 있으며 네트워크 하드웨어는 비트 단위 연산을 효율적으로 수행할 수 있습니다. 172.16.0.0/12 CIDR의 비트마스크는 단일 왼쪽 시프트와 단일 비트 AND를 사용한 주소 확인으로 구성될 수 있습니다.

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

비트 연산을 지원하는 언어를 사용하면 점으로 구분된 10진수 주소를 정수로 쉽게 변환할 수 있습니다.

//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) 네트워크 중 하나에 속하는지 직접 확인할 수 있습니다. shell이나 awk 대신 perl(python이나 ruby도 괜찮습니다)을 선택하고, 단일 비트 단위 연산을 사용하면 작업 부하가 크게 줄어듭니다.

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";
    }
};

Perl 스크립트에서 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); }

답변4

다음 스크립트를 사용하여 출력을 필터링할 수 있습니다(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

관련 정보