1 /*
2 
3                           Firewall Builder
4 
5                  Copyright (C) 2002-2011 NetCitadel, LLC
6 
7   Author:  Vadim Kurland     vadim@fwbuilder.org
8 
9   This program is free software which we release under the GNU General Public
10   License. You may redistribute and/or modify this program under the terms
11   of that license as published by the Free Software Foundation; either
12   version 2 of the License, or (at your option) any later version.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18 
19   To get a copy of the GNU General Public License, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 
22 
23 
24 */
25 
26 #include <assert.h>
27 
28 #include "Compiler.h"
29 
30 #include "fwbuilder/RuleElement.h"
31 #include "fwbuilder/IPService.h"
32 #include "fwbuilder/ICMPService.h"
33 #include "fwbuilder/TCPService.h"
34 #include "fwbuilder/UDPService.h"
35 #include "fwbuilder/UserService.h"
36 #include "fwbuilder/CustomService.h"
37 #include "fwbuilder/TagService.h"
38 #include "fwbuilder/UserService.h"
39 #include "fwbuilder/Policy.h"
40 #include "fwbuilder/Rule.h"
41 #include "fwbuilder/FWObjectDatabase.h"
42 
43 #include <iostream>
44 #include <iomanip>
45 #include <sstream>
46 #include <algorithm>
47 
48 using namespace fwcompiler;
49 using namespace libfwbuilder;
50 using namespace std;
51 
52 
53 /*
54  *  These rule processors should work for both Policy and NAT rules
55  *  without having to build specialized classes inheriting from these.
56  */
57 
processNext()58 bool Compiler::groupServices::processNext()
59 {
60     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
61     string re_type = PolicyRule::isA(rule) ?
62         RuleElementSrv::TYPENAME : RuleElementOSrv::TYPENAME;
63     RuleElement *re_srv = RuleElement::cast(rule->getFirstByType(re_type));
64 
65     if (re_srv->size()==1)
66     {
67         tmp_queue.push_back(rule);
68         return true;
69     }
70 
71     map<int, list<Service*> > services;
72 
73     for (FWObject::iterator i=re_srv->begin(); i!=re_srv->end(); i++)
74     {
75         Service *s = Service::cast(FWReference::getObject(*i));
76         assert(s);
77 
78         int proto = groupingCode(s);
79         services[proto].push_back(s);
80     }
81 
82     for (map<int, list<Service*> >::iterator i1=services.begin();
83          i1!=services.end(); i1++)
84     {
85         list<Service*> &sl=(*i1).second;
86 
87         Rule *r = Rule::cast(compiler->dbcopy->create(rule->getTypeName()));
88         compiler->temp_ruleset->add(r);
89         r->duplicate(rule);
90         RuleElement *nsrv = RuleElement::cast(r->getFirstByType(re_type));
91         nsrv->clearChildren();
92 
93         for (list<Service*>::iterator j=sl.begin(); j!=sl.end(); j++)
94         {
95            nsrv->addRef( (*j) );
96         }
97 
98         tmp_queue.push_back(r);
99     }
100     return true;
101 }
102 
groupingCode(const Service * srv)103 int Compiler::groupServicesByProtocol::groupingCode(const Service *srv)
104 {
105     return srv->getProtocolNumber();
106 }
107 
groupingCode(const Service * srv)108 int Compiler::groupTCPUDPServices::groupingCode(const Service *srv)
109 {
110     return ( TCPService::isA(srv) || UDPService::isA(srv));
111 }
112 
separateServiceObject(const string & name)113 Compiler::separateServiceObject::separateServiceObject(
114     const string &name) : BasicRuleProcessor(name)
115 {
116 }
117 
processNext()118 bool Compiler::separateServiceObject::processNext()
119 {
120     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
121     string re_type = PolicyRule::isA(rule) ?
122         RuleElementSrv::TYPENAME : RuleElementOSrv::TYPENAME;
123     RuleElement *re_srv = RuleElement::cast(rule->getFirstByType(re_type));
124 
125     if (re_srv->size()==1)
126     {
127 	tmp_queue.push_back(rule);
128 	return true;
129     }
130 
131     list<Service*> services;
132     for (FWObject::iterator i=re_srv->begin(); i!=re_srv->end(); i++)
133     {
134 	FWObject *o= *i;
135 	if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
136 	Service *s=Service::cast(o);
137 	assert(s!=NULL);
138 
139 	if (condition(s))
140         {
141             Rule *r = Rule::cast(compiler->dbcopy->create(rule->getTypeName()));
142             compiler->temp_ruleset->add(r);
143             r->duplicate(rule);
144             RuleElement *nsrv = RuleElement::cast(r->getFirstByType(re_type));
145             nsrv->clearChildren();
146             nsrv->addRef( s );
147             tmp_queue.push_back(r);
148             services.push_back(s);
149         }
150     }
151     for (list<Service*>::iterator i=services.begin(); i!=services.end(); i++)
152 	re_srv->removeRef( (*i) );
153 
154     if (!re_srv->isAny())
155 	tmp_queue.push_back(rule);
156 
157     return true;
158 }
159 
160 
161 /**
162  * separate TCP/UDP services that specify source port (can
163  * not be used in combination with destination port with
164  * multiport)
165  */
condition(const Service * srv)166 bool Compiler::separateSrcPort::condition(const Service *srv)
167 {
168     if ( TCPService::isA(srv) || UDPService::isA(srv))
169     {
170         int srs = TCPUDPService::constcast(srv)->getSrcRangeStart();
171         int sre = TCPUDPService::constcast(srv)->getSrcRangeEnd();
172 
173         compiler->normalizePortRange(srs,sre);
174 
175         return (srs!=0 || sre!=0);
176     }
177     return false;
178 }
179 
condition(const Service * srv)180 bool Compiler::separateSrcAndDstPort::condition(const Service *srv)
181 {
182     if ( TCPService::isA(srv) || UDPService::isA(srv))
183     {
184         int srs = TCPUDPService::constcast(srv)->getSrcRangeStart();
185         int sre = TCPUDPService::constcast(srv)->getSrcRangeEnd();
186         int drs = TCPUDPService::constcast(srv)->getDstRangeStart();
187         int dre = TCPUDPService::constcast(srv)->getDstRangeEnd();
188 
189         compiler->normalizePortRange(srs,sre);
190         compiler->normalizePortRange(drs,dre);
191 
192         return ( (srs!=0 || sre!=0) && (drs!=0 || dre!=0) );
193     }
194     return false;
195 }
196 
condition(const Service * srv)197 bool Compiler::separateTCPUDP::condition(const Service *srv)
198 {
199     return ( TCPService::isA(srv) || UDPService::isA(srv));
200 }
201 
condition(const Service * srv)202 bool Compiler::separateTagged::condition(const Service *srv)
203 {
204     return ( TagService::isA(srv));
205 }
206 
condition(const Service * srv)207 bool Compiler::separateCustom::condition(const Service *srv)
208 {
209     return ( CustomService::isA(srv));
210 }
211 
condition(const Service * srv)212 bool Compiler::separateUserServices::condition(const Service *srv)
213 {
214     return ( UserService::isA(srv));
215 }
216 
condition(const Service * srv)217 bool Compiler::separateTOS::condition(const Service *srv)
218 {
219     const IPService *ip = IPService::constcast(srv);
220     return (ip && !ip->getTOSCode().empty());
221 }
222 
condition(const Service * srv)223 bool Compiler::splitIpOptions::condition(const Service *srv)
224 {
225     const IPService *ip = IPService::constcast(srv);
226     return (ip && ip->hasIpOptions());
227 }
228 
condition(const Service * srv)229 bool Compiler::separateTCPWithFlags::condition(const Service *srv)
230 {
231     const TCPService *s = TCPService::constcast(srv);
232     return (s && s->inspectFlags() );
233 }
234 
condition(const Service * srv)235 bool Compiler::separatePortRanges::condition(const Service *srv)
236 {
237     if ( TCPService::isA(srv) || UDPService::isA(srv) )
238     {
239         unsigned srs = TCPUDPService::constcast(srv)->getSrcRangeStart();
240         unsigned sre = TCPUDPService::constcast(srv)->getSrcRangeEnd();
241         unsigned drs = TCPUDPService::constcast(srv)->getDstRangeStart();
242         unsigned dre = TCPUDPService::constcast(srv)->getDstRangeEnd();
243 
244         if (srs!=0 && sre==0) sre = srs;
245         if (drs!=0 && dre==0) dre = drs;
246 
247 /*
248  * I also need to separate rules that use "Any UDP" and "Any TCP"
249  * objects. These objects have all ports set to zero and iptables code
250  * for them should just have "-p udp" or "-p tcp" without any
251  * "--source-port" or "--destination-port" specification. Commands
252  * like this do not combine with commands that do specify port because
253  * they lose their "any udp"/"any tcp" meaning as soon as
254  * "--source-port"/"--destination-port" is added.
255  */
256         if (srs==0 && sre==0 && drs==0 && dre==0) { sre = 65535; dre = 65535; }
257 
258         return (srs!=sre || drs!=dre);
259     }
260     return false;
261 }
262 
263 
264 
265 
266 
267 
268 
processNext()269 bool Compiler::verifyCustomServices::processNext()
270 {
271     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
272     string re_type = PolicyRule::isA(rule) ?
273         RuleElementSrv::TYPENAME : RuleElementOSrv::TYPENAME;
274     RuleElement *re_srv = RuleElement::cast(rule->getFirstByType(re_type));
275 
276     tmp_queue.push_back(rule);
277 
278     for (FWObject::iterator i=re_srv->begin(); i!=re_srv->end(); i++)
279     {
280         FWObject *o = FWReference::getObject(*i);
281 	assert(o!=NULL);
282 	if (CustomService::isA(o) &&
283 	    CustomService::cast(o)->getCodeForPlatform(compiler->myPlatformName()).empty())
284 	    throw FWException("Custom service is not configured for the platform '"+compiler->myPlatformName()+"'. Rule "+rule->getLabel());
285     }
286 
287     return true;
288 }
289 
processNext()290 bool Compiler::CheckForTCPEstablished::processNext()
291 {
292     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
293     string re_type = PolicyRule::isA(rule) ?
294         RuleElementSrv::TYPENAME : RuleElementOSrv::TYPENAME;
295     RuleElement *re_srv = RuleElement::cast(rule->getFirstByType(re_type));
296 
297     for (FWObject::iterator i=re_srv->begin(); i!=re_srv->end(); i++)
298     {
299         FWObject *o = FWReference::getObject(*i);
300 
301         TCPService *s = TCPService::cast( o );
302         if (s==NULL) continue;
303 
304         if (s->getEstablished())
305             compiler->abort(
306                 rule,
307                 string("TCPService object with option \"established\" "
308                        "is not supported by firewall platform \"") +
309                 compiler->myPlatformName() +
310                 string("\". Use stateful rule instead."));
311     }
312 
313     tmp_queue.push_back(rule);
314     return true;
315 }
316 
processNext()317 bool Compiler::CheckForUnsupportedUserService::processNext()
318 {
319     Rule *rule = prev_processor->getNextRule(); if (rule==NULL) return false;
320     string re_type = PolicyRule::isA(rule) ?
321         RuleElementSrv::TYPENAME : RuleElementOSrv::TYPENAME;
322     RuleElement *re_srv = RuleElement::cast(rule->getFirstByType(re_type));
323 
324     for (FWObject::iterator i=re_srv->begin(); i!=re_srv->end(); i++)
325     {
326         FWObject *o = FWReference::getObject(*i);
327 
328         if (UserService::isA(o))
329             compiler->abort(
330                 rule,
331                 string("UserService object is not supported by ") +
332                 compiler->myPlatformName());
333     }
334 
335     tmp_queue.push_back(rule);
336     return true;
337 }
338 
339 
340