Java/Short 개발

[Java/Short] IPv4, IPv6 정규 표현식(RegExp) 구성 방법

adjh54 2024. 1. 29. 11:02
반응형
해당 글에서는 IPv4, IPv6에 대한 정규식을 수행하는 방법에 대해 알아봅니다.


 

 

1) IPv4


💡 IPv4

- 인터넷 프로토콜 버전 4로 컴퓨터와 같은 디바이스가 인터넷을 통해 서로 통신하기 위해 사용하는 주소 체계입니다.
- 각 디바이스에 고유한 식별자를 제공하며, 이를 통해 데이터 패킷이 올바른 위치로 전송될 수 있게 합니다.
- IPv4 주소는 32비트로 구성되며, 일반적으로 점으로 구분된 4개의 숫자로 표현됩니다.

 

 

1. IPv4


💡 IPv4 형태

- Octet의 범위는 점(.)의 구분자를 기준으로 4자리 모두 0 ~ 255자리의 값을 가집니다.
- 또한 0 ~ 255 범위 내에서 ‘0xx 형태의 값’을 가지는 경우 해당 경우에 포함되지 않습니다.
Octet Start Range Octet End Range Example
0 255 0.255.255.255
0 255 255.0.255.255
0 255 255.255.0.255
0 255 255.255.255.0

 

 

[ 더 알아보기 ]

💡 옥텟(Octet)


- 컴퓨터 네트워킹에서 매우 중요한 개념입니다. IPv4 주소는 4개의 옥텟으로 이루어져 있으며, 각 옥텟은 0부터 255까지의 값을 가질 수 있습니다.
- 옥텟이 8비트(또는 1바이트) 데이터를 나타내며, 8비트는 2의 8승인 256개의 유일한 값을 표현할 수 있기 때문입니다. 0부터 세면 총 256개의 값이므로 각 옥텟의 범위는 0부터 255까지입니다.

https://bluecatnetworks.com/glossary/what-is-ipv4/

 

 

2. Ipv4 정규식 유형


💡 정규식 유형

- IPv4 주소의 가장 일반적인 형태의 4개의 0-255 범위의 숫자로 이루어진 그룹을 점(.)으로 구분하는 형태를 검증합니다.

- (([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3} 부분은 0-255 범위의 숫자와 점(.)을 3번 반복하는 패턴입니다.
- 마지막에 있는 ([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]) 부분은 마지막 0-255 범위의 숫자를 나타냅니다.
public static final String REGEXP_IPV4_ADDR = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";

 

 

 

3. Ipv4 사용예시


 💡 사용예시

- 해당 정규식에서 123.023.123.123는 IPv4주소가 될 수 없습니다.
- 각 옥텟은 0부터 255까지의 값을 가져야 하지만 옥텟에 앞에 ‘0’이 붙는 값(023와 같은)이 포함되지 않습니다.
String REGEXP_IPV4_ADDR = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";
String[] ipv4Address = {"123.023.123.123", "1.1.1.12", "119.123.45.39", "127.0.0.1"};

for (String ipAddr : ipv4Address) {
    if (Pattern.matches(REGEXP_IPV4_ADDR, ipAddr)) {
        System.out.println("[+] IPV4 정규식 통과 ::" + ipAddr);
    } else {
        System.out.println("[-] IPV4 정규식 통과 실패 :: " + ipAddr);
    }
}

 

 

 

 

2) IPv6


💡 IPv6

- 인터넷 프로토콜 버전 6으로, IPv4의 주소 공간 제한을 해결하기 위해 개발된 새로운 인터넷 주소 체계입니다.


- IPv6 주소는 128비트로 구성되어 있어, 거의 무한한 수의 유니크한 주소를 제공할 수 있습니다. 

 

 

1. IPv6 형태


💡 IPv6 형태

- IPv6는 총 8개의 4자리 문자와 숫자의 조합으로 콜론(:)의 구분자를 통한 조합으로 이루어져 있습니다.
- 4자리 문자와 숫자의 조합은 16진수 문자(0-9, A-F, a-f)로 이루어져 있습니다.
public static final String REGEXP_IPV6_ADDR = "^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}|([0-9A-Fa-f]{1,4}:){1,5}(:[0-9A-Fa-f]{1,4}){1,2}|([0-9A-Fa-f]{1,4}:){1,4}(:[0-9A-Fa-f]{1,4}){1,3}|([0-9A-Fa-f]{1,4}:){1,3}(:[0-9A-Fa-f]{1,4}){1,4}|([0-9A-Fa-f]{1,4}:){1,2}(:[0-9A-Fa-f]{1,4}){1,5}|[0-9A-Fa-f]{1,4}:((:[0-9A-Fa-f]{1,4}){1,6})|:((:[0-9A-Fa-f]{1,4}){1,7}|:)|fe80:(:[0-9A-Fa-f]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9A-Fa-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))))$"

https://www.computernetworkingnotes.com/networking-tutorials/ipv6-address-types-notation-and-structure-explained.html

 

 

 

2. 정규식 유형


 💡 정규식 유형

- (([0-9A-Fa-f]{1,4}:) 부분은 16진수 문자(0-9, A-F, a-f)를 1개에서 4개까지 허용하며, 이후에 콜론(:)이 오는 패턴을 표현합니다.
String REGEXP_IPV6_ADDR = "^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}|([0-9A-Fa-f]{1,4}:){1,5}(:[0-9A-Fa-f]{1,4}){1,2}|([0-9A-Fa-f]{1,4}:){1,4}(:[0-9A-Fa-f]{1,4}){1,3}|([0-9A-Fa-f]{1,4}:){1,3}(:[0-9A-Fa-f]{1,4}){1,4}|([0-9A-Fa-f]{1,4}:){1,2}(:[0-9A-Fa-f]{1,4}){1,5}|[0-9A-Fa-f]{1,4}:((:[0-9A-Fa-f]{1,4}){1,6})|:((:[0-9A-Fa-f]{1,4}){1,7}|:)|fe80:(:[0-9A-Fa-f]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9A-Fa-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])))$";

 

[ 더 알아보기 ]

💡 IPv6내에서 :: 형태로 나오는 경우가 있는데 이는 뭘까?

- '0'이 연속적으로 나올 때는 'Double Colon(::)'으로 축약이 가능합니다.
- 단, 해당 축약에 대해서는 한 번만 허용합니다. 이는 여러 번 사용하게 되면 몇 개의 '0'이 생략된 지 구분이 안 가기에 한 번만 허용합니다. 

💡 IPv6 내에 정규식을 보면 총 7자리로 되어 있는데 왜 그럴까?

- 해당 이유는 위에서 이야기한 'Double Colon(::)'가 들어 올 수 있다는 정규식을 포함하였기에 7자리로 수행을 합니다.


💡 그러면 7자리에 대해서만 정규식을 수행하는거 아냐?

- 아닙니다. 정규식 내에 "(([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}"는 8개 그룹의 16진수를 허용합니다.
- 이 패턴은 4자리 16진수와 콜론(:)이 정확히 7번 반복되는 것을 나타내고, 그 뒤에 마지막 4자리 16진수가 오게 됩니다. 따라서 이 패턴은 총 8개 그룹의 16진수, 즉 완전한 IPv6 주소를 표현합니다.

 

 

 

3. 사용예시


💡 사용예시

- 119.123.45.39의 값은 IPv4에 해당하기에 해당 정규식을 통과할 수 없습니다.
String[] ipv6Address = {"2001:0db8:85a3:0000:0000:8a2e:0370:7334", "119.123.45.39", "2001:0db8:85a3:0000:0000:8a2e:0370:7335"};
String REGEXP_IPV6_ADDR = "^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}|([0-9A-Fa-f]{1,4}:){1,5}(:[0-9A-Fa-f]{1,4}){1,2}|([0-9A-Fa-f]{1,4}:){1,4}(:[0-9A-Fa-f]{1,4}){1,3}|([0-9A-Fa-f]{1,4}:){1,3}(:[0-9A-Fa-f]{1,4}){1,4}|([0-9A-Fa-f]{1,4}:){1,2}(:[0-9A-Fa-f]{1,4}){1,5}|[0-9A-Fa-f]{1,4}:((:[0-9A-Fa-f]{1,4}){1,6})|:((:[0-9A-Fa-f]{1,4}){1,7}|:)|fe80:(:[0-9A-Fa-f]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9A-Fa-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])))$";

for (String ipAddr : ipv6Address) {
    if (Pattern.matches(REGEXP_IPV6_ADDR, ipAddr)) {
        System.out.println("[+] IPV6 정규식 통과 ::" + ipAddr);
    } else {
        System.out.println("[-] IPV6 정규식 통과 실패 ::" + ipAddr);
    }
}

 

 

 

3) IPv4 + IPv6


💡 IPv4 + IPv6

- 해당 정규식은 위에서 사용한 IPv4와 IPv6 정규식에 대해 “|”(OR) 구분자를 통해서 구성되어 있습니다.
- 이를 통해 IPv4와 IPv6에 대한 값을 정규식으로 필터링할 수 있습니다.
// IPV4 정규식 패턴
String REGEXP_IPV4_ADDR = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";

// IPV6 정규식 패턴
String REGEXP_IPV6_ADDR = "^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|([0-9A-Fa-f]{1,4}:){1,7}:|([0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}|([0-9A-Fa-f]{1,4}:){1,5}(:[0-9A-Fa-f]{1,4}){1,2}|([0-9A-Fa-f]{1,4}:){1,4}(:[0-9A-Fa-f]{1,4}){1,3}|([0-9A-Fa-f]{1,4}:){1,3}(:[0-9A-Fa-f]{1,4}){1,4}|([0-9A-Fa-f]{1,4}:){1,2}(:[0-9A-Fa-f]{1,4}){1,5}|[0-9A-Fa-f]{1,4}:((:[0-9A-Fa-f]{1,4}){1,6})|:((:[0-9A-Fa-f]{1,4}){1,7}|:)|fe80:(:[0-9A-Fa-f]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9A-Fa-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])))$";

// IPV4 OR IPV6 정규식 패턴
String REGEXP_IPV4_IPV6_ADDR = "(" + REGEXP_IPV4_ADDR + "|" + REGEXP_IPV6_ADDR + ")";

String[] ipv4NIpv6Address = {"123.023.123.123", "1.1.1.12", "119.123.45.39", "127.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "119.123.45.39", "2001:0db8:85a3:0000:0000:8a2e:0370:7335"};

for (String ipAddr : ipv4NIpv6Address) {
    if (Pattern.matches(REGEXP_IPV4_IPV6_ADDR, ipAddr)) {
        System.out.println("[+] IPV4 또는 IPV6 정규식 통과 ::" + ipAddr);
    } else {
        System.out.println("[-] IPV4 또는 IPV6 정규식 통과 실패 ::" + ipAddr);
    }
}

 

 

 

 

 

오늘도 감사합니다. 😀

 

 

 

 

 

반응형