View difference between Paste ID: hvHHic1V and 31Wkcnn7
SHOW: | | - or go back to the newest paste.
1
#!/bin/sh
2-
# version: 1.0.0, 06-nov-2021, by eibgrad
2+
#DEBUG= # uncomment/comment to enable/disable debug mode
3-
# href: https://tinyurl.com/????????
3+
4-
# known compatibility: rt-ac68u
4+
#          name: merlin-ac68u-add-networks.sh
5
#       version: 2.0.0, 30-jul-2022, by eibgrad
6-
unset DEBUG INCLUDE_DNSMASQ INCLUDE_FIREWALL
6+
#       purpose: add ip networks using vlans, aps/vaps, bridges, etc.
7-
unset ALLOW_PRIVATE_TO_ANY ALLOW_OVPN_ACCESS
7+
#       type(s): dnsmasq.postconf (optional), firewall-start (optional),
8
#                service-event-end, services-start
9-
# ---------------------- DO NOT CHANGE ABOVE THIS LINE ----------------------- #
9+
#          href: https://tinyurl.com/kumyymcw (version 1.x.x)
10
#          href: https://tinyurl.com/ycxxmw6d (version 2.x.x)
11
#  installation:
12
#    1. enable jffs custom scripts and configs (administration->system)
13-
DEBUG= # uncomment/comment to enable/disable debug mode
13+
#    2. ssh to router and copy/paste the following command:
14
#         curl -kLs bit.ly/merlin-installer|tr -d '\r'|sh -s hvHHic1V
15
#    3. modify script w/ your preferred options using nano editor:
16
#         nano /jffs/configs/merlin-ac68u-add-networks.options
17
#    4. reboot
18
19
# compatibility checks
20
if [ "$(nvram get sw_mode)" != '1' ]; then
21-
# only bridged configurations have port 0 availble for assignment
21+
    echo 'error: script only supports a routed configuration'
22-
#VLAN_PORTS='1/0/1/2/3 3/4'         # vlan1 ports 0 1 2 3, vlan3 port 4
22+
    exit 1
23
elif ! which robocfg &>/dev/null; then
24
    echo 'error: script is NOT compatible w/ this firmware; requires robocfg'
25
    exit 1
26
fi
27
28
CONFIGS_DIR='/jffs/configs'
29
CONFIG="$CONFIGS_DIR/merlin-ac68u-add-networks.options"
30
31
SCRIPTS_DIR='/jffs/scripts'
32
SCRIPT1="$SCRIPTS_DIR/merlin-ac68u-add-networks.dnsmasq"
33
SCRIPT2="$SCRIPTS_DIR/merlin-ac68u-add-networks.firewall"
34
SCRIPT3="$SCRIPTS_DIR/merlin-ac68u-add-networks.service-event-end"
35-
#VLANS_PORTS=''; VLANS_WL=''        # only intended for cleanup purposes
35+
SCRIPT4="$SCRIPTS_DIR/merlin-ac68u-add-networks.services-start"
36
SCRIPT5="$SCRIPTS_DIR/dnsmasq.postconf"
37
SCRIPT6="$SCRIPTS_DIR/firewall-start"
38-
#IPNET_PFX='10.99.' # first two dotted octets only
38+
SCRIPT7="$SCRIPTS_DIR/service-event-end"
39
SCRIPT8="$SCRIPTS_DIR/services-start"
40
41
mkdir -p $CONFIGS_DIR $SCRIPTS_DIR
42
43
# ----------------- begin merlin-ac68u-add-networks.options ------------------ #
44
cat << 'EOF' > $CONFIG
45
46
# ------------------------------ BEGIN OPTIONS ------------------------------- #
47
48
# VLANS_PORTS='[<vlan-id>[/<port>...] ...]'
49
VLANS_PORTS='1/1/2/3 3/4'          # vlan1 ports 1 2 3, vlan3 port 4
50
#VLANS_PORTS='1/1/2 3/3/4'          # vlan1 ports 1 2, vlan3 ports 3 4
51
#VLANS_PORTS='1 10/1/2/3/4'         # vlan1 no ports, vlan10 ports 1 2 3 4
52
#VLANS_PORTS='1/1 10/2 11/3 12/4'   # vlan1/vlan10/vlan11/vlan12, one port each
53
#VLANS_PORTS='1/1/2/3/4t 3/4t'      # vlan1/vlan3 port 4 trunk
54
55
# VLANS_WL='[<vlan-id>[/<wireless-if>...] ...]'
56
#VLANS_WL=''                        # no wireless changes required
57
#VLANS_WL='3/eth1'                  # bridge vlan3 w/ 2.4ghz
58
VLANS_WL='3/eth2'                  # bridge vlan3 w/ 5ghz
59
#VLANS_WL='3/wl0.1/wl1.1'           # bridge vlan3 w/ guest 1 (2.4+5ghz)
60-
if ! which robocfg &>/dev/null; then
60+
61-
echo 'error: script is NOT compatible w/ this firmware; requires robocfg'
61+
62
#VLANS_WL='11/wl0.2/wl1.2'          # bridge vlan11 w/ guest 2 (2.4+5ghz)
63
#VLANS_WL='12/wl0.3/wl1.3'          # bridge vlan12 w/ guest 3 (2.4+5ghz)
64
# bridge vlans 10/11/12 /w guests 1/2/3 respectively
65-
# function router_is_bridged()
65+
66-
router_is_bridged() { ! ifconfig vlan2 2>/dev/null | grep -q 'UP'; }
66+
67
#VLANS_PORTS=''; VLANS_WL=''        # for cleanup purposes only
68-
CONFIGS_DIR='/jffs/configs'; mkdir -p $CONFIGS_DIR
68+
69-
SCRIPTS_DIR='/jffs/scripts'; mkdir -p $SCRIPTS_DIR
69+
70
#IP_PFX='10.99.' # first two dotted octets only
71-
if [ ! "$IPNET_PFX" ]; then
71+
72-
    IPNET_PFX="$(nvram get lan_ipaddr | egrep -o '^(.{1,3}\.){2}')"
72+
73
#   warning: any change requires reinstallation w/ this script!
74
INCLUDE_DNSMASQ=
75-
MIN_VID=3; MAX_VID=255
75+
76-
MIN_PORT=$(router_is_bridged && echo 0 || echo 1); MAX_PORT=4
76+
77
DNS_SERVERS='8.8.8.8,8.8.4.4' # comma-separated
78-
LOG="$([ ${DEBUG+x} ] && echo '/tmp/$(basename $0).$$.log' || echo '/dev/null')"
78+
79
# uncomment/comment to include/exclude pre-defined firewall rules
80-
# -------------------------- begin dnsmasq.conf.add  ------------------------- #
80+
#   warning: any change requires reinstallation w/ this script!
81-
CONFIG="$CONFIGS_DIR/dnsmasq.conf.add"
81+
82
83-
if [ "${INCLUDE_DNSMASQ+x}" ]; then
83+
84-
(
84+
85-
create_config() {
85+
86
# uncomment/comment to allow/deny access to/from openvpn clients/servers
87
#ALLOW_OVPN_ACCESS=
88
89
# these are just examples; uncomment and modify as you see fit
90
DNSMASQ_ADDITIONS='
91
# static leases (hostname and lease time optional)
92
#dhcp-host=br3,47:b5:1d:54:5c:fb,192.168.3.100,desktop,24h
93
#dhcp-host=br3,64:67:16:cd:c7:c0,59:21:2d:99:28:70,192.168.3.101
94
# per-network static leases for device w/ multiple network adapters
95
#dhcp-host=br0,b8:70:f4:b3:4d:6a,38:59:f9:14:1f:d3,192.168.1.99,laptop
96
#dhcp-host=br10,b8:70:f4:b3:4d:6a,38:59:f9:14:1f:d3,192.168.10.99,laptop
97
#dhcp-host=br11,b8:70:f4:b3:4d:6a,38:59:f9:14:1f:d3,192.168.11.99,laptop
98
#dhcp-host=br12,b8:70:f4:b3:4d:6a,38:59:f9:14:1f:d3,192.168.12.99,laptop
99
# hostnames (dynamic leases only)
100
#dhcp-host=a3:fa:ca:ba:07:2c,somehostname1
101
#dhcp-host=43:f3:52:dd:67:d9,somehostname2
102
'
103-
cat << EOF >> $CONFIG
103+
# function firewall_additions( vlan-id )
104-
interface=br${1}
104+
firewall_additions() {
105-
dhcp-range=br${1},${IPNET_PFX}${1}.100,${IPNET_PFX}${1}.254,255.255.255.0,24h
105+
106-
dhcp-option=br${1},3,${IPNET_PFX}${1}.1
106+
local brx=br${1} # generalize reference to current bridge under examination
107-
$([ "$DNS_SERVERS" ] && echo "dhcp-option=br${1},6,$DNS_SERVERS")
107+
108
# useful constants
109
local LAN_IP="$(nvram get lan_ipaddr)" # (e.g., 192.168.1.1)
110
local LAN_NET="$LAN_IP/$(nvram get lan_netmask)" # (e.g., 192.168.1.0/24)
111-
# function add_user_defined_directives()
111+
local LAN_PFX="$(echo $LAN_IP | grep -o '^.*\.')" # (e.g., 192.168.1.)
112-
add_user_defined_directives() {
112+
113
case "$1" in
114-
cat << "EOF" >> $CONFIG
114+
115-
# >>>>>>>>>>>>>>>>>>>>>> begin user-defined directives <<<<<<<<<<<<<<<<<<<<<<< #
115+
# these are just examples; uncomment and modify as you see fit
116
117
3) ### vlan3/br3 rules go here ###
118
# allow access to printer hosted on router
119
#iptables -I INPUT -p tcp -i $brx --dport 9100 -j ACCEPT
120
:;; # DO NOT DISTURB
121
122
4) ### vlan4/br4 rules go here ###
123
# deny routing to internet based on source ip range
124
#iptables -I FORWARD -i $brx -o $WAN_IF -m iprange \
125
#    --src-range "${IP_PFX}${1}.110-${IP_PFX}${1}.119" -j REJECT
126
# deny routing to internet based on source mac address
127-
# >>>>>>>>>>>>>>>>>>>>>>> end user-defined directives <<<<<<<<<<<<<<<<<<<<<<<< #
127+
#iptables -I FORWARD -i $brx -o $WAN_IF -m mac --mac-source \
128
#    0a:32:13:75:7d:95 -j REJECT
129
:;; # DO NOT DISTURB
130
131-
> $CONFIG
131+
132
# deny routing from 10:00PM to 6:00AM, Sunday->Friday (student schedule)
133
#iptables -I FORWARD -i $brx -m time --timestart 22:00 --timestop 00:00 \
134
#    --weekdays Sun,Mon,Tue,Wed,Thu --kerneltz -j REJECT
135
#iptables -I FORWARD -i $brx -m time --timestart 00:00 --timestop 06:00 \
136
#    --weekdays Mon,Tue,Wed,Thu,Fri --kerneltz -j REJECT
137
:;; # DO NOT DISTURB
138
139
# repeat as necessary for additional vlans/bridges
140
141
*) ### rules that apply across all vlans/bridges (br+) go here ###
142
# allow access to printer hosted on private network (other than router)
143
#iptables -I FORWARD -p tcp -i $brx -o br0 -d "${LAN_PFX}100" \
144-
add_user_defined_directives
144+
145
:;; # DO NOT DISTURB
146
147-
if [ -f $CONFIG ]; then
147+
148-
    echo "error: $CONFIG already exists; requires manual installation"
148+
149
150-
    create_config
150+
151-
    echo "installed: $CONFIG"
151+
152
# ---------------------- DO NOT CHANGE BELOW THIS LINE ----------------------- #
153-
)
153+
154
# shared/global functions and constants (do NOT touch!)
155-
# --------------------------- end dnsmasq.conf.add --------------------------- #
155+
156
debug_enabled() { set -o | egrep -q '^xtrace\s+on$'; }
157
158-
SCRIPT="$SCRIPTS_DIR/firewall-start"
158+
BASENAME="$(basename $0)"
159
NOW="$(date +'%Y-%m-%d-%H%M%S')"
160-
if [ "${INCLUDE_FIREWALL+x}" ]; then
160+
LOG="$(debug_enabled && echo /tmp/${BASENAME}_${NOW}_$$.log || echo /dev/null)"
161
MIN_VID=3 MAX_VID=255 MIN_PORT=1 MAX_PORT=4
162
[ "$IP_PFX" ] || IP_PFX="$(nvram get lan_ipaddr | egrep -o '^(.{1,3}\.){2}')"
163-
cat << "EOF" > $SCRIPT
163+
164
EOF
165-
set -x # uncomment/comment to enable/disable debug mode
165+
echo "installed: $CONFIG"
166
# ------------------ end merlin-ac68u-add-networks.options ------------------- #
167
168
# ----------------- begin merlin-ac68u-add-networks.dnsmasq ------------------ #
169-
LAN_IP="$(nvram get lan_ipaddr)" # (e.g., 192.168.1.1)
169+
if grep -q '^INCLUDE_DNSMASQ=' $CONFIG; then
170-
LAN_NET="$LAN_IP/$(nvram get lan_netmask)" # (e.g., 192.168.1.0/24)
170+
cat << 'EOF' > $SCRIPT1
171-
LAN_PFX="$(echo $LAN_IP | grep -o '^.*\.')" # (e.g., 192.168.1.)
171+
172
#set -x # comment/uncomment to disable/enable debug mode
173-
# function router_is_bridged()
173+
. $CONFIG
174-
router_is_bridged() { ! ifconfig vlan2 2>/dev/null | grep -q 'UP'; }
174+
175
. /usr/sbin/helper.sh
176
177
DNSMASQ_CONFIG="$1"
178
179
# function write( string )
180
write() { pc_append "$1" $DNSMASQ_CONFIG; }
181
182
# function validate_vlan_id( vlan-id )
183
validate_vlan_id() {
184
    local vlan_id=$1
185
186
    if ! echo $vlan_id | egrep -q '^[0-9]+$'; then
187
        return 1
188
    elif [[ $vlan_id -lt $MIN_VID || $vlan_id -gt $MAX_VID ]]; then
189
        return 1
190
    fi
191
192-
# limit new bridge to essential router services (dhcp, dns, ping)
192+
193-
iptables -I INPUT -i br${1} -j REJECT
193+
194-
iptables -I INPUT -i br${1} -d ${IPNET_PFX}${1}.1 -p icmp -j ACCEPT
194+
195-
if [ ! "$DNS_SERVERS" ]; then
195+
196-
  iptables -I INPUT -i br${1} -d ${IPNET_PFX}${1}.1 -p tcp --dport 53 -j ACCEPT
196+
197-
  iptables -I INPUT -i br${1} -d ${IPNET_PFX}${1}.1 -p udp --dport 53 -j ACCEPT
197+
    write "interface=br${1}"
198
    write "dhcp-range=br${1},${IP_PFX}${1}.100,${IP_PFX}${1}.254,255.255.255.0,24h"
199-
iptables -I INPUT -i br${1} -p udp --dport 67 -j ACCEPT
199+
    write "dhcp-option=br${1},3,${IP_PFX}${1}.1"
200-
if router_is_bridged; then
200+
    [ "$DNS_SERVERS" ] && write "dhcp-option=br${1},6,$DNS_SERVERS"
201-
  iptables -I INPUT -i lo  -j ACCEPT
201+
202-
  iptables -I INPUT -i br0 -j ACCEPT
202+
203-
  iptables -I INPUT -m state --state INVALID -j DROP
203+
write "# --- begin additions by $BASENAME --- #"
204-
  iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
204+
205
# add dhcp server configuration for each new bridge
206
for vp in $VLANS_PORTS; do
207-
# define routing limits of new bridge (default is internet only)
207+
208-
iptables -I FORWARD -i br${1} -j REJECT
208+
209-
if [ ! "$ALLOW_PRIVATE_TO_ANY" ]; then
209+
210-
  iptables -I FORWARD -i br0 -o br${1} -j REJECT
210+
211
212-
if router_is_bridged; then
212+
213-
  iptables -I FORWARD -i br${1} -o br0 -j ACCEPT
213+
214-
  #iptables -I FORWARD -i br${1} -o br0 ! -d $LAN_NET -j ACCEPT
214+
215-
  iptables -I FORWARD -i br${1} -o br0 -d    10.0.0.0/8  -j REJECT
215+
216-
  iptables -I FORWARD -i br${1} -o br0 -d  172.16.0.0/12 -j REJECT
216+
# add user-defined directives
217-
  iptables -I FORWARD -i br${1} -o br0 -d 192.168.0.0/16 -j REJECT
217+
OIFS="$IFS"; IFS=$'\n'
218-
  iptables -I FORWARD -m state --state INVALID -j DROP
218+
for line in $DNSMASQ_ADDITIONS; do
219-
  iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
219+
    echo $line | grep -Eq '^[[:space:]]*(#|$)' || write "$line"
220-
  iptables -t nat -I POSTROUTING -o br0 -j SNAT --to $LAN_IP
220+
221
IFS="$OIFS"
222-
  if [ "$ALLOW_OVPN_ACCESS" ]; then
222+
223-
    iptables -I FORWARD -i tun2+  -o br${1} -j ACCEPT
223+
write "# ---- end additions by $BASENAME ---- #"
224-
    iptables -I FORWARD -i br${1} -o tun1+  -j ACCEPT
224+
225-
  fi
225+
226-
  iptables -I FORWARD -i br${1} -m conntrack --ctstate DNAT -j ACCEPT
226+
} 2>&1 | tee $LOG | logger -t $BASENAME[$$]
227-
  iptables -I FORWARD -i br${1} -o $WAN_IF -j ACCEPT
227+
228
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT1
229
sed -i "s:\$CONFIG:$CONFIG:g" $SCRIPT1
230
chmod +x $SCRIPT1
231-
# function add_user_defined_rules( bridge-index )
231+
echo "installed: $SCRIPT1"
232-
add_user_defined_rules() {
232+
233
# ------------------ end merlin-ac68u-add-networks.dnsmasq ------------------- #
234-
brx=br${1} # generalize reference to current bridge under examination
234+
235
# ----------------- begin merlin-ac68u-add-networks.firewall ----------------- #
236-
case $1 in
236+
if grep -q '^INCLUDE_FIREWALL=' $CONFIG; then
237-
# >>>>>>>>>>>>>>>>>>>>>>>>> begin user-defined rules <<<<<<<<<<<<<<<<<<<<<<<<< #
237+
cat << 'EOF' > $SCRIPT2
238
#!/bin/sh
239
#set -x # comment/uncomment to disable/enable debug mode
240
. $CONFIG
241
{
242
WAN_IF="$([ $1 ] && echo $1 || echo $(nvram get wan0_ifname))"
243
244
# function validate_vlan_id( vlan-id )
245-
# deny routing based on ip range
245+
246-
#iptables -I FORWARD -i $brx -m iprange \
246+
247-
#    --src-range "${IPNET_PFX}${1}.110-${IPNET_PFX}${1}.119" -j REJECT
247+
248
    if ! echo $vlan_id | egrep -q '^[0-9]+$'; then
249-
# deny routing based on mac address
249+
250-
#iptables -I FORWARD -i $brx -m mac --mac-source 0a:32:13:75:7d:95 -j REJECT
250+
251
        return 1
252
    fi
253
254-
# deny routing from 10:00PM to 6:00AM, Sunday thru Friday (student scheduling)
254+
255
}
256
257
# function add_rules( bridge-index )
258
add_rules() {
259
    # limit new bridge to essential router services (dhcp, dns, ping)
260
    iptables -I INPUT -i br${1} -j REJECT
261
    iptables -I INPUT -i br${1} -d ${IP_PFX}${1}.1 -p icmp -j ACCEPT
262
    if [ ! "$DNS_SERVERS" ]; then
263
        iptables -I INPUT -i br${1} -d ${IP_PFX}${1}.1 -p tcp --dport 53 -j ACCEPT
264
        iptables -I INPUT -i br${1} -d ${IP_PFX}${1}.1 -p udp --dport 53 -j ACCEPT
265
    fi
266
    iptables -I INPUT -i br${1} -p udp --dport 67 -j ACCEPT
267
268
    # define routing limits of new bridge (default is internet only)
269-
# >>>>>>>>>>>>>>>>>>>>>>>>>> end user-defined rules <<<<<<<<<<<<<<<<<<<<<<<<<< #
269+
    iptables -I FORWARD -i br${1} -j REJECT
270
    if [ ! ${ALLOW_PRIVATE_TO_ANY+x} ]; then
271
        iptables -I FORWARD -i br0 -o br${1} -j REJECT
272
    fi
273
    if [ ${ALLOW_OVPN_ACCESS+x} ]; then
274
        iptables -I FORWARD -i tun2+  -o br${1} -j ACCEPT
275
        iptables -I FORWARD -i br${1} -o tun1+  -j ACCEPT
276
    fi
277
    iptables -I FORWARD -i br${1} -m conntrack --ctstate DNAT -j ACCEPT
278
    iptables -I FORWARD -i br${1} -o $WAN_IF -j ACCEPT
279
}
280
281
# add firewall rules for each new bridge
282
for vp in $VLANS_PORTS; do
283
    vlan_id="$(echo $vp | cut -d/ -f1)"
284
285
    # ignore bad/missing input
286-
    add_user_defined_rules $vlan_id
286+
287
288
    validate_vlan_id $vlan_id || continue
289
290-
add_user_defined_rules '+'
290+
291
    add_rules $vlan_id
292
293-
} 2>&1 | tee $LOG | logger -t $(basename $0)[$$]
293+
294
    firewall_additions $vlan_id
295-
[ ${DEBUG+x} ] || sed -ri 's/^(set -x)/#\1/g' $SCRIPT
295+
296-
sed -e "s:\$LOG:$LOG:g" \
296+
297-
    -e "s:\$MIN_VID:$MIN_VID:g" \
297+
298-
    -e "s:\$MAX_VID:$MAX_VID:g" \
298+
firewall_additions '+'
299-
    -e "s:\$VLANS_PORTS:$(echo $VLANS_PORTS):g" \
299+
300-
    -e "s:\${IPNET_PFX}:$IPNET_PFX:g" \
300+
301-
    -e "s:\$DNS_SERVERS:$DNS_SERVERS:g" \
301+
} 2>&1 | tee $LOG | logger -t $BASENAME[$$]
302-
    -e "s:\$ALLOW_PRIVATE_TO_ANY:${ALLOW_PRIVATE_TO_ANY+x}:g" \
302+
303-
    -e "s:\$ALLOW_OVPN_ACCESS:${ALLOW_OVPN_ACCESS+x}:g" \
303+
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT2
304-
    -i $SCRIPT
304+
sed -i "s:\$CONFIG:$CONFIG:g" $SCRIPT2
305-
chmod +x $SCRIPT
305+
chmod +x $SCRIPT2
306
echo "installed: $SCRIPT2"
307
fi
308-
if [ -f $SCRIPT ]; then
308+
# ------------------ end merlin-ac68u-add-networks.firewall ------------------ #
309-
    echo "error: $SCRIPT already exists; requires manual installation"
309+
310
# -------------- begin merlin-ac68u-add-networks.services-start -------------- #
311
cat << 'EOF' > $SCRIPT3
312-
    echo "installed: $SCRIPT"
312+
313
#set -x # comment/uncomment to disable/enable debug mode
314
. $CONFIG
315
{
316
CPU_PORT="$(robocfg show | awk '/vlan1:/{print $NF}')"
317
318
# function validate_vlan_id( vlan-id )
319-
SCRIPT="$SCRIPTS_DIR/service-event-end"
319+
320
    local vlan_id=$1
321
322-
cat << "EOF" > $SCRIPT
322+
323
        if [ $vlan_id == '2' ]; then
324-
set -x # uncomment/comment to enable/disable debug mode
324+
325
            return 1
326
        elif ! echo $vlan_id | egrep -q '^[0-9]+$'; then
327
            echo "error: vlan-id ${vlan_id} not numeric"
328
            return 1
329
        elif [[ $vlan_id -lt $MIN_VID || $vlan_id -gt $MAX_VID ]]; then
330
            echo "error: vlan${vlan_id} out of range ($MIN_VID-$MAX_VID)"
331
            return 1
332
        fi
333
    fi
334
335
    return 0
336
}
337
338
# function add_vlan_and_bridge( vlan-id ports )
339
add_vlan_and_bridge() {
340
    local vlan_id=$1
341
    local ports="$2"
342
343
    # create new vlan w/ specified port(s)
344
    robocfg vlan $vlan_id ports "$ports"
345
346
    # add new vlan to eth0 (cpu) network interface
347
    vconfig add eth0 $vlan_id
348
349
    # bring up new vlan
350
    ifconfig vlan${vlan_id} up
351
352
    # create new bridge and add new vlan
353
    brctl addbr br${vlan_id}
354
    brctl addif br${vlan_id} vlan${vlan_id}
355
356
    # configure new bridge w/ preferred settings
357
    stp=$([ "$(nvram get lan_stp)" == '1' ] && echo 'on' || echo 'off')
358
    brctl stp br${vlan_id} $stp # stp to prevent bridge loops
359
    brctl setfd br${vlan_id} 2  # stp forward delay (2 secs)
360
361
    # config ip on new bridge and bring up network
362
    ifconfig br${vlan_id} ${IP_PFX}${vlan_id}.1 netmask 255.255.255.0 up
363
}
364
365
# respond to *all* wireless events (start/restart/stop)
366
[ "$2" == 'wireless' ] || exit 0
367-
    stp="$([ "$(nvram get lan_stp)" == '1' ] && echo 'on' || echo 'off')"
367+
368
# cleanup any previous vlan/bridge configurations
369
n=$MIN_VID
370
while [ "$(nvram get br${n}_ifname)" ]; do
371
    br="$(nvram get br${n}_ifname)"
372-
    ifconfig br${vlan_id} ${IPNET_PFX}${vlan_id}.1 netmask 255.255.255.0 up
372+
373
374
    ifconfig $br down 2>/dev/null && brctl delbr $br && vconfig rem $vl
375
376
    nvram unset  br${n}_ifname
377
    nvram unset  br${n}_ifnames
378
    nvram unset lan${n}_ifname
379
    nvram unset lan${n}_ifnames
380
381
    [ $((++n)) -le $MAX_VID ] || break
382
done
383
384
# commit changes from cleanup if no other actions requested/required
385
[[ $((n)) -gt $MIN_VID && ! "$VLANS_PORTS" && ! "$VLANS_WL" ]] && nvram commit
386
387
# assign ports to vlans
388
for vp in $VLANS_PORTS; do
389
    vlan_id="$(echo $vp | cut -d/ -f1)"
390
391
    # ignore bad/missing input
392
    [ $vlan_id ] || continue
393
394
    validate_vlan_id $vlan_id || continue
395
396
    # isolate ports from vlan-id
397
    vlan_ports="$(echo $vp | awk -F/ '{$1=""; print $0}')"
398
399
    # validate ports
400
    for p in $vlan_ports; do
401
        if ! echo $p | egrep -q '^[0-9]+[tu*]{0,1}$'; then
402
            echo "error: port $p specification not valid"
403
            continue 2
404
        fi
405
        _p="$(echo $p | egrep -o '^[0-9]*')"
406
        if [[ $_p -lt $MIN_PORT || $_p -gt $MAX_PORT ]]; then
407
            echo "error: port $p out of range ($MIN_PORT-$MAX_PORT)"
408
            continue 2
409
        fi
410
    done
411
412
    # add cpu port to ports
413
    vlan_ports="$(echo $vlan_ports $CPU_PORT)"
414
415
    if [ $vlan_id == '1' ]; then
416
        robocfg vlan 1 ports "$vlan_ports"
417
        continue
418
    fi
419
420
    add_vlan_and_bridge $vlan_id "$vlan_ports"
421
422
    # determine next available bridge/lan index
423
    #n=$vlan_id # doesn't work; must be assigned sequentially
424
    n=$MIN_VID; while [ "$(nvram get lan${n}_ifname)" ]; do let n++; done
425
426
    # add and initialize network interface names
427
    nvram set  br${n}_ifname=br${vlan_id}
428
    nvram set  br${n}_ifnames=vlan${vlan_id}
429
    nvram set lan${n}_ifname=br${vlan_id}
430
    nvram set lan${n}_ifnames=vlan${vlan_id}
431
done
432
433
# bridge wireless to vlans
434
for vw in $VLANS_WL; do
435
    vlan_id="$(echo $vw | cut -d/ -f1)"
436
437
    # ignore bad/missing input
438
    [ $vlan_id ] || continue
439
440
    validate_vlan_id $vlan_id || continue
441
442
    # validate vlan-id usage
443
    if ! ifconfig vlan${vlan_id} &>/dev/null; then
444
        echo "error: vlan${vlan_id} not found"
445
        continue
446
    fi
447
448
    # isolate wireless network interfaces from vlan-id
449
    vlan_wl="$(echo $(echo $vw | awk -F/ '{$1=""; print $0}'))"
450
451
    # move wireless network interfaces to new bridge
452
    for wl in $vlan_wl; do
453
        # validate wireless network interface
454
        case $wl in
455
            'eth1'|'eth2'|'wl0.1'|'wl1.1'|'wl0.2'|'wl1.2'|'wl0.3'|'wl1.3') :;;
456
          *) echo "error: unknown wireless network interface: ${wl}"; continue 2;;
457
        esac
458
459
        # wireless network interface must be up and running
460
        if ! ifconfig $wl &>/dev/null; then
461
            echo "error: wireless network interface not available: ${wl}"
462
            continue 2
463
        fi
464
465
        # delete wireless network interface from current bridge
466
        n=0
467
        if brctl show | grep -q "\s${wl}\$"; then
468
            while ! brctl delif br${n} $wl 2>/dev/null; do
469
                if [ $((++n)) -gt $MAX_VID ]; then
470
                    echo "program error: wireless network interface not found: ${wl}"
471
                    break
472
                fi
473
            done
474
        fi
475
476
        # add wireless network interface to new bridge
477
        brctl addif br${vlan_id} $wl
478
    done
479
480
    # find bridge/lan index for this vlan
481
    n=$MIN_VID
482
    while ! nvram get br${n}_ifnames | egrep -q "^vlan${vlan_id}( |$)"; do
483
        if [ $((++n)) -gt $MAX_VID ]; then
484
            echo "program error: bridge/lan index not found: ($n)"
485
            continue 2
486
        fi
487
    done
488
489
    # add wireless network interface names to corresponding bridge/lan
490
    nvram set  br${n}_ifnames="$(nvram get  br${n}_ifnames) $vlan_wl"
491
    nvram set lan${n}_ifnames="$(nvram get lan${n}_ifnames) $vlan_wl"
492
493
    # convert wireless network interface names to sed search mask
494
    mask=''; for wl in $vlan_wl; do mask="${mask}${wl}(\s|\$)|"; done
495
496
    # remove wireless network interface names from system bridges/lans
497
    for i in 0 1 2; do
498
        [ "$(nvram get  br${i}_ifnames)" ] && \
499
             nvram set  br${i}_ifnames="$(echo $(nvram get  br${i}_ifnames | \
500
                 sed -r s/$mask//g))"
501
        [ "$i" == '0' ] && j='' || j="$i"
502
        [ "$(nvram get lan${j}_ifnames)" ] && \
503
             nvram set lan${j}_ifnames="$(echo $(nvram get lan${j}_ifnames | \
504
                 sed -r s/$mask//g))"
505
    done
506
done
507
508
# force system to recognize any changes
509
eapd
510
511
exit 0
512
} 2>&1 | tee $LOG | logger -t $BASENAME[$$]
513
EOF
514
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT3
515
sed -i "s:\$CONFIG:$CONFIG:g" $SCRIPT3
516
chmod +x $SCRIPT3
517
echo "installed: $SCRIPT3"
518
# --------------- end merlin-ac68u-add-networks.services-start --------------- #
519
520
# ------------ begin merlin-ac68u-add-networks.service-event-end ------------- #
521
cat << 'EOF' > $SCRIPT4
522-
} 2>&1 | tee $LOG | logger -t $(basename $0)[$$]
522+
523
#set -x # comment/uncomment to disable/enable debug mode
524-
[ ${DEBUG+x} ] || sed -ri 's/^(set -x)/#\1/g' $SCRIPT
524+
. $CONFIG
525-
sed -e "s:\$LOG:$LOG:g" \
525+
526-
    -e "s:\$MIN_VID:$MIN_VID:g" \
526+
527-
    -e "s:\$MAX_VID:$MAX_VID:g" \
527+
528-
    -e "s:\$MIN_PORT:$MIN_PORT:g" \
528+
529-
    -e "s:\$MAX_PORT:$MAX_PORT:g" \
529+
/jffs/scripts/service-event-end 'start' 'wireless'
530-
    -e "s:\$VLANS_PORTS:$(echo $VLANS_PORTS):g" \
530+
531-
    -e "s:\$VLANS_WL:$(echo $VLANS_WL):g" \
531+
532-
    -e "s:\${IPNET_PFX}:$IPNET_PFX:g" \
532+
} 2>&1 | tee $LOG | logger -t $BASENAME[$$]
533-
    -i $SCRIPT
533+
534-
chmod +x $SCRIPT
534+
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT4
535
sed -i "s:\$CONFIG:$CONFIG:g" $SCRIPT4
536
chmod +x $SCRIPT4
537-
if [ -f $SCRIPT ]; then
537+
echo "installed: $SCRIPT4"
538-
    echo "error: $SCRIPT already exists; requires manual installation"
538+
# ------------- end merlin-ac68u-add-networks.service-event-end -------------- #
539
540
# -------------------------- begin dnsmasq.postconf -------------------------- #
541-
    echo "installed: $SCRIPT"
541+
if grep -q '^INCLUDE_DNSMASQ=' $CONFIG; then
542
create_script() {
543
cat << 'EOF' > $SCRIPT5
544
#!/bin/sh
545
#set -x # comment/uncomment to disable/enable debug mode
546-
SCRIPT="$SCRIPTS_DIR/services-start"
546+
547
$SCRIPT1 "$1"
548
} 2>&1 | logger -t $(basename $0)[$$]
549-
cat << "EOF" > $SCRIPT
549+
550
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT5
551-
set -x # uncomment/comment to enable/disable debug mode
551+
sed "s:\$SCRIPT1:$SCRIPT1:g" -i $SCRIPT5
552
chmod +x $SCRIPT5
553-
# function router_is_bridged()
553+
554-
router_is_bridged() { ! ifconfig vlan2 2>/dev/null | grep -q 'UP'; }
554+
555
if [ -f $SCRIPT5 ]; then
556-
# in a bridged configuration (e.g., AP mode), the firewall is not activated,
556+
    echo "error: $SCRIPT5 already exists; requires manual installation"
557-
# so we have to manually start the firewall-start script
557+
558
    create_script
559-
if [ "$INCLUDE_FIREWALL" ] && router_is_bridged; then
559+
    echo "installed: $SCRIPT5"
560-
    "$SCRIPTS_DIR/firewall-start"
560+
561
fi
562-
    # enable ip routing for bridged router configurations
562+
# ------------------------ end begin dnsmasq.postconf ------------------------ #
563-
    echo '1' > /proc/sys/net/ipv4/ip_forward
563+
564
# --------------------------- begin firewall-start --------------------------- #
565
if grep -q '^INCLUDE_FIREWALL=' $CONFIG; then
566
create_script() {
567
cat << 'EOF' > $SCRIPT6
568
#!/bin/sh
569
#set -x # comment/uncomment to disable/enable debug mode
570-
"$SCRIPTS_DIR/service-event-end" 'start' 'wireless'
570+
571
$SCRIPT2 "$1"
572
} 2>&1 | logger -t $(basename $0)[$$]
573-
} 2>&1 | tee $LOG | logger -t $(basename $0)[$$]
573+
574
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT6
575-
[ ${DEBUG+x} ] || sed -ri 's/^(set -x)/#\1/g' $SCRIPT
575+
sed "s:\$SCRIPT2:$SCRIPT2:g" -i $SCRIPT6
576-
sed -e "s:\$LOG:$LOG:g" \
576+
chmod +x $SCRIPT6
577-
    -e "s:\$SCRIPTS_DIR:$SCRIPTS_DIR:g" \
577+
578-
    -e "s:\$INCLUDE_FIREWALL:${INCLUDE_FIREWALL+x}:g" \
578+
579-
    -i $SCRIPT
579+
if [ -f $SCRIPT6 ]; then
580-
chmod +x $SCRIPT
580+
    echo "error: $SCRIPT6 already exists; requires manual installation"
581
else
582
    create_script
583-
if [ -f $SCRIPT ]; then
583+
    echo "installed: $SCRIPT6"
584-
    echo "error: $SCRIPT already exists; requires manual installation"
584+
585
fi
586
# ---------------------------- end firewall-start ---------------------------- #
587-
    echo "installed: $SCRIPT"
587+
588
# ------------------------- begin service-event-end -------------------------- #
589-
# ---------------------------- end services-start ---------------------------- #
589+
590
cat << 'EOF' > $SCRIPT7
591-
fi
591+
592
#set -x # comment/uncomment to disable/enable debug mode
593
{
594
$SCRIPT3 "$1" "$2"
595
} 2>&1 | logger -t $(basename $0)[$$]
596
EOF
597
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT7
598
sed "s:\$SCRIPT3:$SCRIPT3:g" -i $SCRIPT7
599
chmod +x $SCRIPT7
600
}
601
602
if [ -f $SCRIPT7 ]; then
603
    echo "error: $SCRIPT7 already exists; requires manual installation"
604
else
605
    create_script
606
    echo "installed: $SCRIPT7"
607
fi
608
# -------------------------- end service-event-end --------------------------- #
609
610
# --------------------------- begin services-start --------------------------- #
611
create_script() {
612
cat << 'EOF' > $SCRIPT8
613
#!/bin/sh
614
#set -x # comment/uncomment to disable/enable debug mode
615
{
616
$SCRIPT4
617
} 2>&1 | logger -t $(basename $0)[$$]
618
EOF
619
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT8
620
sed "s:\$SCRIPT4:$SCRIPT4:g" -i $SCRIPT8
621
chmod +x $SCRIPT8
622
}
623
624
if [ -f $SCRIPT8 ]; then
625
    echo "error: $SCRIPT8 already exists; requires manual installation"
626
else
627
    create_script
628
    echo "installed: $SCRIPT8"
629
fi
630
# ---------------------------- end services-start ---------------------------- #