0xFF

hostapd와 dnsmasq를 이용한 Wi-Fi AP 및 Captive Portal 테스트 본문

LINUX

hostapd와 dnsmasq를 이용한 Wi-Fi AP 및 Captive Portal 테스트

캡스락 2026. 2. 24. 02:23

필자가 진행 중인 프로젝트는 캡티브 포털을 이용하여 사용자가 Wi-Fi 네트워크에 접속하자마자 웹 페이지를 띄우고, 여기서 서비스를 제공한다.
따라서 Wi-Fi 칩셋인 AR9271을 AP 모드(핫스팟)로 작동하게 해야 한다.
이를 위해서는 hostapd가 필요한데, hostapd에는 IP 할당 기능이 없어 dnsmasq등의 DHCP 서버를 함께 사용하여 연결된 station 장치들에게 IP를 할당해 주어야 한다.

$ apt install dnsmasq hostapd nginx

Debian/Ubuntu 환경에서는 위와 같이 간단하게 설치할 수 있다.
여기서 nginx는 captive portal 구현 단계에서 302 리다이렉트를 발생시키기 위해 설치하였다.

# ip addr
...
3: wlxc01c3043146b: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether c0:1c:30:43:14:6b brd ff:ff:ff:ff:ff:ff
...

설치가 끝났다면 ip addr 명령을 입력하여 AP로 사용할 인터페이스의 이름을 확인한다.
필자의 환경에서는 AR9271이 wlxc01c3043146b 이라는 이름으로 인식되었다.

interface=wlxc01c3043146b
hw_mode=g
channel=7
country_code=KR
ieee80211n=1
ssid=SafeCast
ctrl_interface=/var/run/hostapd

/etc/hostapd/hostapd.conf 파일을 만들고, 위와 같은 설정 사항을 입력하였다.
보안을 사용하지 않는 경우 설정할 것이 그렇게 많지 않다는 것을 알 수 있다.

하단의 ctrl_interface=/var/run/hostapd는 유닉스 소켓의 경로를 지정해 주는 것인데,
hostapd_cli 유틸리티를 통해 데몬 상태를 런타임에서 확인하거나 변경할 수 있게 해준다.

channel은 가장 혼잡도가 적은 채널을 선택하는 auto 옵션을 먼저 시도해 보았으나,
에러가 발생하여 일단 고정 채널을 사용하기로 했다.

$ service hostapd restart

 

여기까지 진행 후 hostapd 서비스를 재시작하면 SSID가 표시되는 것은 확인할 수 있지만,
IP 주소가 할당되지 않아 연결까지 이뤄지지는 않는 것을 확인할 수 있었다.
이제 dnsmasq를 설정하여 dhcp에 의한 IP 할당이 이뤄지도록 해보자.
dnsmasq 설정 파일의 경로는 /etc/dnsmasq.conf 이며, 필자가 입력한 내용은 아래와 같다.

no-resolv
dhcp-option=114,"<https://safecast.0xff.kr/captive_info>"
address=/#/10.0.0.1 # 모든 도메인에 대한 resolve 요청을 10.0.0.1을 반환
interface=wlxc01c3043146b
bind-interfaces
dhcp-range=wlxc01c3043146b,10.0.0.2,10.0.0.32,255.255.255.0


다음으로 부팅시 hostapd로 사용되는 네트워크 인터페이스에 게이트웨이 주소가 자동으로 할당되도록 systemd 서비스를 등록한다.
서비스 파일의 경로는 /etc/systemd/system/set-ip4hostapd.service 이다.(파일명은 임의로 지정하여도 무관)

[Unit]
Description=sets ip for hostapd iface
After=network-pre.target

[Service]
Type=oneshot
ExecStart=/usr/sbin/ip addr add 10.0.0.1/24 dev wlxc01c3043146b
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

여기까지 진행했다면 hostapd를 위한 설정은 끝났다.
이제 네트워크에 접속한 기기가 captive portal을 자동으로 감지할 수 있도록 설정해 보자.
접속한 기기가 captive portal의 존재를 인식하는 방법은 크게 두 가지가 있다.
첫 번째는 302 리다이렉트 감지로, 주요 운영체제(iOS, Android 등)에서 와이파이 네트워크 연결 시 약속된 응답을 반환하여야 하는 인터넷상의 웹 주소에 접속해 보는 것이다.
대표적으로 Android 운영체제에서는 새로운 와이파이 네트워크 접속 시 아래와 같은 웹 주소에 접속하여 정해진 응답인 204 No Content가 반환되는지 확인한다.
http://connectivitycheck.gstatic.com/generate_204
디바이스는 제한 없는 인터넷 환경이라면 구글 서버로 접속되어 204를 수신할 것이고, 여기서 만약 captive portal을 띄우기를 원하는 네트워크 운영자는 이 요청을 가로채어 302 Redirect 응답의 Location 헤더를 통해 captive portal의 URL을 전달할 수 있다.

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name safecast.0xff.kr;

		if ($host != "safecast.0xff.kr") {
			return 302 <http://safecast.0xff.kr>;
		}
}

server {
		listen 443 ssl;
		server_name safecast.0xff.kr;
		
		ssl_certificate /etc/letsencrypt/live/safecast.0xff.kr/fullchain.pem;
		ssl_certificate_key /etc/letsencrypt/live/safecast.0xff.kr/privkey.pem;

		root /var/www/html;
		index index.html index.htm;
		
		location /captive_info {
			default_type application/captive+json;
			return 200 '{"captive": true, "user-portal-url": "<https://safecast.0xff.kr>"}';
		}

		location / {
			try_files $uri $uri/ =404;
		}
}

위 내용은 /etc/nginx/sites-available/default 파일의 모습이다.
80 포트에서 실행되는 HTTP 서버 구문을 보면 captive portal의 도메인을 제외한 모든 호스트명에 대해 302를 이용해 무조건 captive portal의 URL로 전환되도록 구성하였다.
두 번째는 2020년부터 RFC 표준으로 제정된 DHCP option 114를 사용하여 captive portal의 URL을 명시적으로 전달하는 것이다.
위 파일 하단의 HTTPS 서버 구문을 보면 DHCP option 114를 통해 전달했던 captive portal API의 주소(dnsmasq 설정 부분 참고)로 접속했을 때 해당 JSON 응답을 반환함으로써
기기가 현재 인터넷 접근이 차단된 상태(captive)에 있으며, 주어진 포털 링크(user-portal-url)로 접속해야 한다는 내용을 전달할 수 있다.

$ chmod 644 /etc/systemd/system/set-ip4hostapd.service
$ systemctl daemon-reload
$ systemctl enable set-ip4hostapd.service
$ systemctl start set-ip4hostapd.service

여기까지 진행한 다음 서비스 권한부여, 데몬 리로드, 서비스를 활성화 및 시작시키고 나면 핫스팟에 접속할 수 있게 된다.

갤럭시 기준으로 네트워크 연결과 동시에 로그인 안내 및 알림이 표시되고, 알림을 누르면 웹뷰를 통해 포털에 접속이 가능한 것을 확인할 수 있었다.(페이지는 구현하지 않아 일단 포털 감지 동작만 확인)
참고로 갤럭시는 애플과 다르게 HTTP 환경에서의 302 리다이렉트만으로는 captive portal 감지 알림이 표시되지 않았고,
약 하루 정도의 삽질 끝에 DHCP 114를 통해 https로 시작하는 captive portal 링크를 전달하였을때만 감지되는 것을 확인할 수 있었다.