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.1, 27-jun-2024, 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. use nano editor to modify script w/ your preferred options:
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-
    if ! echo $vlan_id | egrep -q '^[0-9]+$'; then
91+
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 WAN_IF="$WAN_IF"
110
local LAN_IP="$(nvram get lan_ipaddr)" # (e.g., 192.168.1.1)
111-
# function add_user_defined_directives()
111+
local LAN_NET="$LAN_IP/$(nvram get lan_netmask)" # (e.g., 192.168.1.0/24)
112-
add_user_defined_directives() {
112+
local LAN_PFX="$(echo $LAN_IP | grep -o '^.*\.')" # (e.g., 192.168.1.)
113
114-
cat << "EOF" >> $CONFIG
114+
case "$1" in
115-
# >>>>>>>>>>>>>>>>>>>>>> begin user-defined directives <<<<<<<<<<<<<<<<<<<<<<< #
115+
116
# these are just examples; uncomment and modify as you see fit
117
118
3) ### vlan3/br3 rules go here ###
119
# allow access to printer hosted on router
120
#iptables -I INPUT -p tcp -i $brx --dport 9100 -j ACCEPT
121
:;; # DO NOT DISTURB
122
123
4) ### vlan4/br4 rules go here ###
124
# deny routing to internet based on source ip range
125
#iptables -I FORWARD -i $brx -o $WAN_IF -m iprange \
126
#    --src-range "${IP_PFX}${1}.110-${IP_PFX}${1}.119" -j REJECT
127-
# >>>>>>>>>>>>>>>>>>>>>>> end user-defined directives <<<<<<<<<<<<<<<<<<<<<<<< #
127+
# deny routing to internet based on source mac address
128
#iptables -I FORWARD -i $brx -o $WAN_IF -m mac --mac-source \
129
#    0a:32:13:75:7d:95 -j REJECT
130
:;; # DO NOT DISTURB
131-
> $CONFIG
131+
132
5) ### vlan5/br5 rules go here ###
133
# deny routing from 10:00PM to 6:00AM, Sunday->Friday (student schedule)
134
#iptables -I FORWARD -i $brx -m time --timestart 22:00 --timestop 00:00 \
135
#    --weekdays Sun,Mon,Tue,Wed,Thu --kerneltz -j REJECT
136
#iptables -I FORWARD -i $brx -m time --timestart 00:00 --timestop 06:00 \
137
#    --weekdays Mon,Tue,Wed,Thu,Fri --kerneltz -j REJECT
138
:;; # DO NOT DISTURB
139
140
# repeat as necessary for additional vlans/bridges
141
142
*) ### rules that apply across all vlans/bridges (br+) go here ###
143
# allow access to printer hosted on private network (other than router)
144-
add_user_defined_directives
144+
145
#    --dport 9100 -j ACCEPT
146
:;; # DO NOT DISTURB
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
153-
)
153+
154
155-
# --------------------------- end dnsmasq.conf.add --------------------------- #
155+
# shared/global functions and constants (do NOT touch!)
156
157
debug_enabled() { set -o | grep -Eq '^xtrace\s+on$'; }
158-
SCRIPT="$SCRIPTS_DIR/firewall-start"
158+
159
BASENAME="$(basename $0)"
160-
if [ "${INCLUDE_FIREWALL+x}" ]; then
160+
NOW="$(date +'%Y-%m-%d-%H%M%S')"
161
LOG="$(debug_enabled && echo /tmp/${BASENAME}_${NOW}_$$.log || echo /dev/null)"
162
MIN_VID=3 MAX_VID=255 MIN_PORT=1 MAX_PORT=4
163-
cat << "EOF" > $SCRIPT
163+
[ "$IP_PFX" ] || IP_PFX="$(nvram get lan_ipaddr | grep -Eo '^(.{1,3}\.){2}')"
164
165-
set -x # uncomment/comment to enable/disable debug mode
165+
166
echo "installed: $CONFIG"
167
# ------------------ end merlin-ac68u-add-networks.options ------------------- #
168
169-
LAN_IP="$(nvram get lan_ipaddr)" # (e.g., 192.168.1.1)
169+
# ----------------- begin merlin-ac68u-add-networks.dnsmasq ------------------ #
170-
LAN_NET="$LAN_IP/$(nvram get lan_netmask)" # (e.g., 192.168.1.0/24)
170+
if grep -q '^INCLUDE_DNSMASQ=' $CONFIG; then
171-
LAN_PFX="$(echo $LAN_IP | grep -o '^.*\.')" # (e.g., 192.168.1.)
171+
cat << 'EOF' > $SCRIPT1
172
#!/bin/sh
173-
# function router_is_bridged()
173+
#set -x # comment/uncomment to disable/enable debug mode
174-
router_is_bridged() { ! ifconfig vlan2 2>/dev/null | grep -q 'UP'; }
174+
. $CONFIG
175
{
176
. /usr/sbin/helper.sh
177
178
DNSMASQ_CONFIG="$1"
179
180-
    if ! echo $vlan_id | egrep -q '^[0-9]+$'; then
180+
# function write( string )
181
write() { pc_append "$1" $DNSMASQ_CONFIG; }
182
183
# function validate_vlan_id( vlan-id )
184
validate_vlan_id() {
185
    local vlan_id=$1
186
187
    if ! echo $vlan_id | grep -Eq '^[0-9]+$'; then
188
        return 1
189
    elif [[ $vlan_id -lt $MIN_VID || $vlan_id -gt $MAX_VID ]]; then
190
        return 1
191
    fi
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+
198
    write "interface=br${1}"
199-
iptables -I INPUT -i br${1} -p udp --dport 67 -j ACCEPT
199+
    write "dhcp-range=br${1},${IP_PFX}${1}.100,${IP_PFX}${1}.254,255.255.255.0,24h"
200-
if router_is_bridged; then
200+
    write "dhcp-option=br${1},3,${IP_PFX}${1}.1"
201-
  iptables -I INPUT -i lo  -j ACCEPT
201+
    [ "$DNS_SERVERS" ] && write "dhcp-option=br${1},6,$DNS_SERVERS"
202-
  iptables -I INPUT -i br0 -j ACCEPT
202+
203-
  iptables -I INPUT -m state --state INVALID -j DROP
203+
204-
  iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
204+
write "# --- begin additions by $BASENAME --- #"
205
206
# add dhcp server configuration for each new bridge
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
    [ $vlan_id ] || continue
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+
217-
  iptables -I FORWARD -i br${1} -o br0 -d 192.168.0.0/16 -j REJECT
217+
# add user-defined directives
218-
  iptables -I FORWARD -m state --state INVALID -j DROP
218+
OIFS="$IFS"; IFS=$'\n'
219-
  iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
219+
for line in $DNSMASQ_ADDITIONS; do
220-
  iptables -t nat -I POSTROUTING -o br0 -j SNAT --to $LAN_IP
220+
    echo $line | grep -Eq '^[[:space:]]*(#|$)' || write "$line"
221
done
222-
  if [ "$ALLOW_OVPN_ACCESS" ]; then
222+
IFS="$OIFS"
223-
    iptables -I FORWARD -i tun2+  -o br${1} -j ACCEPT
223+
224-
    iptables -I FORWARD -i br${1} -o tun1+  -j ACCEPT
224+
write "# ---- end additions by $BASENAME ---- #"
225-
  fi
225+
226-
  iptables -I FORWARD -i br${1} -m conntrack --ctstate DNAT -j ACCEPT
226+
227-
  iptables -I FORWARD -i br${1} -o $WAN_IF -j ACCEPT
227+
} 2>&1 | tee $LOG | logger -t $BASENAME[$$]
228
EOF
229
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT1
230
sed -i "s:\$CONFIG:$CONFIG:g" $SCRIPT1
231-
# function add_user_defined_rules( bridge-index )
231+
chmod +x $SCRIPT1
232-
add_user_defined_rules() {
232+
echo "installed: $SCRIPT1"
233
fi
234-
brx=br${1} # generalize reference to current bridge under examination
234+
# ------------------ end merlin-ac68u-add-networks.dnsmasq ------------------- #
235
236-
case $1 in
236+
# ----------------- begin merlin-ac68u-add-networks.firewall ----------------- #
237-
# >>>>>>>>>>>>>>>>>>>>>>>>> begin user-defined rules <<<<<<<<<<<<<<<<<<<<<<<<< #
237+
if grep -q '^INCLUDE_FIREWALL=' $CONFIG; then
238
cat << 'EOF' > $SCRIPT2
239
#!/bin/sh
240
#set -x # comment/uncomment to disable/enable debug mode
241
. $CONFIG
242
{
243
WAN_IF="$([ $1 ] && echo $1 || echo $(nvram get wan0_ifname))"
244
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
249-
# deny routing based on mac address
249+
    if ! echo $vlan_id | grep -Eq '^[0-9]+$'; then
250-
#iptables -I FORWARD -i $brx -m mac --mac-source 0a:32:13:75:7d:95 -j REJECT
250+
251
    elif [[ $vlan_id -lt $MIN_VID || $vlan_id -gt $MAX_VID ]]; then
252
        return 1
253
    fi
254-
# deny routing from 10:00PM to 6:00AM, Sunday thru Friday (student scheduling)
254+
255
    return 0
256
}
257
258
# function add_rules( bridge-index )
259
add_rules() {
260
    # limit new bridge to essential router services (dhcp, dns, ping)
261
    iptables -I INPUT -i br${1} -j REJECT
262
    iptables -I INPUT -i br${1} -d ${IP_PFX}${1}.1 -p icmp -j ACCEPT
263
    if [ ! "$DNS_SERVERS" ]; then
264
        iptables -I INPUT -i br${1} -d ${IP_PFX}${1}.1 -p tcp --dport 53 -j ACCEPT
265
        iptables -I INPUT -i br${1} -d ${IP_PFX}${1}.1 -p udp --dport 53 -j ACCEPT
266
    fi
267
    iptables -I INPUT -i br${1} -p udp --dport 67 -j ACCEPT
268
269-
# >>>>>>>>>>>>>>>>>>>>>>>>>> end user-defined rules <<<<<<<<<<<<<<<<<<<<<<<<<< #
269+
    # define routing limits of new bridge (default is internet only)
270
    iptables -I FORWARD -i br${1} -j REJECT
271
    if [ ! ${ALLOW_PRIVATE_TO_ANY+x} ]; then
272
        iptables -I FORWARD -i br0 -o br${1} -j REJECT
273
    fi
274
    if [ ${ALLOW_OVPN_ACCESS+x} ]; then
275
        iptables -I FORWARD -i tun2+  -o br${1} -j ACCEPT
276
        iptables -I FORWARD -i br${1} -o tun1+  -j ACCEPT
277
    fi
278
    iptables -I FORWARD -i br${1} -m conntrack --ctstate DNAT -j ACCEPT
279
    iptables -I FORWARD -i br${1} -o $WAN_IF -j ACCEPT
280
}
281
282
# add firewall rules for each new bridge
283
for vp in $VLANS_PORTS; do
284
    vlan_id="$(echo $vp | cut -d/ -f1)"
285
286-
    add_user_defined_rules $vlan_id
286+
287
    [ $vlan_id ] || continue
288
289
    validate_vlan_id $vlan_id || continue
290-
add_user_defined_rules '+'
290+
291
    # add rules for this vlan-id
292
    add_rules $vlan_id
293-
} 2>&1 | tee $LOG | logger -t $(basename $0)[$$]
293+
294
    # add user-defined rules (if any) for this vlan-id
295-
[ ${DEBUG+x} ] || sed -ri 's/^(set -x)/#\1/g' $SCRIPT
295+
    firewall_additions $vlan_id
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+
299-
    -e "s:\$VLANS_PORTS:$(echo $VLANS_PORTS):g" \
299+
firewall_additions '+'
300-
    -e "s:\${IPNET_PFX}:$IPNET_PFX:g" \
300+
301-
    -e "s:\$DNS_SERVERS:$DNS_SERVERS:g" \
301+
302-
    -e "s:\$ALLOW_PRIVATE_TO_ANY:${ALLOW_PRIVATE_TO_ANY+x}:g" \
302+
} 2>&1 | tee $LOG | logger -t $BASENAME[$$]
303-
    -e "s:\$ALLOW_OVPN_ACCESS:${ALLOW_OVPN_ACCESS+x}:g" \
303+
304-
    -i $SCRIPT
304+
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT2
305-
chmod +x $SCRIPT
305+
sed -i "s:\$CONFIG:$CONFIG:g" $SCRIPT2
306
chmod +x $SCRIPT2
307
echo "installed: $SCRIPT2"
308-
if [ -f $SCRIPT ]; then
308+
309-
    echo "error: $SCRIPT already exists; requires manual installation"
309+
# ------------------ end merlin-ac68u-add-networks.firewall ------------------ #
310
311
# -------------- begin merlin-ac68u-add-networks.services-start -------------- #
312-
    echo "installed: $SCRIPT"
312+
cat << 'EOF' > $SCRIPT3
313
#!/bin/sh
314
#set -x # comment/uncomment to disable/enable debug mode
315
. $CONFIG
316
{
317
CPU_PORT="$(robocfg show | awk '/vlan1:/{print $NF}')"
318
319-
SCRIPT="$SCRIPTS_DIR/service-event-end"
319+
320
validate_vlan_id() {
321
    local vlan_id=$1
322-
cat << "EOF" > $SCRIPT
322+
323
    if [ $vlan_id != '1' ]; then
324-
set -x # uncomment/comment to enable/disable debug mode
324+
325
            echo "error: changes to vlan2 (wan) NOT supported"
326
            return 1
327
        elif ! echo $vlan_id | grep -Eq '^[0-9]+$'; then
328
            echo "error: vlan-id ${vlan_id} not numeric"
329
            return 1
330
        elif [[ $vlan_id -lt $MIN_VID || $vlan_id -gt $MAX_VID ]]; then
331
            echo "error: vlan${vlan_id} out of range ($MIN_VID-$MAX_VID)"
332
            return 1
333
        fi
334
    fi
335
336-
        elif ! echo $vlan_id | egrep -q '^[0-9]+$'; then
336+
337
}
338
339
# function add_vlan_and_bridge( vlan-id ports )
340
add_vlan_and_bridge() {
341
    local vlan_id=$1
342
    local ports="$2"
343
344
    # create new vlan w/ specified port(s)
345
    robocfg vlan $vlan_id ports "$ports"
346
347
    # add new vlan to eth0 (cpu) network interface
348
    vconfig add eth0 $vlan_id
349
350
    # bring up new vlan
351
    ifconfig vlan${vlan_id} up
352
353
    # create new bridge and add new vlan
354
    brctl addbr br${vlan_id}
355
    brctl addif br${vlan_id} vlan${vlan_id}
356
357
    # configure new bridge w/ preferred settings
358
    stp=$([ "$(nvram get lan_stp)" == '1' ] && echo 'on' || echo 'off')
359
    brctl stp br${vlan_id} $stp # stp to prevent bridge loops
360
    brctl setfd br${vlan_id} 2  # stp forward delay (2 secs)
361
362
    # config ip on new bridge and bring up network
363
    ifconfig br${vlan_id} ${IP_PFX}${vlan_id}.1 netmask 255.255.255.0 up
364
}
365
366
# respond to *all* wireless events (start/restart/stop)
367-
    stp="$([ "$(nvram get lan_stp)" == '1' ] && echo 'on' || echo 'off')"
367+
368
369
# cleanup any previous vlan/bridge configurations
370
n=$MIN_VID
371
while [ "$(nvram get br${n}_ifname)" ]; do
372-
    ifconfig br${vlan_id} ${IPNET_PFX}${vlan_id}.1 netmask 255.255.255.0 up
372+
373
    vl="$(nvram get br${n}_ifnames | cut -d' ' -f1)"
374
375
    ifconfig $br down 2>/dev/null && brctl delbr $br && vconfig rem $vl
376
377
    nvram unset  br${n}_ifname
378
    nvram unset  br${n}_ifnames
379
    nvram unset lan${n}_ifname
380
    nvram unset lan${n}_ifnames
381
382
    [ $((++n)) -le $MAX_VID ] || break
383
done
384
385
# commit changes from cleanup if no other actions requested/required
386
[[ $((n)) -gt $MIN_VID && ! "$VLANS_PORTS" && ! "$VLANS_WL" ]] && nvram commit
387
388
# assign ports to vlans
389
for vp in $VLANS_PORTS; do
390
    vlan_id="$(echo $vp | cut -d/ -f1)"
391
392
    # ignore bad/missing input
393
    [ $vlan_id ] || continue
394
395
    validate_vlan_id $vlan_id || continue
396
397
    # isolate ports from vlan-id
398
    vlan_ports="$(echo $vp | awk -F/ '{$1=""; print $0}')"
399
400
    # validate ports
401
    for p in $vlan_ports; do
402
        if ! echo $p | grep -Eq '^[0-9]+[tu*]{0,1}$'; then
403
            echo "error: port $p specification not valid"
404
            continue 2
405
        fi
406
        _p="$(echo $p | grep -Eo '^[0-9]*')"
407
        if [[ $_p -lt $MIN_PORT || $_p -gt $MAX_PORT ]]; then
408
            echo "error: port $p out of range ($MIN_PORT-$MAX_PORT)"
409
            continue 2
410
        fi
411-
        if ! echo $p | egrep -q '^[0-9]+[tu*]{0,1}$'; then
411+
412
413
    # add cpu port to ports
414
    vlan_ports="$(echo $vlan_ports $CPU_PORT)"
415-
        _p="$(echo $p | egrep -o '^[0-9]*')"
415+
416
    if [ $vlan_id == '1' ]; then
417
        robocfg vlan 1 ports "$vlan_ports"
418
        continue
419
    fi
420
421
    add_vlan_and_bridge $vlan_id "$vlan_ports"
422
423
    # determine next available bridge/lan index
424
    #n=$vlan_id # doesn't work; must be assigned sequentially
425
    n=$MIN_VID; while [ "$(nvram get lan${n}_ifname)" ]; do let n++; done
426
427
    # add and initialize network interface names
428
    nvram set  br${n}_ifname=br${vlan_id}
429
    nvram set  br${n}_ifnames=vlan${vlan_id}
430
    nvram set lan${n}_ifname=br${vlan_id}
431
    nvram set lan${n}_ifnames=vlan${vlan_id}
432
done
433
434
# bridge wireless to vlans
435
for vw in $VLANS_WL; do
436
    vlan_id="$(echo $vw | cut -d/ -f1)"
437
438
    # ignore bad/missing input
439
    [ $vlan_id ] || continue
440
441
    validate_vlan_id $vlan_id || continue
442
443
    # validate vlan-id usage
444
    if ! ifconfig vlan${vlan_id} &>/dev/null; then
445
        echo "error: vlan${vlan_id} not found"
446
        continue
447
    fi
448
449
    # isolate wireless network interfaces from vlan-id
450
    vlan_wl="$(echo $(echo $vw | awk -F/ '{$1=""; print $0}'))"
451
452
    # move wireless network interfaces to new bridge
453
    for wl in $vlan_wl; do
454
        # validate wireless network interface
455
        case $wl in
456
            'eth1'|'eth2'|'wl0.1'|'wl1.1'|'wl0.2'|'wl1.2'|'wl0.3'|'wl1.3') :;;
457
          *) echo "error: unknown wireless network interface: ${wl}"; continue 2;;
458
        esac
459
460
        # wireless network interface must be up and running
461
        if ! ifconfig $wl &>/dev/null; then
462
            echo "error: wireless network interface not available: ${wl}"
463
            continue 2
464
        fi
465
466
        # delete wireless network interface from current bridge
467
        n=0
468
        if brctl show | grep -q "\s${wl}\$"; then
469
            while ! brctl delif br${n} $wl 2>/dev/null; do
470
                if [ $((++n)) -gt $MAX_VID ]; then
471
                    echo "program error: wireless network interface not found: ${wl}"
472
                    break
473
                fi
474
            done
475
        fi
476
477
        # add wireless network interface to new bridge
478
        brctl addif br${vlan_id} $wl
479
    done
480
481
    # find bridge/lan index for this vlan
482
    n=$MIN_VID
483
    while ! nvram get br${n}_ifnames | grep -Eq "^vlan${vlan_id}( |$)"; do
484
        if [ $((++n)) -gt $MAX_VID ]; then
485
            echo "program error: bridge/lan index not found: ($n)"
486
            continue 2
487
        fi
488
    done
489
490
    # add wireless network interface names to corresponding bridge/lan
491
    nvram set  br${n}_ifnames="$(nvram get  br${n}_ifnames) $vlan_wl"
492-
    while ! nvram get br${n}_ifnames | egrep -q "^vlan${vlan_id}( |$)"; do
492+
493
494
    # convert wireless network interface names to sed search mask
495
    mask=''; for wl in $vlan_wl; do mask="${mask}${wl}(\s|\$)|"; done
496
497
    # remove wireless network interface names from system bridges/lans
498
    for i in 0 1 2; do
499
        [ "$(nvram get  br${i}_ifnames)" ] && \
500
             nvram set  br${i}_ifnames="$(echo $(nvram get  br${i}_ifnames | \
501
                 sed -r s/$mask//g))"
502
        [ "$i" == '0' ] && j='' || j="$i"
503
        [ "$(nvram get lan${j}_ifnames)" ] && \
504
             nvram set lan${j}_ifnames="$(echo $(nvram get lan${j}_ifnames | \
505
                 sed -r s/$mask//g))"
506
    done
507
done
508
509
# force system to recognize any changes
510
eapd
511
512
exit 0
513
} 2>&1 | tee $LOG | logger -t $BASENAME[$$]
514
EOF
515
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT3
516
sed -i "s:\$CONFIG:$CONFIG:g" $SCRIPT3
517
chmod +x $SCRIPT3
518
echo "installed: $SCRIPT3"
519
# --------------- end merlin-ac68u-add-networks.services-start --------------- #
520
521
# ------------ begin merlin-ac68u-add-networks.service-event-end ------------- #
522-
} 2>&1 | tee $LOG | logger -t $(basename $0)[$$]
522+
cat << 'EOF' > $SCRIPT4
523
#!/bin/sh
524-
[ ${DEBUG+x} ] || sed -ri 's/^(set -x)/#\1/g' $SCRIPT
524+
#set -x # comment/uncomment to disable/enable debug mode
525-
sed -e "s:\$LOG:$LOG:g" \
525+
. $CONFIG
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+
530-
    -e "s:\$VLANS_PORTS:$(echo $VLANS_PORTS):g" \
530+
/jffs/scripts/service-event-end 'start' 'wireless'
531-
    -e "s:\$VLANS_WL:$(echo $VLANS_WL):g" \
531+
532-
    -e "s:\${IPNET_PFX}:$IPNET_PFX:g" \
532+
533-
    -i $SCRIPT
533+
} 2>&1 | tee $LOG | logger -t $BASENAME[$$]
534-
chmod +x $SCRIPT
534+
535
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT4
536
sed -i "s:\$CONFIG:$CONFIG:g" $SCRIPT4
537-
if [ -f $SCRIPT ]; then
537+
chmod +x $SCRIPT4
538-
    echo "error: $SCRIPT already exists; requires manual installation"
538+
echo "installed: $SCRIPT4"
539
# ------------- end merlin-ac68u-add-networks.service-event-end -------------- #
540
541-
    echo "installed: $SCRIPT"
541+
# -------------------------- begin dnsmasq.postconf -------------------------- #
542
if grep -q '^INCLUDE_DNSMASQ=' $CONFIG; then
543
create_script() {
544
cat << 'EOF' > $SCRIPT5
545
#!/bin/sh
546-
SCRIPT="$SCRIPTS_DIR/services-start"
546+
#set -x # comment/uncomment to disable/enable debug mode
547
{
548
$SCRIPT1 "$1"
549-
cat << "EOF" > $SCRIPT
549+
} 2>&1 | logger -t $(basename $0)[$$]
550
EOF
551-
set -x # uncomment/comment to enable/disable debug mode
551+
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT5
552
sed "s:\$SCRIPT1:$SCRIPT1:g" -i $SCRIPT5
553-
# function router_is_bridged()
553+
chmod +x $SCRIPT5
554-
router_is_bridged() { ! ifconfig vlan2 2>/dev/null | grep -q 'UP'; }
554+
555
556-
# in a bridged configuration (e.g., AP mode), the firewall is not activated,
556+
if [ -f $SCRIPT5 ]; then
557-
# so we have to manually start the firewall-start script
557+
    echo "error: $SCRIPT5 already exists; requires manual installation"
558
else
559-
if [ "$INCLUDE_FIREWALL" ] && router_is_bridged; then
559+
560-
    "$SCRIPTS_DIR/firewall-start"
560+
    echo "installed: $SCRIPT5"
561
fi
562-
    # enable ip routing for bridged router configurations
562+
563-
    echo '1' > /proc/sys/net/ipv4/ip_forward
563+
# ------------------------ end begin dnsmasq.postconf ------------------------ #
564
565
# --------------------------- begin firewall-start --------------------------- #
566
if grep -q '^INCLUDE_FIREWALL=' $CONFIG; then
567
create_script() {
568
cat << 'EOF' > $SCRIPT6
569
#!/bin/sh
570-
"$SCRIPTS_DIR/service-event-end" 'start' 'wireless'
570+
#set -x # comment/uncomment to disable/enable debug mode
571
{
572
$SCRIPT2 "$1"
573-
} 2>&1 | tee $LOG | logger -t $(basename $0)[$$]
573+
} 2>&1 | logger -t $(basename $0)[$$]
574
EOF
575-
[ ${DEBUG+x} ] || sed -ri 's/^(set -x)/#\1/g' $SCRIPT
575+
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT6
576-
sed -e "s:\$LOG:$LOG:g" \
576+
sed "s:\$SCRIPT2:$SCRIPT2:g" -i $SCRIPT6
577-
    -e "s:\$SCRIPTS_DIR:$SCRIPTS_DIR:g" \
577+
chmod +x $SCRIPT6
578-
    -e "s:\$INCLUDE_FIREWALL:${INCLUDE_FIREWALL+x}:g" \
578+
579-
    -i $SCRIPT
579+
580-
chmod +x $SCRIPT
580+
if [ -f $SCRIPT6 ]; then
581
    echo "error: $SCRIPT6 already exists; requires manual installation"
582
else
583-
if [ -f $SCRIPT ]; then
583+
584-
    echo "error: $SCRIPT already exists; requires manual installation"
584+
    echo "installed: $SCRIPT6"
585
fi
586
fi
587-
    echo "installed: $SCRIPT"
587+
588
589-
# ---------------------------- end services-start ---------------------------- #
589+
590
create_script() {
591-
fi
591+
cat << 'EOF' > $SCRIPT7
592
#!/bin/sh
593
#set -x # comment/uncomment to disable/enable debug mode
594
{
595
$SCRIPT3 "$1" "$2"
596
} 2>&1 | logger -t $(basename $0)[$$]
597
EOF
598
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT7
599
sed "s:\$SCRIPT3:$SCRIPT3:g" -i $SCRIPT7
600
chmod +x $SCRIPT7
601
}
602
603
if [ -f $SCRIPT7 ]; then
604
    echo "error: $SCRIPT7 already exists; requires manual installation"
605
else
606
    create_script
607
    echo "installed: $SCRIPT7"
608
fi
609
# -------------------------- end service-event-end --------------------------- #
610
611
# --------------------------- begin services-start --------------------------- #
612
create_script() {
613
cat << 'EOF' > $SCRIPT8
614
#!/bin/sh
615
#set -x # comment/uncomment to disable/enable debug mode
616
{
617
$SCRIPT4
618
} 2>&1 | logger -t $(basename $0)[$$]
619
EOF
620
[ ${DEBUG+x} ] && sed -ri '2 s/^#(set -x)/\1/' $SCRIPT8
621
sed "s:\$SCRIPT4:$SCRIPT4:g" -i $SCRIPT8
622
chmod +x $SCRIPT8
623
}
624
625
if [ -f $SCRIPT8 ]; then
626
    echo "error: $SCRIPT8 already exists; requires manual installation"
627
else
628
    create_script
629
    echo "installed: $SCRIPT8"
630
fi
631
# ---------------------------- end services-start ---------------------------- #