1 /*
2
3 Firewall Builder
4
5 Copyright (C) 2000 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 #include "global.h"
28
29 #include "platforms.h"
30 #include "FWBSettings.h"
31 #include "interfaceProperties.h"
32 #include "interfacePropertiesObjectFactory.h"
33
34 #include <QObject>
35 #include <QStringList>
36 #include <QComboBox>
37 #include <QtDebug>
38
39 #include "fwbuilder/Cluster.h"
40 #include "fwbuilder/Firewall.h"
41 #include "fwbuilder/Interface.h"
42 #include "fwbuilder/FWOptions.h"
43 #include "fwbuilder/Management.h"
44 #include "fwbuilder/Resources.h"
45 #include "fwbuilder/Rule.h"
46 #include "fwbuilder/Policy.h"
47 #include <fwbuilder/FailoverClusterGroup.h>
48 #include <fwbuilder/StateSyncClusterGroup.h>
49
50 #include <algorithm>
51 #include <iostream>
52 #include <memory>
53
54
55 using namespace std;
56 using namespace libfwbuilder;
57
58
59 QStringList emptyList;
60 QStringList logLevels;
61 QStringList logFacilities;
62 QStringList actionsOnReject;
63 QStringList routeOptions_pf_ipf;
64 QStringList routeLoadOptions_pf;
65 QStringList limitSuffixes;
66 QStringList classifyOptions_ipfw;
67
init_platforms()68 void init_platforms()
69 {
70 logLevels.push_back("");
71 logLevels.push_back("");
72 logLevels.push_back(QObject::tr( "alert" ));
73 logLevels.push_back( "alert" );
74 logLevels.push_back(QObject::tr( "crit" ));
75 logLevels.push_back( "crit" );
76 logLevels.push_back(QObject::tr( "error" ));
77 logLevels.push_back( "error" );
78 logLevels.push_back(QObject::tr( "warning"));
79 logLevels.push_back( "warning");
80 logLevels.push_back(QObject::tr( "notice" ));
81 logLevels.push_back( "notice" );
82 logLevels.push_back(QObject::tr( "info" ));
83 logLevels.push_back( "info" );
84 logLevels.push_back(QObject::tr( "debug" ));
85 logLevels.push_back( "debug" );
86
87
88 logFacilities.push_back("");
89 logFacilities.push_back("");
90 logFacilities.push_back(QObject::tr( "kern" ));
91 logFacilities.push_back( "kern" );
92 logFacilities.push_back(QObject::tr( "user" ));
93 logFacilities.push_back( "user" );
94 logFacilities.push_back(QObject::tr( "mail" ));
95 logFacilities.push_back( "mail" );
96 logFacilities.push_back(QObject::tr( "daemon" ));
97 logFacilities.push_back( "daemon" );
98 logFacilities.push_back(QObject::tr( "auth" ));
99 logFacilities.push_back( "auth" );
100 logFacilities.push_back(QObject::tr( "syslog" ));
101 logFacilities.push_back( "syslog" );
102 logFacilities.push_back(QObject::tr( "lpr" ));
103 logFacilities.push_back( "lpr" );
104 logFacilities.push_back(QObject::tr( "news" ));
105 logFacilities.push_back( "news" );
106 logFacilities.push_back(QObject::tr( "uucp" ));
107 logFacilities.push_back( "uucp" );
108 logFacilities.push_back(QObject::tr( "cron" ));
109 logFacilities.push_back( "cron" );
110 logFacilities.push_back(QObject::tr( "authpriv" ));
111 logFacilities.push_back( "authpriv");
112 logFacilities.push_back(QObject::tr( "ftp" ));
113 logFacilities.push_back( "ftp" );
114 logFacilities.push_back(QObject::tr( "local0" ));
115 logFacilities.push_back( "local0" );
116 logFacilities.push_back(QObject::tr( "local1" ));
117 logFacilities.push_back( "local1" );
118 logFacilities.push_back(QObject::tr( "local2" ));
119 logFacilities.push_back( "local2" );
120 logFacilities.push_back(QObject::tr( "local3" ));
121 logFacilities.push_back( "local3" );
122 logFacilities.push_back(QObject::tr( "local4" ));
123 logFacilities.push_back( "local4" );
124 logFacilities.push_back(QObject::tr( "local5" ));
125 logFacilities.push_back( "local5" );
126 logFacilities.push_back(QObject::tr( "local6" ));
127 logFacilities.push_back( "local6" );
128 logFacilities.push_back(QObject::tr( "local7" ));
129 logFacilities.push_back( "local7" );
130
131 actionsOnReject.push_back("");
132 actionsOnReject.push_back("");
133 actionsOnReject.push_back(QObject::tr("ICMP admin prohibited"));
134 actionsOnReject.push_back("ICMP admin prohibited");
135 actionsOnReject.push_back(QObject::tr("ICMP host prohibited"));
136 actionsOnReject.push_back("ICMP host prohibited");
137 actionsOnReject.push_back(QObject::tr("ICMP host unreachable"));
138 actionsOnReject.push_back("ICMP host unreachable");
139 actionsOnReject.push_back(QObject::tr("ICMP net prohibited"));
140 actionsOnReject.push_back("ICMP net prohibited");
141 actionsOnReject.push_back(QObject::tr("ICMP net unreachable"));
142 actionsOnReject.push_back("ICMP net unreachable");
143 actionsOnReject.push_back(QObject::tr("ICMP port unreachable"));
144 actionsOnReject.push_back("ICMP port unreachable");
145 actionsOnReject.push_back(QObject::tr("ICMP protocol unreachable"));
146 actionsOnReject.push_back("ICMP protocol unreachable");
147 actionsOnReject.push_back(QObject::tr("TCP RST"));
148 actionsOnReject.push_back("TCP RST");
149
150 routeOptions_pf_ipf.push_back(QObject::tr("None"));
151 routeOptions_pf_ipf.push_back("none");
152 routeOptions_pf_ipf.push_back(QObject::tr("Route through"));
153 routeOptions_pf_ipf.push_back("route_through");
154 routeOptions_pf_ipf.push_back(QObject::tr("Route reply through"));
155 routeOptions_pf_ipf.push_back("route_reply_through");
156 routeOptions_pf_ipf.push_back(QObject::tr("Route a copy through"));
157 routeOptions_pf_ipf.push_back("route_copy_through");
158
159 routeLoadOptions_pf.push_back(QObject::tr("None"));
160 routeLoadOptions_pf.push_back("none");
161 routeLoadOptions_pf.push_back(QObject::tr("Bitmask"));
162 routeLoadOptions_pf.push_back("bitmask");
163 routeLoadOptions_pf.push_back(QObject::tr("Random"));
164 routeLoadOptions_pf.push_back("random");
165 routeLoadOptions_pf.push_back(QObject::tr("Source Hash"));
166 routeLoadOptions_pf.push_back("source_hash");
167 routeLoadOptions_pf.push_back(QObject::tr("Round Robin"));
168 routeLoadOptions_pf.push_back("round_robin");
169
170 classifyOptions_ipfw.push_back(QObject::tr("None"));
171 classifyOptions_ipfw.push_back("-1");
172 classifyOptions_ipfw.push_back(QObject::tr("dummynet(4) 'pipe'"));
173 classifyOptions_ipfw.push_back("1");
174 classifyOptions_ipfw.push_back(QObject::tr("dummynet(4) 'queue'"));
175 classifyOptions_ipfw.push_back("2");
176
177 limitSuffixes.push_back("");
178 limitSuffixes.push_back("");
179 limitSuffixes.push_back(QObject::tr("/day"));
180 limitSuffixes.push_back("/day");
181 limitSuffixes.push_back(QObject::tr("/hour"));
182 limitSuffixes.push_back("/hour");
183 limitSuffixes.push_back(QObject::tr("/minute"));
184 limitSuffixes.push_back("/minute");
185 limitSuffixes.push_back(QObject::tr("/second"));
186 limitSuffixes.push_back("/second");
187 }
188
189
isUsingNetZone(Firewall * fw)190 bool isUsingNetZone(Firewall *fw)
191 {
192 string platform=fw->getStr("platform");
193 return (platform=="pix" || platform=="fwsm");
194 }
195
isDefaultPolicyRuleOptions(FWOptions * opt)196 bool isDefaultPolicyRuleOptions(FWOptions *opt)
197 {
198 bool res = true;
199 FWObject *p;
200 PolicyRule *rule = NULL;
201
202 p = opt;
203 do {
204 p = p->getParent();
205 if (PolicyRule::cast(p)!=NULL) rule = PolicyRule::cast(p);
206 } while ( p!=NULL && Firewall::cast(p)==NULL );
207
208 if (p==NULL)
209 {
210 qDebug() << "isDefaultPolicyRuleOptions()"
211 << "Can not locate parent Firewall object for the options object";
212 opt->dump(false, true);
213 return true;
214 }
215
216 QString platform = p->getStr("platform").c_str();
217
218 // if (fwbdebug)
219 // qDebug(QString("Options object type: %1").arg(opt->getTypeName()));
220
221 if (PolicyRuleOptions::isA(opt))
222 {
223
224 if (platform=="iptables")
225 {
226 res= ( opt->getStr("log_prefix").empty() &&
227 opt->getStr("log_level").empty() &&
228 opt->getInt("limit_value")<=0 &&
229 ! opt->getBool("limit_value_not") &&
230 opt->getInt("limit_burst")<=0 &&
231 opt->getInt("connlimit_value")<=0 &&
232 ! opt->getBool("connlimit_above_not") &&
233 opt->getInt("connlimit_masklen")<=0 &&
234
235 opt->getStr("hashlimit_name").empty() &&
236 opt->getInt("hashlimit_value")<=0 &&
237 opt->getInt("hashlimit_burst")<=0 &&
238 opt->getInt("hashlimit_size")<=0 &&
239 opt->getInt("hashlimit_max")<=0 &&
240 opt->getInt("hashlimit_expire")<=0 &&
241 opt->getInt("hashlimit_gcinterval")<=0 &&
242
243 opt->getInt("ulog_nlgroup")<=1 &&
244 opt->getStr("limit_suffix").empty() &&
245 opt->getStr("firewall_is_part_of_any_and_networks") == "");
246 }
247
248 if (platform=="pix" || platform=="fwsm")
249 {
250 string vers="version_"+p->getStr("version");
251 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
252 if ( Resources::platform_res[platform.toAscii().constData()]->getResourceBool(
253 "/FWBuilderResources/Target/options/"+vers+"/pix_rule_syslog_settings"))
254 #else
255 if ( Resources::platform_res[platform.toLatin1().constData()]->getResourceBool(
256 "/FWBuilderResources/Target/options/"+vers+"/pix_rule_syslog_settings"))
257 #endif
258 {
259 res= ( opt->getStr("log_level").empty() &&
260 opt->getInt("log_interval")<=0 &&
261 ! opt->getBool("disable_logging_for_this_rule") );
262 }
263 else
264 {
265 res=true;
266 }
267 }
268
269 if (platform=="pf")
270 {
271 string version = p->getStr("version");
272 bool ge_4_0 = XMLTools::version_compare(version, "4.0")>=0;
273 bool ge_4_5 = XMLTools::version_compare(version, "4.5")>=0;
274 if (ge_4_5)
275 {
276 res = (!opt->getBool("pf_no_sync") && !opt->getBool("pf_pflow"));
277 }
278
279 if (ge_4_0)
280 {
281 res = res &&
282 ( opt->getStr("log_prefix").empty() &&
283 opt->getInt("pf_rule_max_state")<=0 &&
284 ! opt->getBool("pf_source_tracking") &&
285 opt->getInt("pf_max_src_conn")<=0 &&
286 opt->getInt("pf_max_src_conn_rate_num")<=0 &&
287 opt->getInt("pf_max_src_conn_rate_seconds")<=0 &&
288 ! opt->getBool("pf_keep_state") &&
289 ! opt->getBool("pf_sloppy_tracker") &&
290 ! opt->getBool("pf_synproxy") &&
291 ! opt->getBool("pf_modulate_state")
292 );
293 }else
294 {
295 res = res &&
296 ( opt->getStr("log_prefix").empty() &&
297 opt->getInt("pf_rule_max_state")<=0 &&
298 ! opt->getBool("pf_source_tracking") &&
299 opt->getInt("pf_max_src_conn")<=0 &&
300 opt->getInt("pf_max_src_conn_rate_num")<=0 &&
301 opt->getInt("pf_max_src_conn_rate_seconds")<=0 &&
302 ! opt->getBool("pf_keep_state") &&
303 ! opt->getBool("pf_sloppy_tracker") &&
304 ! opt->getBool("pf_synproxy") &&
305 ! opt->getBool("pf_modulate_state")
306 );
307 }
308 }
309
310 if (platform=="ipf")
311 {
312 res= ( opt->getStr("ipf_log_facility").empty() &&
313 opt->getStr("log_level").empty() &&
314 ! opt->getBool("ipf_keep_frags") &&
315 ! opt->getBool("ipf_return_icmp_as_dest") );
316 }
317
318 if (platform=="ipfw")
319 {
320 //res= ( ! opt->getBool("stateless") );
321 res = true;
322 }
323
324 if (rule!=NULL)
325 {
326 PolicyRule::Action act = rule->getAction();
327
328 if (act==PolicyRule::Accept)
329 {
330 // by default, these actions are not stateless
331 res = res && (!opt->getBool("stateless"));
332 } else
333 {
334 // other actions are stateless by default
335 res = res && opt->getBool("stateless");
336 }
337
338 }
339
340 // all rules are stateless for IOS ACL
341 if (platform=="iosacl" || platform=="procurve_acl")
342 {
343 res = !opt->getBool("iosacl_add_mirror_rule");
344 }
345
346 }
347 return res;
348 }
349
isDefaultNATRuleOptions(FWOptions * opt)350 bool isDefaultNATRuleOptions(FWOptions *opt)
351 {
352 bool res=true;
353 FWObject *p;
354
355 p=opt;
356 do { p=p->getParent();
357 } while ( p!=NULL && Firewall::cast(p)==NULL );
358
359 assert(p!=NULL);
360
361 QString platform = p->getStr("platform").c_str();
362
363 if (NATRuleOptions::isA(opt))
364 {
365 if (platform=="iptables")
366 {
367 res = !opt->getBool("ipt_use_snat_instead_of_masq") &&
368 !opt->getBool("ipt_nat_random") &&
369 !opt->getBool("ipt_nat_persistent");
370 }
371
372 if (platform=="pf")
373 {
374 // if "pf_pool_type_none" is undefined, then all others
375 // should not be defined too because they all are set by
376 // the same dialog
377 // In this case consider options default.
378 res = (opt->getStr("pf_pool_type_none") == "" ||
379 ( opt->getBool("pf_pool_type_none") &&
380 ! opt->getBool("pf_bitmask") &&
381 ! opt->getBool("pf_random") &&
382 ! opt->getBool("pf_source_hash") &&
383 ! opt->getBool("pf_round_robin") &&
384 ! opt->getBool("pf_static_port") ) );
385 }
386
387 if (platform=="pix" || platform=="fwsm")
388 {
389 res = (! opt->getBool("asa8_nat_dns") &&
390 ! opt->getBool("asa8_nat_static") &&
391 ! opt->getBool("asa8_nat_dynamic"));
392
393 }
394 }
395 return res;
396 }
397
isDefaultRoutingRuleOptions(FWOptions * opt)398 bool isDefaultRoutingRuleOptions(FWOptions *opt)
399 {
400 bool res=true;
401
402 // if (fwbdebug)
403 // qDebug(QString("Options object type: %1").arg(opt->getTypeName()));
404
405 if (RoutingRuleOptions::isA(opt))
406 {
407 res= ( ! opt->getBool("no_fail") );
408 }
409 return res;
410 }
411
getVersionString(const QString & platform,const QString & version)412 QString getVersionString(const QString &platform, const QString &version)
413 {
414 list<QStringPair> vl;
415 getVersionsForPlatform(platform, vl);
416 list<QStringPair>::iterator li =
417 std::find_if(vl.begin(),vl.end(),findFirstInQStringPair(version));
418 QString readableVersion = (li!=vl.end())?li->second:"";
419 return readableVersion;
420 }
421
getVersionsForPlatform(const QString & platform,std::list<QStringPair> & res)422 void getVersionsForPlatform(const QString &platform, std::list<QStringPair> &res)
423 {
424 /* versions are defined here instead of the resource files so that
425 * strings could be localized. We use strings that can be localized
426 * only for iptables but define versions for all platforms here for
427 * uniformity
428 */
429
430 if (platform=="iptables")
431 {
432 res.push_back(QStringPair("", QObject::tr("- any -")));
433 res.push_back(QStringPair("lt_1.2.6", QObject::tr("1.2.5 or earlier")));
434 res.push_back(QStringPair("ge_1.2.6", QObject::tr("1.2.6 to 1.2.8")));
435 res.push_back(QStringPair("1.2.9", QObject::tr("1.2.9 to 1.2.11")));
436 res.push_back(QStringPair("1.3.0", QObject::tr("1.3.x")));
437 res.push_back(QStringPair("1.4.0", QObject::tr("1.4.0 or later")));
438 res.push_back(QStringPair("1.4.1.1", QObject::tr("1.4.1.1 or later")));
439 res.push_back(QStringPair("1.4.3", QObject::tr("1.4.3")));
440 res.push_back(QStringPair("1.4.4", QObject::tr("1.4.4 or later")));
441 res.push_back(QStringPair("1.4.11", QObject::tr("1.4.11 or later")));
442 res.push_back(QStringPair("1.4.20", QObject::tr("1.4.20 or later")));
443 } else
444 {
445 // we list supported versions for the following platforms in
446 // corresponding resource .xml file
447 if (platform=="pix" ||
448 platform=="fwsm" ||
449 platform=="nxosacl" ||
450 platform=="iosacl" ||
451 platform=="procurve_acl")
452 {
453 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
454 QString lst = Resources::platform_res[
455 platform.toAscii().constData()]->getResourceStr(
456 "/FWBuilderResources/Target/versions").c_str();
457 #else
458 QString lst = Resources::platform_res[
459 platform.toLatin1().constData()]->getResourceStr(
460 "/FWBuilderResources/Target/versions").c_str();
461 #endif
462
463 QStringList ll=lst.split(',');
464
465 for (QStringList::iterator i=ll.begin(); i!=ll.end(); ++i)
466 res.push_back(QStringPair(*i,*i));
467 } else
468 {
469 if (platform=="pf")
470 {
471 res.push_back(QStringPair("","- any -"));
472 res.push_back(QStringPair("3.x", QObject::tr("3.x")));
473 res.push_back(QStringPair("ge_3.7", QObject::tr("3.7 to 3.9")));
474 res.push_back(QStringPair("4.0", QObject::tr("4.0 to 4.2")));
475 res.push_back(QStringPair("4.3", QObject::tr("4.3")));
476 res.push_back(QStringPair("4.5", QObject::tr("4.5")));
477 res.push_back(QStringPair("4.6", QObject::tr("4.6")));
478 res.push_back(QStringPair("4.7", QObject::tr("4.7 and later")));
479 /* add pf versions here */
480 } else
481 {
482 if (platform=="ipf")
483 {
484 res.push_back(QStringPair("","- any -"));
485 /* add ipf versions here */
486 } else
487 {
488 if (platform=="ipfw")
489 {
490 res.push_back(QStringPair("","- any -"));
491 /* add ipfw versions here */
492 } else
493 res.push_back(QStringPair("","- any -"));
494 }
495 }
496 }
497 }
498 }
499
500 /*
501 * ticket #58: move state sync types and failover types to resource files.
502 *
503 * Note: this function fills in list of QString pairs, each pair is
504 * <protocol_name>,<user_readable_protocol_name>
505 * The second element in the pair is for QComboBox and is visible to the user.
506 */
getStateSyncTypesForOS(const QString & host_os,std::list<QStringPair> & res)507 void getStateSyncTypesForOS(const QString &host_os, std::list<QStringPair> &res)
508 {
509 Resources* os_res = Resources::os_res[host_os.toStdString()];
510 if (os_res==NULL) return;
511 list<string> protocols;
512 os_res->getResourceStrList("/FWBuilderResources/Target/protocols/state_sync",
513 protocols);
514 _repackStringList(protocols, res);
515 }
516
getFailoverTypesForOS(const QString & host_os,std::list<QStringPair> & res)517 void getFailoverTypesForOS(const QString &host_os, std::list<QStringPair> &res)
518 {
519 Resources* os_res = Resources::os_res[host_os.toStdString()];
520 if (os_res==NULL) return;
521 list<string> protocols;
522 os_res->getResourceStrList("/FWBuilderResources/Target/protocols/failover",
523 protocols);
524 _repackStringList(protocols, res);
525 }
526
getInterfaceTypes(Interface * iface,list<QStringPair> & res)527 void getInterfaceTypes(Interface *iface, list<QStringPair> &res)
528 {
529 FWObject *fw = iface->getParent();
530 string host_os = fw->getStr("host_OS");
531 Resources* os_res = Resources::os_res[host_os];
532 if (os_res==NULL) return;
533 list<string> interface_types;
534
535 if (Cluster::isA(fw))
536 {
537 os_res->getResourceStrList("/FWBuilderResources/Target/interfaces/cluster",
538 interface_types);
539 } else
540 {
541 os_res->getResourceStrList("/FWBuilderResources/Target/interfaces/firewall",
542 interface_types);
543 }
544 _repackStringList(interface_types, res);
545 }
546
547 /*
548 * Return list of types of subinterfaces that given interface can have
549 *
550 * @iface an Interface object. This is not a subinterface, this is a
551 * regular interface. This function returns list of subinterface types
552 * this interface can have.
553 *
554 * @res a list of pairs of QString, each pair is <type>,<description>
555 */
getSubInterfaceTypes(Interface * iface,list<QStringPair> & res)556 void getSubInterfaceTypes(Interface *iface, list<QStringPair> &res)
557 {
558 FWObject *p = Host::getParentHost(iface);
559 //FWObject *p = iface->getParentHost();
560 assert(p!=NULL);
561
562 QString host_os = p->getStr("host_OS").c_str();
563 Resources* os_res = Resources::os_res[host_os.toStdString()];
564 if (os_res==NULL) return;
565
566 FWOptions *ifopt;
567 ifopt = Interface::cast(iface)->getOptionsObject();
568 string parent_type = ifopt->getStr("type");
569
570 // empty parent type is equivalent to "ethernet" for backwards
571 // compatibility
572 if (parent_type.empty()) parent_type = "ethernet";
573
574 QString obj_name = iface->getName().c_str();
575
576 list<string> interface_types;
577 os_res->getResourceStrList(
578 "/FWBuilderResources/Target/subinterfaces/" + parent_type,
579 interface_types);
580 _repackStringList(interface_types, res);
581 }
582
setInterfaceTypes(QComboBox * iface_type,Interface * iface,const QString & current_type)583 void setInterfaceTypes(QComboBox *iface_type,
584 Interface *iface,
585 const QString ¤t_type)
586 {
587 bool this_is_subinterface = Interface::isA(iface->getParent());
588 list<QStringPair> mapping;
589 if (this_is_subinterface)
590 getSubInterfaceTypes(Interface::cast(iface->getParent()), mapping);
591 else getInterfaceTypes(iface, mapping);
592
593 if (st->getBool("Objects/Interface/autoconfigureInterfaces"))
594 {
595 // #335 : if interface name matches naming convention for vlan
596 // interfaces and vlan type is in the list that came from the
597 // resource file, then leave only vlan in the list we return.
598 // Note that if resource file says this subint can not be vlan, we
599 // dan't return vlan type on the list even if its name looks like
600 // it could be one.
601 FWObject *p = Host::getParentHost(iface);
602 //FWObject *p = iface->getParentHost();
603 assert(p!=NULL);
604 QString host_os = p->getStr("host_OS").c_str();
605 QString obj_name = iface->getName().c_str();
606
607 Resources* os_res = Resources::os_res[p->getStr("host_OS")];
608 string os_family = p->getStr("host_OS");
609 if (os_res!=NULL)
610 os_family = os_res->getResourceStr("/FWBuilderResources/Target/family");
611
612 std::auto_ptr<interfaceProperties> int_prop(
613 interfacePropertiesObjectFactory::getInterfacePropertiesObject(
614 os_family));
615 if (int_prop->looksLikeVlanInterface(obj_name))
616 {
617 QString parent_name = iface->getParent()->getName().c_str();
618 QString err;
619 if (int_prop->isValidVlanInterfaceName(obj_name, parent_name, err))
620 {
621 // iface can be valid vlan interface. Leave only vlan type
622 // in the list if it was there to begin with.
623 for (list<QStringPair>::iterator it=mapping.begin();
624 it!=mapping.end(); ++it)
625 {
626 QString itype = it->first;
627 QString rtype = it->second;
628 if (itype == "8021q")
629 {
630 mapping.clear();
631 mapping.push_back(QStringPair(itype, rtype));
632 mapping.push_back(QStringPair("unknown", "Unknown"));
633 break;
634 }
635 }
636 }
637 }
638 }
639
640 list<QStringPair>::iterator it;
641 int idx = 0;
642 int unknown_idx = 0;
643 int current_idx = -1;
644 for (it = mapping.begin(); it != mapping.end(); it++)
645 {
646 if (it->first == "unknown") unknown_idx = idx;
647 iface_type->addItem(it->second);
648 iface_type->setItemData(idx, QVariant(it->first));
649 if (current_type == it->first)
650 current_idx = idx;
651 idx++;
652 }
653 if (current_idx >= 0)
654 iface_type->setCurrentIndex(current_idx);
655 else
656 iface_type->setCurrentIndex(unknown_idx);
657 }
658
659 /* currently we return the same list for all platforms */
getLogLevels(const QString &)660 const QStringList& getLogLevels(const QString&)
661 {
662 return logLevels;
663 }
664
getLogFacilities(const QString &)665 const QStringList& getLogFacilities(const QString&)
666 {
667 return logFacilities;
668 }
669
getActionsOnReject(const QString &)670 const QStringList& getActionsOnReject(const QString&)
671 {
672 return actionsOnReject;
673 }
674
675 /*
676 * need to return mapping list for the parameter 'route_option' of
677 * action 'Routing' regardless of the firewall platform even though
678 * it only makes sense and is needed for pf and ipf. This is because
679 * ActionsDialog is designed with widget stack and therefore must
680 * always initialize widgets for all platforms. Worse, it always
681 * saves all parameters into rule options object, regardless of the
682 * platform. So, if we return an empty mapping list from this method
683 * because platform is not pf or ipf while user is editing action
684 * parameters for iptables, parameters for pf and ipf get saved
685 * uninitizalized and unmapped. QComboBox::currentText() returns the
686 * first item which goes straight into rule options object. This is
687 * ok in English locale, but breaks XML if the item has been
688 * translated and the program runs under national locale. Sigh.
689 */
getRouteOptions_pf_ipf(const QString &)690 const QStringList& getRouteOptions_pf_ipf(const QString&)
691 {
692 return routeOptions_pf_ipf;
693 }
694
getRouteLoadOptions_pf(const QString &)695 const QStringList& getRouteLoadOptions_pf(const QString&)
696 {
697 return routeLoadOptions_pf;
698 }
699
getClassifyOptions_ipfw(const QString &)700 const QStringList& getClassifyOptions_ipfw(const QString&)
701 {
702 return classifyOptions_ipfw;
703 }
704
getLimitSuffixes(const QString &)705 const QStringList& getLimitSuffixes(const QString&)
706 {
707 return limitSuffixes;
708 }
709
710
getScreenNames(const QStringList & sl)711 QStringList getScreenNames(const QStringList &sl)
712 {
713 QStringList res;
714
715 for( QStringList::const_iterator it = sl.begin();
716 it!=sl.end();
717 ++it,++it)
718 {
719 res.push_back(*it);
720 }
721 return res;
722 }
723
getScreenName(QString s,const QStringList & sl)724 QString getScreenName(QString s, const QStringList &sl)
725 {
726 QString res;
727 for( QStringList::const_iterator it = sl.begin();
728 it!=sl.end();
729 ++it)
730 {
731 res=(*it);
732 ++it;
733 if ((*it)==s) break;
734 }
735 return res;
736 }
737
getRuleAction(Rule * rule)738 QString getRuleAction(Rule *rule)
739 {
740 PolicyRule *policy_rule = PolicyRule::cast(rule);
741 NATRule *nat_rule = NATRule::cast(rule);
742 string act;
743 if (policy_rule) act = policy_rule->getActionAsString();
744 if (nat_rule) act = nat_rule->getActionAsString();
745 return act.c_str();
746 }
747
748 /*
749 * will remap names of some actions to make it clear what commands or
750 * configuration language keywords they will be translated to for the
751 * target firewall platform. This should help users who are familiar
752 * with the platform. There are very few places where such mapping is
753 * necessary, plus we need to provide for localization of the mapped
754 * names. That is why action names are not stored in platform resource
755 * files and are not pulled using Rule::getActionAsString.
756 */
757
getActionNameForPlatform(Firewall * fw,Rule * rule)758 QString getActionNameForPlatform(Firewall *fw, Rule *rule)
759 {
760 if (fw==NULL) return "";
761 PolicyRule *policy_rule = PolicyRule::cast(rule);
762 NATRule *nat_rule = NATRule::cast(rule);
763 string act;
764 if (policy_rule) act = policy_rule->getActionAsString();
765 if (nat_rule) act = nat_rule->getActionAsString();
766 return getActionNameForPlatform(fw, act);
767 }
768
getActionNameForPlatform(Firewall * fw,const std::string & action)769 QString getActionNameForPlatform(Firewall *fw, const std::string &action)
770 {
771 if (fw==NULL) return "";
772 string platform = fw->getStr("platform");
773 string name;
774 try
775 {
776 name = Resources::getTargetCapabilityStr(
777 platform, "actions/" + action + "/description");
778 } catch (FWException &ex) { }
779 return name.c_str();
780 }
781
782 /*
783 * this function provides logic for the decision whether the rule
784 * should be stateless by default. Currently it only depends on the
785 * action, but may depend on the platform as well.
786 *
787 * actions Accept, Tag and Route by default assume the rule is
788 * stateful. Other actions by default assume it is stateless
789 * and set rule option accordingly
790 *
791 * See bugs #1676635 and 1671910
792 */
getStatelessFlagForAction(PolicyRule * rule)793 bool getStatelessFlagForAction(PolicyRule *rule)
794 {
795 PolicyRule::Action act = rule->getAction();
796 if (act==PolicyRule::Accept) return false;
797 else
798 return true;
799 }
800
801 /**
802 * Returns translatable string - name of the corresponding rule element.
803 */
getReadableRuleElementName(const string & platform,const string & re_type_name)804 QString getReadableRuleElementName(const string &platform,
805 const string &re_type_name)
806 {
807 bool nat_intf_in = Resources::getTargetCapabilityBool(
808 platform, "inbound_interface_in_nat");
809 bool nat_intf_out = Resources::getTargetCapabilityBool(
810 platform, "outbound_interface_in_nat");
811
812 // The following map TYPENAME of RuleElement classes to readable
813 // translatable names.
814 if (re_type_name == "Src") return QObject::tr("Source");
815 if (re_type_name == "Dst") return QObject::tr("Destination");
816 if (re_type_name == "Srv") return QObject::tr("Service");
817 if (re_type_name == "Itf") return QObject::tr("Interface");
818 if (re_type_name == "When") return QObject::tr("Time");
819
820 if (re_type_name == "OSrc") return QObject::tr("Original Src");
821 if (re_type_name == "ODst") return QObject::tr("Original Dst");
822 if (re_type_name == "OSrv") return QObject::tr("Original Srv");
823
824 if (re_type_name == "TSrc") return QObject::tr("Translated Src");
825 if (re_type_name == "TDst") return QObject::tr("Translated Dst");
826 if (re_type_name == "TSrv") return QObject::tr("Translated Srv");
827
828 if (nat_intf_in != nat_intf_out)
829 {
830 // For some platforms I only show one interface column in nat
831 // rules, in this case nat_intf_in and nat_intf_out have
832 // different values. For example, for PF I hide inbound
833 // interface and show outbound interface column. Columns title
834 // should then be just "Interface"
835 if (re_type_name == "ItfInb") return QObject::tr("Interface");
836 if (re_type_name == "ItfOutb") return QObject::tr("Interface");
837 } else
838 {
839 if (re_type_name == "ItfInb") return QObject::tr("Interface In");
840 if (re_type_name == "ItfOutb") return QObject::tr("Interface Out");
841 }
842
843 if (re_type_name == "RDst") return QObject::tr("Destination");
844 if (re_type_name == "RGtw") return QObject::tr("Gateway");
845 if (re_type_name == "RItf") return QObject::tr("Interface");
846
847 // as of v3.0.x the following are not real rule elements (not separate
848 // classes with names) but just attributes of corresponding Rule class.
849 if (re_type_name == "Direction") return QObject::tr("Direction");
850 if (re_type_name == "Action") return QObject::tr("Action");
851 if (re_type_name == "Options") return QObject::tr("Options");
852 if (re_type_name == "Metric") return QObject::tr("Metric");
853 if (re_type_name == "Comment") return QObject::tr("Comment");
854
855 return QString();
856 }
857
getAllPlatforms(bool filter)858 QMap<QString,QString> getAllPlatforms(bool filter)
859 {
860 QMap<QString,QString> res;
861 map<string,string> platforms = Resources::getPlatforms();
862 map<string,string>::iterator i;
863 for (i=platforms.begin(); i!=platforms.end(); i++)
864 {
865 QString name = i->first.c_str();
866 QString res_status = Resources::platform_res[name.toStdString()]->getResourceStr(
867 "/FWBuilderResources/Target/status/").c_str();
868 QString status = st->getTargetStatus(name, res_status);
869 if (filter && status == "disabled") continue;
870 res[name] = i->second.c_str();
871 }
872 return res;
873 }
874
getAllOS(bool filter)875 QMap<QString,QString> getAllOS(bool filter)
876 {
877 QMap<QString,QString> res;
878 map<string,string> OSs = Resources::getOS();
879 map<string,string>::iterator i;
880 for (i=OSs.begin(); i!=OSs.end(); i++)
881 {
882 QString name = i->first.c_str();
883 QString res_status = Resources::os_res[name.toStdString()]->getResourceStr(
884 "/FWBuilderResources/Target/status/").c_str();
885 QString status = st->getTargetStatus(name, res_status);
886 if (filter && status == "disabled") continue;
887 res[name] = i->second.c_str();
888 }
889 return res;
890 }
891
readPlatform(QComboBox * platform)892 QString readPlatform(QComboBox *platform)
893 {
894 return platform->itemData(platform->currentIndex()).toString();
895 }
896
readHostOS(QComboBox * hostOS)897 QString readHostOS(QComboBox *hostOS)
898 {
899 return hostOS->itemData(hostOS->currentIndex()).toString();
900 }
901
902 /*
903 * Fill combobox widget <platform> with items that exist in resources.
904 * If second argument is not an empty string, make corresponding item current.
905 * If it is an empty string, add an empty item on top to the combo box and make
906 * it current.
907 */
setPlatform(QComboBox * platform,const QString & pl)908 void setPlatform(QComboBox *platform, const QString &pl)
909 {
910 platform->clear();
911 // platforms maps platform name (pix) to readable name (Cisco PIX)
912 QMap<QString,QString> platforms = getAllPlatforms();
913
914 QMap<QString,QString>::iterator i;
915
916 // platform_mapping maps key (<group>.<platform name>) to pair
917 // <group>, <platform name>
918 QMap<QString, QPair<QString, QString> > platform_mapping;
919 QStringList platform_keys;
920
921 for (i=platforms.begin(); i!=platforms.end(); i++)
922 {
923 QString group =
924 Resources::platform_res[i.key().toLatin1().constData()]->
925 getResourceStr("/FWBuilderResources/Target/group").c_str();
926 QString key = group + "." + i.key();
927 platform_mapping[key] = QPair<QString,QString>(group, i.key());
928 platform_keys.push_back(key);
929 }
930
931 qSort(platform_keys);
932
933 QStringList::iterator iter;
934 int ind = 0;
935 int cp = 0;
936
937 if (pl.isEmpty())
938 {
939 platform->addItem("", "");
940 cp++;
941 }
942
943 QString current_group = "";
944 for (iter=platform_keys.begin(); iter!=platform_keys.end(); iter++)
945 {
946 if (fwbdebug) qDebug() << *iter;
947
948 QString group = platform_mapping[*iter].first;
949 QString platform_name = platform_mapping[*iter].second;
950
951 if (platforms.count(platform_name) == 0) continue;
952
953 if (group != current_group)
954 {
955 current_group = group;
956 #if (QT_VERSION > 0x040500)
957 platform->insertSeparator(cp); // QT before 4.4.? does not support separator in QComboBox
958 #else
959 platform->addItem("");
960 #endif
961 cp++;
962 }
963
964 platform->addItem(platforms[platform_name], platform_name);
965 // note that if pl is "", then no real platform name will
966 // match it and ind will remain 0, which makes the top item in
967 // the combobox current.
968 if ( pl == platform_name ) ind = cp;
969 cp++;
970 }
971 platform->setCurrentIndex( ind );
972 }
973
974 /*
975 * Fill in "host os" combo box with list of os supported for the given
976 * platform and make current host os item current.
977 *
978 * If platform == "", then use all known host OS but also add
979 * empty item on top of the combobox and make that item current.
980 * If os == "", make the first OS in the list current.
981 */
setHostOS(QComboBox * hostOS,const QString & platform,const QString & os)982 void setHostOS(QComboBox *hostOS, const QString &platform, const QString &os)
983 {
984 hostOS->clear();
985
986 QStringList supported_os_list;
987
988 if (!platform.isEmpty())
989 {
990 Resources *platform_res = Resources::platform_res[platform.toLatin1().constData()];
991 if (!platform_res)
992 platform_res = Resources::platform_res["unknown"];
993
994 QString supported_os = platform_res->
995 getResourceStr("/FWBuilderResources/Target/supported_os").c_str();
996
997 if (fwbdebug)
998 qDebug("supported_os %s", supported_os.toLatin1().constData());
999
1000 if (supported_os.isEmpty())
1001 {
1002 // something is broken, we have no supported host OS for
1003 // this platform. Just add os to the combo box and return
1004 if (fwbdebug)
1005 qDebug("No supported host OS for platform %s",
1006 platform.toLatin1().constData());
1007
1008 hostOS->addItem(os, os);
1009 hostOS->setCurrentIndex(0);
1010 return;
1011 }
1012 supported_os_list = supported_os.split(",");
1013
1014 int cp = 0;
1015 int ind = 0;
1016 QMap<QString,QString> OSs = getAllOS();
1017 QStringList::iterator os_iter;
1018 for (os_iter=supported_os_list.begin();
1019 os_iter!=supported_os_list.end(); ++os_iter)
1020 {
1021 QString os_code = *os_iter;
1022 if (OSs.count(os_code) > 0)
1023 {
1024 hostOS->addItem( OSs[os_code], os_code);
1025 if ( os == os_code ) ind = cp;
1026 cp++;
1027 }
1028 }
1029 hostOS->setCurrentIndex( ind );
1030 return;
1031 }
1032
1033 // platform is empty
1034
1035 int cp = 0;
1036 int ind = 0;
1037
1038 hostOS->addItem("", "");
1039 cp++;
1040
1041 QMap<QString,QString> OSs = getAllOS();
1042 QMap<QString,QString>::iterator i;
1043 for (i=OSs.begin(); i!=OSs.end(); i++)
1044 {
1045 hostOS->addItem( i.value(), i.key() );
1046 if ( os == i.key() ) ind = cp;
1047 cp++;
1048 }
1049
1050 hostOS->setCurrentIndex( ind );
1051 }
1052
_repackStringList(list<string> & list1,list<QStringPair> & list2)1053 void _repackStringList(list<string> &list1, list<QStringPair> &list2)
1054 {
1055 list2.clear();
1056 foreach(string p, list1)
1057 {
1058 QString str = QString(p.c_str());
1059 QStringList pl = str.split(",");
1060 if (pl.size() == 1)
1061 list2.push_back(QStringPair(str, str));
1062 else
1063 list2.push_back(QStringPair(pl[0], pl[1]));
1064 }
1065 }
1066
setDefaultStateSyncGroupAttributes(StateSyncClusterGroup * grp)1067 void setDefaultStateSyncGroupAttributes(StateSyncClusterGroup *grp)
1068 {
1069 FWObject *p = grp;
1070 while (p && Cluster::cast(p)==NULL) p = p->getParent();
1071 assert(p != NULL);
1072 Cluster *cluster = Cluster::cast(p);
1073 Resources *os_res = Resources::os_res[cluster->getStr("host_OS")];
1074 assert(os_res != NULL);
1075
1076 list<string> protocols;
1077 os_res->getResourceStrList("/FWBuilderResources/Target/protocols/state_sync",
1078 protocols);
1079
1080 QStringList protocol_names = QString(protocols.front().c_str()).split(",");
1081
1082 grp->setName(protocol_names[1].toStdString());
1083 grp->setStr("type", protocol_names[0].toStdString());
1084 }
1085
setDefaultFailoverGroupAttributes(FailoverClusterGroup * grp)1086 void setDefaultFailoverGroupAttributes(FailoverClusterGroup *grp)
1087 {
1088 FWObject *p = grp;
1089 while (p && Cluster::cast(p)==NULL) p = p->getParent();
1090 assert(p != NULL);
1091 Cluster *cluster = Cluster::cast(p);
1092 Resources *os_res = Resources::os_res[cluster->getStr("host_OS")];
1093 assert(os_res != NULL);
1094
1095 FWOptions *gropt = grp-> getOptionsObject();
1096 assert(gropt != NULL);
1097
1098 string failover_protocol = grp->getStr("type");
1099
1100 if (failover_protocol == "carp")
1101 {
1102 gropt->setStr("carp_password", "");
1103 gropt->setInt("carp_vhid", 1);
1104 gropt->setInt("carp_advbase", 1);
1105 gropt->setInt("carp_master_advskew", 10);
1106 gropt->setInt("carp_default_advskew", 20);
1107 }
1108
1109 if (failover_protocol == "vrrp")
1110 {
1111 gropt->setStr("vrrp_secret", "");
1112 gropt->setInt("vrrp_vrid", 1);
1113 gropt->setBool("vrrp_over_ipsec_ah", false);
1114 }
1115
1116 if (failover_protocol == "heartbeat")
1117 {
1118 string default_address =
1119 os_res->getResourceStr(
1120 "/FWBuilderResources/Target/protocols/heartbeat/default_address");
1121 string default_port =
1122 os_res->getResourceStr(
1123 "/FWBuilderResources/Target/protocols/heartbeat/default_port");
1124
1125 gropt->setStr("heartbeat_address", default_address);
1126 gropt->setStr("heartbeat_port", default_port);
1127 gropt->setBool("heartbeat_unicast", false);
1128 }
1129
1130 if (failover_protocol == "openais")
1131 {
1132 string default_address =
1133 os_res->getResourceStr(
1134 "/FWBuilderResources/Target/protocols/openais/default_address");
1135 string default_port =
1136 os_res->getResourceStr(
1137 "/FWBuilderResources/Target/protocols/openais/default_port");
1138 gropt->setStr("openais_address", default_address);
1139 gropt->setStr("openais_port", default_port);
1140 }
1141
1142 if (failover_protocol == "pix_failover")
1143 {
1144 gropt->setStr("pix_failover_key", "");
1145 }
1146 }
1147
guessInterfaceLabel(InterfaceData * idata)1148 void guessInterfaceLabel(InterfaceData *idata)
1149 {
1150 /*
1151 * some firewalls report fairly regular names for interfaces through
1152 * their built-in SNMP agent. We can use this to assign labels
1153 * automatically.
1154 *
1155 * in PIX interfaces have names like "PIX Firewall 'inside' interface"
1156 *
1157 */
1158 QString qs_name = idata->name.c_str();
1159 QString qs_label;
1160
1161 QRegExp pat1("Adaptive Security Appliance '(.*)' interface");
1162 QRegExp pat2("Cisco PIX Security Appliance '(.*)' interface");
1163 QRegExp pat3("PIX Firewall '(.*)' interface");
1164
1165 if (pat1.indexIn(qs_name) > -1) qs_label = pat1.cap(1);
1166 if (pat2.indexIn(qs_name) > -1) qs_label = pat2.cap(1);
1167 if (pat3.indexIn(qs_name) > -1) qs_label = pat3.cap(1);
1168
1169 idata->label = qs_label.toStdString();
1170
1171 if ( ! idata->isDyn &&
1172 ! idata->isUnnumbered &&
1173 ! idata->isBridgePort &&
1174 idata->addr_mask.size()!=0 &&
1175 idata->addr_mask.front()->getAddressPtr()->toString() == InetAddr::getLoopbackAddr().toString())
1176 idata->label = "loopback";
1177 }
1178
guessSecurityLevel(const string &,InterfaceData * idata)1179 void guessSecurityLevel(const string&, InterfaceData *idata)
1180 {
1181 InetAddrMask n10(InetAddr("10.0.0.0"), InetAddr("255.0.0.0"));
1182 InetAddrMask n172(InetAddr("172.16.0.0"), InetAddr("255.240.0.0"));
1183 InetAddrMask n192(InetAddr("192.168.0.0"), InetAddr("255.255.0.0"));
1184
1185 idata->securityLevel = -1;
1186
1187 string llbl = idata->label;
1188
1189 for (string::size_type i=0; i<llbl.length(); i++)
1190 llbl[i] = tolower( llbl[i] );
1191
1192 if ( llbl=="out" ||
1193 llbl=="ext" ||
1194 llbl=="internet" ||
1195 llbl=="wan" ||
1196 llbl=="dsl" ||
1197 llbl=="cable" ||
1198 llbl.find("outside")!=string::npos ||
1199 llbl.find("external")!=string::npos) idata->securityLevel = 0;
1200
1201 if ( llbl=="lan" ||
1202 llbl=="in" ||
1203 llbl.find("inside")!=string::npos ||
1204 llbl.find("internal")!=string::npos ) idata->securityLevel = 100;
1205
1206 if ( llbl.find("dmz")!=string::npos ) idata->securityLevel = 50;
1207
1208 if ((*(idata->addr_mask.front()->getAddressPtr()))==InetAddr::getLoopbackAddr())
1209 idata->securityLevel = 100;
1210
1211 if (idata->name=="Null0") idata->securityLevel = 100;
1212
1213 if (idata->securityLevel==-1 &&
1214 ! idata->isDyn && ! idata->isUnnumbered && ! idata->isBridgePort)
1215 {
1216 if (n10.belongs(InetAddr(*(idata->addr_mask.front()->getAddressPtr()))))
1217 idata->securityLevel = 100;
1218
1219 if (n172.belongs(InetAddr(*(idata->addr_mask.front()->getAddressPtr()))))
1220 idata->securityLevel = 100;
1221
1222 if (n192.belongs(InetAddr(*(idata->addr_mask.front()->getAddressPtr()))))
1223 idata->securityLevel = 100;
1224 }
1225
1226 if (idata->isDyn || idata->isUnnumbered || idata->isBridgePort)
1227 idata->securityLevel = 0;
1228
1229 if (idata->securityLevel==-1) idata->securityLevel = 0;
1230 }
1231
guessOSAndPlatformFromSysDescr(const QString & sysDescr,QString & platform,QString & hostOS,QString & version)1232 void guessOSAndPlatformFromSysDescr(
1233 const QString &sysDescr, QString &platform, QString &hostOS, QString &version)
1234 {
1235 QList<QRegExp> pix_re;
1236 pix_re << QRegExp("Cisco PIX Firewall Version ([0-9\\.]+)")
1237 << QRegExp("Cisco PIX Security Appliance Version ([0-9\\.]+)")
1238 << QRegExp("Cisco Adaptive Security Appliance Version ([0-9\\.]+)");
1239
1240 QList<QRegExp> ios_re;
1241 ios_re << QRegExp("Cisco Internetwork Operating System Software .* Version ([0-9\\.]+)");
1242
1243 platform = "";
1244 hostOS = "";
1245 version = "";
1246
1247 if (fwbdebug)
1248 qDebug() << "guessOSAndPlatformFromSysDescr:"
1249 << "sysdescr=" << sysDescr;
1250
1251 list<QStringPair> allowed_versions;
1252 QString version_from_sysdescr;
1253
1254 foreach (QRegExp re, pix_re)
1255 {
1256 if (re.indexIn(sysDescr) > -1)
1257 {
1258 platform = "pix";
1259 hostOS = "pix_os";
1260 version_from_sysdescr = re.cap(1);
1261 }
1262 }
1263
1264
1265 foreach (QRegExp re, ios_re)
1266 {
1267 if (re.indexIn(sysDescr) > -1)
1268 {
1269 platform = "iosacl";
1270 hostOS = "ios";
1271 version_from_sysdescr = re.cap(1);
1272 }
1273 }
1274
1275 if (fwbdebug)
1276 qDebug() << "guessOSAndPlatformFromSysDescr:"
1277 << "platform=" << platform
1278 << "hostOS=" << hostOS
1279 << "version=" << version_from_sysdescr;
1280
1281 if ( ! platform.isEmpty())
1282 version = findBestVersionMatch(platform, version_from_sysdescr);
1283
1284 }
1285
findBestVersionMatch(const QString & platform,const QString & discovered_version)1286 QString findBestVersionMatch(const QString &platform,
1287 const QString &discovered_version)
1288 {
1289 list<QStringPair> allowed_versions;
1290
1291 getVersionsForPlatform(platform, allowed_versions);
1292
1293 if ( ! discovered_version.isEmpty())
1294 {
1295 QString version_fit;
1296 list<QStringPair>::iterator it;
1297 foreach (QStringPair p, allowed_versions)
1298 {
1299 QString vers = p.first;
1300 if (XMLTools::version_compare(vers.toStdString(),
1301 discovered_version.toStdString())>0)
1302 break;
1303 version_fit = vers;
1304 }
1305 return version_fit;
1306 }
1307 return "";
1308 }
1309
1310
1311
1312