1 (* HCoop
Domtool (http
://hcoop
.sourceforge
.net
/)
2 * Copyright (c
) 2006-2007, Adam Chlipala
3 * Copyright (c
) 2011 Clinton Ebadi
5 * This program is free software
; you can redistribute it
and/or
6 * modify it under the terms
of the GNU General Public License
7 * as published by the Free Software Foundation
; either version
2
8 * of the License
, or (at your option
) any later version
.
10 * This program is distributed
in the hope that it will be useful
,
11 * but WITHOUT ANY WARRANTY
; without even the implied warranty
of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
. See the
13 * GNU General Public License for more details
.
15 * You should have received a copy
of the GNU General Public License
16 * along
with this program
; if not
, write to the Free Software
17 * Foundation
, Inc
., 51 Franklin Street
, Fifth Floor
, Boston
, MA
02110-1301, USA
.
20 (* Firewall management
*)
22 (* Contains portions from Fwtool
Copyright (C
) 2005 Adam Chlipala
, GPL v2 or later
*)
24 structure Firewall
:> FIREWALL
= struct
26 type firewall_rules
= { server_rules
: (string list DataStructures
.StringMap
.map
),
27 client_rules
: (string list DataStructures
.StringMap
.map
)}
29 structure StringMap
= DataStructures
.StringMap
33 val inf
= TextIO.openIn Config
.Firewall
.firewallRules
34 val out_lines
= ref StringMap
.empty
35 val in_lines
= ref StringMap
.empty
37 fun confLine
r (uname
, line
) =
39 val line
= String.concat
["\t", line
, "\n"]
40 val lines
= case StringMap
.find (!r
, uname
) of
44 r
:= StringMap
.insert (!r
, uname
, line
:: lines
)
47 val confLine_in
= confLine in_lines
48 val confLine_out
= confLine out_lines
50 fun parsePorts ports
=
51 case String.fields (fn ch
=> ch
= #
",") ports
of
53 | pps
=> String.concat
["(", String.concatWith
" " pps
, ")"]
55 fun parseHosts addr hosts
=
58 |
[host
] => String.concat
[" ", addr
, " ", host
]
59 | _
=> String.concat
[" ", addr
, " (", String.concatWith
" " hosts
, ")"]
62 case TextIO.inputLine inf
of
65 case String.tokens
Char.isSpace line
of
68 "Client" :: ports
:: hosts
=>
69 confLine_out (uname
, String.concat
["dport ", parsePorts ports
, parseHosts
"daddr" hosts
, " ACCEPT;"])
70 |
"Server" :: ports
:: hosts
=>
71 confLine_in (uname
, String.concat
["dport ", parsePorts ports
, parseHosts
"daddr" hosts
, " ACCEPT;"])
72 |
["LocalServer", ports
] =>
73 confLine_in (uname
, String.concat
["saddr $WE dport ", parsePorts ports
, " ACCEPT;"])
74 | _
=> print
"Invalid config line\n";
79 {server_rules
= !in_lines
, client_rules
= !out_lines
}
84 val rules
= parseRules ()
86 getOpt (StringMap
.find (#server_rules rules
, uname
), []) @
getOpt (StringMap
.find (#client_rules rules
, uname
), [])
90 fun generateFirewallConfig
{server_rules
, client_rules
} =
91 (* rule generation must happen on the
node (not really
, but I
'd rather
92 avoid codifying that uids must be consistent between hosts
) *)
94 val users_tcp_out_conf
= TextIO.openOut (Config
.Firewall
.firewallDir ^
"/users_tcp_out.conf")
95 val users_tcp_in_conf
= TextIO.openOut (Config
.Firewall
.firewallDir ^
"/users_tcp_in.conf")
96 val users_conf
= TextIO.openOut (Config
.Firewall
.firewallDir ^
"/users.conf")
98 fun write_user_tcp_conf (rules
, outf
, suffix
) =
99 StringMap
.appi (fn (uname
, lines
) =>
101 val uid
= SysWord
.toInt (Posix
.ProcEnv
.uidToWord (Posix
.SysDB
.Passwd
.uid (Posix
.SysDB
.getpwnam uname
)))
103 TextIO.output (outf
, String.concat
104 ["mod owner uid-owner ",
109 "; goto lreject; }\n"]);
110 (* Is there any point to splitting the rules like this?
*)
111 TextIO.output (users_conf
,
112 String.concat ("chain user_"
118 end handle OS
.SysErr _
=> print
"Invalid user in firewall config, skipping.\n")
121 write_user_tcp_conf (server_rules
, users_tcp_in_conf
, "_tcp_in");
122 write_user_tcp_conf (client_rules
, users_tcp_out_conf
, "_tcp_out");
124 TextIO.closeOut users_conf
;
125 TextIO.closeOut users_tcp_out_conf
;
126 TextIO.closeOut users_tcp_in_conf
;
131 fun publishConfig _
=
132 Slave
.shell
[Config
.Firewall
.reload
]