令人发指.com 的宕机
这个 Blog 最近经常宕机,请不必太担忧。不是被墙了,我也还没有机会去喝茶。只是我爹妈家的猫很喜欢我放那儿的路由器,经常在上面爬来爬去;俺娘又怕电着了猫(解释电压之类是没用的),经常把电源断了。我整天天涯海角的乱跑,也实在鞭长莫及。几个月不 update 的 blog 还老宕机,实在不好意思,撰文以纪念。--
Best Regards
Yale Huang <mailto: calvino.huang@gmail.com>
Labels: OpenWRT
Labels: OpenWRT
#!/bin/sh
# /usr/local/bin/nas_watchdog
pid="$(cat /var/run/nas.lan.pid 2>&-)"
[ -n "$pid" -a -d "/proc/$pid" ] && exit 0
echo "Restarting WPA ..."
/etc/init.d/S41wpa
exit 1
*/2 * * * * /usr/local/bin/nas_watchdog
Labels: OpenWRT
#!/bin/sh
case "$1" in
start)
openvpn --daemon --config /etc/openvpn/openvpn_peer.conf
;;
restart)
$0 stop
sleep 3
$0 start
;;
reload)
killall -SIGHUP openvpn
;;
stop)
killall openvpn
;;
### network options
port 1194
#proto udp
proto tcp
dev tun
### certificate and key files
ca /etc/openvpn/ca.crt
cert /etc/openvpn/server.crt
key /etc/openvpn/server.key
dh /etc/openvpn/dh1024.pem
### (optional) use a shared key to initialize TLS negotiation
#tls-auth /etc/openvpn/shared.key
### VPN subnet
server 10.8.0.0 255.255.255.0
### (optional) make local network behind the VPN server accessible for the VPN clients
push "route 192.168.1.0 255.255.255.0"
### (optional) make the VPN server a gateway for the internet for the VPN clients
#push "redirect-gateway"
### (optional) compression (might make your WRT sluggish or not, depending on the model and what you have running...)
comp-lzo
keepalive 10 120
status /tmp/openvpn.status
# route to peer subnets
client-config-dir /etc/openvpn/ccd
route 192.168.3.0 255.255.255.0
iroute 192.168.3.0 255.255.255.0
Labels: OpenWRT
I'm not sure that whether any other customized files will be affected by
upgrading. But chances are that there's no protection for them during
upgrading. And unfortunately, there's no version check for package
dependency. So, upgrading will be a complex manual task.
Labels: OpenWRT
###########################################################
#
# perl-error
#
###########################################################
PERL-MODULE_BASENAME=perl-error
PERL-MODULE_ORG_BASENAME=Error
PERL-MODULE_SITE=http://search.cpan.org/CPAN/authors/id/S/SH/SHLOMIF
PERL-MODULE_VERSION=0.17014
PERL-MODULE_MAINTAINER?=Yale Huang
include make/perl-module.mk.inc
Labels: OpenWRT
tar: Pattern matching characters used in file names. Please,
tar: use --wildcards to enable pattern matching, or --no-wildcards to
tar: suppress this warning.
tar: *control.tar.gz: Not found in archive
tar: Error exit delayed from previous errors
--- ipkg.py.org 2008-06-16 12:01:25.000000000 +0800
+++ ipkg.py 2008-06-16 12:10:23.000000000 +0800
@@ -93,9 +93,9 @@
self.filename = os.path.basename(fn)
## sys.stderr.write(" extracting control.tar.gz from %s\n"% (fn,))
if self.isdeb:
- control = os.popen("ar p "+fn+" control.tar.gz | tar xfzO - '*control'","r")
+ control = os.popen("ar p "+fn+" control.tar.gz | tar xzO --wildcards -f - '*control'","r")
else:
- control = os.popen("tar xfzO "+fn+" '*control.tar.gz' | tar xfzO - '*control'","r")
+ control = os.popen("tar xzO --wildcards -f "+fn+" '*control.tar.gz' | tar xzO --wildcards -f - '*control'","r")
line = control.readline()
while 1:
if not line: break
@@ -122,7 +122,7 @@
if self.isdeb:
data = os.popen("ar p "+fn+" data.tar.gz | tar tfz -","r")
else:
- data = os.popen("tar xfzO "+fn+" '*data.tar.gz' | tar tfz -","r")
+ data = os.popen("tar xz0 --wildcards -f "+fn+" '*data.tar.gz' | tar tfz -","r")
while 1:
line = data.readline()
if not line: break
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
So, you have OpenWrt running now. Why do you still waste time on starting desktop/laptop just for an SSH terminal? How about a lightweight terminal for OpenWrt?
Dr. Philip Endecott provides a perfect tutorial about building an interactive terminal fo NSLU2. Of cause, we can do the same thing with OpenWrt. But there are more options.
At first, let's review what devices I have to attach to OpenWrt:
I cannot describe the detail of using USB kayboard and LCM before I got them. To attach an additonal input to a terminal, it's not hard. Screen and socat can help. With screen, I can type with my Windows PuTTY terminal and watch the output with My E61 now.
Labels: OpenWRT
WEB and WAP are the most important interfaces for the routers. Quite some HTTP server applications are available for this purpose, and also more Web programming tools and frameworks.
Following are Web servers available in ipkg:
Following are Web programming languages and tools available in ipkg:
Database packages:
Following is a typical spec of OpenWrt supported system (my WL-500g):
After testing various Web and Wiki frameworks, I found the major bottleneck is the memory. Following are memory usage and process list of my box:
root@KubaoGW:/usr/lib/ipkg/lists# free
total used free shared buffers
Mem: 14308 13672 636 0 836
Swap: 31288 2892 28396
Total: 45596 16564 29032
root@KubaoGW:/usr/lib/ipkg/lists# ps -ea
PID Uid VmSize Stat Command
1 root 64 S init
2 root SW [keventd]
3 root RWN [ksoftirqd_CPU0]
4 root SW [kswapd]
5 root SW [bdflush]
6 root SW [kupdated]
9 root SW [mtdblockd]
54 root SWN [jffs2_gcd_mtd4]
78 root 48 S logger -s -p 6 -t
81 root 152 S klogd
106 root 132 S /sbin/syslogd -C16 -m 0
206 root SW [khubd]
241 root SW [usb-storage-0]
242 root SW [scsi_eh_0]
333 root SW [kjournald]
358 root SW [kjournald]
565 root 80 S /bin/sh /sbin/ifup.pppoe wan
666 root 124 S /usr/sbin/dropbear
706 root 84 S httpd -p 80 -h /www -r KubaoGW
716 root 36 S telnetd -l /bin/login
767 root 200 S /usr/sbin/crond
880 nobody 132 S dnsmasq -l /tmp/dhcp.leases -K -F lan,192.168.1.2,192
1047 root 52 S vtund[s]: waiting for connections on port 5050
1140 root 136 S /usr/sbin/ez-ipupdate -d -F /var/run/ez-ipupdate.pid
5763 root 132 S /sbin/wifi
27268 root 76 S /usr/sbin/dropbear
27269 root 112 S -ash
1561 root 116 S /usr/sbin/dropbear
1589 yale 112 S -ash
7336 root 520 S /mnt/disc0_1/var/MailRoot/bin/XMail
7345 root 168 S didiwiki
7346 root 520 S /mnt/disc0_1/var/MailRoot/bin/XMail
7347 root 520 S /mnt/disc0_1/var/MailRoot/bin/XMail
7348 root 520 S /mnt/disc0_1/var/MailRoot/bin/XMail
7349 root 520 S /mnt/disc0_1/var/MailRoot/bin/XMail
7350 root 520 S /mnt/disc0_1/var/MailRoot/bin/XMail
7351 root 520 S /mnt/disc0_1/var/MailRoot/bin/XMail
7352 root 520 S /mnt/disc0_1/var/MailRoot/bin/XMail
7353 root 520 S /mnt/disc0_1/var/MailRoot/bin/XMail
7354 root 520 S /mnt/disc0_1/var/MailRoot/bin/XMail
8648 root 236 S /usr/sbin/pppd nodetach plugin rp-pppoe.so connect /b
8729 root 168 S miniupnpd -i ppp0 -a 192.168.1.1 -p 5000 -U -B 131072
8779 root 432 S
So, only very few free memory are available now. Druing my test, MoinMoin, CakePHP, Django all cost over 4MB memory can cause swap thrash. And even worse, it's found lighttpd has a bug, which hangs it up when reading slow fds. I used to wait for minutes for MoinMoin diaplaying one page. But when I executed the same test with my WL-HDD with most services shutted down, it's about 4 ~ 5 times faster. But I don't want to deploy one box for each searvice. And you know, MySQL and Postgres also require MBs of memory.
So, the fundemantal strategy is, to limite the memory footprint. Comparing Django with CakePHP, I prefer the latter, which may be slower, but releases memory after the request is replied. But Webif + Sqlite is still recommended for most cases, which is almost the lightest solution. And it will be the fundemantal framework of Web service of LRFZ box. Busybox is powerful enough for most general usage. But it's lack of the feature of virtual host. Lighttpd will be great once the above bug is fixed (according to Lighttpd's trac, it should be version 1.5).
Alternatively, it's also possible to engage the physical memroy size. Fortunately, I found a retailer which provides routers with 64MB memory. I wish Django and MoinMoin will run smoothly on it.
Labels: OpenWRT
So, which part is wrong? The hard disk? I searched for document about hard disk life, and found some read laptop disk cannot work continuously for days. Actually, I just kept it running for over one week. :(
Whatever, I won't be able to check it by hand until this weekend. So, what a robust system my WL-500G is, which has run for months already.
Update: I was wrong. I updated the gateway WL-500G tonight and found WL-HDD. So, maybe the issue was caused by WL-500G? Something wrong with the bridge module? Not sure, just wait for reproducing.
Labels: OpenWRT
Last weekend, I set up WDS with my WL-500G and WL-HDD. Following are my tips for setting up WDS with WPA:
Then I enabled 802.11g for both devices(OpenWrt uses 802.11b by defaule), and start Samba at WL-HDD. The Windows client was connected to WL-500G via 802.11g. When coping files from and to WL-HDD, the througput were both about 1MBps. Not exciting, but acceptable for playing most RMVB.
Labels: OpenWRT
WL-500G, my gateway server, runs network services including lighttpd, xmail, didiwiki, vtund, dnsmasq, and dropbear:
root@OpenWrt:/mnt/disc0_1/home/yale# time gs -dNOPAUSE -dPARANOIDSAFER -dBATCH -r600x600 -sDEVICE=pbmraw -sOutputFile=output.pbm output.ps
AFPL Ghostscript 8.50 (2004-12-10)
Copyright (C) 2004 artofcode LLC, Benicia, CA. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
real 2m 32.57s
user 0m 9.87s
sys 0m 23.93s
root@OpenWrt:/mnt/disc0_1/home/yale# free
total used free shared buffers
Mem: 14308 12312 1996 0 684
Swap: 31288 3652 27636
Total: 45596 15964 29632
root@OpenWrt:/mnt/disc0_1/home/yale# cat /proc/cpuinfo
system type : Broadcom BCM947XX
processor : 0
cpu model : BCM4710 V0.0
BogoMIPS : 82.94
wait instruction : no
microsecond timers : yes
tlb_entries : 32
extra interrupt vector : no
hardware watchpoint : no
VCED exceptions : not available
VCEI exceptions : not available
WL-HDD, runs services nfsd, smbd and dropbear:
root@KubaoHDD:/home/root$ time gs -dNOPAUSE -dPARANOIDSAFER -dBATCH -r600x600 -sDEVICE=pbmraw -sOutputFile=output.pbm output.ps
AFPL Ghostscript 8.50 (2004-12-10)
Copyright (C) 2004 artofcode LLC, Benicia, CA. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
real 0m 32.50s
user 0m 9.84s
sys 0m 21.00s
root@KubaoHDD:/home/root$ free
total used free shared buffers
Mem: 14308 9172 5136 0 228
Swap: 72284 1572 70712
Total: 86592 10744 75848
root@KubaoHDD:/home/root$ cat /proc/cpuinfo
system type : Broadcom BCM947XX
processor : 0
cpu model : BCM4710 V0.0
BogoMIPS : 82.94
wait instruction : no
microsecond timers : yes
tlb_entries : 32
extra interrupt vector : no
hardware watchpoint : no
VCED exceptions : not available
VCEI exceptions : not available
The .ps file is only a 2-page text file. 32.50s costed by WL-HDD is still acceptable, while 2m 32.57s of WL-500G is much longer than expected. The major difference between these two machines is the memory usage. For a wireless router, gs consumes quite some memory(up 5MB during this test), and causes frequent memory switching when the system is short of memory. I'm not sure whether the IDE based swap of WL-HDD helps againt the MMC card based swap for WL-500G.
Unfortunately, the Canon LBP-660 printer I'm going to deploy is LPT based, which can only fit with WL-500G. So, it seems that I have to migrate some services to WL-HDD to save some memory on WL-500G for the print service.
----- End forwarded message -----
Labels: OpenWRT
冷静了一下, 仔细看看, 有问题的 IP 在以太口上. 以太口? 我的 WL-HDD 啊. 上周走的匆忙, WL-HDD 的 Wifi 没加密. 先把 Wifi 口从网桥摘掉, 等回家设加密吧. 我真是好人啊, 不然继续让这些坏蛋用, dump 下来把密码全找出来. 只是估计盗用的家伙也不是美女, 就没这个兴趣了.
Labels: OpenWRT
WL-500G, my gateway server, runs network services including lighttpd, xmail, didiwiki, vtund, dnsmasq, and dropbear:
root@OpenWrt:/mnt/disc0_1/home/yale# time gs -dNOPAUSE -dPARANOIDSAFER -dBATCH -r600x600 -sDEVICE=pbmraw -sOutputFile=output.pbm output.ps
AFPL Ghostscript 8.50 (2004-12-10)
Copyright (C) 2004 artofcode LLC, Benicia, CA. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
real 2m 32.57s
user 0m 9.87s
sys 0m 23.93s
root@OpenWrt:/mnt/disc0_1/home/yale# free
total used free shared buffers
Mem: 14308 12312 1996 0 684
Swap: 31288 3652 27636
Total: 45596 15964 29632
root@OpenWrt:/mnt/disc0_1/home/yale# cat /proc/cpuinfo
system type : Broadcom BCM947XX
processor : 0
cpu model : BCM4710 V0.0
BogoMIPS : 82.94
wait instruction : no
microsecond timers : yes
tlb_entries : 32
extra interrupt vector : no
hardware watchpoint : no
VCED exceptions : not available
VCEI exceptions : not available
WL-HDD, runs services nfsd, smbd and dropbear:
root@KubaoHDD:/home/root$ time gs -dNOPAUSE -dPARANOIDSAFER -dBATCH -r600x600 -sDEVICE=pbmraw -sOutputFile=output.pbm output.ps
AFPL Ghostscript 8.50 (2004-12-10)
Copyright (C) 2004 artofcode LLC, Benicia, CA. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
real 0m 32.50s
user 0m 9.84s
sys 0m 21.00s
root@KubaoHDD:/home/root$ free
total used free shared buffers
Mem: 14308 9172 5136 0 228
Swap: 72284 1572 70712
Total: 86592 10744 75848
root@KubaoHDD:/home/root$ cat /proc/cpuinfo
system type : Broadcom BCM947XX
processor : 0
cpu model : BCM4710 V0.0
BogoMIPS : 82.94
wait instruction : no
microsecond timers : yes
tlb_entries : 32
extra interrupt vector : no
hardware watchpoint : no
VCED exceptions : not available
VCEI exceptions : not available
The .ps file is only a 2-page text file. 32.50s costed by WL-HDD is still acceptable, while 2m 32.57s of WL-500G is much longer than expected. The major difference between these two machines is the memory usage. For a wireless router, gs consumes quite some memory(up 5MB during this test), and causes frequent memory switching when the system is short of memory. I'm not sure whether the IDE based swap of WL-HDD helps againt the MMC card based swap for WL-500G.
Unfortunately, the Canon LBP-660 printer I'm going to deploy is LPT based, which can only fit with WL-500G. So, it seems that I have to migrate some services to WL-HDD to save some memory on WL-500G for the print service.
Labels: OpenWRT
Labels: OpenWRT
So, I implemented a script to walk around the hijacked requests:
#!/bin/ash
#
# fuck_china_telecom.sh
# Walk around HTTP requests hijacked by China Telecom.
#
TEST_FILE=`mktemp /tmp/fuck_china_telecom.XXXXXX`
TEST_PATTERN='dyndns'
TEST_URL='http://members.3322.org'
RETRIES=30
C=0
while [ $C -lt $RETRIES ]; do
wget -O $TEST_FILE $TEST_URL
grep $TEST_PATTERN $TEST_FILE && rm $TEST_FILE && return 0
rm $TEST_FILE
let C=$C+1
sleep 1
done
return 1
And call it in my ez-ipupdate script for iface hotplug (/etc/hotplug.d/iface/10-ez-ipupdate):
. /etc/functions.sh
NAME=ez-ipupdate
CONFIG=/etc/$NAME.conf
COMMAND=/usr/sbin/$NAME
[ "$ACTION" = "ifup" -a "$INTERFACE" = "wan" ] && {
[ -x $COMMAND ] && [ -r $CONFIG ] && {
IFNAME=$(nvram get ${INTERFACE}_ifname)
/usr/local/bin/fuck_china_telecom.sh 2>&1 | logger -t $NAME
$COMMAND -c $CONFIG -i $IFNAME 2>&1 | logger -t $NAME
} &
}
Labels: OpenWRT
It's so glad to find some other interesting guys working with NSLU2, who set up their development env with native compilers and distcc. A compiler farm in house, how LRFZ it is!
Labels: OpenWRT
I have a VPN between my machines in Nanjing and Shanghai. It was based on UDP. For months, I suffer the ill-behaved VPN, especially when transfer files from Shanghai to Nanjing. Last night, I tuned the MTU of VPN device to a smaller number and found scp worked better.
But today, when I was trying to write a file via NFS from Shanghai to Nanjing, it always failed. So, I dumped packets at the client, the server and also the gateway at Nanjing. I found a UDP packet was always lost after sending from SH PPPoE interface!
08:45:19.253691 IP (tos 0x0, ttl 64, id 11499, offset 0, flags [DF], proto: UDP (17), length: 942) 218.79.145.142.2051 > 58.217.165.43.5050: UDP, length 914
It's the raw PPPoE interface, nothing to do with VPN. So, the only possible reason is that the packet was dropped somewhere after it was sent from my SH box, and before it reached at
my NJ box. China Telecom.
So, the only thing I can do is to switch the VPN to TCP based. But I don't like this mode. You know, it requires extra handshake on error.
Labels: OpenWRT
There's no doubt that root fs on USB & IDE will work. But NFS still needs testing. Even more, I found a doc for NSLU2 about swap over NFS. I think it will work. So, NFS will be a good solution for the LIGHTEST box in OpenWRT clusters.
Another pending issue is kernel image. While the whole root fs is in the USB/IDE/NFS storage, kernel image, basic kernel modules and utils are still in ROM. ROM refreshing is still required for kernel upgrading.
Labels: OpenWRT
My .esmtprc:
hostname=www.lrfz.com:25
username="xxx@lrfz.com"
password="xxx"
mda="/mnt/disc0_1/usr/bin/procmail -d %T"
I'm not sure whether the mda option is must-have.
My .muttrc:
set sendmail = "/mnt/disc0_1/opt/bin/esmtp -v -X ~/.esmtplog"
set pop_host = "pop://www.lrfz.com"
set pop_user = xxx
set spoolfile = "pop://www.lrfz.com"
#set folder = "pop://www.lrfz.com"
It's recommanded to do these with a normal user instead of root. You should be able to set it up for your mailboxes like Gmail in minutes.
Labels: OpenWRT
#!/bin/sh
HDD_MNT_POINT=/mnt/hda1
ORG_ROOT=/mnt/hda1/mnt/jffs
DEV_HDA=/dev/hda
DEV_HDA1=/dev/hda1
mount_hdd() {
# [ -z "$boot_dev" ] && return 1
# install modules needed for ide and the ext3 filesystem
for module in ide-core pdc202xx_old ide-detect ide-disk ext2 jbd ext3; do {
insmod $module || return 1
}; done
# this may need to be higher if your disk is slow to initialize
sleep 4
mknod $DEV_HDA b 3 0 || return 1
mknod $DEV_HDA1 b 3 1 || return 1
mount $DEV_HDA1 $HDD_MNT_POINT -t ext3 || return 1
# [ -x "$HDD_MNT_POINT/sbin/init" ] || return 1
# pivot_root "$HDD_MNT_POINT" "$ORG_ROOT" || return 1
return 0
}
switch_root() {
if [ -x "$HDD_MNT_POINT/sbin/init" ]; then
mount -o move /proc "$HDD_MNT_POINT/proc" || return 1
pivot_root "$HDD_MNT_POINT" "$ORG_ROOT" || return 1
mount -o move "/mnt/jffs/dev" /dev
mount -o move "/mnt/jffs/tmp" /tmp
mount -o move "/mnt/jffs/jffs" /jffs 2>&-
#mount -o move "/mnt/jffs/sys" /sys 2>&-
else
return 1
fi
return 0
}
# change nvram variable 'boot_dev' to your root filesystem
#boot_dev=`nvram get boot_dev`
mount_hdd && switch_root
# switch_root
# finally, run the real init
exec /bin/busybox init
mkdir /mnt/hda1
mount -t ext3 /dev/ide/host0/bus0/target0/lun0/part1 /mnt/hda1
mkdir -p /mnt/hda1/mnt/jffs
umount /mnt/hda1
#!/bin/sh
#/jffs/sbin/init.disk
DEFAULT=/etc/default/init.disk
#DISK_MNT_POINT=/mnt/hda1
#JFFS_MNT_POINT=/mnt/jffs
#ORG_ROOT=$DISK_MNT_POINT/$JFFS_MNT_POINT
#DEV_DISK=/dev/hda
#DEV_PARTITION=/dev/hda1
#DEV_MAJOR=3
#DEF_MINOR=1
#FS_TYPE=ext3
#MODULES='ide-core pdc202xx_old ide-detect ide-disk ext2 jbd ext3'
#MODULE_LOAD_WAIT=4
[ -f $DEFAULT ] && . $DEFAULT
mount_disk() {
# [ -z "$boot_dev" ] && return 1
# install modules needed for ide and the ext3 filesystem
for module in $MODULES; do {
insmod $module || return 1
}; done
# this may need to be higher if your disk is slow to initialize
sleep $MODULE_LOAD_WAIT
# mknod $DEV_DISK b 3 0 || return 1
# mknod $DEV_PARTITION b $DEV_MAJOR $DEV_MINOR || return 1
mount $DEV_PARTITION $DISK_MNT_POINT -t $FS_TYPE || return 1
[ -x "$DISK_MNT_POINT/sbin/init" ] || return 1
pivot_root "$DISK_MNT_POINT" "$ORG_ROOT" || return 1
return 0
}
switch_root() {
if [ -x "$DISK_MNT_POINT/sbin/init" ]; then
mount -o move /proc "$DISK_MNT_POINT/proc" || return 1
pivot_root "$DISK_MNT_POINT" "$ORG_ROOT" || return 1
mount -o move "$JFFS_MNT_POINT/dev" /dev
mount -o move "$JFFS_MNT_POINT/tmp" /tmp
mount -o move "$JFFS_MNT_POINT/jffs" /jffs 2>&-
#mount -o move "$JFFS_MNT_POINT/sys" /sys 2>&-
mount -o move "$JFFS_MNT_POINT/rom" /rom 2>&-
else
return 1
fi
return 0
}
# change nvram variable 'boot_dev' to your root filesystem
#boot_dev=`nvram get boot_dev`
mount_disk && switch_root
# switch_root
# finally, run the real init
exec /bin/busybox init
#/jffs/etc/default/init.disk.usb
DISK_MNT_POINT=/mnt/disc3_1
JFFS_MNT_POINT=/mnt/jffs
ORG_ROOT="$DISK_MNT_POINT/$JFFS_MNT_POINT"
#DEV_DISK=/dev/hda
DEV_PARTITION=/dev/root_disk
DEV_MAJOR=8
DEF_MINOR=49
FS_TYPE=ext3
MODULES='usbcore usb-ohci scsi_mod sd_mod usb-storage ext2 jbd ext3'
MODULE_LOAD_WAIT=8
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT
Labels: OpenWRT