1 /*
2 
3                           Firewall Builder
4 
5                  Copyright (C) 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 #include "config.h"
25 
26 #include "NamedObject.h"
27 
28 #include "fwbuilder/AddressRange.h"
29 #include "fwbuilder/ICMPService.h"
30 #include "fwbuilder/TCPService.h"
31 #include "fwbuilder/UDPService.h"
32 #include "fwbuilder/CustomService.h"
33 #include "fwbuilder/Interface.h"
34 #include "fwbuilder/IPv4.h"
35 #include "fwbuilder/Network.h"
36 #include "fwbuilder/Interface.h"
37 
38 #include <assert.h>
39 #include <sstream>
40 
41 #include <QStringList>
42 #include <QSet>
43 
44 
45 using namespace libfwbuilder;
46 using namespace fwcompiler;
47 using namespace std;
48 
49 /*
50  * Reserved words for all versions of IOS and ASA that support named
51  * objects. It does not make sense to maintain sets of reserved words
52  * separately for each version because it would take a lot of effort
53  * for very little gain. We will maintain super-set of words that
54  * corresponds to the version that has most extensive set.
55  */
56 const char* rw[] = {
57     "ah",
58     "eigrp",
59     "esp",
60     "gre",
61     "icmp",
62     "icmp6",
63     "igmp",
64     "igrp",
65     "ip",
66     "ipinip",
67     "ipsec",
68     "nos",
69     "ospf",
70     "pcp",
71     "pim",
72     "pptp",
73     "snp",
74     "tcp",
75     "udp",
76     "tcp-aol",
77     "tcp-bgp",
78     "tcp-chargen",
79     "tcp-cifs",
80     "tcp-citrix-ica",
81     "tcp-ctiqbe",
82     "tcp-daytime",
83     "tcp-discard",
84     "tcp-domain",
85     "tcp-echo",
86     "tcp-exec",
87     "tcp-finger",
88     "tcp-ftp",
89     "tcp-ftp-data",
90     "tcp-gopher",
91     "tcp-ident",
92     "tcp-imap4",
93     "tcp-irc",
94     "tcp-hostname",
95     "tcp-kerberos",
96     "tcp-klogin",
97     "tcp-kshell",
98     "tcp-ldap",
99     "tcp-ldaps",
100     "tcp-login",
101     "tcp-lotusnotes",
102     "tcp-nfs",
103     "tcp-netbios-ssn",
104     "tcp-whois",
105     "tcp-nntp",
106     "tcp-pcanywhere-data",
107     "tcp-pim-auto-rp",
108     "tcp-pop2",
109     "tcp-pop3",
110     "tcp-pptp",
111     "tcp-lpd",
112     "tcp-rsh",
113     "tcp-rtsp",
114     "tcp-sip",
115     "tcp-smtp",
116     "tcp-ssh",
117     "tcp-sunrpc",
118     "tcp-tacacs",
119     "tcp-talk",
120     "tcp-telnet",
121     "tcp-uucp",
122     "tcp-www",
123     "tcp-http",
124     "tcp-https",
125     "tcp-cmd",
126     "tcp-sqlnet",
127     "tcp-h323",
128     "tcp-udp-cifs",
129     "tcp-udp-discard",
130     "tcp-udp-domain",
131     "tcp-udp-echo",
132     "tcp-udp-kerberos",
133     "tcp-udp-nfs",
134     "tcp-udp-pim-auto-rp",
135     "tcp-udp-sip",
136     "tcp-udp-sunrpc",
137     "tcp-udp-tacacs",
138     "tcp-udp-www",
139     "tcp-udp-http",
140     "tcp-udp-talk",
141     "udp-biff",
142     "udp-bootpc",
143     "udp-bootps",
144     "udp-cifs",
145     "udp-discard",
146     "udp-domain",
147     "udp-dnsix",
148     "udp-echo",
149     "udp-www",
150     "udp-http",
151     "udp-nameserver",
152     "udp-kerberos",
153     "udp-mobile-ip",
154     "udp-nfs",
155     "udp-netbios-ns",
156     "udp-netbios-dgm",
157     "udp-ntp",
158     "udp-pcanywhere-status",
159     "udp-pim-auto-rp",
160     "udp-radius",
161     "udp-radius-acct",
162     "udp-rip",
163     "udp-secureid-udp",
164     "udp-sip",
165     "udp-snmp",
166     "udp-snmptrap",
167     "udp-sunrpc",
168     "udp-syslog",
169     "udp-tacacs",
170     "udp-talk",
171     "udp-tftp",
172     "udp-time",
173     "udp-who",
174     "udp-xdmcp",
175     "udp-isakmp",
176     "icmp6-unreachable",
177     "icmp6-packet-too-big",
178     "icmp6-time-exceeded",
179     "icmp6-parameter-problem",
180     "icmp6-echo",
181     "icmp6-echo-reply",
182     "icmp6-membership-query",
183     "icmp6-membership-report",
184     "icmp6-membership-reduction",
185     "icmp6-router-renumbering",
186     "icmp6-router-solicitation",
187     "icmp6-router-advertisement",
188     "icmp6-neighbor-solicitation",
189     "icmp6-neighbor-advertisement",
190     "icmp6-neighbor-redirect",
191     "icmp-echo",
192     "icmp-echo-reply",
193     "icmp-unreachable",
194     "icmp-source-quench",
195     "icmp-redirect",
196     "icmp-alternate-address",
197     "icmp-router-advertisement",
198     "icmp-router-solicitation",
199     "icmp-time-exceeded",
200     "icmp-parameter-problem",
201     "icmp-timestamp-request",
202     "icmp-timestamp-reply",
203     "icmp-information-request",
204     "icmp-information-reply",
205     "icmp-mask-request",
206     "icmp-mask-reply",
207     "icmp-traceroute",
208     "icmp-conversion-error",
209     "icmp-mobile-redirect",
210     NULL
211     };
212 
213 QSet<QString> NamedObject::reserved_words;
214 map<QString,int> NamedObject::name_disambiguation;
215 
216 
NamedObject(const FWObject * _obj,const QString & _platform)217 NamedObject::NamedObject(const FWObject *_obj, const QString &_platform)
218 {
219     obj = _obj;
220     platform = _platform;
221     if (reserved_words.empty())
222     {
223         const char** cptr = rw;
224         while (*cptr!=NULL)
225         {
226             reserved_words.insert(QString(*cptr));
227             cptr++;
228         }
229     }
230     name = sanitizeObjectName(QString::fromUtf8(obj->getName().c_str()));
231 }
232 
getCommandWord()233 QString NamedObject::getCommandWord()
234 {
235     if (Address::constcast(obj)!=NULL && Address::constcast(obj)->isAny())
236         return "any";
237 
238     if (Service::constcast(obj)!=NULL && Service::constcast(obj)->isAny())
239         return "any";
240 
241     if (Interface::constcast(obj))
242         return "interface";
243 
244     return name;
245 }
246 
sanitizeObjectName(const QString & name)247 QString NamedObject::sanitizeObjectName(const QString &name)
248 {
249     QString qs = name;
250     qs = qs.replace(" ", "_").replace("/", "_").left(64);
251 
252     if (reserved_words.contains(qs))
253     {
254         qs = qs + "_obj";
255     }
256 
257     int n = name_disambiguation[qs];
258     name_disambiguation[qs] = n + 1;
259     qs = QString("%1.%2").arg(qs).arg(n);
260 
261     return qs;
262 }
263 
createNetworkObjectCommand(const Address * addr_obj)264 QString NamedObject::createNetworkObjectCommand(const Address *addr_obj)
265 {
266     if (addr_obj == NULL) return "";
267     if (addr_obj->isAny()) return "";
268     if (Interface::constcast(obj)) return "";
269 
270     QStringList res;
271 
272     res << QString("object network %1") .arg(name);
273 
274     if (AddressRange::isA(addr_obj))
275     {
276         const AddressRange *ar = AddressRange::constcast(addr_obj);
277         res << QString("  range %1 %2")
278             .arg(ar->getRangeStart().toString().c_str())
279             .arg(ar->getRangeEnd().toString().c_str());
280     } else
281     {
282         string addr = addr_obj->getAddressPtr()->toString();
283 
284         if (IPv4::isA(addr_obj))
285         {
286             res << QString("  host %1").arg(addr.c_str());
287         }
288 
289         if (Network::isA(addr_obj))
290         {
291             string netm = addr_obj->getNetmaskPtr()->toString();
292             res << QString("  subnet %1 %2")
293                 .arg(addr.c_str())
294                 .arg(netm.c_str());
295         }
296     }
297 
298 
299     res << "exit";
300     res << "";
301     return res.join("\n");
302 }
303 
printPorts(int rs,int re)304 QString NamedObject::printPorts(int rs, int re)
305 {
306     QStringList res;
307 
308     if (rs<0) rs = 0;
309     if (re<0) re = 0;
310 
311     if (rs>0 || re>0)
312     {
313         if (rs==re)  res << "eq" << QString::number(rs);
314         else
315             if (rs==0 && re!=0) res << "lt" << QString::number(re);
316             else
317                 if (rs!=0 && re==65535) res << "gt" << QString::number(rs);
318                 else
319                     res << "range " << QString::number(rs)
320                         << "" << QString::number(re);
321     }
322     return res.join(" ");
323 }
324 
createServiceObjectCommand(const Service * serv_obj)325 QString NamedObject::createServiceObjectCommand(const Service *serv_obj)
326 {
327     if (serv_obj == NULL) return "";
328     if (serv_obj->isAny()) return "";
329 
330     QStringList res;
331 
332     QString proto_name = serv_obj->getProtocolName().c_str();
333 
334     res << QString("object service %1").arg(name);
335 
336     QStringList service_line;
337 
338     service_line << "  service";
339 
340     if (TCPService::isA(serv_obj) || UDPService::isA(serv_obj))
341     {
342         service_line << proto_name;
343 
344 	int rs = TCPUDPService::constcast(serv_obj)->getSrcRangeStart();
345 	int re = TCPUDPService::constcast(serv_obj)->getSrcRangeEnd();
346         if (rs != 0 || re != 0)
347         {
348             service_line << "source" << printPorts(rs, re);
349         }
350 
351 	rs = TCPUDPService::constcast(serv_obj)->getDstRangeStart();
352 	re = TCPUDPService::constcast(serv_obj)->getDstRangeEnd();
353         if (rs != 0 || re != 0)
354         {
355             service_line << "destination" << printPorts(rs, re);
356         }
357     }
358 
359     if (ICMPService::isA(serv_obj))
360     {
361         service_line << proto_name;
362         if (serv_obj->getInt("type")!=-1)
363             service_line << QString::number(serv_obj->getInt("type"));
364     }
365 
366     if (CustomService::isA(serv_obj))
367     {
368         service_line << CustomService::constcast(serv_obj)->getCodeForPlatform(
369             platform.toStdString()).c_str();
370     }
371 
372     res << service_line.join(" ");
373     res << "exit";
374     res << "";
375     return res.join("\n");
376 }
377 
378 
getCommand()379 QString NamedObject::getCommand()
380 {
381     if (Address::constcast(obj)!=NULL)
382         return createNetworkObjectCommand(Address::constcast(obj));
383 
384     if (Service::constcast(obj)!=NULL)
385         return createServiceObjectCommand(Service::constcast(obj));
386 
387     return "";
388 }
389 
getCommandWhenObjectGroupMember()390 QString NamedObject::getCommandWhenObjectGroupMember()
391 {
392     if (Address::constcast(obj)!=NULL) return "network-object object " + name;
393     if (Service::constcast(obj)!=NULL) return "service-object object " + name;
394     return "";
395 }
396 
397 
398