OpenWRT
Installation
Please refer to the hardware model on how to install OpenWRT.
Trunk
If, for some reason we have to install from trunk, we may have to install some LuCI modules:
#!/bin/sh # Required: grep, wget, ssh, and scp, signify # Adjust if needed user="root" ip_address="192.168.1.1" if [ $# -ne 1 ]; then echo "Usage: $0 [arch]" exit 1 else architecture="$1" fi url="https://downloads.openwrt.org/snapshots/trunk/${architecture}/generic/packages/" tmpdir="/tmp/luci-offline" packages_base="liblua lua libuci-lua libubus libubus-lua uhttpd rpcd" packages_luci="luci-base luci-lib-ip luci-lib-nixio luci-theme-bootstrap luci-mod-admin-full luci-lib-jsonc" mkdir -p "$tmpdir" && cd "$tmpdir" echo "### Getting base/packages..." wget -Nq "${url}base/Packages" for pkg in $packages_base; do pkgfile="$(grep -Eoe " ${pkg}_.+" Packages | tail -c +2)" pkgurl="${url}base/${pkgfile}" wget -Nq "$pkgurl" done echo "### Getting luci/packages..." wget -Nq "${url}luci/Packages" for pkg in $packages_luci; do pkgfile="$(grep -Eoe " ${pkg}_.+" Packages | tail -c +2)" pkgurl="${url}luci/${pkgfile}" wget -Nq "$pkgurl" done echo "### Getting luci..." wget -Nq "${url}luci" for pkg in $packages_luci; do pkgfile="$(grep -Eoe " ${pkg}_.+" Packages | tail -c +2)" pkgurl="${url}luci/${pkgfile}" wget -Nq "$pkgurl" done scp -r "$tmpdir" "${user}@${ip_address}":/tmp/ ssh "${user}@${ip_address}" opkg install /tmp/luci-offline-packages/*.ipk ssh "${user}@${ip_address}" rm -rf /tmp/luci-offline-packages/ ssh "${user}@${ip_address}" "/etc/init.d/uhttpd start; /etc/init.d/uhttpd enable"
Some devices require special drivers and firmware too:
opkg install ath10k-firmware-qca988x kmod-ath10k
Being trunk
, some packages may not work properly yet:
- uhttpd: sh: 1: unknown operand when
ddns-scripts
are installed. - ...
Configuration
Packages
Install some essential packages:
opkg install ca-certificates curl diffutils dnscrypt-proxy haveged iftop iperf nrpe rsync script-utils snmpd vnstat
DNS
WAN interface
For some reason, dnsmasq is listening on the WAN interface[1] too, answering DNS lookups to the entire internet and even gives out internal records. Instead of creating a firewall rule[2] we just disable dnsmasq on the WAN interface:
$ grep ^interface /etc/dnsmasq.conf interface=lo interface=br-lan
Or, in /etc/config/dhcp
:
config dnsmasq [...] option interface 'lo br-lan'
Restart DNSmasq:
$ /etc/init.d/dnsmasq restart
With that in place, dnsmasq
only listens on loopback
and the local network
interface.
CNAME
The documentation states that it is possible to add a CNAME resource record:
$ grep -A2 cname /etc/config/dhcp config 'cname' option cname 'mail' option target 'server'
However, as of 10.03.1 this feature does not seem to be implemented. Patching the initscript helps:
--- /etc/init.d/dnsmasq.orig Wed Nov 23 17:13:22 2011 +++ /etc/init.d/dnsmasq Sun Jul 15 16:43:44 2012 @@ -346,6 +346,19 @@ done } +dhcp_cname_add() { + local cfg="$1" + local cname target + + config_get cname "$cfg" cname + [ -n "$cname" ] || return 0 + + config_get target "$cfg" target + [ -n "$target" ] || return 0 + + append args "--cname=${cname},${target}" +} + start() { include /lib/network scan_interfaces @@ -367,6 +380,7 @@ config_foreach dhcp_subscrid_add subscrid config_foreach dhcp_domain_add domain config_foreach dhcp_add dhcp + config_foreach dhcp_cname_add cname # add own hostname [ -z "$lanaddr" ] || {
AAAA Records
With nowhere else to put this right now, this is a neat trick[3] to have dnsmasq
only ask for A
records:
server=/example.net/1.2.3.4 address=/example.net/::
DNSCrypt
DNSCrypt secures the client-server communication for DNS lookups. For trunk
, installation is quite straightforward:
opkg update opkg install dnscrypt-proxy
Configure /etc/config/dnscrypt-proxy
like this:
config dnscrypt-proxy ns1
option address '127.0.0.1'
option port '5353'
option resolver 'fvz-anyone'
# option resolvers_list '/usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv'
option ephemeral_keys '1'
- The
resolvers_list
is hosted in a Github repository and should already be in place. - The OpenNIC project also lists public DNS servers, some with DNSCrypt enabled.
- The
resolver
is the name of a group of public DNS servers in theresolvers_list
. One group perdnscrypt-proxy
instance can be specified.
$ cut -d, -f1 /usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv | cut -d- -f1 | sort | uniq -c | sort -n | tail -5 4 adguard 4 cisco 4 fvz 12 cs 35 d0wn
Now that dnscrypt-proxy
is configured, we need to configure dnsmasq
too. In /etc/config/dhcp
, change the following:
config dnsmasq option domainneeded '1' option boguspriv '1' option localise_queries '1' option rebind_protection '1' option rebind_localhost '1' option expandhosts '1' option authoritative '1' option readethers '1' option leasefile '/tmp/dhcp.leases' # option resolvfile '/tmp/resolv.conf.auto' option noresolv '1' option localservice '1' option local '/lan/' option domain 'lan' option nonwildcard '1' list server '127.0.0.1#5353' list server '/pool.ntp.org/208.67.222.222' list interface 'br-lan' list notinterface 'eth0'
DNS over TLS
Install stubby:
opkg install stubby
In /etc/config/dhcp
:
config dnsmasq [...] list server '127.0.0.1#5453' list server '0::1#5453'
Enable & start:
/etc/init.d/stubby enable /etc/init.d/stubby start /etc/init.d/dnsmasq restart
Adding other DNS over TLS providers[4] in /etc/config/stubby
:
config resolver option address '9.9.9.9' option tls_auth_name 'dns.quad9.net' config resolver option address '149.112.112.112' option tls_auth_name 'dns.quad9.net' [...]
Dynamic DNS
The DDNS Client configuration changed quite a bit over the last OpenWRT versions, the following should be valid for OpenWRT 15.05.1.
Install the DDNS client and the LuCI frontend:
opkg install ddns-scripts luci-app-ddns
Configure our DDNS service:
uci set ddns.myddns_ipv4.service_name='freedns.afraid.org' # Must match a name from /usr/lib/ddns/services uci set ddns.myddns_ipv4.use_https='1' uci set ddns.myddns_ipv4.domain='foo.example.org' uci set ddns.myddns_ipv4.username='joe' uci set ddns.myddns_ipv4.password='s3cr3t' uci set ddns.myddns_ipv4.check_interval='10' uci set ddns.myddns_ipv4.check_unit='hours' uci set ddns.myddns_ipv4.enabled='1' uci set ddns.myddns_ipv6.service_name='freedns.afraid.org' # Must match a name from /usr/lib/ddns/services uci set ddns.myddns_ipv6.use_https='1' uci set ddns.myddns_ipv6.domain='foo.example.org' uci set ddns.myddns_ipv6.username='joe' uci set ddns.myddns_ipv6.password='s3cr3t' uci set ddns.myddns_ipv6.check_interval='10' uci set ddns.myddns_ipv6.check_unit='hours' uci set ddns.myddns_ipv6.enabled='1' uci commit ddns
With the last command, /etc/config/ddns
will be written. The DDNS daemon will be started with the next reboot or can be started as such:
sh
. /usr/lib/ddns/dynamic_dns_functions.sh
start_daemon_for_all_ddns_sections "wan"
exit
The wan parameter is the ip_network
value in /etc/config/ddns
. Let's see if this worked:
$ nslookup foo.dyndns.org ns.dyndns.org Server: 204.13.248.75 Address 1: 204.13.248.75 ns1.dyndns.org Name: foo.dyndns.org Address 1: 61.161.53.31 pppoe321.isp.example.com
DuckDNS
TBD
FreeDNS
In earlier OpenWRT versions, /usr/lib/ddns/services
had to be tweaked for afraid.org hosts:[5][6]
"freedns.afraid.org" "http://freedns.afraid.org/dynamic/update.php?[PASSWORD]&address=[IP]"
DynDNS
dyndns.org supported[7][8] options like wildcard DNS or MX records[9], but this can only be set online and the OpenWrt DynDNS client must be tought to handle these settings. This can only be done via tweaking /usr/lib/ddns/services
:
"dyndns.org" "http://[USERNAME]:[PASSWORD]@members.dyndns.org/nic/update?hostname=[DOMAIN]&myip=[IP]&wildcard=ON&mx=NOCHG"
Ad-Blocker
YoYo
We use dnsmasq
to block adservers and use a blocklist from yoyo.org:
$ wget -O /etc/dnsmasq.adservers "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=dnsmasq&mimetype=plaintext" $ tail -3 /etc/dnsmasq.conf bind-interfaces conf-file=/etc/dnsmasq.adservers # Adjust the target address as needed, e.g. conf-file=/etc/dnsmasq.work # address=/.corp/10.10.0.30 to blackhole all .corp $ /etc/init.d/dnsmasq restart
Add a cronjob to update the blocklists
$ crontab -l 0 23 * * 1 /root/bin/dl-adservers.sh restart
Pi-hole
The Pi-hole™ distribution uses several blocklists to generate a single list[10][11], and we could do the same:
TBD
Guest WLAN
TBD
- Configure a guest WLAN using the Luci web-interface
- OpenWRT and Guest Networks on the Netgear WNDR3700
- Transparent Tor Gateway on OpenWRT
NRPE
With OpenWRT 15.05, nrpe
appears to be unmaintained[12]. We should built the package manually[13]. In the meantime, we have just copied the package from our backups:
/usr/lib/opkg/info/nrpe.list /usr/lib/opkg/info/nagios-plugins.list
Example:
cd ~/backup/router/ && find . -name "*nrpe*" -o -name "check_*" | xargs tar -cf - ) | \ ssh router "tar -C / -xvf -"
Almost there:
$ ldd /usr/sbin/nrpe # Note: lddisused to be a shell function! # LD_TRACE_LOADED_OBJECTS=1 libssl.so.1.0.0 => not found libcrypto.so.1.0.0 => not found libwrap.so.0 => not found libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x77a64000) libc.so.0 => /lib/libc.so.0 (0x779f7000) ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x77a88000)
Install dependencies:
opkg install libopenssl libwrap
Add nagios
user:
echo 'nagios:x:50:' >> /etc/group echo 'nagios:x:50:50:nagios:/var/run/nagios:/bin/false' >> /etc/passwd echo 'nagios::16874:0:99999:7:::' >> /etc/shadow
Configure nrpe
:
$ grep ^[a-z] /etc/nrpe.cfg pid_file=/var/run/nrpe.pid server_port=5666 server_address=192.168.0.2 nrpe_user=nagios nrpe_group=nagios allowed_hosts=192.168.0.106,192.168.0.116 dont_blame_nrpe=0 debug=0 command_timeout=60 connection_timeout=300 command[check_dummy]=/usr/libexec/nagios/check_dummy 0 command[check_dns]=/usr/libexec/nagios/check_dns -H ping.example.com -s localhost -w 0.1 -c 0.5 command[check_entropy]=/root/bin/check_entropy.sh -w 1024 -c 512 command[check_http]=/usr/libexec/nagios/check_http -H localhost -w 0.1 -c 0.5 command[check_load]=/usr/libexec/nagios/check_load -w 4,3,2 -c 5,4,3 command[check_ntp_time]=/usr/libexec/nagios/check_ntp_time -H 0.openwrt.pool.ntp.org -w 0.5 -c 1.0 command[check_ssh]=/usr/libexec/nagios/check_ssh -4 router command[check_softwareupdate_opkg]=/root/bin/check_softwareupdate.sh opkg command[check_users]=/usr/libexec/nagios/check_users -w 3 -c 5
Let's try to start it, and enable it if it works:
$ /etc/init.d/nrpe start $ ps | grep nrp[e] 5320 nagios 2908 S /usr/sbin/nrpe -c /etc/nrpe.cfg -d $ /etc/init.d/nrpe enable
haveged
$ sysctl kernel.random.entropy_avail kernel.random.entropy_avail = 140
Install haveged:
opkg update opkg install haveged
With that, haveged should already be enabled and running, otherwise:
/etc/init.d/haveged enable /etc/init.d/haveged start
Now it should look like this:
$ sysctl kernel.random.entropy_avail kernel.random.entropy_avail = 1393
IPv6
There's an excellent OpenWrt Howto on how to get IPv6 up & running. Here's the short story:
$ opkg update && opkg install 6in4 Downloading http://downloads.openwrt.org/backfire/10.03.1/brcm-2.4/packages/Packages.gz. Inflating http://downloads.openwrt.org/backfire/10.03.1/brcm-2.4/packages/Packages.gz. Updated list of available packages in /var/opkg-lists/packages. Installing 6in4 (10-1) to root... Installing ip (2.6.29-1-2) to root... Installing kmod-ipv6 (2.4.37.9-1) to root... Installing kmod-sit (2.4.37.9-1) to root... Configuring ip. Configuring kmod-ipv6. Configuring kmod-sit. Warning: loading sit will taint the kernel: no license See http://www.tux.org/lkml/#export-tainted for information about tainted modules Configuring 6in4.
When using HE, one can just use their "Example Configuration", since they're providing a full OpenWRT configuration:
uci set network.henet=interface uci set network.henet.proto=6in4 uci set network.henet.peeraddr=1.2.3.4 uci set network.henet.ip6addr='2001:123:45:67::8/64' uci set network.henet.tunnelid=123456 uci set network.henet.username=UserName uci set network.henet.password='s3cr3t' uci commit network uci set firewall.@zone[1].network='wan henet' uci commit firewall ifup henet /etc/init.d/firewall restart
We want to setup routing through this tunnel interface. For HE, we have to use the "Routed IPv6 Prefix" (Routed /64) and add it to our configuration. This prefix can be calculated by incrementing the last digit of the third quad in the tunneling prefix:
$ uci show network.henet.ip6addr network.henet.ip6addr=2001:123:45:67::8/64 $ uci set network.lan.ip6addr='2001:123:46:67::8/64' $ uci commit network
- Upgrade ASUS wl-500g Premium v1 from DD-WRT to OpenWrt
- Using OpenWRT as a IPv6 router
- #10019: he.net was changed updating tunnel ip API
- Turning Comcast IPv6 Up on a NetGear 3800 with OpenWRT
muninlite
MuninLite is a shell script implementing the Munin protocol and providing some Linux specific plugins.
$ opkg install muninlite # This will also install xinetd $ /etc/init.d/xinetd enable
Be sure to add the bind
option to xinetd
's config, otherwise we'd listen even on the WAN interface:
$ cat /etc/xinetd.d/munin
service munin
{
socket_type = stream
protocol = tcp
wait = no
user = root
group = root
server = /usr/sbin/munin-node
disable = no
bind = 10.0.0.1
}
Start xinetd
:
$ /etc/init.d/xinetd start $ echo list | nc localhost 4949 # munin node at router cpu if_eth0 if_eth0VLAN0 if_eth0VLAN1 if_br_lan if_err_eth0 if_err_eth0VLAN0 \ if_err_eth0VLAN1 if_err_br_lan load memory processes uptime interrupts irqstats
nrpe
Note: NRPE is currently not available for OpenWRT, as it's unmaintained.[14]
opkg update opkg install nrpe
Configure in /etc/nrpe.cfg
, then:
/etc/init.d/nrpe enable /etc/init.d/nrpe start
SNMP
opkg install snmpd # mini-snmpd can't handle 64-bit counters[15]
Adjust /etc/config/snmpd
, e.g.:
config agent option agentaddress udp:10.0.0.1:161 [...] config system option sysLocation 'UK' option sysContact 'root@mailhub' option sysName 'router' # option sysServices 72 # option sysDescr 'home router' # option sysObjectID '1.2.3.4'
Enable & start snmpd
:
/etc/init.d/snmpd enable /etc/init.d/snmpd start
snmpd
should be running now:
# netstat -an | grep :161 udp 0 0 192.168.0.2:161 0.0.0.0:* # ls -l /var/run/snmpd.conf -rw-r--r-- 1 root root 430 Dec 9 22:52 /var/run/snmpd.conf
vnStat
opkg update opkg install vnstat
With that, vnstat should already be configured and vnstatd
should be running:
$ ps | grep vn[s] 5288 root 988 S /usr/sbin/vnstatd -d
We may want to move the traffic database to a permanent storage[16], so it will be saved across reboots:
$ mv /var/lib/vnstat/ /root/.vnstat $ cat /etc/vnstat.conf Interface "eth1" DatabaseDir "/root/.vnstat" $ /etc/init.d/vnstat restart
If we need to configure vnstat
manually:
$ uci get network.wan.ifname
eth1
Our LAN
interface is often handled by a bridge:
$ brctl show
bridge name bridge id STP enabled interfaces
br-lan 6fff.2be01a132618 no eth0.1
wlan0
wlan1
Initialize the databases for both the WAN
and LAN
interface:
vnstat -u -i eth1 vnstat -u -i br-lan
If we decide against running the vnstatd
daemon, we'll have to update the database with a cronjob:
$ crontab -l # /etc/crontabs/root */5 * * * * /usr/bin/vnstat -u -i eth1 */5 * * * * /usr/bin/vnstat -u -i br-lan $ /etc/init.d/cron enable $ /etc/init.d/cron start
Backup
sysupgrade
To backup the OpenWrt configuratin[17], use sysupgrade:
sysupgrade --create-backup /tmp/backup-$(uname -n)-$(date +%F).tar.gz
This can be restored via the web interface later on:
System → Backup / Flash Firmware → Backup / Restore
Or, manually on the command line:
tar -xzvf -C / backup.tar.gz
Manual
We want to save some other parts of the system too:
uci show > uci-show.txt uci export > uci-export.txt opkg list-installed > opkg-installed.txt
Backups can be created from the GUI (System → Backup) or via command line. Since Busybox tar(1) does not support --exclude
but only -X
(exclude from a file),[18] a backup command will look something like this:
$ ssh router "cat /root/backup.exclude" dev lib/modules usr/lib proc sys $ ssh router "cd / && tar -X /root/backup.exclude -cf - ." | xz -9ec > router-backup.tar.xz
And the other way around, to restore:
xz -dc router-backup.tar.xz | ssh router "cd / && tar -xvf -"
Update
Caution: although upgrading packages is possible[19] via opkg
it's not recommended and can be dangerous![20] Use only when you how to reset[21] and debrick[22] your device!
To update all (outdated) packages:
opkg update && opkg list-upgradable
opkg upgrade $(opkg list-upgradable | awk '{print $1}') # See the warning above!
Find all updated files:
find /overlay/ -type f -exec ls -ltrd '{}' + | grep "$(date +%b\ \ %-d)" # May not work, since it's padding the # days and +%-d may not supported yet.
Note: the It has been enabled again[23][24] in late 2015:
-mtime
option in OpenWRT's version of BusyBox/findutils was disabled and may not be available.
find /overlay/ -type f -mtime -1 -exec ls -ltrd '{}' +
Find leftover configuration files:
find /etc/ -name "*opkg" -exec ls -lhtrd '{}' +
Sometimes configuration formats have changed and uci
throws an error:
uci: Parse error (too many arguments) at line 124, byte 23
Let's find out where the error was generated:
$ for c in /etc/config/*; do uci show ${c#/etc/config/} > /dev/null || echo $c; done
uci: Parse error (too many arguments) at line 124, byte 23
/etc/config/snmpd
After fixing this configuration file, the error should be gone.
Upgrade
As a preparation step, let's check and save modified configuration files:
cd /root for f in $(opkg list-changed-conffiles); do grep -q $f /etc/sysupgrade.conf || echo "missing: $f"; done
Save package lists:
opkg list-installed | awk '{print $1}' | sort > opkg_installed
awk '/^Package:/ {PKG= $2} /^Status: .*user installed/ {print PKG}' /usr/lib/opkg/status | sort > status_installed
After backing up the device once more, start the actual upgrade over a wired connection using the correct image and after verifying its checksum:
sysupgrade -v /tmp/*sysupgrade.bin
Postinstall:
opkg list-installed | sort > foo
for p in `awk '!/^lib/ {print $1}' opkg_installed`; do grep -qw $p foo || echo "to be installed: $p"; done
Install missing packages and check for leftover configuration files:
find /etc -name "*opkg"
Enable necessary services again:
for s in haveged snmpd vnstat; do /etc/init.d/$s enable; done for s in haveged snmpd vnstat; do /etc/init.d/$s start; done
Decommissioning
To decommision a router with OpenWRT installed:
- Reset via Failsafe mode: unplug the power cord, press and hold the reset button, put in the power cord, release the reset button when the DMZ-LED lits up.
- Connect to the router and reset all settings:
> telnet 192.168.1.1 # no password required $ mount_root switching to jffs2 # rootfs is now mounted read/write $ passwd Changing password for root ... Password for root changed by root # password set to "root" $ firstboot firstboot has already been run jffs2 partition is mounted, only resetting files
This should've been enough, but just for fun:
$ mtd -r erase rootfs_data Unlocking rootfs_data ... Erasing rootfs_data ... Rebooting ...
And again, to overwrite the backing device:
> telnet 192.168.1.1 $ cat /dev/urandom > /foo # This is in fact /overlay/upper/foo cat: writing 'foo': No space left on device $ rm -f /foo $ echo s > /proc/sysrq-trigger $ echo u > /proc/sysrq-trigger $ dmesg | tail SysRq : Emergency Sync Syncing device 1f:02 ... OK Syncing device 1f:04 ... OK Done. SysRq : Emergency Remount R/O Remounting device 1f:02 ... R/O Remounting device 1f:04 ... OK Done.
We can also install a fresh firmware image onto the system:
- Download the correct
squashfs-factory.img
image. - Reset router and put it into failsafe mode:[25]
- Power off the router
- Press and hold the reset button
- Power on the router and continue to press the reset button.
- After a while, the router will respond to
ping
on 192.168.1.1/24 - Release the reset button
- Install via TFTP[26]:
$ echo -e "binary\nrexmt 1\ntimeout 60\ntrace\nput openwrt-XXX-squashfs-factory.img\n" | tftp 192.168.1.1
Packet tracing on.
sent DATA <block=6655, 512 bytes>
received ACK <block=6655>
[...]
Sent 3408005 bytes in 1.2 seconds
The router will automatically reboot into the new firmware.
LEDE
The LEDE project and OpenWRT merged back together in January 2018.[27]
Links
- VLAN
- Build
- DD-WRT
- Tomato
- OpenNIC - Alternative DNS servers (DDG list)
- Turris Omnia
- A set of scripts for maintaining and testing OpenWrt
References
- ↑ dnsmasq port 53 open on WAN port
- ↑ DNS on WAN port open -> allows local nameresolution from WAN
- ↑ disable AAAA response for a given domain
- ↑ Public recursive name server
- ↑ ddns-scripts: Add logging (2011-06-08)
- ↑ ddns-scripts: Add logging (offline)
- ↑ DynDNS: Wildcard No More (2009-06-04)
- ↑ Dynamic DNS - how to "Enable Wildcards" (2009-09-24)
- ↑ DNS Update API: Perform Update
- ↑ pi-hole/gravity.sh
- ↑ Customising Sources for Ad Lists
- ↑ nagios nrpe daemon need to configure with '--enable-command-args' to support 'dont_blame_nrpe=1' on nrpe.cfg
- ↑ How to Build a Single Package
- ↑ NRPE daemon port
- ↑ 64 bit counters in mini-snmpd
- ↑ The OpenWrt Flash Layout
- ↑ Generic Backup
- ↑ tar --exclude option does not work (but exists in --help and config help)
- ↑ Opkg Package Manager: Package Manipulation
- ↑ upgrade_packages_warning
- ↑ Failsafe Mode, Factory Reset, and Recovery Mode
- ↑ OpenWrt Debricking Guide
- ↑ busybox: enable find mtime support by default (2015-11-02)
- ↑ busybox find, mtime option missing
- ↑ Netgear WNDR3800: Recovery flash in failsafe mode
- ↑ Installing OpenWrt via TFTP
- ↑ OpenWrt LEDE merge