From ec95f39fbe75c414e53f5f922b75390a0179e916 Mon Sep 17 00:00:00 2001 From: Clinton Ebadi Date: Tue, 29 Nov 2011 02:08:16 -0500 Subject: [PATCH] Port firewall generation from Domtool1/fwtool * fwtool was a bit of a hack -- try to clean things up... * Parsing and generating the config are split (somewhat) * Only one set of rules for all nodes with a firewall --- configDefault/firewall.cfg | 8 +++ configDefault/firewall.cfs | 1 + configDefault/firewall.csg | 7 +++ src/plugins/firewall.sig | 2 + src/plugins/firewall.sml | 119 +++++++++++++++++++++++++++++++------ 5 files changed, 118 insertions(+), 19 deletions(-) create mode 100644 configDefault/firewall.cfg create mode 100644 configDefault/firewall.cfs create mode 100644 configDefault/firewall.csg diff --git a/configDefault/firewall.cfg b/configDefault/firewall.cfg new file mode 100644 index 0000000..f07ecad --- /dev/null +++ b/configDefault/firewall.cfg @@ -0,0 +1,8 @@ +(* -*- sml -*- *) +structure Firewall :> FIREWALL_CONFIG = struct + +val firewallRules = "/home/clinton/misc/hcoop/firewall/user.rules" +val firewallDir = "/home/clinton/misc/hcoop/firewall/output" +val firewallNodes = ["bog"] + +end diff --git a/configDefault/firewall.cfs b/configDefault/firewall.cfs new file mode 100644 index 0000000..b21e779 --- /dev/null +++ b/configDefault/firewall.cfs @@ -0,0 +1 @@ +structure Firewall : FIREWALL_CONFIG diff --git a/configDefault/firewall.csg b/configDefault/firewall.csg new file mode 100644 index 0000000..95bb6bd --- /dev/null +++ b/configDefault/firewall.csg @@ -0,0 +1,7 @@ +(* -*- sml -*- *) +signature FIREWALL_CONFIG = sig + + val firewallNodes : string list (* Nodes to firewall *) + val firewallDir : string (* Output directory for ferm config *) + val firewallRules : string (* Rules file *) +end diff --git a/src/plugins/firewall.sig b/src/plugins/firewall.sig index ec30375..94a838a 100644 --- a/src/plugins/firewall.sig +++ b/src/plugins/firewall.sig @@ -23,4 +23,6 @@ signature FIREWALL = sig val query : string -> string list (* List a user's local firewall rules. *) + val generateFirewallConfig : unit -> unit + end diff --git a/src/plugins/firewall.sml b/src/plugins/firewall.sml index 6a4bb30..65c9db1 100644 --- a/src/plugins/firewall.sml +++ b/src/plugins/firewall.sml @@ -1,5 +1,6 @@ (* HCoop Domtool (http://hcoop.sourceforge.net/) * Copyright (c) 2006-2007, Adam Chlipala + * Copyright (c) 2011 Clinton Ebadi * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -16,31 +17,111 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *) -(* Firewall rule querying *) +(* Firewall management *) + +(* Contains portions from Fwtool Copyright (C) 2005 Adam Chlipala, GPL v2 or later *) structure Firewall :> FIREWALL = struct +structure StringMap = DataStructures.StringMap + +fun parseRules _ = + let + val inf = TextIO.openIn Config.Firewall.firewallRules + val out_lines = ref StringMap.empty + val in_lines = ref StringMap.empty + + fun confLine r (uname, line) = + let + val line = String.concat ["\t", line, "\n"] + val lines = case StringMap.find (!r, uname) of + NONE => [] + | SOME lines => lines + in + r := StringMap.insert (!r, uname, line :: lines) + end + + val confLine_in = confLine in_lines + val confLine_out = confLine out_lines + + fun parsePorts ports = + case String.fields (fn ch => ch = #",") ports of + [pp] => pp + | pps => String.concat ["(", String.concatWith " " pps, ")"] + + fun parseHosts addr hosts = + case hosts of + [] => "" + | [host] => String.concat [" ", addr, " ", host] + | _ => String.concat [" ", addr, " (", String.concatWith " " hosts, ")"] + + fun loop () = + case TextIO.inputLine inf of + NONE => () + | SOME line => + case String.tokens Char.isSpace line of + uname :: rest => + (case rest of + "Client" :: ports :: hosts => + confLine_out (uname, String.concat ["dport ", parsePorts ports, parseHosts "daddr" hosts, " ACCEPT;"]) + | "Server" :: ports :: hosts => + confLine_in (uname, String.concat ["dport ", parsePorts ports, parseHosts "daddr" hosts, " ACCEPT;"]) + | ["LocalServer", ports] => + confLine_in (uname, String.concat ["saddr $WE dport ", parsePorts ports, " ACCEPT;"]) + | _ => print "Invalid config line\n"; + loop ()) + | _ => loop () + val _ = loop () + in + {server_rules = !in_lines, client_rules = !out_lines} + end + fun query uname = let - val inf = TextIO.openIn "/etc/firewall/users.rules" - - fun loop rules = - case TextIO.inputLine inf of - NONE => List.rev rules - | SOME line => - if String.sub (line, 0) = #"#" then - loop rules - else case String.tokens Char.isSpace line of - uname'::rest => - if uname = uname' then - loop (String.concatWith " " rest :: rules) - else - loop rules - | _ => loop rules + val rules = parseRules () in - loop [] - before TextIO.closeIn inf - end handle IO.Io _ => [] + getOpt (StringMap.find (#server_rules rules, uname), []) @ getOpt (StringMap.find (#client_rules rules, uname), []) + end + +fun generateFirewallConfig _ = +(* rule generation must happen on the node (not really, but I'd rather + avoid codifying that uids must be consistent between hosts) *) + let + val {server_rules, client_rules} = parseRules () + val users_tcp_out_conf = TextIO.openOut (Config.Firewall.firewallDir ^ "/users_tcp_out.conf") + val users_tcp_in_conf = TextIO.openOut (Config.Firewall.firewallDir ^ "/users_tcp_in.conf") + val users_conf = TextIO.openOut (Config.Firewall.firewallDir ^ "/users.conf") + + fun write_user_tcp_conf (rules, outf, suffix) = + StringMap.appi (fn (uname, lines) => + let + val uid = SysWord.toInt (Posix.ProcEnv.uidToWord (Posix.SysDB.Passwd.uid (Posix.SysDB.getpwnam uname))) + in + TextIO.output (outf, String.concat + ["mod owner uid-owner ", + Int.toString uid, + " { goto user_", + uname, + suffix, + "; goto lreject; }\n"]); + (* Is there any point to splitting the rules like this? *) + TextIO.output (users_conf, + String.concat ("chain user_" + :: uname + :: suffix + :: " proto tcp {\n" + :: lines + @ ["}\n\n"])) + end handle OS.SysErr _ => print "Invalid user in firewall config, skipping.\n") + rules + in + write_user_tcp_conf (server_rules, users_tcp_in_conf, "_tcp_in"); + write_user_tcp_conf (client_rules, users_tcp_out_conf, "_tcp_out"); + TextIO.closeOut users_conf; + TextIO.closeOut users_tcp_out_conf; + TextIO.closeOut users_tcp_in_conf + end + end -- 2.20.1