Per-host firewall rules
authorClinton Ebadi <clinton@unknownlamer.org>
Tue, 27 Mar 2012 03:06:39 +0000 (23:06 -0400)
committerClinton Ebadi <clinton@unknownlamer.org>
Tue, 27 Mar 2012 03:06:39 +0000 (23:06 -0400)
* 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
src/plugins/firewall.sml

index 0bb8611..3283824 100644 (file)
@@ -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. *)
index 70c45b5..378e127 100644 (file)
 
 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_"