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 ---------------------------- # |