1 /*
2
3 Firewall Builder
4
5 Copyright (C) 2002 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 "PolicyCompiler_pix.h"
27 #include "PIXObjectGroup.h"
28 #include "NamedObjectsManager.h"
29 #include "PortRangeConverter.h"
30
31 #include "fwbuilder/Firewall.h"
32 #include "fwbuilder/AddressRange.h"
33 #include "fwbuilder/RuleElement.h"
34 #include "fwbuilder/IPService.h"
35 #include "fwbuilder/ICMPService.h"
36 #include "fwbuilder/TCPService.h"
37 #include "fwbuilder/UDPService.h"
38 #include "fwbuilder/CustomService.h"
39 #include "fwbuilder/Policy.h"
40 #include "fwbuilder/FWOptions.h"
41 #include "fwbuilder/FWObjectDatabase.h"
42 #include "fwbuilder/Interface.h"
43 #include "fwbuilder/IPv4.h"
44 #include "fwbuilder/Network.h"
45 #include "fwbuilder/Management.h"
46 #include "fwbuilder/Resources.h"
47
48 #include <iostream>
49 #include <iomanip>
50 #include <fstream>
51 #include <sstream>
52 #include <algorithm>
53 #include <functional>
54
55 #include <assert.h>
56
57 #include <QStringList>
58
59
60 using namespace libfwbuilder;
61 using namespace fwcompiler;
62 using namespace std;
63
64
_printAction(PolicyRule * rule)65 string PolicyCompiler_pix::PrintRule::_printAction(PolicyRule *rule)
66 {
67 ostringstream str;
68
69 switch (rule->getAction()) {
70 case PolicyRule::Accept: str << "permit "; break;
71 case PolicyRule::Deny: str << "deny "; break;
72 case PolicyRule::Reject: str << "deny "; break;
73 default: str << rule->getActionAsString() << " ";
74 }
75 return str.str();
76 }
77
_printACL(PolicyRule * rule)78 string PolicyCompiler_pix::PrintRule::_printACL(PolicyRule *rule)
79 {
80 // PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
81
82 string acl_name=rule->getStr("acl");
83 assert (acl_name!="");
84
85 return acl_name+" ";
86 }
87
_printLog(PolicyRule * rule)88 string PolicyCompiler_pix::PrintRule::_printLog(PolicyRule *rule)
89 {
90 string platform = compiler->fw->getStr("platform");
91 string vers = compiler->fw->getStr("version");
92 if (platform=="pix" && (vers=="6.1" || vers=="6.2")) return "";
93
94 // PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
95 FWOptions *ruleopt =rule->getOptionsObject();
96 QStringList str;
97
98 if (ruleopt->getBool("disable_logging_for_this_rule"))
99 return "log disable ";
100
101 if (rule->getLogging())
102 {
103 string level = ruleopt->getStr("log_level");
104 int logint = ruleopt->getInt("log_interval");
105 /*
106 * PIX always adds logging interval in "show * access-list" command,
107 * so we should always add it, too. Otherwise ACL lines look
108 * different when diff is generated.
109 */
110 if (logint<=0)
111 logint = Resources::platform_res[platform]->getResourceInt(
112 string("/FWBuilderResources/Target/options/") +
113 "version_" + compiler->fw->getStr("version") +
114 "/pix_default_logint");
115
116 if (level.empty())
117 level = compiler->fw->getOptionsObject()->getStr(
118 "pix_logging_trap_level");
119
120 if (level.empty())
121 level = Resources::platform_res[platform]->getResourceStr(
122 string("/FWBuilderResources/Target/options/") +
123 "version_" + compiler->fw->getStr("version") +
124 "/pix_default_loglevel");
125
126 if (level=="alert") level = "1";
127 if (level=="crit") level = "2";
128 if (level=="error") level = "3";
129 if (level=="warning") level = "4";
130 if (level=="notice") level = "5";
131 if (level=="info") level = "6";
132 if (level=="debug") level = "7";
133
134 str << "log" << level.c_str();
135
136 if (logint>0 || platform=="pix") // can't use "interval 0" on fwsm
137 {
138 str << "interval" << QString().setNum(logint);
139 }
140 }
141 return str.join(" ").toStdString();
142 }
143
_printPortRangeOp(int rs,int re)144 string PolicyCompiler_pix::PrintRule::_printPortRangeOp(int rs, int re)
145 {
146 return PortRangeConverter(rs, re).toString();
147 }
148
_printSrcService(Service * srv)149 string PolicyCompiler_pix::PrintRule::_printSrcService(Service *srv)
150 {
151 if (TCPService::isA(srv) || UDPService::isA(srv))
152 {
153 int rs = TCPUDPService::cast(srv)->getSrcRangeStart();
154 int re = TCPUDPService::cast(srv)->getSrcRangeEnd();
155 return _printPortRangeOp(rs, re);
156 }
157 return "";
158 }
159
_printDstService(Service * srv)160 string PolicyCompiler_pix::PrintRule::_printDstService(Service *srv)
161 {
162 ostringstream str;
163
164 if (TCPService::isA(srv) || UDPService::isA(srv))
165 {
166 int rs=TCPUDPService::cast(srv)->getDstRangeStart();
167 int re=TCPUDPService::cast(srv)->getDstRangeEnd();
168 str << _printPortRangeOp(rs, re);
169 }
170
171 if (ICMPService::isA(srv) && srv->getInt("type")!=-1)
172 {
173 str << srv->getStr("type") << " ";
174 }
175
176 if (CustomService::isA(srv))
177 {
178 str << CustomService::cast(srv)->getCodeForPlatform(
179 compiler->myPlatformName() ) << " ";
180 }
181
182 const IPService *ip_srv = IPService::constcast(srv);
183 if (ip_srv && ip_srv->hasIpOptions())
184 compiler->warning("PIX can not match IP options");
185
186 return str.str();
187 }
188
_printAddr(libfwbuilder::Address * o)189 string PolicyCompiler_pix::PrintRule::_printAddr(libfwbuilder::Address *o)
190 {
191 if (Interface::cast(o)!=NULL)
192 {
193 Interface *interface_=Interface::cast(o);
194 if (interface_->isDyn())
195 {
196 return string("interface ") + interface_->getLabel() + " ";
197 }
198 }
199
200 ostringstream str;
201
202 const InetAddr *srcaddr = o->getAddressPtr();
203 if (srcaddr)
204 {
205 InetAddr srcmask = *(o->getNetmaskPtr());
206
207 if (Interface::cast(o)!=NULL)
208 srcmask = InetAddr(InetAddr::getAllOnes());
209
210 if (IPv4::cast(o)!=NULL)
211 srcmask = InetAddr(InetAddr::getAllOnes());
212
213
214 if (srcaddr->isAny() && srcmask.isAny())
215 {
216 str << "any ";
217 } else {
218 if (srcmask.isHostMask())
219 {
220 str << "host " << srcaddr->toString() << " ";
221 } else
222 {
223 str << srcaddr->toString() << " ";
224 str << srcmask.toString() << " ";
225 }
226 }
227 return str.str();
228 }
229 ostringstream errstr;
230 errstr << "Object "
231 << o->getName()
232 << " (id="
233 << o->getId()
234 << ") "
235 << " has no ip address and can not be used "
236 << "in the rule.";
237 compiler->abort(errstr.str());
238 return ""; // to make compiler happy
239 }
240
suppressDuplicateICMPCommands(const string & cmd)241 bool PolicyCompiler_pix::PrintRule::suppressDuplicateICMPCommands(const string &cmd)
242 {
243 list<string>::iterator i;
244 i = std::find(seen_icmp_commands.begin(), seen_icmp_commands.end(), cmd);
245 if (i!=seen_icmp_commands.end()) return true;
246 seen_icmp_commands.push_back(cmd);
247 return false;
248 }
249
_printICMPCommand(PolicyRule * rule)250 string PolicyCompiler_pix::PrintRule::_printICMPCommand(PolicyRule *rule)
251 {
252 ostringstream str;
253 Address *src = compiler->getFirstSrc(rule);
254 RuleElementSrv *srvrel = rule->getSrv();
255 FWObject *srv = srvrel->front();
256 if (FWReference::cast(srv)!=NULL) srv = FWReference::cast(srv)->getPointer();
257
258 // Interface *rule_iface =
259 // Interface::cast(compiler->dbcopy->findInIndex(rule->getInterfaceId()));
260
261 RuleElementItf *intf_re = rule->getItf();
262 Interface *rule_iface = Interface::cast(
263 FWObjectReference::getObject(intf_re->front()));
264
265 assert(rule_iface);
266
267 if (PIXObjectGroup::cast(srv)!=NULL)
268 {
269 for (FWObject::iterator i1=srv->begin(); i1!=srv->end(); ++i1)
270 {
271 ICMPService *s = ICMPService::cast(FWReference::getObject(*i1));
272 assert(s!=NULL);
273
274 ostringstream str1;
275 str1 << "icmp ";
276 str1 << _printAction(rule);
277 str1 << _printAddr( src );
278 str1 << s->getStr("type");
279 str1 << " ";
280 str1 << rule_iface->getLabel();
281 str1 << endl;
282
283 if ( ! suppressDuplicateICMPCommands(str1.str())) str << str1.str();
284 }
285 return str.str();
286
287 } else
288 {
289 str << "icmp ";
290 str << _printAction(rule);
291 str << _printAddr( src );
292 str << _printDstService( Service::cast(srv) );
293 str << " ";
294 str << rule_iface->getLabel();
295 str << endl;
296
297 if ( ! suppressDuplicateICMPCommands(str.str())) return str.str();
298 }
299
300 return "";
301 }
302
_printSSHTelnetCommand(PolicyRule * rule)303 string PolicyCompiler_pix::PrintRule::_printSSHTelnetCommand(PolicyRule *rule)
304 {
305 ostringstream str;
306 int port;
307
308 RuleElementSrc *rel = rule->getSrc();
309 Service *srv = compiler->getFirstSrv(rule);
310
311 RuleElementItf *intf_re = rule->getItf();
312 Interface *rule_iface = Interface::cast(
313 FWObjectReference::getObject(intf_re->front()));
314 assert(rule_iface);
315
316 port = TCPUDPService::cast(srv)->getDstRangeStart();
317
318 for (FWObject::iterator i=rel->begin(); i!=rel->end(); ++i)
319 {
320 FWObject *o = FWReference::getObject(*i);
321
322 if (dynamic_cast<PIXObjectGroup*>(o)!=NULL)
323 {
324 for (FWObject::iterator j=o->begin(); j!=o->end(); ++j)
325 {
326 Address *a = Address::cast(FWReference::getObject(*j));
327 assert(a!=NULL);
328 str << _printSingleSSHTelnetCommand(port, a, rule_iface->getLabel());
329 }
330 } else
331 {
332 Address *a = Address::cast(o);
333 assert(a!=NULL);
334 str << _printSingleSSHTelnetCommand(port, a, rule_iface->getLabel());
335 }
336 }
337
338 return str.str();
339 }
340
_printSingleSSHTelnetCommand(int port,Address * a,const string & interfaceLabel)341 string PolicyCompiler_pix::PrintRule::_printSingleSSHTelnetCommand(
342 int port, Address *a, const string &interfaceLabel)
343 {
344 string res;
345
346 if (port==22) res = "ssh ";
347 if (port==23) res = "telnet ";
348 if (port==80) res = "http ";
349
350 if (!res.empty())
351 {
352 res += a->getAddressPtr()->toString() + " "
353 + a->getNetmaskPtr()->toString() + " "
354 + interfaceLabel + "\n";
355 }
356
357 return res;
358 }
359
360 /*
361 * the following additional attributes should have been defined by now:
362 *
363 * "acl" - string, name of the access list
364 * choices are: outside-in, outside-out, inside-in, indside-out,
365 * dmz-in, dmz-out etc.
366 * General rule for the acl name: "iface_name-{in,out}"
367 */
processNext()368 bool PolicyCompiler_pix::PrintRule::processNext()
369 {
370 PolicyCompiler_pix *pix_comp = dynamic_cast<PolicyCompiler_pix*>(compiler);
371 PolicyRule *rule = getNext(); if (rule==NULL) return false;
372
373 tmp_queue.push_back(rule);
374
375 ostringstream comment;
376
377 compiler->output << compiler->printComment(rule, current_rule_label1, "!");
378
379 if (rule->getBool("icmp_cmd"))
380 {
381 compiler->output << _printICMPCommand(rule);
382 // need to generate access list command as well as icmp command
383 // in order to properly serve icmp through nat
384 // 04/21/06 --vk
385 // return true;
386 }
387
388 if (rule->getBool("tcp_service_to_fw"))
389 {
390 compiler->output << _printSSHTelnetCommand(rule);
391 return true;
392 }
393
394 /*
395 * all three rule elements contain exactly one object, which can
396 * be either group (in case processor CreateObjectGroups created
397 * object group for it) or a regular object
398 */
399 RuleElementSrc *src = rule->getSrc();
400 RuleElementDst *dst = rule->getDst();
401 RuleElementSrv *srv = rule->getSrv();
402
403 assert(src->size()==1);
404 assert(dst->size()==1);
405 assert(srv->size()==1);
406
407 FWObject *srcobj = FWReference::getObject(src->front());
408 FWObject *dstobj = FWReference::getObject(dst->front());
409 FWObject *srvobj = FWReference::getObject(srv->front());
410
411 assert(srcobj);
412 assert(dstobj);
413 assert(srvobj);
414
415 ostringstream aclstr;
416
417 string acl_name = rule->getStr("acl");
418 assert(acl_name!="");
419
420 ciscoACL *acl = pix_comp->acls[acl_name];
421 assert(acl!=NULL);
422
423 if (compiler->fw->getOptionsObject()->getBool("pix_use_acl_remarks"))
424 {
425 compiler->output << acl->addRemark(rule->getLabel(), rule->getComment());
426 }
427
428 /*
429 * Assemble ACL command in aclstr
430 */
431
432 aclstr << _printAction(rule);
433
434 /*
435 * processor groupServicesByProtocol guaranties that rule has
436 * services of the same type (that is, the same protocol, like all
437 * tcp, all udp, all icmp or all IP with the same protocol
438 * number). PIX can use object-group for protocol only if protocol
439 * numbers are different and these are not icmp/tcp/udp
440 * protocols. This means that because of processor
441 * groupServicesByProtocol we never use object-group in protocol
442 * part of ACL.
443 */
444
445 PIXObjectGroup *pgsrv = PIXObjectGroup::cast(srvobj);
446 PIXObjectGroup *pgsrc = PIXObjectGroup::cast(srcobj);
447 PIXObjectGroup *pgdst = PIXObjectGroup::cast(dstobj);
448 Service *srv_s = Service::cast(srvobj);
449 assert(pgsrv!=NULL || srv_s!=NULL);
450
451 if ( pgsrv!=NULL && pgsrv->isServiceGroup())
452 {
453 aclstr << pgsrv->getSrvTypeName();
454 } else
455 aclstr << srv_s->getProtocolName();
456
457 aclstr << " ";
458
459 NamedObject* asa8_object;
460
461 asa8_object = pix_comp->named_objects_manager->getNamedObject(srcobj);
462 if (asa8_object)
463 {
464 aclstr << "object " << asa8_object->getCommandWord().toStdString() << " ";
465 } else
466 {
467 if (pgsrc!=NULL)
468 {
469 aclstr << "object-group " << srcobj->getName() << " ";
470 } else
471 {
472 aclstr << _printAddr(Address::cast(srcobj));
473 }
474 }
475
476 if ( pgsrv==NULL )
477 aclstr << _printSrcService( compiler->getFirstSrv(rule) );
478
479 asa8_object = pix_comp->named_objects_manager->getNamedObject(dstobj);
480 if (asa8_object)
481 {
482 aclstr << "object " << asa8_object->getCommandWord().toStdString() << " ";
483 } else
484 {
485 if (pgdst!=NULL)
486 {
487 aclstr << "object-group " << dstobj->getName() << " ";
488 } else
489 {
490 aclstr << _printAddr(Address::cast(dstobj));
491 }
492 }
493
494 if (pgsrv!=NULL)
495 {
496 aclstr << "object-group " << srvobj->getName() << " ";
497 } else
498 {
499 aclstr << _printDstService(Service::cast(srvobj));
500 }
501
502 aclstr << _printLog( rule );
503
504 // aclstr << endl;
505
506 compiler->output << acl->addLine(aclstr.str());
507
508 return true;
509 }
510
511