Build Linux Router In Stupid Way

Someone said to me,

Stupid guys doing smart things. Smart guys doing stupid thing.

In this article, I’m trying to build up a Linux wireless router in stupid way - step by step, pic by pic.

From the first line to the end, it’ll take about 45 minutes. So, that’s it, let’s go!

Phase 1 - Install Ubuntu Server 16.04 LTS As Much As Defaults

This part takes about 12 minutes.

To make the installation faster, please plug cable off before going.

  1. Install Ubuntu server

    Install Ubuntu Server 16.04.03 LTS

  2. Select default language and keyboard.

    Select English as language

    Select United States as location

    Do not detect keyboard layout

    Select English (US) as country of origin for the keyboard

    Select English (US) as keyboard layout

  3. Select whatever a network interface and cancel the DHCP detection. While It shows Network autoconfiguration failed. Never mind it, just select continue, we will fix it later. In the next screen, select Do not configure the network at this time.

    Select whatever a network interface

    Confirm network autoconfiguration failed

    Do not configure the network at this time

  4. Set hostname as Orion, or whatever the name you like.

    Set hostname

  5. Setup the first user’s username and password. BTW, choose a long enough password, for example length of 20, can protect the router much.

    Set full name for new user

    Set username for your account

    Choose a password for the new user

    Re-enter password to verify

  6. Unless you do realy known how to control the encrypted partition/directory in Linux, please don’t select Encrypt your home directory.

    Do not encrypt your home directory

  7. Select Eastern as router’s time zone.

    Select eastern as the time zone

  8. Select partition as Guided - use entire disk and set up LVM. LVM is a good optioin, which supports reduce or extend the partition at run time (except the root partition’s modification needs offline operation). I maybe story about optimize router sometimes later when I have the time. No matter what, choose LVM now.

    Use entire disk and set up LVM

    Select disk to partition

    Write the changes to disks and configure LVM

    Set all to valume group to use for guided partitioning

  9. Maybe your machine’s firmware has both UEFI and BIOS compatibility mode. In this case, the router we are building will run Linux only, it’s safe to select Force UEFI installation.

    Force UEFI installation

    Write the changes to disks

  10. Optionally, select Install security updates automatically. So the Linux will manage security updates in background by itself.

    Choose to install security updates automatically

  11. Select OpenSSH server in the selection of software to install. The standard system utilities is strongly suggested. Don’t uncheck it.

    Choose software to install

  12. Finally, select Continue at installation complete to finish this part. Let’s continue the next phase after reboot.

    Installation complete

Phase 2 - Customize OS Into Router

This part takes about 30 minutes.

Login into OS with the account created at installation, and sudo as the root account by command sudo su -. All steps following need the root permission.

  1. Plug in cable.

    At the time now, we temporary need a traditional router, I call it as Router #1, to doing some system update and software installation. Link the Internet inbound cable to Router #1, and link the router we are building, called Router #2, to Router #1. I assume the cable was linked as the char below,

     +----------+    +-----------+
     | Internet |----| Router #1 | <-- ready to replace in minutes
     +----------+    +-----------+
                           |
                     +-----------+
                     | Router #2 |  <-- now we're building
                     +-----------+
    
  2. Setup network interfaces and online Router #2.

     cat > /tmp/interfaces << EOF
     auto enp1s0
     iface enp1s0 inet dhcp
     EOF
    
     ifup -i /tmp/interfaces enp1s0
    
     ip address | grep enp1s0 | grep inet
    

    It’ll show up the DHCP IP address in form

     inet 192.168.1.100/24 brd 255.255.255.255 scope global enp1s0
    

    The 192.168.1.100 part is the router’s IP address currently. I login into the router from another PC by command,

     ssh 192.168.1.100
    

    After login, sudo su - as root again.

  3. Customize apt repository. It’s Optional.

     mv /etc/apt/sources.list /etc/apt/sources.list.us
     sed 's/us\.archive/cn.archive/g' /etc/apt/sources.list.us \
         > /etc/apt/sources.list.cn
     ln -s /etc/apt/sources.list.cn /etc/apt/sources.list
    
  4. Setup basic firewall rules and apply. We’ll setup the full firewall at end.

     iptables -A INPUT -i lo -j ACCEPT
     iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
     iptables -A INPUT -j DROP
     if which ip6tables >/dev/null; then
         ip6tables -A INPUT -i lo -j ACCEPT
         ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
         ip6tables -A INPUT -j DROP
     fi
    
  5. Update OS by command,

     apt update && apt upgrade --yes
    

    Sometimes the kernel will be updated. In this case, the OS may suggest you to reboot. The rebooting is not needed right now. To save time, maybe you’d like to reboot in minutes later.

  6. Install dnsmasq, hostapd, bridge-utils, pppoeconf, wireless-tools and rng-tools by apt commands,

     apt install --yes dnsmasq hostapd bridge-utils pppoeconf \
                       wireless-tools rng-tools
     systemctl stop dnsmasq hostapd
    

    We need these APPs for purpose,

    • dnsmasq provides DNS cache and DHCP service;
    • hostapd manages the wireless radio;
    • bridge-utils is use to combine wired and wireless into one network;
    • pppoeconf manages the dial up;
    • wireless-tools is in charge of limit radio radiation;
    • rng-tools is a golden key to make random number generated faster, which is needed in every contact between wireless device and router.
  7. Setup dnsmasq by following commands,

     mkdir -p /etc/dnsmasq.d-available  # ensure "/etc/dnsmasq.d-available" exists
    
     cat > /etc/dnsmasq.d-available/router.conf << EOF
     # /etc/dnsmasq.d-available/router.conf
     # vim: ft=dnsmasq
     #
     # Configuration file for dnsmasq.
     #
     # Format is one option per line, legal options are the same
     # as the long options legal on the command line. See
     # "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
    
     local=/lan/
     interface=br0
     bind-interfaces
     #localise-queries  # What's this?
     domain=lan
     domain-needed
     cache-size=10000
    
     dhcp-range=192.168.2.100,192.168.2.150,12h
     dhcp-option=252,"http://router.lan/wpad.dat"
     read-ethers
    
     # Debug options
     #log-queries
     #log-dhcp
     EOF
    
     ln -s /etc/dnsmasq.d-available/router.conf \
           /etc/dnsmasq.d/router.conf
    
     touch /etc/ethers  # ensure "/etc/ethers" exists
    
  8. Setup hostapd by commands,

     cat > /etc/hostapd/hostapd.conf << EOF
     # /etc/hostapd/hostapd.conf
     # vim: ts=4 sw=4 noet ft=conf
     #
     # hostapd configuration file
    
     interface=wlp3s0
    
     # For nl80211, request the AP interface, wlp3s0, to be added to
     # the bridge automatically. Sometimes, the \`brctl\` may refuse
     # to do this before hostapd has been start to change the
     # interface mode.
     bridge=br0
    
     # If \`lsmod | grep mac80211\` shows up something, the driver
     # parameter should be specified as nl80211. Please refers
     # hostapd's document for details.
     driver=nl80211
    
     ssid=MyRouter
    
     country_code=CN
    
     ieee80211d=1  # Related to "country_code".
    
     hw_mode=g
    
     channel=9
     beacon_int=100
    
     # 1 = Open System Authentication
     # 2 = Shared Key Authentication (requires WEP)
     # 3 = Open System Authentication & WEP
     auth_algs=1
    
     # 0 = Broadcast SSID
     # 1 = Send empty (length=0) SSID in beacon and ignore probe
     #     request for broadcast SSID
     # 2 = Clear SSID (ASCII 0), but keep the original length (this
     #     may be required with some clients that do not support
     #     empty SSID) and ignore probe requests for broadcast SSID
     ignore_broadcast_ssid=0
    
     wmm_enabled=1
     disassoc_low_ack=1
     ieee80211n=1
    
     ht_capab=[HT40-][SHORT-GI-40][RX-STBC1]
    
     # If this option is turned on, Windows PC will NOT work. But
     # Linux and Android will get a bit more bandwidth.
     #require_ht=1
    
     wpa=2
     wpa_passphrase=some-random-words
     wpa_key_mgmt=WPA-PSK
     rsn_pairwise=CCMP
     EOF
    
     sed -i "s/^#*DAEMON_CONF=.*/DAEMON_CONF=\"\/etc\/hostapd\/hostapd.conf\"/" /etc/default/hostapd
    
  9. Setup network interfaces by commands,

     cat > /etc/network/interfaces.d/router << EOF
     # /etc/network/interfaces.d/router
     # vim: ts=4 sw=4 noet ft=conf.interfaces
     #
     # This file describes the network interfaces available on your
     # system and how to activate them. For more information, see
     # interfaces(5).
    
     # The primary network interface
     allow-hotplug enp1s0
     iface enp1s0 inet manual
    
     # There's no need to bring up inteface enp2s0 and wlp3s0, because
     # they're controlled by bridge br0. So, I commented 3 lines
     # below.
     #auto enp2s0 wlp3s0
     #iface enp2s0 inet manual
     #iface wlp3s0 inet manual
    
     auto br0
     iface br0 inet static
         address 192.168.2.1
         network 192.168.2.0
         netmask 255.255.255.0
         broadcast 192.168.2.255
         # For nl80211 driven interface, wlp3s0 will add into br0
         # by hostapd. Please refer the config file,
         # "/etc/hostapd/hostapd.conf".
         #
         # In fact, if I add wlp3s0 here below, i.e.
         #
         #   bridge-ports enp2s0 wlp3s0
         #
         # the router stuck at start up. So I choose to NOT TO BRIDGE
         # wlp3s0 as line shows below,
         bridge-ports enp2s0
    
         # If the router start up slowly, please uncomment the line
         # below. For some reason, the system will stuck at boot for
         # 30 seconds up to 5 minutes while enp2s0 is not cable
         # plugged. This option could speed up the booting.
         bridge-maxwait 0
     EOF
    
  10. Setup start up script

    cat > ~/router.sh << "EOF"
    #!/bin/sh
    # vim: ts=4 sw=4
    #
    # /root/router.sh
    
    #### SETTINGS ####
    DEBUG=
    WANIF=ppp+
    LANIF=br0
    LANIP=192.168.2/24
    
    
    #### SOURCE CODE ####
    PATH=/sbin:$PATH
    
    # Wait for system up
    sleep 3
    
    # Allow IP forward as a honest router always do
    sysctl net.ipv4.ip_forward=1
    
    # Setup firewall
    cleanup_rules() {
        # Clean up iptables rules
        iptables -F
        iptables -X
        iptables -Z
        iptables -t nat -F
        iptables -t nat -X
        iptables -t nat -Z
    }; [ ${DEBUG} ] && cleanup_rules
    setup_basic_rules() {
        # Allow router local trans
        # Allow related trans which fired from LAN & router
        # Allow `ping` from LAN
        iptables -A INPUT -i lo -j ACCEPT
        iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
        iptables -A INPUT -i ${LANIF} -p icmp -j ACCEPT
    }; setup_basic_rules
    allow_services_from_wan() {
        # WAITING FOR YOUR CALL
        return
        # Example,
        # # Allow HTTP/HTTPS from WAN
        # iptables -A INPUT -i ${WANIF} -p tcp -m multiport --dports http,https -j ACCEPT
    }; allow_services_from_wan
    allow_services_from_lan() {
        # Allow `ssh` from LAN
        iptables -A INPUT -i ${LANIF} -p tcp --dport ssh -j ACCEPT
        # Allow DNS & DHCP from LAN
        iptables -A INPUT -i ${LANIF} -p tcp --dport domain -j ACCEPT
        iptables -A INPUT -i ${LANIF} -p udp -m multiport --dports domain,bootps,bootpc -j ACCEPT
        # Allow Samba from LAN
        iptables -A INPUT -i ${LANIF} -p tcp -m multiport --dports netbios-ssn,microsoft-ds -j ACCEPT
        iptables -A INPUT -i ${LANIF} -p udp -m multiport --dports netbios-ssn,microsoft-ds -j ACCEPT
        # Allow NFS from LAN
        iptables -A INPUT -i ${LANIF} -p tcp -m multiport --dports netbios-ns,netbios-dgm -j ACCEPT
        iptables -A INPUT -i ${LANIF} -p udp -m multiport --dports netbios-ns,netbios-dgm -j ACCEPT
    }; allow_services_from_lan
    drop_dirty_requests() {
        # Hey hacker! DON'T TOUCH ME!
        iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
        iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
        iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
        iptables -A INPUT -j DROP
    }; drop_dirty_requests
    
    enable_router() {
        iptables -A FORWARD -i ${WANIF} -o ${LANIF} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
        iptables -A FORWARD -i ${LANIF} -o ${WANIF} -j ACCEPT
        [ ${DEBUG} ] && iptables -A FORWARD -m limit --limit 5 -j LOG --log-prefix "FW-DROP: "
    
        iptables -t nat -A POSTROUTING -s ${LANIP} ! -d ${LANIP} -o ppp+ -j MASQUERADE
    }; enable_router
    
    cleanup_ipv6_rules() {
        # Clean up ip6tables rules
        ip6tables -F
        ip6tables -X
        ip6tables -Z
    }; [ ${DEBUG} ] && cleanup_ipv6_rules
    setup_basic_ipv6_rules() {
        ip6tables -A INPUT -i lo -j ACCEPT
        ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
        ip6tables -A INPUT -i ${LANIF} -p icmp -j ACCEPT
    }; setup_basic_ipv6_rules
    allow_ipv6_services_from_lan() {
        ip6tables -A INPUT -p tcp --dport ssh -j ACCEPT
    }; allow_ipv6_services_from_lan
    drop_dirty_ipv6_requests() {
        ip6tables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
        ip6tables -A INPUT -p udp -j REJECT --reject-with icmp6-port-unreachable
        ip6tables -A INPUT -j DROP
    }; drop_dirty_ipv6_requests
    EOF
    
    chmod +x ~/router.sh
    
  11. Setup cron job in root account to launch router function related APPs at start up. Type the following lines into root’s crontab by command crontab -e.

    # setup router
    @reboot ~/router.sh >> ~/crontab.log 2>&1
    
    # limit radio power
    @reboot /sbin/iwconfig wlp3s0 txpower 12 >> ~/crontab.log 2>&1
    
    # use swap only phy memory ran out
    @reboot /sbin/sysctl vm.swappiness=0 >> ~/crontab.log 2>&1
    
  12. Plug inbound cable into the router box.

    The cable linking is assumed as the char below,

    +----------+
    | Internet |   (Router 1 here is removed)
    +----------+
                \
                 \
                  +----------+
                  | Router 2 |  <-- now we building
                  +----------+
    

    From now on, the traditional router is ready to retire.

  13. Setup PPPoE by typing command pppoeconf in CLI. Follow the instruction.

    Discover PPPoE device Confirm popular options Enter username for dial Enter password for dial Confirm to use peer DNS Confirm MSS 1452 Allow dial on boot Allow dial now Finish PPPoE setup

  14. Finish

    Now, it’s the time to reboot! After the router rebooted, now we can search wireless AP with name MyRouter, and connect it with the passwords some-random-words.


Edit History

  • First pushlish @2017-08-15T18:10:43-04:00
  • Update @2017-08-26T10:32:43-04:00
  • Fix crontab @2017-08-26T22:26:32-04:00