
MAC 주소: 물리적 네트워크 식별자
IP는 이사 가면 바뀌지만, MAC 주소는 바뀌지 않습니다. 주민등록번호와 집 주소의 차이. 공장 출고 때 찍히는 고유 번호.

IP는 이사 가면 바뀌지만, MAC 주소는 바뀌지 않습니다. 주민등록번호와 집 주소의 차이. 공장 출고 때 찍히는 고유 번호.
내 서버는 왜 걸핏하면 뻗을까? OS가 한정된 메모리를 쪼개 쓰는 처절한 사투. 단편화(Fragmentation)와의 전쟁.

미로를 탈출하는 두 가지 방법. 넓게 퍼져나갈 것인가(BFS), 한 우물만 팔 것인가(DFS). 최단 경로는 누가 찾을까?

이름부터 빠릅니다. 피벗(Pivot)을 기준으로 나누고 또 나누는 분할 정복 알고리즘. 왜 최악엔 느린데도 가장 많이 쓰일까요?

매번 3-Way Handshake 하느라 지쳤나요? 한 번 맺은 인연(TCP 연결)을 소중히 유지하는 법. HTTP 최적화의 기본.

내가 네트워크를 처음 공부할 때 가장 헷갈렸던 게 "왜 주소가 두 개야?"였다. IP 주소라는 게 있는데, MAC 주소라는 것도 따로 있다고 한다. 둘 다 주소인데 뭐가 다른 걸까?
나는 이렇게 이해했다. IP 주소는 집 주소, MAC 주소는 주민등록번호. 이사 가면 집 주소는 바뀐다. 하지만 내 주민등록번호는 평생 그대로다. 네트워크 장비도 마찬가지다. 네트워크를 바꾸면 IP 주소는 바뀐다. 하지만 MAC 주소는 공장에서 출고될 때 박힌 번호로 평생 간다.
이게 왜 필요한지, 어떻게 작동하는지, 그리고 왜 가끔 문제가 되는지. 실제로 겪은 네트워크 장애 경험을 포함해 정리해본다.
MAC(Media Access Control) Address는 네트워크 인터페이스 카드(NIC)에 할당된 48비트 물리 주소다. 공장에서 랜카드나 와이파이 칩을 만들 때 각 장비마다 고유한 번호를 새긴다. 이론상 전 세계에 똑같은 MAC 주소는 존재하지 않는다.
형식은 이렇다:
00:1A:2B:3C:4D:5E
콜론으로 구분된 6개의 16진수 쌍(octet). 총 48비트다. 대시(-)로 구분하는 경우도 있다: 00-1A-2B-3C-4D-5E.
이 12자리 숫자는 두 부분으로 나뉜다:
00:1A:2B는 특정 제조사 전용 번호다.결국 OUI + UAA = 전 세계적으로 유일한 식별자가 된다.
나는 이걸 '디지털 지문'이라고 받아들였다. 사람의 지문처럼, 태어날 때(공장 출고 시) 정해지고 바꿀 수 없다. 물론 소프트웨어적으로 위조할 수는 있지만, 원래의 하드웨어에 새겨진 번호는 변하지 않는다.
처음엔 "IP 주소로 통신하는데 왜 MAC 주소가 필요해?"라고 생각했다. 택배 보낼 때 집 주소만 쓰면 되는데, 왜 주민등록번호가 필요하냐는 식이었다.
하지만 네트워크 계층을 공부하면서 이해했다. IP 주소는 3계층(네트워크 계층), MAC 주소는 2계층(데이터 링크 계층). 역할이 다르다.
| 구분 | IP 주소 | MAC 주소 |
|---|---|---|
| 계층 | Layer 3 (Network) | Layer 2 (Data Link) |
| 역할 | 네트워크 간 라우팅 | 같은 네트워크 내 전달 |
| 범위 | 전 세계 인터넷 | 로컬 네트워크 (LAN) |
| 변경 | 네트워크 바뀌면 변경 | 하드웨어 고정 |
| 예시 | 192.168.0.10 | AA:BB:CC:DD:EE:FF |
비유하자면 이렇다. 해외에서 한국으로 편지를 보낼 때:
라우터는 IP 주소를 보고 패킷을 목적지 네트워크까지 배달한다. 하지만 같은 네트워크 안에서는 스위치가 MAC 주소를 보고 정확한 장비로 전달한다.
그럼 질문이 생긴다. "내가 192.168.0.5로 데이터를 보내고 싶은데, 그 장비의 MAC 주소를 어떻게 알아?"
여기서 ARP(Address Resolution Protocol)가 등장한다. 나는 이걸 '동네 방송'이라고 이해했다.
"여기 있는 모든 분들! IP 192.168.0.5 쓰시는 분, MAC 주소 좀 알려주세요!"
목적지 MAC: FF:FF:FF:FF:FF:FF (브로드캐스트)
"저예요! 제 MAC 주소는 AA:BB:CC:DD:EE:FF입니다."
실제로 내 맥북에서 ARP 테이블을 확인해보면:
arp -a
출력:
? (192.168.0.1) at 00:11:22:33:44:55 on en0 ifscope [ethernet]
? (192.168.0.5) at aa:bb:cc:dd:ee:ff on en0 ifscope [ethernet]
? (192.168.0.255) at ff:ff:ff:ff:ff:ff on en0 ifscope [ethernet]
이 테이블은 "IP → MAC" 매핑 정보를 캐싱한다. 매번 브로드캐스트하면 네트워크가 혼잡해지니까, 한 번 알아낸 정보는 일정 시간 동안 저장한다.
윈도우에서는:
arp -a
리눅스에서는:
ip neigh show
결국 이거였다. IP는 목적지를 찾는 주소, MAC은 실제 배달하는 주소. 우체부는 "서울시 강남구"로 찾아가지만(IP), 아파트 경비실에선 "302호 김철수"(MAC)로 찾는 것과 같다.
스위치는 네트워크 내에서 트래픽을 분배하는 장비다. 허브와 달리 스위치는 MAC 주소 테이블을 유지한다.
스위치가 패킷을 받으면:
이 덕분에 불필요한 트래픽이 줄어든다. 허브는 모든 포트로 데이터를 보내지만, 스위치는 정확한 포트로만 보낸다.
MAC 주소 테이블은 시간이 지나면 만료된다(보통 5분). 장비가 네트워크를 떠났을 수도 있으니까.
예전에 회사에서 이상한 일이 있었다. 특정 서버(192.168.1.100)에 접속이 안 되는 거다. 핑도 안 간다. 하지만 서버는 살아있었다.
문제를 추적하다가 ARP 테이블을 확인했다:
arp -a | grep 192.168.1.100
출력:
192.168.1.100 at 00:00:00:00:00:00 on en0
MAC 주소가 00:00:00:00:00:00이었다. 말이 안 되는 값이다. ARP 캐시가 망가진 거였다.
해결 방법:
# macOS/Linux
sudo arp -d 192.168.1.100
# Windows
arp -d 192.168.1.100
ARP 엔트리를 삭제하고, 다시 통신을 시도하니 새로운 ARP Request가 발생했고, 정상적인 MAC 주소를 받아왔다. 문제 해결.
이후로 나는 네트워크 장애가 생기면 항상 ARP 테이블부터 확인한다. Layer 2 문제는 종종 간과되기 때문이다.
내 장비의 MAC 주소를 확인하는 방법:
ifconfig en0 | grep ether
출력:
ether a4:83:e7:12:34:56
또는:
networksetup -getmacaddress en0
ip link show
출력에서 link/ether 부분:
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
또는:
cat /sys/class/net/eth0/address
ipconfig /all
"Physical Address" 항목이 MAC 주소다.
또는:
getmac /v
FF:FF:FF:FF:FF:FF는 특별한 MAC 주소다. 브로드캐스트 주소. 같은 네트워크의 모든 장비에게 전송할 때 쓴다.
ARP Request가 대표적인 예다. "IP 192.168.0.5 가진 사람?"이라고 물을 때, 누군지 모르니까 일단 모두에게 물어본다. 목적지 MAC을 FF:FF:FF:FF:FF:FF로 설정한다.
또 하나 특별한 주소는 00:00:00:00:00:00. "주소 없음"을 의미한다. 보통 장비가 부팅 중이거나 설정되지 않았을 때 나타난다.
MAC 주소는 하드웨어에 박혀있지만, 소프트웨어적으로 변경할 수 있다. MAC Spoofing이라고 한다.
# 현재 MAC 확인
ifconfig en0 | grep ether
# 인터페이스 다운
sudo ifconfig en0 down
# MAC 주소 변경
sudo ifconfig en0 ether 00:11:22:33:44:55
# 인터페이스 업
sudo ifconfig en0 up
sudo ip link set dev eth0 down
sudo ip link set dev eth0 address 00:11:22:33:44:55
sudo ip link set dev eth0 up
레지스트리나 장치 관리자에서 가능하지만, 일부 드라이버는 지원하지 않는다.
왜 이게 필요할까? 몇 가지 합법적 사용 사례:
하지만 악의적으로도 쓰인다:
스위치의 MAC 주소 테이블은 크기가 제한되어 있다. 공격자가 가짜 MAC 주소를 대량으로 생성해 테이블을 가득 채우면, 스위치는 모든 포트로 패킷을 전송하는 허브 모드로 전환된다.
이러면 공격자가 네트워크의 모든 트래픽을 스니핑할 수 있다.
방어 방법:
나는 이런 공격을 직접 본 적은 없지만, 스위치 설정에서 port security를 켜는 게 좋다고 배웠다.
일부 공유기는 MAC 필터링 기능을 제공한다. 특정 MAC 주소만 네트워크 접속을 허용하는 화이트리스트 방식이다.
설정 예:
허용된 MAC 주소:
- AA:BB:CC:DD:EE:01
- AA:BB:CC:DD:EE:02
- AA:BB:CC:DD:EE:03
보안 효과가 있을까? 솔직히 말하면 미약하다. MAC Spoofing이 쉽기 때문이다. 공격자는 허용된 MAC 주소를 스니핑한 뒤, 자기 장비의 MAC을 그 주소로 바꾸면 된다.
진짜 보안은 WPA3 암호화 + 강력한 비밀번호에서 나온다.
하지만 MAC 필터링도 쓸모가 있다:
요즘 스마트폰은 프라이버시 보호를 위해 MAC 주소 랜덤화를 사용한다.
문제 상황: 공용 와이파이가 MAC 주소로 사용자를 추적한다. 커피숍에 갈 때마다 "이 사람이 또 왔네"라고 알 수 있다. 심지어 여러 장소에서 동일 MAC 주소를 추적하면 이동 경로까지 파악 가능하다.
해결책: iOS 14+, Android 10+는 와이파이 네트워크마다 다른 랜덤 MAC 주소를 사용한다. 스타벅스에서는 AA:BB:..., 맥도날드에서는 CC:DD:... 이런 식이다.
iPhone 설정:
설정 > Wi-Fi > (특정 네트워크) > 비공개 Wi-Fi 주소
이게 켜져 있으면 해당 네트워크에 접속할 때마다 랜덤 MAC 주소를 쓴다.
단점: MAC 필터링을 쓰는 네트워크에서 문제가 생긴다. 회사 와이파이가 MAC 화이트리스트를 쓴다면, 랜덤화를 꺼야 한다.
IPv6에는 흥미로운 기능이 있다. MAC 주소를 이용해 IPv6 주소를 자동 생성하는 EUI-64 방식이다.
MAC 주소가 AA:BB:CC:DD:EE:FF라면:
FF:FE를 삽입: AA:BB:CC:FF:FE:DD:EE:FFA8:BB:CC:FF:FE:DD:EE:FF이걸 IPv6 주소의 하위 64비트로 쓴다:
2001:0db8:85a3:0000:a8bb:ccff:fedd:eeff
장점: DHCP 없이도 고유한 IP 주소 생성 가능 (SLAAC, Stateless Address Autoconfiguration).
단점: 프라이버시 문제. IPv6 주소만 봐도 MAC 주소를 역으로 추적할 수 있다. 어떤 장비를 쓰는지, 어느 제조사 제품인지 알 수 있다.
그래서 최근에는 Privacy Extensions(RFC 4941)를 쓴다. 랜덤한 하위 64비트를 생성해서 주기적으로 바꾼다.
# macOS에서 IPv6 주소 확인
ifconfig en0 | grep inet6
출력:
inet6 fe80::1234:5678:9abc:def0%en0 prefixlen 64 secured scopeid 0x4
inet6 2001:db8::a8bb:ccff:fedd:eeff prefixlen 64 autoconf
inet6 2001:db8::1234:5678:9abc:def0 prefixlen 64 autoconf temporary
temporary가 붙은 주소가 프라이버시 확장으로 생성된 임시 주소다.
실제 프로그래밍에서 MAC 주소를 다루는 예제:
import uuid
import subprocess
import re
def get_mac_address():
"""현재 장비의 MAC 주소 가져오기"""
mac = uuid.getnode()
mac_str = ':'.join(('%012X' % mac)[i:i+2] for i in range(0, 12, 2))
return mac_str
def get_arp_table():
"""ARP 테이블 파싱"""
result = subprocess.run(['arp', '-a'], capture_output=True, text=True)
arp_entries = []
# 정규식으로 파싱
pattern = r'\(([0-9.]+)\) at ([0-9a-f:]+)'
for line in result.stdout.split('\n'):
match = re.search(pattern, line)
if match:
ip = match.group(1)
mac = match.group(2)
arp_entries.append({'ip': ip, 'mac': mac})
return arp_entries
def find_mac_by_ip(ip_address):
"""특정 IP의 MAC 주소 찾기"""
arp_table = get_arp_table()
for entry in arp_table:
if entry['ip'] == ip_address:
return entry['mac']
return None
# 사용 예
print(f"내 MAC 주소: {get_mac_address()}")
print(f"\nARP 테이블:")
for entry in get_arp_table():
print(f"{entry['ip']:15} -> {entry['mac']}")
target_ip = '192.168.0.1'
target_mac = find_mac_by_ip(target_ip)
if target_mac:
print(f"\n{target_ip}의 MAC 주소: {target_mac}")
else:
print(f"\n{target_ip}의 MAC 주소를 찾을 수 없습니다.")
이 코드는:
uuid.getnode()로 현재 장비의 MAC 주소를 10진수로 가져온다.arp -a 명령어 출력을 파싱해서 IP-MAC 매핑을 추출한다.MAC 주소는 네트워크 스택의 최하위 계층에 있다. IP 주소만큼 눈에 띄지 않는다. 하지만 실제 데이터 전송은 결국 MAC 주소로 이루어진다.
처음엔 "왜 주소가 두 개야?"라고 헷갈렸지만, 이제는 이해했다. 계층의 분리다. IP는 큰 그림에서 목적지를 찾고, MAC은 로컬 네트워크에서 정확한 장비를 찾는다. 우편 시스템의 국가-도시-번지수-상세주소와 같은 계층 구조다.
ARP 테이블을 직접 보고, MAC 주소를 변경해보고, 네트워크 장애를 디버깅하면서, MAC 주소가 단순한 숫자 이상이라는 걸 체감했다. 보안 문제(MAC Spoofing, MAC Flooding), 프라이버시 문제(MAC 추적, 랜덤화), 그리고 IPv6와의 통합(EUI-64)까지. 작지만 깊은 주제였다.
네트워크 문제가 생기면, 3계층(IP)만 보지 말고 2계층(MAC)도 확인하자. arp -a, ip neigh, 그리고 스위치의 MAC 테이블. 종종 답은 더 낮은 계층에 있다.