add webif-configurable scripts for firewalling and port forwarding
authorFelix Fietkau <nbd@openwrt.org>
Sun, 19 Feb 2006 03:05:32 +0000 (03:05 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 19 Feb 2006 03:05:32 +0000 (03:05 +0000)
SVN-Revision: 3255

openwrt/package/base-files/default/etc/config/firewall [new file with mode: 0644]
openwrt/package/base-files/default/etc/init.d/S45firewall
openwrt/package/base-files/default/usr/lib/common.awk [new file with mode: 0644]
openwrt/package/base-files/default/usr/lib/firewall.awk [new file with mode: 0644]
openwrt/package/base-files/ipkg/base-files.conffiles
openwrt/package/webif/files/usr/lib/webif/apply-firewall.sh [new file with mode: 0644]
openwrt/package/webif/files/www/cgi-bin/webif/firewall.sh [new file with mode: 0755]

diff --git a/openwrt/package/base-files/default/etc/config/firewall b/openwrt/package/base-files/default/etc/config/firewall
new file mode 100644 (file)
index 0000000..7edd4ba
--- /dev/null
@@ -0,0 +1,46 @@
+# RULE SYNTAX:
+#
+# forward:<match>:<target>[:<port>]
+#      - forwards all packets matched by <match> to <target>,
+#        optionally changing the port to <port>
+#
+# accept:<match>
+#      - accepts all traffic matched by <match>
+#
+# drop:<match>
+#      - drops all traffic matched by <match>
+#
+#
+# MATCHING OPTIONS:
+#
+# src=<ip>
+#      - match the source ip <ip>
+#
+# dest=<ip>
+#      - match the destination ip <ip>
+#
+# proto=<proto>
+#      - match the protocol by name or number
+#
+# sport=<port(s)>
+#      - match the source port(s), see below for syntax
+#
+# dport=<port(s)>
+#      - match the destination port(s), see below for syntax
+#
+#
+#
+# PORT SYNTAX:
+#
+# You can enter an arbitrary list of ports and port ranges in the following format:
+#   - 22,53,993,1000-1024 
+#
+# If you don't set the protocol to tcp or udp, it will apply to both
+#
+#
+#
+# EXAMPLES:
+#
+# drop:dport=22 src=1.3.3.7
+# accept:proto=tcp dport=22
+# forward:dport=60168:192.168.1.2:60169
index 96ac521334b3d1182b9c98b9c7ca50dfc8a58c6f..8a573835e0aab5aad30aa0262422bf8d8ce105d7 100755 (executable)
@@ -90,3 +90,9 @@ iptables -t nat -N postrouting_rule
 
 ## USER RULES
 [ -f /etc/firewall.user ] && . /etc/firewall.user
+[ -e /etc/config/firewall ] && {
+       rm -f /tmp/.firewall.sh
+       awk -f /usr/lib/common.awk -f /usr/lib/firewall.awk /etc/config/firewall > /tmp/.firewall.sh
+       . /tmp/.firewall.sh
+       rm -f /tmp/.firewall.sh
+}
diff --git a/openwrt/package/base-files/default/usr/lib/common.awk b/openwrt/package/base-files/default/usr/lib/common.awk
new file mode 100644 (file)
index 0000000..860c649
--- /dev/null
@@ -0,0 +1,46 @@
+function portstr(type, str) {
+       if (str ~ /^[0-9]+-[0-9]+$/) {
+               gsub(/-/, ":", str)
+               if (type == "src") return " --sport " str
+               else return " --dport " str
+       } else {
+               if (insmod_mport != 1) {
+                       print "insmod ipt_multiport >&- 2>&-"
+                       insmod_mport = 1
+               }
+               if (type == "src") return " -m multiport --sports " str
+               else return " -m multiport --dports " str
+       }
+}
+
+function str2ipt(str) {
+       str2data(str)
+       _cmd = ""
+       if (_l["src"] != "") _cmd = _cmd " -s " _l["src"]
+       if (_l["dest"] != "") _cmd = _cmd " -d " _l["dest"]
+       if (_l["proto"] != "") {
+               _cmd = _cmd " -p " _l["proto"]
+       }
+       # scripts need to check for proto="" and emit two rules in that case
+       if ((_l["proto"] == "") || (_l["proto"] == "tcp") || (_l["proto"] == "udp")) {
+               if (_l["sport"] != "") _cmd = _cmd portstr("src", _l["sport"])
+               if (_l["dport"] != "") _cmd = _cmd portstr("dest", _l["dport"])
+       }
+       if (_l["layer7"] != "") {
+               if (insmod_l7 != 1) {
+                       print "insmod ipt_layer7 >&- 2>&-"
+                       insmod_l7 = 1
+               }
+               _cmd = _cmd " -m layer7 --l7proto " _l["layer7"]
+       }
+       return _cmd
+}
+
+function str2data(str) {
+       delete _l
+       _n = split(str, _o, "[\t ]")
+       for (_i = 1; _i <= _n; _i++) {
+               _n2 = split(_o[_i], _c, "=")
+               if (_n2 == 2) _l[_c[1]] = _c[2]
+       }
+}
diff --git a/openwrt/package/base-files/default/usr/lib/firewall.awk b/openwrt/package/base-files/default/usr/lib/firewall.awk
new file mode 100644 (file)
index 0000000..d5fba05
--- /dev/null
@@ -0,0 +1,64 @@
+BEGIN {
+       print "proto=\"$(nvram get wan_proto)\""
+       print "[ -z \"$proto\" -o \"$proto\" = \"none\" ] && exit"
+       print "ifname=\"$(nvram get wan_ifname)\""
+       print "[ -z \"$ifname\" ] && exit"
+       print ""
+       print "iptables -X input_$ifname 2>&- >&-"
+       print "iptables -N input_$ifname"
+       print "iptables -X forward_$ifname 2>&- >&-"
+       print "iptables -N forward_$ifname"
+       print "iptables -t nat -X prerouting_$ifname 2>&- >&-"
+       print "iptables -t nat -N prerouting_$ifname"
+       print ""
+       print "iptables -A input_rule -i \"$ifname\" -j input_$ifname"
+       print "iptables -A forwarding_rule -i \"$ifname\" -j forward_$ifname"
+       print "iptables -t nat -A prerouting_rule -i \"$ifname\" -j prerouting_$ifname"
+       print ""
+       FS=":"
+}
+
+($1 == "accept") || ($1 == "drop") || ($1 == "forward") {
+       delete _opt
+       str2data($2)
+       if ((_l["proto"] == "") && (_l["sport"] _l["dport"] != "")) {
+               _opt[0] = " -p tcp"
+               _opt[1] = " -p udp"
+       } else {
+               _opt[0] = ""
+       }
+}
+
+($1 == "accept") {
+       target = " -j ACCEPT"
+       for (o in _opt) {
+               print "iptables -t nat -A prerouting_$ifname" _opt[o] str2ipt($2) target
+               print "iptables        -A input_$ifname     " _opt[o] str2ipt($2) target
+               print ""
+       }
+}
+
+($1 == "drop") {
+       for (o in _opt) {
+               print "iptables -t nat -A prerouting_$ifname" _opt[o] str2ipt($2) " -j DROP"
+               print ""
+       }
+}
+
+($1 == "forward") {
+       target = " -j DNAT --to " $3
+       fwopts = ""
+       if ($4 != "") {
+               if ((_l["proto"] == "tcp") || (_l["proto"] == "udp") || (_l["proto"] == "")) {
+                       if (_l["proto"] != "") fwopts = " -p " _l["proto"]
+                       fwopts = fwopts " --dport " $4
+                       target = target ":" $4
+               }
+               else fwopts = ""
+       }
+       for (o in _opt) {
+               print "iptables -t nat -A prerouting_$ifname" _opt[o] str2ipt($2) target
+               print "iptables        -A forward_$ifname   " _opt[o] " -d " $3 fwopts " -j ACCEPT"
+               print ""
+       }
+}
index be064d856b97d755c879dd8c2b0a7654b81df49b..4c317bd68e5b83ed7b2c37fbbf043c28b7b5d80d 100644 (file)
@@ -1,3 +1,4 @@
+/etc/config/firewall
 /etc/firewall.user
 /etc/group
 /etc/hosts
diff --git a/openwrt/package/webif/files/usr/lib/webif/apply-firewall.sh b/openwrt/package/webif/files/usr/lib/webif/apply-firewall.sh
new file mode 100644 (file)
index 0000000..8d33ec8
--- /dev/null
@@ -0,0 +1,3 @@
+HANDLERS_file="${HANDLERS_file}
+       firewall) mv /tmp/.webif/file-firewall /etc/config/firewall && /etc/init.d/S45firewall;;
+"
diff --git a/openwrt/package/webif/files/www/cgi-bin/webif/firewall.sh b/openwrt/package/webif/files/www/cgi-bin/webif/firewall.sh
new file mode 100755 (executable)
index 0000000..0fd84f8
--- /dev/null
@@ -0,0 +1,333 @@
+#!/usr/bin/webif-page
+<? 
+. /usr/lib/webif/webif.sh
+
+mkdir -p /tmp/.webif
+exists /tmp/.webif/file-firewall && FW_FILE=/tmp/.webif/file-firewall || FW_FILE=/etc/config/firewall
+exists "$FW_FILE" || touch "$FW_FILE" >&- 2>&-
+FW_FILE_NEW="/tmp/.webif/file-firewall-new"
+
+empty "$FORM_cancel" || {
+       FORM_save=""
+       FORM_edit=""
+}
+
+empty "$FORM_save" || {
+       SAVED=1
+       case "$FORM_proto" in
+               tcp|udp|"") proto_valid=1;;
+               *) proto_valid=invalid;;
+       esac
+       validate <<EOF
+int|proto_valid|@TR<<Protocol>>||$proto_valid
+string|FORM_target|@TR<<Target>>|required|$FORM_target
+string|FORM_proto|@TR<<Protocol>>||$FORM_proto
+ip|FORM_src|@TR<<Source IP>>||$FORM_src
+ip|FORM_dest|@TR<<Destination IP>>||$FORM_dest
+ports|FORM_sport|@TR<<Source Ports>>||$FORM_sport
+ports|FORM_dport|@TR<<Destination Ports>>||$FORM_dport
+ip|FORM_target_ip|@TR<<Forward to>>||$FORM_target_ip
+port|FORM_target_port|@TR<<Port>>||$FORM_target_port
+EOF
+       equal "$?" 0 || {
+               unset FORM_save
+       }
+       equal "$FORM_target" "forward" && empty "$FORM_target_ip$FORM_target_port" && {
+               ERROR="${ERROR}@TR<<No_Target_IP_Port|Target IP and Port cannot both be empty>><br />"
+               FORM_save=""
+       }
+}
+
+empty "$FORM_up$FORM_down$FORM_save$FORM_delete$FORM_new" || {
+       empty "$FORM_up" || equal "$FORM_up" 1 || {
+               FORM_down="$(($FORM_up - 1))"
+       }
+       awk \
+               -v down="$FORM_down" \
+               -v save="$FORM_save" \
+               -v del="$FORM_delete" \
+               -v edit="$FORM_edit" \
+               -v proto="$FORM_proto" \
+               -v src="$FORM_src" \
+               -v sport="$FORM_sport" \
+               -v dest="$FORM_dest" \
+               -v dport="$FORM_dport" \
+               -v layer7="$FORM_layer7" \
+               -v target="$FORM_target" \
+               -v target_ip="$FORM_target_ip" \
+               -v target_port="$FORM_target_port" \
+               -v new="$FORM_new" \
+               -v new_target="$FORM_new_target" \
+               -f - "$FW_FILE" > "$FW_FILE_NEW" <<EOF
+BEGIN {
+       FS=":"
+}
+
+function addnew(new) {
+       new = target ":";
+       if (proto != "") new = new "proto=" proto " "
+       if (src != "") new = new "src=" src " "
+       if (dest != "") new = new "dest=" dest " "
+       if (sport != "") new = new "sport=" sport " "
+       if (dport != "") new = new "dport=" dport " "
+       if (layer7 != "") new = new "layer7=" layer7 " "
+       gsub(/ $/, "", new);
+       if (target == "forward") {
+               new = new ":" target_ip
+               if (target_port != "") new = new ":" target_port
+       }
+       print new
+}
+
+(\$1 == "drop") || (\$1 == "accept") || (\$1 == "forward" ) {
+       n++
+       if (noprint == 1) {
+               noprint = 0
+       }
+       if (down == n) {
+               line_down = \$0
+               noprint = 1
+       }
+       if (del == n) {
+               noprint = 1
+       }
+       if (edit == n) {
+               if ((target == "forward") && (target == \$1)) {
+                       noprint = 1
+               }
+               if ((\$1 != "forward") && ((target == "accept") || (target == "drop"))) {
+                       noprint = 1
+               }
+               if (noprint == 1) {
+                       addnew()
+               }
+       }
+}
+
+{
+       if ((\$1 == "drop") || (\$1 == "accept") || (\$1 == "forward" )) {
+               if (noprint != 1) print \$0
+       } else {
+               print \$0
+       }
+}
+
+(line_down != "") && (n > down) {
+       print line_down
+       line_down = ""
+}
+
+END {
+       if (line_down != "") print line_down
+       if (new_target == "forward") new_target = new_target "::192.168.1.1"
+       if ((new != "") && (new_target != "")) print new_target
+}
+EOF
+       FW_FILE=/tmp/.webif/file-firewall
+       mv "$FW_FILE_NEW" "$FW_FILE"
+       empty "$FORM_new" && FORM_edit=""
+}
+
+header "Network" "Firewall" "@TR<<Firewall Configuration>>" ''
+
+?>
+<style>
+td.edit_title {
+       font-weight: bold;
+       text-align: right;
+       padding-top: 0.8em;
+       padding-right: 0.5em;
+       padding-bottom: auto;
+}
+td.match_title {
+       width: 10em;
+       text-align: right;
+       padding-top: 0.8em;
+       padding-right: 0.5em;
+       padding-bottom: auto;
+}
+</style>
+<?
+
+awk \
+       -v edit="$FORM_edit" \
+       -v save="$FORM_save" \
+       -v proto="$FORM_proto" \
+       -v src="$FORM_src" \
+       -v sport="$FORM_sport" \
+       -v dest="$FORM_dest" \
+       -v dport="$FORM_dport" \
+       -v layer7="$FORM_layer7" \
+       -v target="$FORM_target" \
+       -v target_ip="$FORM_target_ip" \
+       -v target_port="$FORM_target_port" \
+       -v del_proto="$FORM_del_proto" \
+       -v del_src="$FORM_del_src" \
+       -v del_sport="$FORM_del_sport" \
+       -v del_dest="$FORM_del_dest" \
+       -v del_dport="$FORM_del_dport" \
+       -v del_layer7="$FORM_del_layer7" \
+       -v data_submit="$FORM_data_submit" \
+       -v new_match="$FORM_new_match" \
+       -f /usr/lib/webif/common.awk \
+       -f /usr/lib/common.awk \
+       -f - "$FW_FILE" <<EOF
+function set_data() {
+       _l["proto"] = proto
+       _l["src"] = src
+       _l["sport"] = sport
+       _l["dest"] = dest
+       _l["dport"] = dport
+       _l["layer7"] = layer7
+       
+       if (del_proto != "") _l["proto"] = ""
+       if (del_src != "") _l["src"] = ""
+       if (del_sport != "") _l["sport"] = ""
+       if (del_dest != "") _l["dest"] = ""
+       if (del_dport != "") _l["dport"] = ""
+       if (del_layer7 != "") _l["layer7"] = ""
+}
+function iptstr2web(str, ret) {
+       ret = ""
+       str2data(str);
+       if (_l["proto"] != "") ret = ret "@TR<<Protocol>>: " _l["proto"] "<br />"
+       if (_l["src"] != "") ret = ret "@TR<<Source IP>>: " _l["src"] "<br />"
+       if (_l["sport"] != "") ret = ret "@TR<<Source Ports>>: " _l["sport"] "<br />"
+       if (_l["dest"] != "") ret = ret "@TR<<Destination IP>>: " _l["dest"] "<br />"
+       if (_l["dport"] != "") ret = ret "@TR<<Destination Ports>>: " _l["dport"] "<br />"
+#      if (_l["layer7"] != "") ret = ret "@TR<<Application Protocol>>: " _l["layer7"] "<br />"
+       if (ret == "") ret = ret "@TR<<Everything>>"
+       return ret
+}
+function delbutton(name) {
+       return button("del_" name, "Delete")
+}
+function input_line(caption, name, value) {
+       return "<tr><td class=\\"match_title\\">@TR<<" caption ">>: </td><td>" textinput(name, value) delbutton(name) "</td></tr>"
+}
+function iptstr2edit(str, edit) {
+       edit = ""
+       str2data(str);
+       if (int(data_submit) == 1) set_data()
+       if (new_match == "proto") _l["proto"] = "tcp"
+       if ((new_match == "src") || (new_match == "dest")) _l[new_match] = "0.0.0.0"
+       if ((new_match == "sport") || (new_match == "dport")) _l[new_match] = "0"
+       if ((new_match != "") && (_l[new_match] == "")) _l[new_match] = " "
+       
+       if (_l["proto"] != "") {
+               edit = edit "<tr><td class=\\"match_title\\">@TR<<Protocol>>: </td><td>"
+               edit = edit "<select name=\\"proto\\">"
+               edit = edit sel_option("tcp", "TCP", _l["proto"])
+               edit = edit sel_option("udp", "UDP", _l["proto"])
+               edit = edit "</select>" delbutton("proto")
+               edit = edit "</td></tr>"
+       }
+       if (_l["src"] != "") edit = edit input_line("Source IP", "src", _l["src"])
+       if (_l["sport"] != "") edit = edit input_line("Source Ports", "sport", _l["sport"])
+       if (_l["dest"] != "") edit = edit input_line("Destination IP", "dest", _l["dest"])
+       if (_l["dport"] != "") edit = edit input_line("Destination Ports", "dport", _l["dport"])
+       if (_l["layer7"] != "") edit = edit input_line("Application Protocol", "layer7", _l["layer7"])
+
+       edit = edit "<tr><td class=\\"match_title\\">&nbsp;</td><td><select name=\\"new_match\\">"
+       edit = edit sel_option("none", "---")
+       if (_l["proto"] == "") edit = edit sel_option("proto", "Protocol")
+       if (_l["src"] == "") edit = edit sel_option("src", "Source IP")
+       if (_l["dest"] == "") edit = edit sel_option("dest", "Destination IP")
+       if ((_l["proto"] == "tcp") || (_l["proto"] == "udp") || (_l["proto"] == "")) {
+               if (_l["sport"] == "") edit = edit sel_option("sport", "Source Ports")
+               if (_l["dport"] == "") edit = edit sel_option("dport", "Destination Ports")
+#              if (_l["layer7"] == "") edit = edit sel_option("layer7", "Application Protocol")
+       }
+       edit = edit "</select>"
+       edit = edit button("add_match", "Add") "</td></tr>"
+
+       return edit
+}
+
+BEGIN {
+       print start_form("@TR<<Firewall Rules>>");
+       print "<table width=\\"100%\\">"
+       print "<tr><th>@TR<<Match>></th><th>@TR<<Target>></th><th>@TR<<Port>></th><th>&nbsp;</th></tr>"
+       FS=":"
+       n = 0
+}
+
+(\$1 == "drop") || (\$1 == "accept") || (\$1 == "forward" ) {
+       n++
+       print "<tr><td colspan=\\"5\\"><hr class=\\"separator\\" /></td></tr>"
+       if (n == edit) {
+               print "<form enctype=\\"multipart/form-data\\" method=\\"post\\" action=\\"$SCRIPT_NAME\\">"
+               print hidden("data_submit", "1") hidden("edit", edit)
+               print "<tr><td colspan=\\"5\\">"
+               print "<table width=\\"100%\\">"
+               print iptstr2edit(\$2)
+               print "<tr><td><hr class=\\"separator\\" /></td><td>&nbsp;</td></tr>"
+       } else {
+               printf "<tr><td>" iptstr2web(\$2) "</td>"
+       }
+}
+
+(\$1 == "drop") || (\$1 == "accept") {
+       if (n == edit) {
+               if (int(data_submit) == 1) \$1 = target
+               printf "<tr>"
+               printf "<td class=\\"edit_title\\">@TR<<Target>>:</td><td>"
+               printf "<select name=\\"target\\">"
+               printf sel_option("accept", "Accept", \$1)
+               printf sel_option("drop", "Drop", \$1)
+               printf "</td>"
+               printf "</tr>"
+       } else {
+               printf "<td colspan=\\"2\\">" \$1 "</td>"
+       }
+}
+
+\$1 == "forward" {
+       if (n == edit) {
+               if (target_ip == "") target_ip = \$3
+               if (target_port == "") target_port = \$4
+               print "<tr><td class=\\"edit_title\\">@TR<<Forward to>>:</b></td><td>" textinput("target_ip", target_ip) hidden("target", "forward") "</td></tr>"
+               print "<tr><td class=\\"edit_title\\">@TR<<Port>>:</b></td><td>" textinput("target_port", target_port) "</td></tr>"
+       } else {
+               if (\$3 \$4 == "") \$3 = "forward"
+               printf "<td>" \$3 "</td><td>" \$4 "</td>"
+       }
+}
+
+(\$1 == "drop") || (\$1 == "accept") || (\$1 == "forward" ) {
+       if (n == edit) {
+               printf "<tr><td>&nbsp;</td><td>" button("save", "Save") button("cancel", "Cancel") "</td></tr>"
+               
+               print "</table>"
+               print "</td></tr>"
+               print "</form>"
+       } else {
+               printf "<td style=\\"text-align: right; padding-right: 0.5em\\">"
+               printf "<a href=\\"$SCRIPT_NAME?up=" n "\\">@TR<<Up>></a><br />"
+               printf "<a href=\\"$SCRIPT_NAME?down=" n "\\">@TR<<Down>></a>"
+               printf "</td><td>"
+               printf "<a href=\\"$SCRIPT_NAME?edit=" n "\\">@TR<<Edit>></a><br />"
+               printf "<a href=\\"$SCRIPT_NAME?delete=" n "\\">@TR<<Delete>></a>"
+               print "</td></tr>"
+       }
+}
+
+END {
+       print "<tr><td colspan=\\"5\\"><hr class=\\"separator\\" /></td></tr>"
+       print "<tr><td class=\\"edit_title\\">@TR<<New Rule>>: </td><td colspan=\\"4\\">"
+       print "<form method=\\"POST\\" action=\\"$SCRIPT_NAME\\" enctype=\\"multipart/form-data\\">"
+       print hidden("edit", n + 1);
+       print "<select name=\\"new_target\\">"
+       print sel_option("forward", "Forward")
+       print sel_option("accept", "Accept")
+       print sel_option("drop", "Drop")
+       print "</select>" button("new", "Add") "</form></td></tr>"
+       print "</table>"
+       print end_form("...");
+}
+EOF
+
+footer ?>
+<!--
+##WEBIF:name:Network:9:Firewall
+-->