1 /*
2 
3                           Firewall Builder
4 
5                  Copyright (C) 2003 NetCitadel, LLC
6 
7   Author:  Vadim Kurland     vadim@fwbuilder.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 #include "utils.h"
29 
30 #include "FWBTree.h"
31 #include "NetworkDialog.h"
32 #include "ProjectPanel.h"
33 #include "FWBSettings.h"
34 #include "FWCmdChange.h"
35 
36 #include "fwbuilder/Library.h"
37 #include "fwbuilder/Network.h"
38 #include "fwbuilder/Interface.h"
39 #include "fwbuilder/FWException.h"
40 #include "fwbuilder/Inet6AddrMask.h"
41 
42 #include <memory>
43 
44 #include <qlineedit.h>
45 #include <qspinbox.h>
46 #include <qcheckbox.h>
47 #include <qtextedit.h>
48 #include <qcombobox.h>
49 #include <qmessagebox.h>
50 #include <qpushbutton.h>
51 #include <QUndoStack>
52 #include <QtDebug>
53 #include <QApplication>
54 
55 
56 using namespace std;
57 using namespace libfwbuilder;
58 
NetworkDialog(QWidget * parent)59 NetworkDialog::NetworkDialog(QWidget *parent) : BaseObjectDialog(parent)
60 {
61     m_dialog = new Ui::NetworkDialog_q;
62     m_dialog->setupUi(this);
63     obj=NULL;
64 
65     connectSignalsOfAllWidgetsToSlotChange();
66 }
67 
~NetworkDialog()68 NetworkDialog::~NetworkDialog() { delete m_dialog; }
69 
loadFWObject(FWObject * o)70 void NetworkDialog::loadFWObject(FWObject *o)
71 {
72     obj = o;
73     Network *s = dynamic_cast<Network*>(obj);
74     assert(s!=NULL);
75 
76     init = true;
77 
78     // See #893 No need to show address and mask 0.0.0.0 to the user
79     // if the object is "Any", especially because the same object is
80     // used as "any" for both ipv4 and ipv6 rules. It can be confusing
81     // if they see address "0.0.0.0" while they want to find object
82     // "any" for ipv6.
83 
84     // see also #2454, trying to do even more handholding for users
85     // who do not understand what "any" means in a rule.
86 
87     if (obj->getId() == FWObjectDatabase::ANY_ADDRESS_ID)
88     {
89         m_dialog->object_attributes->hide();
90         m_dialog->commentKeywords->setReadOnlyComment(
91             QObject::tr(
92                 "When used in the Source or Destination field of a rule, "
93                 "the Any object will match all "
94                 "IP addresses. To update your rule to match only specific "
95                 "IP addresses, drag-and-drop an object from "
96                 "the Object tree into the field in the rule."));
97     } else
98     {
99         m_dialog->obj_name->setText( QString::fromUtf8(s->getName().c_str()) );
100         m_dialog->address->setText( s->getAddressPtr()->toString().c_str() );
101         m_dialog->netmask->setText( s->getNetmaskPtr()->toString().c_str() );
102         m_dialog->commentKeywords->loadFWObject(o);
103 
104         m_dialog->object_attributes->show();
105 
106         m_dialog->obj_name->setEnabled(!o->isReadOnly());
107         setDisabledPalette(m_dialog->obj_name);
108 
109         m_dialog->address->setEnabled(!o->isReadOnly());
110         setDisabledPalette(m_dialog->address);
111 
112         m_dialog->netmask->setEnabled(!o->isReadOnly());
113         setDisabledPalette(m_dialog->netmask);
114     }
115 
116     init = false;
117 }
118 
validate(bool * result)119 void NetworkDialog::validate(bool *result)
120 {
121     if (fwbdebug) qDebug() << "NetworkDialog::validate";
122 
123     *result = true;
124 
125     if (!validateName(this,obj,m_dialog->obj_name->text()))
126     {
127         *result = false;
128         return;
129     }
130 
131     Network *s = dynamic_cast<Network*>(obj);
132     assert(s!=NULL);
133     try
134     {
135         InetAddr( m_dialog->address->text().toStdString() );
136     } catch (FWException &ex)
137     {
138         *result = false;
139         if (QApplication::focusWidget() != NULL)
140         {
141             blockSignals(true);
142             QMessageBox::critical(
143                 this, "Firewall Builder",
144                 tr("Illegal IP address '%1'").arg(m_dialog->address->text()),
145                 tr("&Continue"), 0, 0,
146                 0 );
147             blockSignals(false);
148         }
149         return;
150     }
151 
152     InetAddr addr(m_dialog->address->text().toStdString());
153 
154     try
155     {
156         QString len = m_dialog->netmask->text() ;
157         bool ok = false ;
158         int ilen = len.toInt(&ok);
159         if (ok)
160         {
161             // permit netmask 0.0.0.0 if the address is also 0.0.0.0
162             if (addr.isAny() && ilen == 0) return;
163 
164             if (ilen>0 && ilen < 32)
165             {
166                 return ;
167             }
168             else
169             {
170                 *result = false;
171                 QMessageBox::critical(
172                     this, "Firewall Builder",
173                     tr("Illegal netmask '%1'").arg( m_dialog->netmask->text() ),
174                     tr("&Continue"), 0, 0,
175                     0 );
176                 return;
177             }
178         }
179 
180         InetAddr nm( m_dialog->netmask->text().toStdString() );
181 
182         if (nm.isAny())
183         {
184             // permit netmask 0.0.0.0 if the address is also 0.0.0.0
185             if (addr.isAny()) return;
186             else
187             {
188                 *result = false;
189                 if (QApplication::focusWidget() != NULL)
190                 {
191                     blockSignals(true);
192                     // Do not allow netmask of 0 bits See #251
193                     QMessageBox::critical(
194                         this, "Firewall Builder",
195                         tr("Network object should not have netmask '0.0.0.0'"),
196                         tr("&Continue"), 0, 0,
197                         0 );
198                     blockSignals(false);
199                 }
200                 return;
201             }
202         }
203 
204         if (!nm.isValidV4Netmask())
205         {
206             *result = false;
207             if (QApplication::focusWidget() != NULL)
208             {
209                 blockSignals(true);
210                 // Do not allow netmask with zeroes inside.
211                 QMessageBox::critical(
212                     this, "Firewall Builder",
213                     tr("Netmasks with zeroes in the middle are not supported"),
214                     tr("&Continue"), 0, 0,
215                     0 );
216                 blockSignals(false);
217             }
218             return;
219         }
220 
221     } catch (FWException &ex)
222     {
223 
224         *result = false;
225         if (QApplication::focusWidget() != NULL)
226         {
227             blockSignals(true);
228             QMessageBox::critical(
229                 this, "Firewall Builder",
230                 tr("Illegal netmask '%1'").arg( m_dialog->netmask->text() ),
231                 tr("&Continue"), 0, 0,
232                 0 );
233             blockSignals(false);
234         }
235     }
236 }
237 
238 
239 
applyChanges()240 void NetworkDialog::applyChanges()
241 {
242     std::auto_ptr<FWCmdChange> cmd( new FWCmdChange(m_project, obj));
243     FWObject* new_state = cmd->getNewState();
244 
245     Network *s = dynamic_cast<Network*>(new_state);
246     assert(s!=NULL);
247 
248     string oldname = obj->getName();
249     new_state->setName(string(m_dialog->obj_name->text().toUtf8().constData()));
250     m_dialog->commentKeywords->applyChanges(new_state);
251 
252     try
253     {
254         s->setAddress(InetAddr(m_dialog->address->text().toStdString()));
255     } catch (FWException &ex)
256     {
257 // exception thrown if user types illegal m_dialog->address or
258 // m_dialog->netmask
259     }
260 
261     try
262     {
263         QString len = m_dialog->netmask->text() ;
264         bool ok = false ;
265         int ilen = len.toInt (&ok);
266         if (ok)
267         {
268             s->setNetmask(InetAddr(ilen));
269         }
270         else
271         {
272             s->setNetmask(InetAddr(m_dialog->netmask->text().toStdString()));
273         }
274     } catch (FWException &ex)
275     {
276 // exception thrown if user types illegal m_dialog->address or
277 // m_dialog->netmask
278 //        bool ok = false ;
279     }
280 
281     if (!cmd->getOldState()->cmp(new_state, true))
282     {
283         if (fwbdebug)
284             qDebug() << "Pushing FWCmdChange to undo stack";
285 
286         if (obj->isReadOnly()) return;
287         m_project->undoStack->push(cmd.release());
288     }
289 
290 }
291 
addressEntered()292 void NetworkDialog::addressEntered()
293 {
294     try
295     {
296         QString addr = m_dialog->address->text();
297         InetAddrMask address_and_mask(string(addr.toStdString()));
298         if (addr.contains('/'))
299         {
300             m_dialog->address->setText(
301                 address_and_mask.getAddressPtr()->toString().c_str());
302             m_dialog->netmask->setText(
303                 address_and_mask.getNetmaskPtr()->toString().c_str());
304         }
305     } catch (FWException &ex)
306     {
307         // exception thrown if user types illegal m_dialog->address do
308         // not show error dialog. This method is called by
309         // editingFinished signal and therefore is invoked when user
310         // switches focus from the address input widget to some other
311         // widget or even when user switches to another application to
312         // look up the address. Error dialog interrupts the workflow
313         // in the latter case which is annoying.
314     }
315 
316 }
317 
318