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