From 9a8de13739d797ae324dcf0387f24eda3cdcb4a9 Mon Sep 17 00:00:00 2001 From: Clinton Ebadi Date: Mon, 26 Mar 2012 23:06:39 -0400 Subject: [PATCH] Per-host firewall rules * The implementation is ugly (terribleness with tuples, filtering at generation time, etc.), but my SML-fu is too weak to do this properly in a time efficient manner * Needs to check if user has some domtool permission to that node, ideally --- src/plugins/firewall.sig | 4 ++-- src/plugins/firewall.sml | 38 +++++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/plugins/firewall.sig b/src/plugins/firewall.sig index 0bb8611..3283824 100644 --- a/src/plugins/firewall.sig +++ b/src/plugins/firewall.sig @@ -21,8 +21,8 @@ signature FIREWALL = sig - type firewall_rules = { server_rules : (string list DataStructures.StringMap.map), - client_rules : (string list DataStructures.StringMap.map)} + type firewall_rules = { server_rules : ((string * string) list DataStructures.StringMap.map), + client_rules : ((string * string) list DataStructures.StringMap.map)} val query : string -> string list (* List a user's local firewall rules. *) diff --git a/src/plugins/firewall.sml b/src/plugins/firewall.sml index 70c45b5..378e127 100644 --- a/src/plugins/firewall.sml +++ b/src/plugins/firewall.sml @@ -23,20 +23,20 @@ structure Firewall :> FIREWALL = struct -type firewall_rules = { server_rules : (string list DataStructures.StringMap.map), - client_rules : (string list DataStructures.StringMap.map)} +type firewall_rules = { server_rules : ((string * string) list DataStructures.StringMap.map), + client_rules : ((string * string) list DataStructures.StringMap.map)} structure StringMap = DataStructures.StringMap -fun parseRules _ = +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) = + fun confLine r (node, uname, line) = let - val line = String.concat ["\t", line, "\n"] + val line = (node, String.concat ["\t", line, "\n"]) val lines = case StringMap.find (!r, uname) of NONE => [] | SOME lines => lines @@ -63,14 +63,14 @@ fun parseRules _ = NONE => () | SOME line => case String.tokens Char.isSpace line of - uname :: rest => + node :: uname :: rest => (case rest of "Client" :: ports :: hosts => - confLine_out (uname, String.concat ["dport ", parsePorts ports, parseHosts "daddr" hosts, " ACCEPT;"]) + confLine_out (node, 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;"]) + confLine_in (node, uname, String.concat ["dport ", parsePorts ports, parseHosts "daddr" hosts, " ACCEPT;"]) | ["LocalServer", ports] => - confLine_in (uname, String.concat ["saddr $WE dport ", parsePorts ports, " ACCEPT;"]) + confLine_in (node, uname, String.concat ["saddr $WE dport ", parsePorts ports, " ACCEPT;"]) | _ => print "Invalid config line\n"; loop ()) | _ => loop () @@ -83,22 +83,30 @@ fun query uname = let val rules = parseRules () in - getOpt (StringMap.find (#server_rules rules, uname), []) @ getOpt (StringMap.find (#client_rules rules, uname), []) + List.map (fn (n,r) => r ^ " #host: " ^ n) (getOpt (StringMap.find (#server_rules rules, uname), []) @ getOpt (StringMap.find (#client_rules rules, uname), [])) end fun generateFirewallConfig {server_rules, client_rules} = -(* rule generation must happen on the node (not really, but I'd rather - avoid codifying that uids must be consistent between hosts) *) + (* rule generation must happen on the node (mandating the even + service users be pts users would make it possible to do on the + server, but that's not happening any time soon) *) let 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") + val users_conf = TextIO.openOut (Config.Firewall.firewallDir ^ "/user_chains.conf") + + fun filter_node_rules lines = + (* filter out rules for other hosts here... really not + ideal, but it should work for the time being *) + List.map (fn (node, line) => line) + (List.filter (fn (node, line) => node = Slave.hostname ()) lines) fun write_user_tcp_conf (rules, outf, suffix) = - StringMap.appi (fn (uname, lines) => + StringMap.appi (fn (uname, rules) => let val uid = SysWord.toInt (Posix.ProcEnv.uidToWord (Posix.SysDB.Passwd.uid (Posix.SysDB.getpwnam uname))) + val lines = filter_node_rules rules in TextIO.output (outf, String.concat ["mod owner uid-owner ", @@ -106,7 +114,7 @@ fun generateFirewallConfig {server_rules, client_rules} = " { goto user_", uname, suffix, - "; goto lreject; }\n"]); + "; DROP; }\n"]); (* Is there any point to splitting the rules like this? *) TextIO.output (users_conf, String.concat ("chain user_" -- 2.20.1