개요
IPv6 주소 체계에서는 'Special IPv6 addresses' 라고 부르는, 미리 정의된 특별한 주소들이 있다.
미리 정의된 비트 패턴(bit pattern) 으로 각 주소의 역할을 구분한다.
최근들어 C언어로 네트워크 프로그래밍을 하면서 IPv6 주소를 다루게 되는 경우가 발생하곤 하는데, 이 주소가 특정 Special IPv6 address 인지 아닌지를 확인 해야 하는 경우가 있었다.
그래서 조금 찾아보니, 이런 경우 유용하게 사용 할 수 있는 매크로 함수가 C의 표준 라이브러리인 glibc 의 netinet/in.h 헤더에 정의가 되어 있었다.
이번 포스팅에서는 이들 매크로 함수들을 간단히 소개한다.
특수 IPv6 주소(Special IPv6 Address) 검사 매크로 함수
IEEE Std 1003.1, 2004 Edition 에는, <netinet/in.h> 헤더는 아래와 같은 매크로들을 정의해야 한다고 권고하고 있다.
이 각각의 매크로들은 인자로 하나의 const struct in6_addr * type을 받으며, 인자의 IPv6 주소가 special IPv6 addresses 인지 아닌지를 검사하고 int type으로 참인 경우 1 / 거짓인 경우 0을 반환하는 기능을 한다.
아래 내용중, 실제 정의 내용은 glibc/inet/netinet/in.h 에서 발췌했다. 정확한 버전은 기억나지 않는다.
변경될 만한 성격의 것이 아니라 버전마다 다를 가능성은 적지만, 단언하긴 어려우며 확인이 필요하다.
IN6_IS_ADDR_UNSPECIFIED(addr)
정의되지 않은 주소(Unspecified address) 여부를 검사한다.
정의되지 않은 주소이면 1을 반환한다.
정의되지 않은 주소가 아니면 0을 반환한다.
참고로 IPv6에서 정의되지 않은 주소는 ::/128 이다.
헤더파일에는 아래와 같이 정의되어 있다.
#ifdef __GNUC__
# define IN6_IS_ADDR_UNSPECIFIED(a) \
(__extension__ \
({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
__a->__in6_u.__u6_addr32[0] == 0 \
&& __a->__in6_u.__u6_addr32[1] == 0 \
&& __a->__in6_u.__u6_addr32[2] == 0 \
&& __a->__in6_u.__u6_addr32[3] == 0; }))
#else
# define IN6_IS_ADDR_UNSPECIFIED(a) \
(((const uint32_t *) (a))[0] == 0 \
&& ((const uint32_t *) (a))[1] == 0 \
&& ((const uint32_t *) (a))[2] == 0 \
&& ((const uint32_t *) (a))[3] == 0)
#endif
IN6_IS_ADDR_LOOPBACK(addr)
local host로의 루프백 주소(Loopback address) 여부를 검사한다.
루프백 주소이면 1을 반환한다.
루프백 주소가 아니면 0을 반환한다.
참고로 IPv6에서 루프백 주소는 ::1/128 이다. IPv4의 127.0.0.1과 같은 역할을 한다.
헤더파일에는 아래와 같이 정의되어 있다.
#ifdef __GNUC__
# define IN6_IS_ADDR_LOOPBACK(a) \
(__extension__ \
({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
__a->__in6_u.__u6_addr32[0] == 0 \
&& __a->__in6_u.__u6_addr32[1] == 0 \
&& __a->__in6_u.__u6_addr32[2] == 0 \
&& __a->__in6_u.__u6_addr32[3] == htonl (1); }))
#else
# define IN6_IS_ADDR_LOOPBACK(a) \
(((const uint32_t *) (a))[0] == 0 \
&& ((const uint32_t *) (a))[1] == 0 \
&& ((const uint32_t *) (a))[2] == 0 \
&& ((const uint32_t *) (a))[3] == htonl (1))
#endif
IN6_IS_ADDR_MULTICAST(addr)
멀티캐스트 주소 (Multicast address) 여부를 검사한다.
멀티캐스트 주소이면 1을 반환한다.
멀티캐스트 주소가 아니면 0을 반환한다.
IPv6 에서 멀티캐스트 주소라고 하면, ff0X:: 로 시작하는 주소이다. 여기서 X는 16 진수 값으로 예약되어 있으므로 멀티캐스트 그룹에 할당하면 안된다. 이 예약에 대해서는 IANA (Internet Assigned Numbers Authority)가 관리한다. 현재까지는, 이 X의 값으로 scope를 구분한다.
현재는 0, 1, 2, 3, 5, 6, 7, 8, e, f 가 사용되고 있는데, 이중.. 1 (interface-local), 2 (link-local), 5 (site-local)를 의미한다. 다른 값들도 특정한 의미가 있다.
간단히 예를 들어보면, ff02::2 는 link-local의 모든 라우터를 지칭하는 주소이고, ff01::2 는 interface-local의 모든 라우터를 지칭하는 주소이며, ff05::2는 site-local의 모든 라우터를 지칭하는 주소인 식이다.
이에 대해서는 별도의 포스팅으로 한번 더 다뤄보겠다.
헤더파일에는 이 매크로를 아래와 같이 정의하고 있다.
#define IN6_IS_ADDR_MULTICAST(a) (((const uint8_t *) (a))[0] == 0xff)
IN6_IS_ADDR_LINKLOCAL(addr)
유니캐스트 링크로컬 주소(Unicast link-local address) 여부를 검사한다.
유니캐스트 링크로컬 주소이면 1을 반환한다.
유니캐스트 링크로컬 주소가 아니면 0을 반환한다.
헤더파일에는 아래와 같이 정의하고 있다.
#ifdef __GNUC__
# define IN6_IS_ADDR_LINKLOCAL(a) \
(__extension__ \
({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
(__a->__in6_u.__u6_addr32[0] & htonl (0xffc00000)) == htonl (0xfe800000); }))
#else
# define IN6_IS_ADDR_LINKLOCAL(a) \
((((const uint32_t *) (a))[0] & htonl (0xffc00000)) \
== htonl (0xfe800000))
#endif
IN6_IS_ADDR_SITELOCAL(addr)
유니캐스트 사이트 로컬 주소(Unicast site-local address) 여부를 검사한다.
유니캐스트 사이트 로컬 주소이면 1을 반환한다.
유니캐스트 사이트 로컬 주소가 아니면 0을 반환한다.
헤더파일에는 아래와 같이 정의되어 있다.
#ifdef __GNUC__
# define IN6_IS_ADDR_SITELOCAL(a) \
(__extension__ \
({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
(__a->__in6_u.__u6_addr32[0] & htonl (0xffc00000)) == htonl (0xfec00000); }))
#else
# define IN6_IS_ADDR_SITELOCAL(a) \
((((const uint32_t *) (a))[0] & htonl (0xffc00000)) \
== htonl (0xfec00000))
#endif
IN6_IS_ADDR_V4MAPPED(addr)
IPv4 매핑된 주소(IPv4 mapped address) 여부를 검사한다.
참고로 IPv4 mapped address는 prefix가 ::ffff:0:0/96 이고, 범위는 ::ffff:0.0.0.0부터 ::ffff:255.255.255.255 까지 이다.
이 매크로는, 인자 addr이 이에 해당하는 지를 검사하여 결과를 반환한다.
헤더파일에는 아래와 같이 정의되어 있다.
#ifdef __GNUC__
# define IN6_IS_ADDR_V4MAPPED(a) \
(__extension__ \
({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
__a->__in6_u.__u6_addr32[0] == 0 \
&& __a->__in6_u.__u6_addr32[1] == 0 \
&& __a->__in6_u.__u6_addr32[2] == htonl (0xffff); }))
#else
# define IN6_IS_ADDR_V4MAPPED(a) \
((((const uint32_t *) (a))[0] == 0) \
&& (((const uint32_t *) (a))[1] == 0) \
&& (((const uint32_t *) (a))[2] == htonl (0xffff)))
#endif
IN6_IS_ADDR_V4COMPAT(addr)
IPv4 호환 주소(IPv4-compatible address) 여부를 검사한다.
참고로 IPv4-compatible address의 prefix는 ::/96 이다. 그러나 이 주소 prefix는 deprecated 되었음을 기억하자.
이 매크로는 헤더파일에 아래와 같이 정의되어 있다.
#ifdef __GNUC__
# define IN6_IS_ADDR_V4COMPAT(a) \
(__extension__ \
({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
__a->__in6_u.__u6_addr32[0] == 0 \
&& __a->__in6_u.__u6_addr32[1] == 0 \
&& __a->__in6_u.__u6_addr32[2] == 0 \
&& ntohl (__a->__in6_u.__u6_addr32[3]) > 1; }))
#else
# define IN6_IS_ADDR_V4COMPAT(a) \
((((const uint32_t *) (a))[0] == 0) \
&& (((const uint32_t *) (a))[1] == 0) \
&& (((const uint32_t *) (a))[2] == 0) \
&& (ntohl (((const uint32_t *) (a))[3]) > 1))
#endif
IN6_IS_ADDR_MC_NODELOCAL
멀티캐스트 노드 로컬 주소 (Multicast node-local address) 여부를 검사한다.
이 매크로는 헤더파일에 아래와 같이 정의되어 있다.
#define IN6_IS_ADDR_MC_NODELOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) \
&& ((((const uint8_t *) (a))[1] & 0xf) == 0x1))
IN6_IS_ADDR_MC_LINKLOCAL
멀티캐스트 링크 로컬 주소 (Multicast link-local address) 여부를 검사한다.
이 매크로는 헤더파일에 아래와 같이 정의되어 있다.
#define IN6_IS_ADDR_MC_LINKLOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) \
&& ((((const uint8_t *) (a))[1] & 0xf) == 0x2))
IN6_IS_ADDR_MC_SITELOCAL
멀티캐스트 사이트-로컬 주소(Multicast site-local address) 여부를 검사한다.
멀티캐스트 사이트-로컬 주소이면 1을 반환한다.
멀티캐스트 사이트-로컬 주소가 아니면 0을 반환한다.
헤더파일에는 아래와 같이 정의되어 있다.
#define IN6_IS_ADDR_MC_SITELOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) \
&& ((((const uint8_t *) (a))[1] & 0xf) == 0x5))
IN6_IS_ADDR_MC_ORGLOCAL
멀티캐스트 organization-local 주소(Multicast organization-local address) 여부를 검사한다.
참고로 organization-local 주소의 prefix는 ffx8::/16 이고, IPv4의 239.192.0.0/14 와 동일하다.
헤더파일에는 아래와 같이 정의되어 있다.
#define IN6_IS_ADDR_MC_ORGLOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) \
&& ((((const uint8_t *) (a))[1] & 0xf) == 0x8))
IN6_IS_ADDR_MC_GLOBAL
멀티캐스트 글로벌 주소(Multicast global address) 여부를 검사한다.
멀티캐스트 글로벌 주소이면 1을 반환한다.
멀티캐스트 글로벌 주소가 아니면 0을 반환한다.
헤더파일에는 아래와 같이 정의되어 있다.
#define IN6_IS_ADDR_MC_GLOBAL(a) \
(IN6_IS_ADDR_MULTICAST(a) \
&& ((((const uint8_t *) (a))[1] & 0xf) == 0xe))
참조 - 예약된 IPv6 주소(Reserved IPv6 address)
Special IPv6 address와 같이 볼 것이 있는데, Reserved IPv6 address 이다. IPv6 주소 체계에서 특수 목적으로 예약된 몇몇 주소들인데, 아래 wiki의 표와 같다.
https://en.wikipedia.org/wiki/Reserved_IP_addresses#IPv6
'개발자의 기록 노트 > C' 카테고리의 다른 글
pow( ) - 거듭제곱 함수 구현하기(정수 기반) (0) | 2017.12.21 |
---|---|
[네트워크/C reference] inet_pton 함수 (0) | 2017.11.12 |
[네트워크/C reference] inet_ntop 함수 (0) | 2017.11.02 |
[C][CURL] CURLOPT_FOLLOWLOCATION 의 버전별 동작 차이 (0) | 2017.08.31 |
[네트워크/C] addrinfo 구조체 (0) | 2017.06.16 |
[네트워크/C] getaddrinfo 함수 (0) | 2017.06.16 |