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

반응형

본 글에서는 리눅스 시스템의 네트워크 인터페이스에 MAC 주소를 설정하는 프로그램을 작성하는 방법에 대해 설명한다. 

 

프로그램 상에서 네트워크 인터페이스의 MAC 주소를 설정하는 기본 절차는 다음과 같다.

 

  • socket() 함수로 네트워크 인터페이스에 대한 소켓 파일 디스크립터를 연다.
  • struct ifreq 구조체 변수에 설정할 네트워크 인터페이스의 이름(예: eth0), 주소 등을 저장한다.
  • ioctl() 함수의 SIOCSIFHWADDR 명령을 통해 네트워크 인터페이스를 설정한다.

 

다음은 C 언어로 작성된 예제 프로그램의 소스 코드이다.

#include <net/if.h>
#include <net/if_arp.h>
#include <sys/ioctl.h> 
#include <sys/socket.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>


/// MAC 주소 길이
#define MAC_ALEN 6

/// MAC 주소 출력 매크로
#define MAC_ADDR_FMT "%02X:%02X:%02X:%02X:%02X:%02X" 
#define MAC_ADDR_FMT_ARGS(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]


/**
 * @brief 네트워크 인터페이스에 MAC 주소를 설정한다.
 *
 * @param[in] ifname        네트워크 인터페이스 이름
 * @param[in] mac_addr      설정할 MAC 주소 (6바이트 길이)
 * 
 * @retval  0: 성공
 * @retval  -1: 실패
 */
int SetInterfaceMacAddress(const char *ifname, const uint8_t *mac_addr)
{
  struct ifreq ifr;
  int sockfd, ret;

  printf("Set interface(%s) MAC address as "MAC_ADDR_FMT"\n", ifname, MAC_ADDR_FMT_ARGS(mac_addr));

  /*
   * 네트워크 인터페이스 소켓을 연다.
   */
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  if(sockfd < 0) {
    printf("Fail to set interface MAC address - socket() failed - %m\n");
    return -1;
  }

  /*
   * 네트워크 인터페이스의 MAC 주소를 설정한다.
   */
  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
  memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, MAC_ALEN);
  ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
  ret = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
  if (ret < 0) {
    printf("Fail to set interface MAC address - ioctl(SIOCSIFHWADDR) failed - %m\n");
    close(sockfd);
    return -1;
  }

  /*
   * 네트워크 인터페이스 소켓을 닫는다.
   */
  close(sockfd);

  printf("Success to set interface MAC address\n");
  return 0;
}


/**
 * 테스트 어플리케이션
 */ 
int main(int argc, char *argv[])
{
  const char *ifname = "eth0";
  const uint8_t mac_addr[MAC_ALEN] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };

  return SetInterfaceMacAddress(ifname, mac_addr);
}

 

 

 

위 코드를 빌드 후 실행하면 다음과 같이 eth0 인터페이스의 MAC 주소가 변경되는 것을 확인할 수 있다.

root@1ab6ed1b1eec:/workspace# gcc test.c
root@1ab6ed1b1eec:/workspace# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:02
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:10 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:836 (836.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

root@1ab6ed1b1eec:/workspace# ./a.out
Set interface(eth0) MAC address as 00:01:02:03:04:05
Success to set interface MAC address
root@1ab6ed1b1eec:/workspace# ifconfig
eth0      Link encap:Ethernet  HWaddr 00:01:02:03:04:05
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:906 (906.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

root@1ab6ed1b1eec:/workspace#

 

참고로 위 프로그램을 도커 컨테이너 상에서 실행할 경우에는, 네트워크 디바이스로의 접근을 위해 privileged 모드 컨테이너 상에서 실행해야 한다.

댓글

Designed by JB FACTORY