리눅스 네트워크 프로그래밍 - 네트워크 인터페이스 MAC 주소 설정하기
- 프로그래밍/리눅스 프로그래밍
- 2020. 2. 15.
반응형
본 글에서는 리눅스 시스템의 네트워크 인터페이스에 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 모드 컨테이너 상에서 실행해야 한다.
'프로그래밍 > 리눅스 프로그래밍' 카테고리의 다른 글
리눅스 네트워크 프로그래밍 - 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 |
리눅스 네트워크 프로그래밍 - inet_ntop() : IPv6 주소를 문자열로 변환 (0) | 2020.02.12 |
리눅스 네트워크 프로그래밍 - 네트워크 인터페이스 IPv6 주소 설정하기 (0) | 2020.02.09 |
리눅스 네트워크 프로그래밍 - 네트워크 인터페이스 IPv6 주소 확인하기 (0) | 2020.02.08 |