1 /*
2
3 Firewall Builder
4
5 Copyright (C) 2009 NetCitadel, LLC
6
7 Author: Vadim Kurland vadim@vk.crocodile.org
8
9 $Id$
10
11 This program is free software which we release under the GNU General Public
12 License. You may redistribute and/or modify this program under the terms
13 of that license as published by the Free Software Foundation; either
14 version 2 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 To get a copy of the GNU General Public License, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
24 */
25
26 #include "../../config.h"
27
28 #include "CompilerDriver_ipt.h"
29 #include "MangleTableCompiler_ipt.h"
30 #include "PolicyCompiler_ipt.h"
31 #include "PolicyCompiler_secuwall.h"
32 #include "OSConfigurator_linux24.h"
33
34 #include "Configlet.h"
35
36 #include "fwbuilder/FWObjectDatabase.h"
37 #include "fwbuilder/FWException.h"
38 #include "fwbuilder/Firewall.h"
39 #include "fwbuilder/Interface.h"
40 #include "fwbuilder/Policy.h"
41 #include "fwbuilder/Resources.h"
42 #include "fwbuilder/Library.h"
43
44 #include <fstream>
45 #include <iostream>
46 #include <memory>
47
48
49 using namespace std;
50 using namespace libfwbuilder;
51 using namespace fwcompiler;
52
53 // we always first process all non-top rule sets, then all top rule
54 // sets
processPolicyRuleSet(Firewall * fw,FWObject * ruleset,const string & single_rule_id,ostringstream & filter_rules_stream,ostringstream & mangle_rules_stream,ostringstream & automatic_rules_stream,ostringstream & automatic_mangle_stream,OSConfigurator_linux24 * oscnf,int policy_af,std::map<const std::string,bool> & minus_n_commands_filter,std::map<const std::string,bool> & minus_n_commands_mangle)55 bool CompilerDriver_ipt::processPolicyRuleSet(
56 Firewall *fw,
57 FWObject *ruleset,
58 const string &single_rule_id,
59 ostringstream &filter_rules_stream,
60 ostringstream &mangle_rules_stream,
61 ostringstream &automatic_rules_stream,
62 ostringstream &automatic_mangle_stream,
63 OSConfigurator_linux24 *oscnf,
64 int policy_af,
65 std::map<const std::string, bool> &minus_n_commands_filter,
66 std::map<const std::string, bool> &minus_n_commands_mangle)
67 {
68 int policy_rules_count = 0;
69 int mangle_rules_count = 0;
70 bool empty_output = true;
71 string prolog_place = fw->getOptionsObject()->getStr("prolog_place");
72 string platform = fw->getStr("platform");
73 string host_os = fw->getStr("host_OS");
74 bool flush_and_set_default_policy = Resources::getTargetOptionBool(
75 host_os, "default/flush_and_set_default_policy");
76 string platform_family = Resources::platform_res[platform]->
77 getResourceStr("/FWBuilderResources/Target/family");
78 string os_family = Resources::os_res[host_os]->
79 getResourceStr("/FWBuilderResources/Target/family");
80
81
82 Policy *policy = Policy::cast(ruleset);
83 assignRuleSetChain(policy);
84 string branch_name = policy->getName();
85
86 if (!policy->matchingAddressFamily(policy_af)) return true;
87
88 bool ipv6_policy = (policy_af == AF_INET6);
89
90 std::auto_ptr<MangleTableCompiler_ipt> mangle_compiler(
91 new MangleTableCompiler_ipt(objdb , fw,
92 ipv6_policy , oscnf,
93 &minus_n_commands_mangle ));
94
95 if (!policy->isTop())
96 mangle_compiler->registerRuleSetChain(branch_name);
97
98 mangle_compiler->setSourceRuleSet( policy );
99 mangle_compiler->setRuleSetName(branch_name);
100 mangle_compiler->setPersistentObjects(persistent_objects);
101
102 mangle_compiler->setSingleRuleCompileMode(single_rule_id);
103 mangle_compiler->setDebugLevel( dl );
104 if (rule_debug_on) mangle_compiler->setDebugRule( drp );
105 mangle_compiler->setVerbose( (bool)(verbose) );
106 mangle_compiler->setHaveDynamicInterfaces(have_dynamic_interfaces);
107 if (inTestMode()) mangle_compiler->setTestMode();
108 if (inEmbeddedMode()) mangle_compiler->setEmbeddedMode();
109
110 if ( (mangle_rules_count = mangle_compiler->prolog()) > 0 )
111 {
112 mangle_compiler->compile();
113 mangle_compiler->epilog();
114
115 // We need to generate automatic rules in mangle
116 // table (-j CONNMARK --restore-mark) if CONNMARK
117 // target is present in any ruleset, not only in
118 // the top-level ruleset. So we keep global
119 // boolean flags for this condition which will
120 // become true if any ruleset has such
121 // rules. We'll call
122 // MangleTableCompiler_ipt::flushAndSetDefaultPolicy
123 // later if either of these flags is true after
124 // all rulesets have been processed.
125
126 have_connmark |= mangle_compiler->haveConnMarkRules();
127 have_connmark_in_output |= mangle_compiler->haveConnMarkRulesInOutput();
128
129 long m_str_pos = mangle_rules_stream.tellp();
130
131 if (mangle_compiler->getCompiledScriptLength() > 0)
132 {
133 ostringstream tmp;
134
135 tmp << mangle_compiler->getCompiledScript();
136
137 if (tmp.tellp() > 0)
138 {
139 if (!single_rule_compile_on)
140 {
141 mangle_rules_stream << "# ================ Table 'mangle', ";
142 mangle_rules_stream << "rule set " << branch_name << "\n";
143 }
144 mangle_rules_stream << tmp.str();
145 }
146 }
147
148 if (mangle_compiler->haveErrorsAndWarnings())
149 {
150 all_errors.push_back(mangle_compiler->getErrors("").c_str());
151 mangle_compiler->clearErrors();
152 }
153
154 if (m_str_pos!=mangle_rules_stream.tellp())
155 {
156 //mangle_rules_stream << "\n";
157 empty_output = false;
158 }
159
160 }
161
162 std::auto_ptr<PolicyCompiler_ipt> policy_compiler = createPolicyCompiler(
163 fw, ipv6_policy, oscnf, &minus_n_commands_filter);
164
165 policy_compiler->setSingleRuleCompileMode(single_rule_id);
166 policy_compiler->setDebugLevel( dl );
167 if (rule_debug_on) policy_compiler->setDebugRule( drp );
168 policy_compiler->setVerbose( (bool)(verbose) );
169 policy_compiler->setHaveDynamicInterfaces(have_dynamic_interfaces);
170 if (inTestMode()) policy_compiler->setTestMode();
171 if (inEmbeddedMode()) policy_compiler->setEmbeddedMode();
172 if (!policy->isTop()) policy_compiler->registerRuleSetChain(branch_name);
173
174 policy_compiler->setSourceRuleSet( policy );
175 policy_compiler->setRuleSetName(branch_name);
176 policy_compiler->setPersistentObjects(persistent_objects);
177
178 if ( (policy_rules_count=policy_compiler->prolog()) > 0 )
179 {
180 policy_compiler->compile();
181 policy_compiler->epilog();
182
183 if (policy_compiler->getCompiledScriptLength() > 0)
184 {
185 ostringstream tmp;
186
187 tmp << policy_compiler->getCompiledScript();
188
189 if (tmp.tellp() > 0)
190 {
191 empty_output = false;
192 if (!single_rule_compile_on)
193 {
194 filter_rules_stream << "# ================ Table 'filter', ";
195 filter_rules_stream << "rule set " << branch_name << "\n";
196 }
197 filter_rules_stream << tmp.str();
198 }
199 }
200
201 if (policy_compiler->haveErrorsAndWarnings())
202 {
203 all_errors.push_back(policy_compiler->getErrors("").c_str());
204 policy_compiler->clearErrors();
205 }
206 }
207
208 /* bug #2550074: "Automatic rules for filter table included twice
209 * in iptables". If user had two policy ruleset objects marked as
210 * "top" rule set, then automaitc rules were added twice. Since we
211 * add rules to automatic_rules_stream only in this one place, it
212 * is sufficient to check if the stream is empty to avoid
213 * duplication. Note that on windows tellp() seems to return -1
214 * if no data has ever been written to the stream.
215 */
216 long auto_rules_stream_position = automatic_rules_stream.tellp();
217
218 if (policy->isTop() && auto_rules_stream_position <= 0)
219 {
220 ostringstream tmp;
221
222 if (flush_and_set_default_policy)
223 tmp << policy_compiler->flushAndSetDefaultPolicy();
224
225 /*
226 * commented out for #1707
227 *
228
229 if (!prolog_done && prolog_place == "after_flush" &&
230 !fw->getOptionsObject()->getBool("use_iptables_restore"))
231 {
232 tmp << "prolog_commands" << endl;
233 prolog_done = true;
234 }
235 */
236
237 tmp << policy_compiler->printAutomaticRules();
238
239 // printAutomaticRules() can generate errors and warnings
240 if (policy_compiler->haveErrorsAndWarnings())
241 {
242 all_errors.push_back(policy_compiler->getErrors("").c_str());
243 policy_compiler->clearErrors();
244 }
245
246 if (tmp.tellp() > 0)
247 {
248 empty_output = false;
249 if (!single_rule_compile_on)
250 {
251 automatic_rules_stream
252 << "# ================ Table 'filter', automatic rules"
253 << "\n";
254 }
255 automatic_rules_stream << tmp.str();
256 }
257 }
258
259 long auto_mangle_stream_position = automatic_mangle_stream.tellp();
260 if (policy->isTop() && auto_mangle_stream_position <= 0)
261 {
262 // Note that we process non-top rule sets first and then
263 // deal with the top rule set. By the time we get here the
264 // have_connmark flags reflect the state of all other rule
265 // sets and the top one.
266
267 ostringstream tmp_m;
268 tmp_m << mangle_compiler->printAutomaticRulesForMangleTable(
269 have_connmark, have_connmark_in_output);
270
271 // printAutomaticRulesForMangleTable() can generate errors and warnings
272 if (mangle_compiler->haveErrorsAndWarnings())
273 {
274 all_errors.push_back(mangle_compiler->getErrors("").c_str());
275 mangle_compiler->clearErrors();
276 }
277
278 if (tmp_m.tellp() > 0)
279 {
280 if (!single_rule_compile_on)
281 {
282 automatic_mangle_stream << "# ================ Table 'mangle', ";
283 automatic_mangle_stream << "automatic rules";
284 automatic_mangle_stream << "\n";
285 }
286 automatic_mangle_stream << tmp_m.str();
287 }
288 }
289
290 return empty_output;
291 }
292