-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathvpn-samba.sh
More file actions
177 lines (143 loc) · 7.28 KB
/
vpn-samba.sh
File metadata and controls
177 lines (143 loc) · 7.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/bin/sh
# Made by Jack'lul <jacklul.github.io>
#
# Allow VPN clients to access Samba shares in LAN without reconfiguring each device
#
#jas-update=vpn-samba.sh
#shellcheck shell=ash
#shellcheck disable=SC2155
#shellcheck source=./common.sh
readonly common_script="$(dirname "$0")/common.sh"
if [ -f "$common_script" ]; then . "$common_script"; else { echo "$common_script not found" >&2; exit 1; } fi
VPN_NETWORKS="" # VPN networks (IPv4) to allow access to Samba from, in format '10.6.0.0/24', separated by spaces, empty means auto detect
VPN_NETWORKS6="" # same as VPN_NETWORKS but for IPv6, separated by spaces, no auto detect available
LAN_NETWORK="" # IPv4 LAN network, in format '192.168.0.0/24', empty means auto detect
LAN_NETWORK6="" # IPv6 LAN network, in format 'fd12:3456:789a::/48', if left empty then IPv6 connections will not be handled
BRIDGE_INTERFACE="" # the bridge interface to set rules for, empty means set to LAN bridge interface
USE_LEGACY_PORTS=false # also use legacy NetBIOS ports 137-139 (true/false), set to true only if you really need them
EXECUTE_COMMAND="" # execute a command after firewall rules are applied or removed (receives arguments: $1 = action - add/remove)
RUN_EVERY_MINUTE= # verify that the rules are still set (true/false), empty means false when service-event script is available but otherwise true
RETRY_ON_ERROR=false # retry setting the rules on error (once per run)
load_script_config
readonly CHAIN="jas-${script_name}"
firewall_rules() {
if { [ -z "$VPN_NETWORKS" ] && [ -z "$VPN_NETWORKS6" ] ; }; then
if [ "$(nvram get wgs_enable)" = "1" ]; then
local _wgs_addr="$(nvram get wgs_addr)" # WireGuard - 10.6.0.1/32
if [ -n "$_wgs_addr" ]; then
VPN_NETWORKS="$VPN_NETWORKS $(echo "$_wgs_addr" | cut -d '.' -f -3).0/24"
fi
fi
if [ "$(nvram get vpn_server_state)" = "2" ]; then
local _vpn_server_sn="$(nvram get vpn_server_sn)" # OpenVPN - 10.8.0.0
local _vpn_server_nm="$(nvram get vpn_server_nm)" # OpenVPN - 255.255.255.0
if [ -n "$_vpn_server_sn" ] && [ -n "$_vpn_server_nm" ]; then
local _openvpn_network="$_vpn_server_sn/$(mask_to_cidr "$_vpn_server_nm")"
[ -n "$_openvpn_network" ] && VPN_NETWORKS="$VPN_NETWORKS $_openvpn_network"
fi
fi
if [ "$(nvram get ipsec_server_enable)" = "1" ]; then
local _ipsec_profile=s"$(nvram get ipsec_profile_1)" # IPSec - after 14th '>' is 10.10.10
if [ -n "$_ipsec_profile" ]; then
VPN_NETWORKS="$VPN_NETWORKS $(echo "$_ipsec_profile" | cut -d '>' -f 15).0/24"
fi
fi
# PPTP has build-in toggle for Samba access, so this is not needed
#if [ "$(nvram get pptpd_enable)" = "1" ]; then
# local _pptpd_clients="$(nvram get pptpd_clients)"
#
# if [ -n "$_pptpd_clients" ]; then
# VPN_NETWORKS="$VPN_NETWORKS $(echo "$_pptpd_clients" | cut -d '.' -f -3).0/24"
# fi
#fi
{ [ -z "$VPN_NETWORKS" ] && [ -z "$VPN_NETWORKS6" ] ; } && return # silently exit
fi
[ -z "$BRIDGE_INTERFACE" ] && BRIDGE_INTERFACE="$(nvram get lan_ifname)"
# If xt_comment module is not available, disable comments to avoid errors and continue working without them
modprobe xt_comment 2> /dev/null && iptables_comment="jas-$script_name" || iptables_comment=""
lockfile lockwait
local _for_iptables="iptables"
[ "$(nvram get ipv6_service)" != "disabled" ] && _for_iptables="$_for_iptables ip6tables"
local _iptables _rules_action _rules_error _vpn_networks _lan_network _lan_ipaddr _lan_netmask _cidr _network _vpn_network
for _iptables in $_for_iptables; do
if [ "$_iptables" = "ip6tables" ]; then
_vpn_networks="$VPN_NETWORKS6"
_lan_network="$LAN_NETWORK6"
else
_vpn_networks="$VPN_NETWORKS"
_lan_network="$LAN_NETWORK"
if [ -z "$_lan_network" ]; then
_lan_ipaddr="$(nvram get lan_ipaddr)"
_lan_netmask="$(nvram get lan_netmask)"
_cidr="$(mask_to_cidr "$_lan_netmask")"
_network="$(calculate_network "$_lan_ipaddr" "$_lan_netmask")"
{ [ -z "$_cidr" ] || [ -z "$_network" ] ; } && { logecho "Error: Failed to calculate destination IPv4 network" error; exit 1; }
_lan_network="$_network/$_cidr"
fi
fi
[ -z "$_vpn_networks" ] && continue
[ -z "$_lan_network" ] && continue
case "$1" in
"add")
if ! $_iptables -t nat -nL "$CHAIN" > /dev/null 2>&1; then
$_iptables -t nat -N "$CHAIN"
$_iptables -t nat -A "$CHAIN" -p tcp --dport 445 -j MASQUERADE # SMB
if [ "$USE_LEGACY_PORTS" = true ]; then # NetBIOS, legacy ports
$_iptables -t nat -A "$CHAIN" -p tcp --dport 139 -j MASQUERADE
$_iptables -t nat -A "$CHAIN" -p udp --dport 138 -j MASQUERADE
$_iptables -t nat -A "$CHAIN" -p udp --dport 137 -j MASQUERADE
fi
for _vpn_network in $_vpn_networks; do
$_iptables -t nat -A POSTROUTING -s "$_vpn_network" -d "$_lan_network" -o "$BRIDGE_INTERFACE" -j "$CHAIN" \
${iptables_comment:+-m comment --comment "$iptables_comment"} \
&& _rules_action=1 || _rules_error=1
done
fi
;;
"remove")
remove_iptables_rules_by_comment "$_iptables" "nat" && _rules_action=-1
if $_iptables -t nat -nL "$CHAIN" > /dev/null 2>&1; then
$_iptables -t nat -F "$CHAIN"
$_iptables -t nat -X "$CHAIN" || _rules_error=1
fi
;;
esac
done
[ "$_rules_error" = 1 ] && logecho "Errors detected while modifying firewall rules ($1)" error
if [ -n "$_rules_action" ]; then
if [ "$_rules_action" = 1 ]; then
logecho "Masquerading Samba connections coming from VPN networks: $(echo "$VPN_NETWORKS $VPN_NETWORKS6" | awk '{$1=$1};1')" alert
else
logecho "Stopped masquerading Samba connections coming from VPN networks: $(echo "$VPN_NETWORKS $VPN_NETWORKS6" | awk '{$1=$1};1')" alert
fi
fi
[ -n "$EXECUTE_COMMAND" ] && [ -n "$_rules_action" ] && eval "$EXECUTE_COMMAND $1"
lockfile unlock
[ -z "$_rules_error" ] && return 0 || return 1
}
case "$1" in
"run")
firewall_rules add || { [ "$RETRY_ON_ERROR" = true ] && firewall_rules add; }
;;
"start")
firewall_rules add
# Set value of empty RUN_EVERY_MINUTE depending on situation
execute_script_basename "service-event.sh" check && service_event_active=true
[ -z "$RUN_EVERY_MINUTE" ] && [ -z "$service_event_active" ] && RUN_EVERY_MINUTE=true
if [ "$RUN_EVERY_MINUTE" = true ]; then
crontab_entry add "*/1 * * * * $script_path run"
fi
;;
"stop")
crontab_entry delete
firewall_rules remove
;;
"restart")
sh "$script_path" stop
sh "$script_path" start
;;
*)
echo "Usage: $0 run|start|stop|restart"
exit 1
;;
esac