Captive DNS Server


This tutorial demonstrates how Mongoose Library can be used to implement a captive DNS portal. It is usually required for device configuration. For example, an un-configured device starts its own WiFi network, and on this network, any DNS name gets resolved to that device. This way, a user might not know device's IP address to get to the WiFi configuration page.

Full source code for this tutorial is at

Build and test

  • Follow the Build Tools tutorial to setup your development environment.

  • Start a terminal in the project directory; clone the Mongoose Library repo, and run the make all command:

git clone
cd mongoose/tutorials/udp/captive-dns-portal
make all
cc mongoose.c main.c -W -Wall -Wextra -g -DMG_IO_SIZE=8192 -DMG_ENABLE_LINES -o example
f7292e1 3 net.c:182:mg_listen           1 0x4 udp://

Usually DNS servers use port 53. However that port is privileged - a program that opens that port must have root permissions. That is why our example uses port 5533 instead of port 53.

Now start another terminal and type a command that resolves any domain name, for example "":

dig @localhost -p 5533 -4 A
;			IN	A

Here we see that "" has been resolved to "" which is hardcoded by the server.

How it works

In the usual event manager initialisation code, we start a UDP listener:

In the event handler function, we catch MG_EV_READ, which is triggered every time we receive a DNS request:

There, we try to parse the received message. If it is a valid DNS request, we craft a response which has a hardcoded IP address of "", send the response back, and clean up the c->recv IO buffer.