Skip to content

Proper DNS and DHCP for your LAN

If you are like me you don’t like the fact that most routers do a terrible job at providing DNS for the LAN-side. Sure, routers are easy to setup and will get you up and going quickly, but most of them suck in more advanced areas. I mean is it too much to ask for to be able to type in a hostname or IP address and have a consistent experience across all devices? Also, what about if I know an IP address but I have no idea what devices it belongs to. I don’t want to login to the router and search the logs for a Mac address that I may or may not recognize and I don’t want to waste time running nmap to try and fingerprint the system in hopes of identifying it. The router should provide reverse DNS lookup so I don’t have to! Oh and don’t get me started about the crappy DNS servers that ISPs provide!

So what we will be doing here is setting up BIND and DHCPd for our local network. It will provide IP address to our devices, register host (DNS) names, provide a local DNS server for queries, and give us reverse DNS.

Before we get started make sure you install dhcpd and bind9. You will probably also want to install bind-tools or whatever your distro calls it.

Now we will configure dhcpd by editing /etc/dhcp/dhcpd.conf and setting the following options (snippet):

server-identifier 192.168.1.1;
authoritative;
option routers 192.168.1.1; # use main router
option domain-name-servers 192.168.1.1;
option domain-name “”;
ddns-domainname “”;
ddns-rev-domainname “in-addr.arpa”;
ddns-update-style interim;
ddns-updates on;
allow client-updates;
update-conflict-detection false;
update-static-leases on;
include “/etc/bind/rndc.key”;
zone {
primary 127.0.0.1;
key rndc-key;
}
zone 1.168.192.in-addr.arpa {
primary 127.0.0.1;
key rndc-key;
}
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.100 192.168.1.254;
default-lease-time 259200;
max-lease-time 518400;
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.1.255;
allow unknown-clients;
zone { primary 192.168.1.1; key rndc-key; }
zone 1.168.192.in-addr.arpa { primary 192.168.1.1; key rndc-key; }
}


Next we will be editing /etc/bind/named.conf. Under ‘acl “trusted”‘ add the hosts IP address. Then under the zone section you will want to add two new ones:

zone “” IN {
type master;
file “pri/.zone”;
allow-query { any; };
allow-transfer { any; };
notify yes;
allow-update { key “rndc-key”; };
};

zone “1.168.192.in-addr.arpa” IN {
type master;
file “pri/rev.zone”;
allow-query { any; };
allow-transfer { any; };
notify yes;
allow-update { key “rndc-key”; };
};


Create a normal BIND zone config file under /etc/bind/pri/.zone and also create a /etc/bind/pri/rev.zone just like a normal zone file except swap out the SOA domain with “1.168.192.in-addr.arpa” and the origin will be “$ORIGIN 1.168.192.in-addr.arpa.” Other than that it should look like a standard BIND zone config.

At this point we can disable the DHCP and DNS on the existing router and start dhcpd and named on the new one. Be sure to test it out before calling it “good” and walking away.

router ~$ host foo
foo. has address 192.168.1.230

router ~$ host 192.168.1.230
230.1.168.192.in-addr.arpa domain name pointer foo..


We are all set and can sleep soundly knowing that our network works correctly!

Transitioning Between LAN and WLAN By Bonding Ethernet and WiFi

Here’s the situation: you like to have the LAN cable plugged into your laptop when you are sitting at your desk to take advantage of the gigabit speeds, but you sometimes like to roam around by connecting to the WiFi. However, when switching between the two you don’t want to lose your connection/have to get a new IP address. The solution? bond the ethernet and wireless connections to make a seamless transition back and forth.

I use Gentoo on my personal machines and this guide is written specifically for that distribution. I also think systemd is a pile of shit that is turning Linux into a binary blob OS – if I wanted to use a binary blob OS I’d run the original: Windows!

First make sure your wired and wireless connections already work!

Let’s create a new init for the bonded interface:

# cd /etc/init.d/ && ln -s net.lo net.bond0


Now remove net.eth0 and net.wlan0 from autostarting:

rc-update del net.eth0

rc-update del net.wlan0


We can also bring down our connections:

service net.eth0 stop

service net.wlan0 stop


Next edit /etc/conf.d/net:

config_eth0=”null”
config_wlan0=”null”
slaves_bond0=”eth0 wlan0″
config_bond0=”dhcp”

#
# Notes: if network get hosed and you try to restart net.bond0 and it
# fails, you have to manually bring eth0 && wlan0 up with ifconfig.
#
preup() {
if [[ $IFACE -eq “bond0” ]]; then
# bring up the interfaces because sometimes when eth0 isn’t connected it fails to bring anything up
/bin/ifconfig eth0 up ; /bin/ifconfig wlan0 up ; rfkill unblock wlan0 ; /usr/sbin/wpa_supplicant -iwlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf -B
fi
return 0;
}

postdown() {
if [[ $IFACE -eq “bond0” ]]; then
if [[ -S /var/run/wpa_supplicant/wlan0 ]]; then
killall wpa_supplicant
rm -f /var/run/wpa_supplicant/wlan0
fi
fi
return 0;
}


Also, if you use ifplugd you’ll want to disable/remove it or it may interfere with switching the active interface.

We should also set the bonded interface to autostart:

rc-update add net.bond0 default


Next we want to tell the kernel how we want the bonded interface to function. Specifically we want eth0 to be primary and only use the wireless if the ethernet is down. We can tell it to do all of this by creating a file in /etc/modprobe.d/bonding.conf:

options bonding mode=1 miimon=100 primary=eth0


Now let’s start the new bonded interface:

service net.bond0 start


If all goes well one of the interfaces should be made active and you should be back on the network. If not make note of any errors and see where things went awry.

The only issues I’ve had with this setup is getting the wireless to work if a new configuration is added after the system is already up and running. In that case sometimes getting wpa_supplicant to run with a new config without hosing bond0 can be trying!

Update 2020-02-12: It was pointed out by “Mick” that sometimes the WiFi is disabled or softblocked. You can use rfkill to get it going again:

rfkill unblock wlan0


I updated the pre_up() configuration to include this for future reference.

Dual ISPs or How To Survive Out In The Sticks

So you are living in a remote area that has poor Internet connectivity options and you are a nerd that can’t survive off of a single slow DSL connection. What can one do?! Well with an older computer, three NICs, and a little help from our favorite Linux distro we make a buffet of low quality Internet connections seem like one semi-decent connection. What we want to get out of this is the download bandwidth of a satellite connection but the latency (ping) of a DSL connection. That way we can watch Netflix and YouTube on the satellite and play games, SSH, and do other latency sensitive things on the DSL.

What I used specifically was a DSL connection from the local phone company that is sold as 1.5 Mbit/s but typically shows speeds of around 800 Kbit/s on a good day and a satellite connection from Exede. An old dual CPU AMD Opteron with 3 gigabit NICs and an install of Gentoo or your favorite Linux distro will be our router. In this setup eth0 will be the LAN-connected NIC, eth1 will be the DSL and eth2 the satellite connection. Each of the connections were tested individually with my laptop to ensure they were functional and to get some speed tests for comparison. eth1-2 are dynamically (dhcp) assigned IPs from the ISP provided modems and eth0 has a static IP for our LAN.

Once you have everything ready, connect and then after unconnect, each ISP modem to its designated NIC and then let’s test each of the connections real quick:

$ ping -c10 http://www.google.com


Now we will connect all of the ISP modems and verify everything is connected with ‘ifconfig’ or ‘ip addr’ and check that each NIC has an appropriate IP address. You will want to note each IP address and which modem/ISP it is from/for – maybe even write it down on a piece of paper for quick reference.

If each one works, then let’s continue with creating a router script at /usr/local/bin/router.sh:

#/bin/bash
# Set what interface is which
LAN=eth0
WAN0=eth2
WAN1=eth1
LAN_IP=192.168.1.1
WAN0_IP=192.168.0.3
WAN1_IP=162.72.156.86
LAN_GW=192.168.1.1
WAN0_GW=192.168.0.1
WAN1_GW=162.72.152.1

# SNAT packets going out WAN0 to DSL ISP
iptables -t nat -A POSTROUTING -o ${WAN0} -j SNAT –to-source ${WAN0_IP}

# SNAT packets going out WAN1 to SAT ISP
iptables -t nat -A POSTROUTING -o ${WAN1} -j SNAT –to-source ${WAN1_IP}

# chain which marks a packet (MARK) and its connection (CONNMARK) with MARK 1 for DSL ISP
iptables -t mangle -N MARK-DSL-ISP
iptables -t mangle -A MARK-DSL-ISP -j MARK –set-mark 1
iptables -t mangle -A MARK-DSL-ISP -j CONNMARK –save-mark
# icmp echo requests (ping)
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p icmp -j MARK-DSL-ISP
# ssh
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 22 -j MARK-DSL-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p udp –dport 22 -j MARK-DSL-ISP
# time
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 37 -j MARK-DSL-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p udp –dport 37 -j MARK-DSL-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 123 -j MARK-DSL-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p udp –dport 123 -j MARK-DSL-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 23 -j MARK-DSL-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p udp –dport 23 -j MARK-DSL-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 992 -j MARK-DSL-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p udp –dport 992 -j MARK-DSL-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 107 -j MARK-DSL-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p udp –dport 107 -j MARK-DSL-ISP
# dns
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 53 -j MARK-DSL-ISP
# Star Trek Online
for STO_IP in 208.95.184.{0..255} 208.95.185.{0..255} 208.95.186.{0..255} 208.95.187.{0..255}; do
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp -d $STO_IP -j MARK-DSL-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p udp -d $STO_IP -j MARK-DSL-ISP
done
# chain which marks a packet (MARK) and its connection (CONNMARK) with MARK 2 for SAT ISP
iptables -t mangle -N MARK-SAT-ISP
iptables -t mangle -A MARK-SAT-ISP -j MARK –set-mark 2
iptables -t mangle -A MARK-SAT-ISP -j CONNMARK –save-mark
# http
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 80 -j MARK-SAT-ISP
# https
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 443 -j MARK-SAT-ISP
# smtp
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 25 -j MARK-SAT-ISP
# imap2
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 143 -j MARK-SAT-ISP
# pop2
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 109 -j MARK-SAT-ISP
# pop3
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 110 -j MARK-SAT-ISP
# imaps
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 993 -j MARK-SAT-ISP
# pop3s
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 995 -j MARK-SAT-ISP
# ftp
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 21 -j MARK-SAT-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p udp –dport 21 -j MARK-SAT-ISP
# ftp-data
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 20 -j MARK-SAT-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p udp –dport 20 -j MARK-SAT-ISP
# sftp
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 115 -j MARK-SAT-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p udp –dport 115 -j MARK-SAT-ISP
# rsync
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp –dport 873 -j MARK-SAT-ISP
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p udp –dport 873 -j MARK-SAT-ISP
#
# Special rules for certain hosts (they have static IPs)
#
# We want the Wii to use DSL all the time for playing online games
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp -s 192.168.1.95 -j MARK-DSL-ISP
#
# For Samsung Bluray Player using Netflix we want it to use the SAT
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate NEW -p tcp -s 192.168.1.90 -j MARK-SAT-ISP
# If a packet is not NEW, then there must be a connection for it somewhere, so go find the connection mark and apply it to the packet
# Packets from Internal network
iptables -t mangle -A PREROUTING -i ${LAN} -m conntrack –ctstate ESTABLISHED,RELATED -j CONNMARK –restore-mark

# add local routes too
ip route flush table dsl
ip route add table dsl default dev ${WAN0} via ${WAN0_GW}
ip route add table dsl 192.168.0.0/24 dev ${WAN0} src 192.168.0.3
ip route add table dsl 162.72.156.0/24 dev ${WAN1} src 162.72.156.86
ip route add table dsl 192.168.1.0/24 dev ${LAN} src 192.168.1.1/24

# ditto
ip route flush table sat
ip route add table sat default dev ${WAN1} via ${WAN1_GW}
ip route add table sat 192.168.0.0/24 dev ${WAN0} src 192.168.0.3
ip route add table sat 162.72.156.0/24 dev ${WAN1} src 162.72.156.86
ip route add table sat 192.168.1.0/24 dev ${LAN} src 192.168.1.1/24

# Now add rules to actually use them…
ip rule del from all fwmark 2 2>/dev/null
ip rule del from all fwmark 1 2>/dev/null
ip rule add fwmark 1 table dsl
ip rule add fwmark 2 table sat
ip route flush cache

# We need to allow packet forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward

# Finally, make sure that the rp_filter option is disabled on the router, otherwise it could drop packets!
for i in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > “$i”; done

# That’s it!


In this firewall I route traffic based on the port number and I also included one example of how to route traffic for a game (Star Trek Online). That should be enough to get you up and running and some examples to make your own customizations.

The next step is to make the firewall script executable and run it:

# chmod +x /usr/local/bin/firewall

# /usr/local/bin/firewall


The last part is to add the script so it gets autoloaded by your system on boot, but that depends on the distribution you are using so consult with Google.

Now you have a semi-decent Internet connection despite being in a remote location and traffic should get routed to the most appropriate connection.