본 글에서는 리눅스 시스템의 각 네트워크 인터페이스에 할당되어 있는 IPv6 주소(들)을 확인하는 프로그램을 작성하는 법에 대해 설명한다.
본 글에서 다루는 IPv6 주소 확인 관련 기능은 다음과 같으며, 각 기능 별 예제 프로그램은 C 언어로 작성되었다.
- 네트워크 인터페이스에 할당된 모든 IPv6 주소 확인하기
- 네트워크 인터페이스에 할당된 링크-로컬 IPv6 주소 확인하기
- 네트워크 인터페이스에 할당된 사이트-로컬 IPv6 주소 확인하기
- 네트워크 인터페이스에 할당된 글로벌 IPv6 주소 확인하기
- 네트워크 인터페이스에 할당된 루프백 IPv6 주소 확인하기
네트워크 인터페이스에 IPv6 주소를 할당(추기)하거나 제거하는 방법은 아래 글에 설명되어 있다.
2020/02/08 - [프로그래밍/리눅스 프로그래밍] - 리눅스 네트워크 프로그래밍 - 네트워크 인터페이스 IPv6 주소 설정하기
개요
리눅스 시스템 상에서, 각 네트워크 인터페이스에 할당된 IPv6 주소는 /proc/net/if_inet6 파일에서 확인할 수 있다. 해당 파일은 각 라인 별로 하나의 IPv6 주소 정보를 담고 있다.
해당 파일은 사람이 읽을 수 있는 문자열 형태로 작성된 텍스트 파일이며, 사용자가 읽을 수는 있으나 수정할 수는 없다.
리눅스 터미널 상에서 cat 명령을 이용하여 해당 파일의 내용을 읽을 수 있다.
$ cat /proc/net/if_inet6
fe80000000000000024954fffe454b01 05 40 20 80 eth0
본 글에 소개된 모든 예제에서는, 프로그램 상에서 위 파일을 읽어 들여 파싱함으로써 IPv6 주소를 확인하는 방법을 사용한다.
네트워크 인터페이스에 할당된 모든 IPv6 주소 확인하기
프로그램 상에서 /proc/net/if_inet6 파일을 읽어 들여, 각 네트워크 인터페이스 별로 할당된 IPv6 주소를 확인한다.
다음은 네트워크 인터페이스에 할당된 IPv6 주소들을 화면에 출력하는 예제 함수이다.
#include <arpa/inet.h>
#include <net/if.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/// 라인버퍼 길이
#define LINE_BUF_LEN 255
/// IPv6 주소 길이
#define IPv6_ALEN 16
/// IPv6 주소 문자열 최대 길이
#define IPv6_ADDR_STR_MAX_LEN ((IPv6_ALEN*2) + 7)
/**
* 특정 네트워크 인터페이스에 할당된 IPv6 주소들을 출력한다.
* @param[in] if_name 네트워크 인터페이스 이름(예: eth0)
* @retval 0: 성공
* @retval -1: 실패
*/
int PrintIPv6Addressess(const char *if_name)
{
/*
* IPv6 주소정보파일을 연다.
*/
FILE *fp = fopen("/proc/net/if_inet6", "r");
if (fp == NULL) {
perror("Fail to fopen(): ");
return -1;
}
int n, prefix_len, scope, flags, size;
char line[LINE_BUF_LEN];
char ifname[IFNAMSIZ+1];
char ip_addr_hex_str[(IPv6_ALEN*2)+1]; // 예: "fe80000000000000024954fffe454b01"
char ip_addr_str[IPv6_ADDR_STR_MAX_LEN+1]; // 예: "fe80::1"
uint8_t ip_addr[IPv6_ALEN];
/*
* IPv6 주소정보파일의 각 라인을 확인하면서, 원하는 네트워크 인터페이스에 대한 정보인 경우, 해당 IPv6 주소를 화면에 출력한다.
* IPv6 주소정보파일은 각 라인 별로 하나의 IPv6 주소 정보를 담고 있으며, 그 형식은 다음과 같다.
* - address, netlink device number(hex), prefix length(hex), scope(hex), flags, name
* - 예: fe80000000000000024954fffe454b01 05 40 20 80 eth0
*/
while(!feof(fp))
{
// 한 줄을 읽는다.
memset(line, 0, sizeof(line));
if(fgets(line, sizeof(line), fp) == NULL) {
break;
}
// 읽은 줄의 내용을 항목 별로 파싱한다.
memset(ip_addr_hex_str, 0, sizeof(ip_addr_hex_str));
memset(ifname, 0, sizeof(ifname));
sscanf(line, "%s %d %x %x %x %s", ip_addr_hex_str, &n, &prefix_len, &scope, &flags, ifname);
// 원하는 인터페이스 이름을 가질 경우, IPv6 주소를 화면에 출력한다.
if(!strcmp(ifname, if_name)) {
ConvertHexStrToArray(ip_addr_hex_str, ip_addr);
printf("%s/%d\n", inet_ntop(AF_INET6, ip_addr, ip_addr_str, sizeof(ip_addr_str)), prefix_len);
}
}
/*
* IPv6 주소정보파일을 닫는다.
*/
fclose(fp);
return 0;
}
네트워크 인터페이스에 할당된 링크-로컬 IPv6 주소 확인하기
기본적인 방법은 위에서 설명한 IPv6 주소 확인 방법과 동일하다.
/proc/net/if_inet6 파일에서 읽어들인 주소 정보 중 scope 값이 IPV6_ADDR_LINKLOCAL(0x0020U)인 주소가 링크-로컬 IPv6 주소이다. 참고로 IPV6_ADDR_LINKLOCAL 은 net/ipv6.h 헤더 파일에 정의되어 있다.
다음은 네트워크 인터페이스에 할당된 IPv6 주소 중 링크-로컬 IPv6 주소만 화면에 출력하는 예제 함수이다.
#include <arpa/inet.h>
#include <net/if.h>
#include <net/ipv6.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/// 라인버퍼 길이
#define LINE_BUF_LEN 255
/// IPv6 주소 길이
#define IPv6_ALEN 16
/// IPv6 주소 문자열 최대 길이
#define IPv6_ADDR_STR_MAX_LEN ((IPv6_ALEN*2) + 7)
/**
* 특정 네트워크 인터페이스에 할당된 링크로컬 IPv6 주소를 출력한다.
* @param[in] if_name 네트워크 인터페이스 이름(예: eth0)
* @retval 0: 성공
* @retval -1: 실패
*/
int PrintLinkLocalIPv6Addressess(const char *if_name)
{
/*
* IPv6 주소정보파일을 연다.
*/
FILE *fp = fopen("/proc/net/if_inet6", "r");
if (fp == NULL) {
perror("Fail to fopen(): ");
return -1;
}
int n, prefix_len, scope, flags, size;
char line[LINE_BUF_LEN];
char ifname[IFNAMSIZ+1];
char ip_addr_hex_str[(IPv6_ALEN*2)+1]; // 예: "fe80000000000000024954fffe454b01"
char ip_addr_str[IPv6_ADDR_STR_MAX_LEN+1]; // 예: "fe80::1"
uint8_t ip_addr[IPv6_ALEN];
/*
* IPv6 주소정보파일의 각 라인을 확인하면서, 원하는 네트워크 인터페이스에 대한 정보인 경우, 해당 IPv6 주소를 화면에 출력한다.
* IPv6 주소정보파일은 각 라인 별로 하나의 IPv6 주소 정보를 담고 있으며, 그 형식은 다음과 같다.
* - address, netlink device number(hex), prefix length(hex), scope(hex), flags, name
* - 예: fe80000000000000024954fffe454b01 05 40 20 80 eth0
*/
while(!feof(fp))
{
// 한 줄을 읽는다.
memset(line, 0, sizeof(line));
if(fgets(line, sizeof(line), fp) == NULL) {
break;
}
// 읽은 줄의 내용을 항목 별로 파싱한다.
memset(ip_addr_hex_str, 0, sizeof(ip_addr_hex_str));
memset(ifname, 0, sizeof(ifname));
sscanf(line, "%s %d %x %x %x %s", ip_addr_hex_str, &n, &prefix_len, &scope, &flags, ifname);
// 원하는 인터페이스 이름을 가질 경우, 링크로컬 IPv6 주소를 화면에 출력한다.
if(!strcmp(ifname, if_name) && (scope == IPV6_ADDR_LINKLOCAL)) {
ConvertHexStrToArray(ip_addr_hex_str, ip_addr);
printf("%s/%d\n", inet_ntop(AF_INET6, ip_addr, ip_addr_str, sizeof(ip_addr_str)), prefix_len);
}
}
/*
* IPv6 주소정보파일을 닫는다.
*/
fclose(fp);
return 0;
}
네트워크 인터페이스에 할당된 사이트-로컬 IPv6 주소 확인하기
기본적인 방법은 위에서 설명한 IPv6 주소 확인 방법과 동일하다.
/proc/net/if_inet6 파일에서 읽어들인 주소 정보 중 scope 값이 IPV6_ADDR_SITELOCAL(0x0040U)인 주소가 사이트-로컬 IPv6 주소이다. 참고로 IPV6_ADDR_SITELOCAL 은 net/ipv6.h 헤더 파일에 정의되어 있다.
다음은 네트워크 인터페이스에 할당된 IPv6 주소 중 사이트-로컬 IPv6 주소만 화면에 출력하는 예제 함수이다.
#include <arpa/inet.h>
#include <net/if.h>
#include <net/ipv6.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/// 라인버퍼 길이
#define LINE_BUF_LEN 255
/// IPv6 주소 길이
#define IPv6_ALEN 16
/// IPv6 주소 문자열 최대 길이
#define IPv6_ADDR_STR_MAX_LEN ((IPv6_ALEN*2) + 7)
/**
* 특정 네트워크 인터페이스에 할당된 사이트-로컬 IPv6 주소를 출력한다.
* @param[in] if_name 네트워크 인터페이스 이름(예: eth0)
* @retval 0: 성공
* @retval -1: 실패
*/
int PrintSiteLocalIPv6Addressess(const char *if_name)
{
/*
* IPv6 주소정보파일을 연다.
*/
FILE *fp = fopen("/proc/net/if_inet6", "r");
if (fp == NULL) {
perror("Fail to fopen(): ");
return -1;
}
int n, prefix_len, scope, flags, size;
char line[LINE_BUF_LEN];
char ifname[IFNAMSIZ+1];
char ip_addr_hex_str[(IPv6_ALEN*2)+1]; // 예: "fe80000000000000024954fffe454b01"
char ip_addr_str[IPv6_ADDR_STR_MAX_LEN+1]; // 예: "fe80::1"
uint8_t ip_addr[IPv6_ALEN];
/*
* IPv6 주소정보파일의 각 라인을 확인하면서, 원하는 네트워크 인터페이스에 대한 정보인 경우, 해당 IPv6 주소를 화면에 출력한다.
* IPv6 주소정보파일은 각 라인 별로 하나의 IPv6 주소 정보를 담고 있으며, 그 형식은 다음과 같다.
* - address, netlink device number(hex), prefix length(hex), scope(hex), flags, name
* - 예: fe80000000000000024954fffe454b01 05 40 20 80 eth0
*/
while(!feof(fp))
{
// 한 줄을 읽는다.
memset(line, 0, sizeof(line));
if(fgets(line, sizeof(line), fp) == NULL) {
break;
}
// 읽은 줄의 내용을 항목 별로 파싱한다.
memset(ip_addr_hex_str, 0, sizeof(ip_addr_hex_str));
memset(ifname, 0, sizeof(ifname));
sscanf(line, "%s %d %x %x %x %s", ip_addr_hex_str, &n, &prefix_len, &scope, &flags, ifname);
// 원하는 인터페이스 이름을 가질 경우, 사이트-로컬 IPv6 주소를 화면에 출력한다.
if(!strcmp(ifname, if_name) && (scope == IPV6_ADDR_SITELOCAL)) {
ConvertHexStrToArray(ip_addr_hex_str, ip_addr);
printf("%s/%d\n", inet_ntop(AF_INET6, ip_addr, ip_addr_str, sizeof(ip_addr_str)), prefix_len);
}
}
/*
* IPv6 주소정보파일을 닫는다.
*/
fclose(fp);
return 0;
}
네트워크 인터페이스에 할당된 글로벌 IPv6 주소 확인하기
기본적인 방법은 위에서 설명한 IPv6 주소 확인 방법과 동일하다.
/proc/net/if_inet6 파일에서 읽어들인 주소 정보 중 scope 값이 IPV6_ADDR_ANY(0x0000U)인 주소가 글로벌 IPv6 주소이다. 참고로 IPV6_ADDR_ANY 는 net/ipv6.h 헤더 파일에 정의되어 있다.
다음은 네트워크 인터페이스에 할당된 IPv6 주소 중 글로벌 IPv6 주소만 화면에 출력하는 예제 함수이다.
#include <arpa/inet.h>
#include <net/if.h>
#include <net/ipv6.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/// 라인버퍼 길이
#define LINE_BUF_LEN 255
/// IPv6 주소 길이
#define IPv6_ALEN 16
/// IPv6 주소 문자열 최대 길이
#define IPv6_ADDR_STR_MAX_LEN ((IPv6_ALEN*2) + 7)
/**
* 특정 네트워크 인터페이스에 할당된 글로벌 IPv6 주소를 출력한다.
* @param[in] if_name 네트워크 인터페이스 이름(예: eth0)
* @retval 0: 성공
* @retval -1: 실패
*/
int PrintGlobalIPv6Addressess(const char *if_name)
{
/*
* IPv6 주소정보파일을 연다.
*/
FILE *fp = fopen("/proc/net/if_inet6", "r");
if (fp == NULL) {
perror("Fail to fopen(): ");
return -1;
}
int n, prefix_len, scope, flags, size;
char line[LINE_BUF_LEN];
char ifname[IFNAMSIZ+1];
char ip_addr_hex_str[(IPv6_ALEN*2)+1]; // 예: "fe80000000000000024954fffe454b01"
char ip_addr_str[IPv6_ADDR_STR_MAX_LEN+1]; // 예: "fe80::1"
uint8_t ip_addr[IPv6_ALEN];
/*
* IPv6 주소정보파일의 각 라인을 확인하면서, 원하는 네트워크 인터페이스에 대한 정보인 경우, 해당 IPv6 주소를 화면에 출력한다.
* IPv6 주소정보파일은 각 라인 별로 하나의 IPv6 주소 정보를 담고 있으며, 그 형식은 다음과 같다.
* - address, netlink device number(hex), prefix length(hex), scope(hex), flags, name
* - 예: fe80000000000000024954fffe454b01 05 40 20 80 eth0
*/
while(!feof(fp))
{
// 한 줄을 읽는다.
memset(line, 0, sizeof(line));
if(fgets(line, sizeof(line), fp) == NULL) {
break;
}
// 읽은 줄의 내용을 항목 별로 파싱한다.
memset(ip_addr_hex_str, 0, sizeof(ip_addr_hex_str));
memset(ifname, 0, sizeof(ifname));
sscanf(line, "%s %d %x %x %x %s", ip_addr_hex_str, &n, &prefix_len, &scope, &flags, ifname);
// 원하는 인터페이스 이름을 가질 경우, 글로벌 IPv6 주소를 화면에 출력한다.
if(!strcmp(ifname, if_name) && (scope == IPV6_ADDR_ANY)) {
ConvertHexStrToArray(ip_addr_hex_str, ip_addr);
printf("%s/%d\n", inet_ntop(AF_INET6, ip_addr, ip_addr_str, sizeof(ip_addr_str)), prefix_len);
}
}
/*
* IPv6 주소정보파일을 닫는다.
*/
fclose(fp);
return 0;
}
네트워크 인터페이스에 할당된 루프백 IPv6 주소 확인하기
기본적인 방법은 위에서 설명한 IPv6 주소 확인 방법과 동일하다.
/proc/net/if_inet6 파일에서 읽어들인 주소 정보 중 scope 값이 IPV6_ADDR_LOOPBACK(0x0010U)인 주소가 루프백 IPv6 주소이다. 참고로 IPV6_ADDR_LOOPBACK 은 net/ipv6.h 헤더 파일에 정의되어 있다.
다음은 네트워크 인터페이스에 할당된 IPv6 주소 중 루프백 IPv6 주소만 화면에 출력하는 예제 함수이다.
#include <arpa/inet.h>
#include <net/if.h>
#include <net/ipv6.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/// 라인버퍼 길이
#define LINE_BUF_LEN 255
/// IPv6 주소 길이
#define IPv6_ALEN 16
/// IPv6 주소 문자열 최대 길이
#define IPv6_ADDR_STR_MAX_LEN ((IPv6_ALEN*2) + 7)
/**
* 특정 네트워크 인터페이스에 할당된 루프백 IPv6 주소를 출력한다.
* @param[in] if_name 네트워크 인터페이스 이름(예: eth0)
* @retval 0: 성공
* @retval -1: 실패
*/
int PrintLoopbackIPv6Addressess(const char *if_name)
{
/*
* IPv6 주소정보파일을 연다.
*/
FILE *fp = fopen("/proc/net/if_inet6", "r");
if (fp == NULL) {
perror("Fail to fopen(): ");
return -1;
}
int n, prefix_len, scope, flags, size;
char line[LINE_BUF_LEN];
char ifname[IFNAMSIZ+1];
char ip_addr_hex_str[(IPv6_ALEN*2)+1]; // 예: "fe80000000000000024954fffe454b01"
char ip_addr_str[IPv6_ADDR_STR_MAX_LEN+1]; // 예: "fe80::1"
uint8_t ip_addr[IPv6_ALEN];
/*
* IPv6 주소정보파일의 각 라인을 확인하면서, 원하는 네트워크 인터페이스에 대한 정보인 경우, 해당 IPv6 주소를 화면에 출력한다.
* IPv6 주소정보파일은 각 라인 별로 하나의 IPv6 주소 정보를 담고 있으며, 그 형식은 다음과 같다.
* - address, netlink device number(hex), prefix length(hex), scope(hex), flags, name
* - 예: fe80000000000000024954fffe454b01 05 40 20 80 eth0
*/
while(!feof(fp))
{
// 한 줄을 읽는다.
memset(line, 0, sizeof(line));
if(fgets(line, sizeof(line), fp) == NULL) {
break;
}
// 읽은 줄의 내용을 항목 별로 파싱한다.
memset(ip_addr_hex_str, 0, sizeof(ip_addr_hex_str));
memset(ifname, 0, sizeof(ifname));
sscanf(line, "%s %d %x %x %x %s", ip_addr_hex_str, &n, &prefix_len, &scope, &flags, ifname);
// 원하는 인터페이스 이름을 가질 경우, 루프백 IPv6 주소를 화면에 출력한다.
if(!strcmp(ifname, if_name) && (scope == IPV6_ADDR_LOOPBACK)) {
ConvertHexStrToArray(ip_addr_hex_str, ip_addr);
printf("%s/%d\n", inet_ntop(AF_INET6, ip_addr, ip_addr_str, sizeof(ip_addr_str)), prefix_len);
}
}
/*
* IPv6 주소정보파일을 닫는다.
*/
fclose(fp);
return 0;
}
'프로그래밍 > 리눅스 프로그래밍' 카테고리의 다른 글
리눅스 네트워크 프로그래밍 - CAN(Controller Area Network) 통신 (2) | 2020.04.27 |
---|---|
리눅스 네트워크 프로그래밍 - UDP6(UDP over IPv6) 송수신 (0) | 2020.03.04 |
리눅스 네트워크 프로그래밍 - 네트워크 인터페이스 비활성화하기 (0) | 2020.02.16 |
리눅스 네트워크 프로그래밍 - 네트워크 인터페이스 활성화하기 (0) | 2020.02.15 |
리눅스 네트워크 프로그래밍 - 네트워크 인터페이스 MAC 주소 확인하기 (0) | 2020.02.15 |
리눅스 네트워크 프로그래밍 - 네트워크 인터페이스 MAC 주소 설정하기 (0) | 2020.02.15 |
리눅스 네트워크 프로그래밍 - inet_ntop() : IPv6 주소를 문자열로 변환 (0) | 2020.02.12 |
리눅스 네트워크 프로그래밍 - 네트워크 인터페이스 IPv6 주소 설정하기 (0) | 2020.02.09 |