aboutsummaryrefslogtreecommitdiffstats
path: root/package/firewall/files/lib/core_redirect.sh
blob: fe396c1c12828c46aa66968934c5f68e548f6092 (plain)
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
# Copyright (C) 2009-2010 OpenWrt.org

fw_config_get_redirect() {
	[ "${redirect_NAME}" != "$1" ] || return
	fw_config_get_section "$1" redirect { \
		string _name "$1" \
		string name "" \
		string src "" \
		ipaddr src_ip "" \
		ipaddr src_dip "" \
		string src_mac "" \
		string src_port "" \
		string src_dport "" \
		string dest "" \
		ipaddr dest_ip "" \
		string dest_port "" \
		string proto "tcpudp" \
		string family "" \
		string target "DNAT" \
		string extra "" \
	} || return
	[ -n "$redirect_name" ] || redirect_name=$redirect__name
}

fw_load_redirect() {
	fw_config_get_redirect "$1"

	fw_callback pre redirect

	local fwdchain natchain natopt nataddr natports srcdaddr srcdports
	if [ "$redirect_target" == "DNAT" ]; then
		[ -n "${redirect_src#*}" -a -n "$redirect_dest_ip$redirect_dest_port" ] || {
			fw_log error "DNAT redirect ${redirect_name}: needs src and dest_ip or dest_port, skipping"
			return 0
		}

		fwdopt=""
		fwdchain=""

		# Check whether only ports are given or whether the given dest ip is local,
		# in this case match only DNATed traffic and allow it on input, not forward
		if [ -z "$redirect_dest_ip" ] || /sbin/ifconfig | grep -qE "addr:${redirect_dest_ip//./\\.}\b"; then
			fwdopt="-m conntrack --ctstate DNAT"
			fwdchain="zone_${redirect_src}"
		else
			fwdchain="zone_${redirect_src}_forward"
		fi

		natopt="--to-destination"
		natchain="zone_${redirect_src}_prerouting"
		nataddr="$redirect_dest_ip"
		fw_get_port_range natports "${redirect_dest_port#!}" "-"

		fw_get_negation srcdaddr '-d' "${redirect_src_dip:+$redirect_src_dip/$redirect_src_dip_prefixlen}"
		fw_get_port_range srcdports "$redirect_src_dport" ":"
		fw_get_negation srcdports '--dport' "$srcdports"

		list_contains FW_CONNTRACK_ZONES $redirect_src || \
			append FW_CONNTRACK_ZONES $redirect_src

	elif [ "$redirect_target" == "SNAT" ]; then
		[ -n "${redirect_dest#*}" -a -n "$redirect_src_dip" ] || {
			fw_log error "SNAT redirect ${redirect_name}: needs dest and src_dip, skipping"
			return 0
		}

		fwdchain="${redirect_src:+zone_${redirect_src}_forward}"

		natopt="--to-source"
		natchain="zone_${redirect_dest}_nat"
		nataddr="$redirect_src_dip"
		fw_get_port_range natports "${redirect_src_dport#!}" "-"

		fw_get_negation srcdaddr '-d' "${redirect_dest_ip:+$redirect_dest_ip/$redirect_dest_ip_prefixlen}"
		fw_get_port_range srcdports "$redirect_dest_port" ":"
		fw_get_negation srcdports '--dport' "$srcdports"

		list_contains FW_CONNTRACK_ZONES $redirect_dest || \
			append FW_CONNTRACK_ZONES $redirect_dest

	else
		fw_log error "redirect ${redirect_name}: target must be either DNAT or SNAT, skipping"
		return 0
	fi

	local mode
	fw_get_family_mode mode ${redirect_family:-x} ${redirect_src:-$redirect_dest} I

	local srcaddr
	fw_get_negation srcaddr '-s' "${redirect_src_ip:+$redirect_src_ip/$redirect_src_ip_prefixlen}"

	local srcports
	fw_get_port_range srcports "$redirect_src_port" ":"
	fw_get_negation srcports '--sport' "$srcports"

	local destaddr
	fw_get_negation destaddr '-d' "${redirect_dest_ip:+$redirect_dest_ip/$redirect_dest_ip_prefixlen}"

	local destports
	fw_get_port_range destports "${redirect_dest_port:-$redirect_src_dport}" ":"
	fw_get_negation destports '--dport' "$destports"

	[ "$redirect_proto" == "tcpudp" ] && redirect_proto="tcp udp"
	local pr; for pr in $redirect_proto; do
		fw_get_negation pr '-p' "$pr"
		local sm; for sm in ${redirect_src_mac:-""}; do
			fw_get_negation sm '--mac-source' "$sm"
			fw add $mode n $natchain $redirect_target + \
				{ $redirect_src_ip $redirect_dest_ip } { \
				$srcaddr $srcdaddr $pr \
				$srcports $srcdports \
				${sm:+-m mac $sm} \
				$natopt $nataddr${natports:+:$natports} \
				$redirect_options \
			}

			fw add $mode f ${fwdchain:-forward} ACCEPT + \
				{ $redirect_src_ip $redirect_dest_ip } { \
				$srcaddr $destaddr \
				$pr \
				$srcports $destports \
				${sm:+-m mac $sm} \
				$fwdopt \
				$redirect_extra \
			}
		done
	done

	fw_callback post redirect
}