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