Using OSPF instead of overriding DNS entries for DMZ services

Posted in networking by aangelis on 10 October 2016

In order to give local users access to servers with private IPs that are located in our DMZ area, we use DNS overriding. That is a proven method with its own disadvantages.

Unfortunately there are services that are DNS agnostic, protocols that do not like private IPs and security policies that best work with public IPs. In these cases DNS overriding is not a solution.

(Dynamic) Routing is an alternative solution for this problem, even in environments that we are using dynamic public IPs.

OSPF is a dynamic routing protocol light and efficient enough for this purpose. It runs in almost every router and firewall used today in production and it can be easily installed in linux machines.

In this short tutorial we use Bird. Installing Bird in a Linux box is pretty easy using official packages located in distributions repositories.

We will install and maintain dynamic public IP in which our service is advertised in loopback interface.

# ip a add [ PUBLIC IP ]/32 dev lo label lo:2

# ip a list dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  inet scope host lo
  inet [ PUBLIC IP ]/32 scope global lo:2
  inet6 ::1/128 scope host
     valid_lft forever preferred_lft forever

We can keep this consistent using some scheduled script. A simple one is shown below.

# cat
publicip=$(curl -s
locurrentip=$(ip a | grep lo:2 | awk '{print $2}')
if [ "$publicip" == "$locurrentip" ]; then
    echo "Public IP equals loopback IP ($locurrentip), no action needed."
    ip a del $locurrentip/32 dev lo
    ip a add $publicip/32 dev lo label lo:2
    echo "Loopback IP updated to $publicip."

Next step is to advertise service IP to local router and local network, so our users can access it.

# cat /etc/bird.conf
log syslog all;
router id;
protocol direct direct1 {
        interface "lo";
protocol device {
    scan time 10;
protocol ospf {
    import none;
    export all;
    area 0 {
            networks {
            stub no;
            interface "eth0" {
            interface "lo:2" {

Restart Bird service and install the update script in cron.

Now we are good to go, everything is configured and hopefully our internal users can access our service without any modification in DNS.