리눅스 네트워크 프로그래밍 - 네트워크 인터페이스 IPv6 주소 확인하기

반응형

본 글에서는 리눅스 시스템의 각 네트워크 인터페이스에 할당되어 있는 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;
}

 

댓글

Designed by JB FACTORY