summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier Blin <oblin@mandriva.org>2005-09-28 12:52:36 +0000
committerOlivier Blin <oblin@mandriva.org>2005-09-28 12:52:36 +0000
commit36c0bad1fa4d61860a9cb4688759a49fa22cde67 (patch)
tree44f4c1dcb29c5fa37a46aa2eb76bdeadedf06647
parent1ed8ad88617b996a1dc37deddd2f44dd36adf4af (diff)
downloadmandi-36c0bad1fa4d61860a9cb4688759a49fa22cde67.tar
mandi-36c0bad1fa4d61860a9cb4688759a49fa22cde67.tar.gz
mandi-36c0bad1fa4d61860a9cb4688759a49fa22cde67.tar.bz2
mandi-36c0bad1fa4d61860a9cb4688759a49fa22cde67.tar.xz
mandi-36c0bad1fa4d61860a9cb4688759a49fa22cde67.zip
Initial revisionr0topic/v0
-rw-r--r--COPYING340
-rw-r--r--Makefile18
-rw-r--r--conf/mandi.conf36
-rw-r--r--mandi.spec152
-rw-r--r--rules.d/psd1
-rw-r--r--scripts/mandi.init45
-rw-r--r--scripts/start5
-rw-r--r--scripts/stop3
-rw-r--r--src/Makefile25
-rw-r--r--src/mandi_daemon.c269
-rw-r--r--src/plugin.h21
-rw-r--r--src/plugins/ifw/black_list.c76
-rw-r--r--src/plugins/ifw/black_list.h20
-rw-r--r--src/plugins/ifw/ifw.h48
-rw-r--r--src/plugins/ifw/ifw_dbus.c456
-rw-r--r--src/plugins/ifw/ifw_dbus.h43
-rw-r--r--src/plugins/ifw/ipset.c89
-rw-r--r--src/plugins/ifw/ipset.h22
-rw-r--r--src/plugins/ifw/libnl_ifw.c62
-rw-r--r--src/plugins/ifw/libnl_ifw.h35
-rw-r--r--src/plugins/ifw/list.h155
-rw-r--r--src/plugins/ifw/plugin.c224
-rw-r--r--src/plugins/ifw/report_list.c81
-rw-r--r--src/plugins/ifw/report_list.h24
-rw-r--r--src/plugins/ifw/white_list.c119
-rw-r--r--src/plugins/ifw/white_list.h23
-rw-r--r--src/plugins/wireless/plugin.c148
-rw-r--r--src/plugins/wireless/wpa_ctrl.c238
-rw-r--r--src/plugins/wireless/wpa_ctrl.h179
29 files changed, 2957 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2f30e1c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,18 @@
+PACKAGE = mandi
+VERSION := $(shell rpm -q --qf '%{VERSION}\n' --specfile $(PACKAGE).spec | head -1)
+RELEASE := $(shell rpm -q --qf '%{RELEASE}\n' --specfile $(PACKAGE).spec | head -1)
+
+all:
+ (cd src; make)
+
+clean:
+ find -maxdepth 1 -type d -name 'mandi-*' -exec rm -r {} \;
+ find -name '*~' -exec rm {} \;
+ make -C src clean
+
+dist: clean
+ mkdir ../$(PACKAGE)-$(VERSION)
+ tar c . | tar x -C ../$(PACKAGE)-$(VERSION)
+ tar cvjf ../mandi-$(VERSION).tar.bz2 ../mandi-$(VERSION)
+ rm -rf ../mandi-$(VERSION)
+ rpm -ts ../mandi-$(VERSION).tar.bz2
diff --git a/conf/mandi.conf b/conf/mandi.conf
new file mode 100644
index 0000000..0ae9f8e
--- /dev/null
+++ b/conf/mandi.conf
@@ -0,0 +1,36 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="root">
+ <allow own="com.mandriva.monitoring"/>
+
+ <allow send_destination="com.mandriva.monitoring"/>
+ <allow send_interface="com.mandriva.monitoring.ifw"/>
+ <allow send_interface="com.mandriva.monitoring.wireless"/>
+
+ <allow receive_sender="com.mandriva.monitoring"/>
+ <allow receive_interface="com.mandriva.monitoring.ifw"/>
+ <allow receive_interface="com.mandriva.monitoring.wireless"/>
+ </policy>
+ <policy at_console="true">
+ <allow send_destination="com.mandriva.monitoring"/>
+ <allow send_interface="com.mandriva.monitoring.ifw"/>
+ <allow send_interface="com.mandriva.monitoring.wireless"/>
+
+ <allow receive_sender="com.mandriva.monitoring"/>
+ <allow receive_interface="com.mandriva.monitoring.ifw"/>
+ <allow receive_interface="com.mandriva.monitoring.wireless"/>
+ </policy>
+ <policy context="default">
+ <deny own="com.mandriva.monitoring"/>
+
+ <deny send_destination="com.mandriva.monitoring"/>
+ <deny send_interface="com.mandriva.monitoring.ifw"/>
+ <deny send_interface="com.mandriva.monitoring.wireless"/>
+
+ <deny receive_sender="com.mandriva.monitoring"/>
+ <deny receive_interface="com.mandriva.monitoring.ifw"/>
+ <deny receive_interface="com.mandriva.monitoring.wireless"/>
+ </policy>
+</busconfig>
diff --git a/mandi.spec b/mandi.spec
new file mode 100644
index 0000000..a96815b
--- /dev/null
+++ b/mandi.spec
@@ -0,0 +1,152 @@
+%define name mandi
+%define version 0.7.2
+%define release 2mdk
+
+Summary: Monitoring daemon bridge
+Name: %{name}
+Version: %{version}
+Release: %{release}
+Source0: %{name}-%{version}.tar.bz2
+License: GPL
+Group: Networking/Other
+Url: http://cvs.mandriva.com/cgi-bin/cvsweb.cgi/soft/
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
+BuildRequires: dbus-devel
+Requires(post): rpm-helper
+Requires: dbus
+
+%description
+Mandi is a monitoring daemon which acts as a bridge from root
+monitoring libraries to user applications, using D-Bus.
+Its plugin system allows to monitor different kind of events.
+A built-in plugin forwards wireless scan results from wpa_supplicant
+to user applications.
+
+Mandi ain't no daemon, idiot! (c) rgs
+
+%package ifw
+Summary: Firewall rules for Interactive Firewall
+Group: Networking/Other
+Requires(post): shorewall
+Requires: mandi = %{version}
+Requires: ipset
+
+%description ifw
+This package contains the iptables rules used to forward intrusion
+detections to the mandi daemon.
+It is a component of Interactive Firewall.
+
+%prep
+%setup -q
+
+%build
+%make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+install -D -m755 src/%{name} $RPM_BUILD_ROOT%{_sbindir}/%{name}
+install -D -m644 conf/%{name}.conf $RPM_BUILD_ROOT%{_sysconfdir}/dbus-1/system.d/%{name}.conf
+install -D -m755 scripts/%{name}.init %buildroot%{_initrddir}/%{name}
+install -d -m755 %buildroot%{_sysconfdir}/ifw/rules.d/
+install -m644 rules.d/* %buildroot%{_sysconfdir}/ifw/rules.d/
+install -m644 scripts/{start,stop} $RPM_BUILD_ROOT%{_sysconfdir}/ifw
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+%_post_service mandi
+
+%preun
+%_preun_service mandi
+
+%triggerpostun ifw -- mandi-ifw < 0.7.2-2mdk
+STARTFILE=%{_sysconfdir}/shorewall/start
+if [ -f $STARTFILE ]; then
+ grep -v -E "^INCLUDE ifw$" $STARTFILE > $STARTFILE.new
+ mv -f $STARTFILE.new $STARTFILE
+fi
+
+%files
+%defattr(-,root,root)
+%{_sbindir}/%{name}
+%config %{_sysconfdir}/dbus-1/system.d/%{name}.conf
+%{_initrddir}/mandi
+
+%files ifw
+%dir %{_sysconfdir}/ifw/
+%{_sysconfdir}/ifw/start
+%{_sysconfdir}/ifw/stop
+%{_sysconfdir}/ifw/rules.d/*
+
+%changelog
+* Sun Sep 4 2005 Olivier Blin <oblin@mandriva.com> 0.7.2-2mdk
+- remove "INCLUDE ifw" in shorewall start file on upgrade
+
+* Thu Sep 1 2005 Olivier Blin <oblin@mandriva.com> 0.7.2-1mdk
+- mandi: save white list right after adding/modifying entries
+
+* Thu Sep 1 2005 Olivier Blin <oblin@mandriva.com> 0.7.1-1mdk
+- 0.7.1:
+ o add start/stop scripts
+ o add rules.d directorty, with a sample psd rule
+ o shorewall isn't required by the package anymore
+ o remove shorewall workarounds, it'is better done by drakfirewall now
+ o notify attacks even if attacker is already present in log
+ o don't create ipsets in the daemon
+
+* Thu Aug 25 2005 Olivier Blin <oblin@mandriva.com> 0.7-2mdk
+- use clean tarball (fix build on 64 bits, thanks couriousous)
+
+* Wed Aug 24 2005 Olivier Blin <oblin@mandriva.com> 0.7-1mdk
+- 0.7, IFW plugin improvements:
+ o keep logs and allow to clear them
+ o allow applications to notify themselves when the user has
+ checked reports or asked to manage the lists
+ o send notifications in automatic mode too
+
+* Mon Aug 22 2005 Olivier Blin <oblin@mandriva.com> 0.6-4mdk
+- do not match for ESTABLISHED,RELATED connections (Samir),
+ this should avoid DNS blacklist
+
+* Mon Aug 22 2005 Olivier Blin <oblin@mandriva.com> 0.6-3mdk
+- remove ifw inclusion in shorewall on full removal only
+
+* Sat Aug 20 2005 Olivier Blin <oblin@mandriva.com> 0.6-2mdk
+- really fix dbus permissions
+
+* Fri Aug 19 2005 Olivier Blin <oblin@mandriva.com> 0.6-1mdk
+- 0.6
+ o create ipsets in shorewall start script
+ o start mandi service after messagebus
+ o allow console users to use Interactive Firewall
+
+* Thu Aug 18 2005 Olivier Blin <oblin@mandriva.com> 0.5-1mdk
+- 0.5
+ o use an Ifw chain in shorewall/iptables
+ o handle blacklist and whitelist in the Ifw chain
+
+* Thu Aug 18 2005 Olivier Blin <oblin@mandriva.com> 0.4-1mdk
+- 0.4 (ignore notifications from the loopback interface)
+- start mandi daemon as a service
+- add a mandi-ifw subpackage to insert Interactive Firewall in
+ shorewall start rules
+- use psd to detect port scans
+
+* Thu Aug 11 2005 Olivier Blin <oblin@mandriva.com> 0.3-1mdk
+- 0.3, Interactive Firewall improvements:
+ o really support ipset (using iptrees)
+ o use correct byte order to add IP addresses in iptrees
+ o send only one attack report per IP address
+ o fix description (thanks to Mathieu Geli)
+
+* Fri Jul 29 2005 Olivier Blin <oblin@mandriva.com> 0.2-1mdk
+- 0.2 (small bugfix)
+- Requires ipset
+
+* Thu Jul 28 2005 Olivier Blin <oblin@mandriva.com> 0.1-1mdk
+- allow to select a wireless network
+- enable fake Active Firewall mode
+
+* Fri Jul 15 2005 Olivier Blin <oblin@mandriva.com> 0.1-0.1mdk
+- initial release
diff --git a/rules.d/psd b/rules.d/psd
new file mode 100644
index 0000000..c482764
--- /dev/null
+++ b/rules.d/psd
@@ -0,0 +1 @@
+iptables -A Ifw -m state --state NEW,INVALID -m psd --psd-weight-threshold 10 --psd-delay-threshold 10000 --psd-lo-ports-weight 1 --psd-hi-ports-weight 2 -j IFWLOG --log-prefix SCAN
diff --git a/scripts/mandi.init b/scripts/mandi.init
new file mode 100644
index 0000000..1fa205c
--- /dev/null
+++ b/scripts/mandi.init
@@ -0,0 +1,45 @@
+#!/bin/sh
+#
+# Startup script for the mandi daemon (oblin@mandriva.com)
+#
+# chkconfig: 2345 26 59
+#
+# description: Network monitoring daemon (Interactive Firewall and wireless)
+#
+#
+
+. /etc/init.d/functions
+
+case "$1" in
+ start)
+ gprintf "Starting mandi daemon: "
+ daemon /usr/sbin/mandi -d
+ RETVAL=$?
+ echo
+ [ $RETVAL -eq 0 ] && touch /var/lock/subsys/mandi
+ ;;
+ stop)
+ gprintf "Shutting down mandi daemon: "
+ killproc mandi
+ RETVAL=$?
+ echo
+ [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/mandi
+ ;;
+ status)
+ status mandi
+ RETVAL=$?
+ ;;
+ restart|reload)
+ $0 stop
+ $0 start
+ ;;
+ condrestart)
+ [ -f /var/lock/subsys/mandi ] && restart || :
+ ;;
+ *)
+ gprintf "Usage: %s {start|stop|status|restart}\n" "$0"
+ RETVAL=1
+ ;;
+esac
+
+exit $RETVAL
diff --git a/scripts/start b/scripts/start
new file mode 100644
index 0000000..b416e8b
--- /dev/null
+++ b/scripts/start
@@ -0,0 +1,5 @@
+iptables -N Ifw
+ipset -N ifw_wl iptree
+iptables -A Ifw -m set --set ifw_wl src -j RETURN
+ipset -N ifw_bl iptree --timeout 3600
+iptables -A Ifw -m set --set ifw_bl src -j DROP
diff --git a/scripts/stop b/scripts/stop
new file mode 100644
index 0000000..1e9af67
--- /dev/null
+++ b/scripts/stop
@@ -0,0 +1,3 @@
+ipset -X ifw_bl
+ipset -X ifw_wl
+iptables -X Ifw
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..ba8b1c8
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,25 @@
+CC = gcc
+CFLAGS = -Wall -g
+DEFS = -DDBUS_API_SUBJECT_TO_CHANGE=1
+INCLUDES = $(shell pkg-config dbus-1 --cflags) -I$(PWD)
+LDFLAGS = $(shell pkg-config dbus-1 --libs)
+
+DAEMON_LDFLAGS =
+DAEMON_OBJS = mandi_daemon.o
+DAEMON_TARGET = mandi
+
+DAEMON_OBJS += $(addprefix plugins/wireless/,plugin.o wpa_ctrl.o)
+
+#CFLAGS += -DIFW_FAKE
+DAEMON_OBJS += $(addprefix plugins/ifw/,plugin.o ifw_dbus.o ipset.o white_list.o black_list.o report_list.o libnl_ifw.o)
+
+all: $(DAEMON_TARGET)
+
+.c.o:
+ $(CC) $(CFLAGS) $(DEFS) $(INCLUDES) -c $< -o $@
+
+$(DAEMON_TARGET): $(DAEMON_OBJS)
+ $(CC) $(CFLAGS) $(DAEMON_OBJS) $(LDFLAGS) $(DAEMON_LDFLAGS) -o $@
+
+clean:
+ rm -f $(DAEMON_OBJS) $(DAEMON_TARGET)
diff --git a/src/mandi_daemon.c b/src/mandi_daemon.c
new file mode 100644
index 0000000..6c67d88
--- /dev/null
+++ b/src/mandi_daemon.c
@@ -0,0 +1,269 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <time.h>
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+#include <errno.h>
+
+#include "plugin.h"
+
+#define MANDI_DAEMON_SERVICE PLUGIN_ROOT_INTF
+
+typedef struct {
+ DBusConnection *bus;
+ DBusWatch *bus_read_watch;
+ int bus_read_fd;
+} mandi_daemon_t;
+
+extern plugin_t wpa_supplicant_plugin;
+extern plugin_t ifw_plugin;
+plugin_t *plugins[] = {
+ &wpa_supplicant_plugin,
+ &ifw_plugin,
+ NULL,
+};
+
+static mandi_daemon_t *mandi_daemon_p; /* global variable used in signal handlers only */
+static void sigquit(int signum);
+static int mandi_daemon_init(mandi_daemon_t *daemon);
+static void mandi_daemon_exit(mandi_daemon_t *daemon, int exit_code);
+static void mandi_daemon_handle_dbus(mandi_daemon_t *daemon);
+static int mandi_daemon_acquire_service(mandi_daemon_t *daemon);
+static int mandi_daemon_init_watch(mandi_daemon_t *daemon);
+static dbus_bool_t mandi_daemon_add_watch(DBusWatch *watch, void *data);
+static void mandi_daemon_toggle_watch(DBusWatch *watch, void *data);
+static void mandi_daemon_remove_watch(DBusWatch *watch, void *data);
+static DBusConnection *mandi_daemon_get_system_bus();
+static int mandi_daemon_init_path(mandi_daemon_t *daemon, plugin_t *plugin);
+static void mandi_daemon_object_path_unregister(DBusConnection *connection, void *user_data);
+static DBusHandlerResult mandi_daemon_object_path_handle_message(DBusConnection *connection, DBusMessage *message, void *user_data);
+
+int main(int argc, char **argv)
+{
+ mandi_daemon_t mandi_daemon;
+
+ /* set up signal handlers to exit nicely when needed */
+ mandi_daemon_p = &mandi_daemon;
+ signal(SIGINT, sigquit);
+ signal(SIGTERM, sigquit);
+ signal(SIGQUIT, sigquit);
+
+ mandi_daemon_init(&mandi_daemon);
+
+ if (getopt(argc, argv, "d") == 'd') {
+ daemon(0, 0);
+ }
+
+ printf("Monitoring daemon waiting for events ...\n");
+
+ while (1) {
+ int num_fds;
+ fd_set read_fds;
+ plugin_t **ptr;
+ plugin_t *plugin;
+
+ FD_ZERO(&read_fds);
+ FD_SET(mandi_daemon.bus_read_fd, &read_fds);
+ num_fds = mandi_daemon.bus_read_fd + 1;
+ for (ptr = plugins; *ptr; ptr++) {
+ plugin = *ptr;
+ if (plugin->fd >= 0) {
+ FD_SET(plugin->fd, &read_fds);
+ if (plugin->fd + 1 > num_fds) {
+ num_fds = plugin->fd + 1;
+ }
+ }
+ }
+
+ if (select(num_fds, &read_fds, NULL, NULL, NULL) > 0) {
+ if (FD_ISSET(mandi_daemon.bus_read_fd, &read_fds)) {
+ mandi_daemon_handle_dbus(&mandi_daemon);
+ }
+ for (ptr = plugins; *ptr; ptr++) {
+ plugin = *ptr;
+ if (plugin->fd >= 0 && FD_ISSET(plugin->fd, &read_fds)) {
+ plugin->handle_incoming(plugin, mandi_daemon.bus);
+ }
+ }
+ } else {
+ fprintf(stderr, "unhandled error in select(): %s\n", strerror(errno));
+
+ }
+ }
+
+ mandi_daemon_exit(&mandi_daemon, EXIT_SUCCESS);
+ return 0;
+}
+
+static void sigquit(int signum) {
+ printf("SIGINT, SIGTERM or SIGQUIT catched, trying to exit nicely\n");
+ mandi_daemon_exit(mandi_daemon_p, EXIT_SUCCESS);
+}
+
+static int mandi_daemon_init(mandi_daemon_t *daemon) {
+ plugin_t **ptr;
+ plugin_t *plugin;
+
+ daemon->bus = mandi_daemon_get_system_bus();
+ if (!daemon->bus) {
+ mandi_daemon_exit(daemon, EXIT_FAILURE);
+ }
+
+ if (mandi_daemon_init_watch(daemon) != 0) {
+ fprintf(stderr, "unable to init DBus watch\n");
+ mandi_daemon_exit(daemon, EXIT_FAILURE);
+ }
+
+ if (mandi_daemon_acquire_service(daemon) != 0) {
+ fprintf(stderr, "unable to init DBus service\n");
+ mandi_daemon_exit(daemon, EXIT_FAILURE);
+ }
+
+ for (ptr = plugins; *ptr; ptr++) {
+ plugin = *ptr;
+ if (plugin->init(plugin, daemon->bus) != 0) {
+ fprintf(stderr, "unable to init \"%s\" plugin\n", plugin->name);
+ mandi_daemon_exit(daemon, EXIT_FAILURE);
+ }
+
+ mandi_daemon_init_path(daemon, plugin);
+ }
+
+ return 0;
+}
+
+static void mandi_daemon_exit(mandi_daemon_t *daemon, int exit_code) {
+ plugin_t **ptr;
+ plugin_t *plugin;
+ for (ptr = plugins; *ptr; ptr++) {
+ plugin = *ptr;
+ plugin->deinit(plugin, daemon->bus);
+ }
+ /* unregister dbus */
+ exit(exit_code);
+}
+
+static void mandi_daemon_handle_dbus(mandi_daemon_t *daemon) {
+ dbus_watch_handle(daemon->bus_read_watch, DBUS_WATCH_READABLE);
+ dbus_connection_dispatch(daemon->bus);
+}
+
+int mandi_daemon_acquire_service(mandi_daemon_t *daemon) {
+ DBusError error;
+ dbus_error_init(&error);
+
+ if (dbus_bus_acquire_service(daemon->bus, MANDI_DAEMON_SERVICE, 0, &error) == -1) {
+ fprintf(stderr, "dbus_bus_acquire_service(): %s\n", error.message);
+ fprintf(stderr, "Make sure a DBus policy allows you to acquire this service.\n");
+ dbus_error_free(&error);
+ return -1;
+ }
+ dbus_connection_dispatch(daemon->bus);
+
+ dbus_error_free(&error);
+ return 0;
+}
+
+/* get fds to be watched */
+static int mandi_daemon_init_watch(mandi_daemon_t *daemon) {
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ if (dbus_connection_set_watch_functions(daemon->bus,
+ mandi_daemon_add_watch,
+ mandi_daemon_toggle_watch,
+ mandi_daemon_remove_watch,
+ (void *) daemon,
+ NULL) == FALSE) {
+ fprintf(stderr, "dbus_connection_set_watch_functions(): %s\n", error.message);
+ dbus_error_free(&error);
+ return -1;
+ }
+ dbus_connection_dispatch(daemon->bus);
+
+ dbus_error_free(&error);
+ return 0;
+}
+
+static dbus_bool_t mandi_daemon_add_watch(DBusWatch *watch, void *data) {
+ mandi_daemon_t *daemon = (mandi_daemon_t *) data;
+ if (dbus_watch_get_flags(watch) & DBUS_WATCH_READABLE) {
+ fprintf(stderr, "mandi_daemon_add_watch(): READABLE\n");
+ daemon->bus_read_watch = watch;
+ daemon->bus_read_fd = dbus_watch_get_fd(daemon->bus_read_watch);
+ }
+ /* do nothing for WRITABLE watch, we dispatch when needed */
+ return TRUE;
+}
+
+static void mandi_daemon_toggle_watch(DBusWatch *watch, void *data) {
+ fprintf(stderr, "mandi_daemon_toggle_watch()\n");
+ /* FIXME : do we need to do something here ? */
+}
+
+static void mandi_daemon_remove_watch(DBusWatch *watch, void *data) {
+ if (dbus_watch_get_flags(watch) & DBUS_WATCH_READABLE) {
+ fprintf(stderr, "mandi_daemon_remove_watch(): READABLE\n");
+ /* FIXME : do we need to do something here ? */
+ }
+}
+
+/* set a connection to the system bus */
+static DBusConnection *mandi_daemon_get_system_bus() {
+ DBusConnection *bus;
+ DBusError error;
+ dbus_error_init(&error);
+
+ bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (!bus) {
+ fprintf(stderr, "Failed to connect to the D-BUS daemon: %s\n", error.message);
+ dbus_error_free(&error);
+ return NULL;
+ }
+
+ dbus_error_free(&error);
+ return bus;
+}
+
+static int mandi_daemon_init_path(mandi_daemon_t *daemon, plugin_t *plugin) {
+ struct DBusObjectPathVTable object_path_vtable = {
+ mandi_daemon_object_path_unregister,
+ mandi_daemon_object_path_handle_message,
+ NULL, NULL, NULL, NULL
+ };
+
+ DBusError error;
+ dbus_error_init(&error);
+
+ if (dbus_connection_register_object_path(daemon->bus, plugin->path, &object_path_vtable, plugin) == FALSE) {
+ fprintf(stderr, "dbus_connection_register_object_path(): not enough memory\n");
+ dbus_error_free(&error);
+ return -1;
+ }
+ dbus_connection_dispatch(daemon->bus);
+
+ dbus_error_free(&error);
+ return 0;
+}
+
+static void mandi_daemon_object_path_unregister(DBusConnection *connection, void *user_data) {
+}
+
+static DBusHandlerResult mandi_daemon_object_path_handle_message(DBusConnection *connection, DBusMessage *message, void *user_data) {
+ plugin_t *plugin = (plugin_t *) user_data;
+
+ printf("handling method call '%s' on interface '%s'\n",
+ dbus_message_get_member(message),
+ dbus_message_get_interface(message));
+
+ return plugin->handle_message(connection, message, plugin);
+}
diff --git a/src/plugin.h b/src/plugin.h
new file mode 100644
index 0000000..ad3973a
--- /dev/null
+++ b/src/plugin.h
@@ -0,0 +1,21 @@
+#ifndef PLUGIN_H
+#define PLUGIN_H
+
+#include <dbus/dbus.h>
+
+#define PLUGIN_ROOT_INTF "com.mandriva.monitoring"
+#define PLUGIN_ROOT_PATH "/com/mandriva/monitoring"
+
+typedef struct plugin_s plugin_t;
+struct plugin_s {
+ const char *name;
+ const char *path;
+ int fd;
+ void *priv;
+ int (*init)(plugin_t *plugin, DBusConnection *connection);
+ void (*handle_incoming)(plugin_t *plugin, DBusConnection *connection);
+ DBusHandlerResult (*handle_message)(DBusConnection *connection, DBusMessage *message, plugin_t *plugin);
+ void (*deinit)(plugin_t *plugin, DBusConnection *connection);
+};
+
+#endif /* PLUGIN_H */
diff --git a/src/plugins/ifw/black_list.c b/src/plugins/ifw/black_list.c
new file mode 100644
index 0000000..1e7dbbb
--- /dev/null
+++ b/src/plugins/ifw/black_list.c
@@ -0,0 +1,76 @@
+#include "black_list.h"
+#include "ipset.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+void black_list_init(black_list_t *list) {
+ INIT_LIST_HEAD(list);
+}
+
+void black_list_add(black_list_t *list, msg_usr_t *attack) {
+ black_list_cell_t *cell;
+
+ cell = malloc(sizeof(black_list_cell_t));
+ if (!cell) {
+ fprintf(stderr, "unable to alloc enough memory for black list cell, skipping\n");
+ return;
+ }
+ cell->info = *attack;
+ INIT_LIST_HEAD(&cell->list);
+ list_add_tail(&cell->list, list);
+
+ ipset_blacklist_add(cell->info.s_addr);
+}
+
+black_list_cell_t *black_list_find(black_list_t *list, u_int32_t addr) {
+ struct list_head *entry;
+
+ __list_for_each(entry, list) {
+ black_list_cell_t *cell;
+ cell = list_entry(entry, black_list_cell_t, list);
+ if (cell->info.s_addr == addr) {
+ return cell;
+ }
+ }
+
+ return NULL;
+}
+
+void black_list_remove(black_list_t *list, u_int32_t addr) {
+ black_list_cell_t *cell, *n, *prev;
+
+ ipset_blacklist_remove(addr);
+
+ prev = NULL;
+ list_for_each_entry_safe(cell, n, list, list) {
+ if (prev)
+ free(prev);
+ if (cell->info.s_addr == addr) {
+ list_del(&cell->list);
+ prev = cell;
+ } else {
+ prev = NULL;
+ }
+ }
+ if (prev)
+ free(prev);
+}
+
+
+void black_list_print(black_list_t *list) {
+ struct list_head *entry;
+
+ printf("* black list {\n");
+ __list_for_each(entry, list) {
+ black_list_cell_t *cell;
+ struct in_addr addr;
+ cell = list_entry(entry, black_list_cell_t, list);
+ addr.s_addr = cell->info.s_addr;
+ printf("%s,\n", inet_ntoa(addr));
+ }
+ printf("} black list *\n");
+}
diff --git a/src/plugins/ifw/black_list.h b/src/plugins/ifw/black_list.h
new file mode 100644
index 0000000..4cfe74b
--- /dev/null
+++ b/src/plugins/ifw/black_list.h
@@ -0,0 +1,20 @@
+#ifndef BLACK_LIST_H
+#define BLACK_LIST_H
+
+#include "list.h"
+typedef struct list_head black_list_t;
+
+#include "ifw.h"
+
+typedef struct {
+ struct list_head list;
+ msg_usr_t info;
+} black_list_cell_t;
+
+void black_list_init(black_list_t *list);
+void black_list_add(black_list_t *list, msg_usr_t *attack);
+black_list_cell_t *black_list_find(black_list_t *list, u_int32_t addr);
+void black_list_remove(black_list_t *list, u_int32_t addr);
+void black_list_print(black_list_t *list);
+
+#endif /* BLACK_LIST_H */
diff --git a/src/plugins/ifw/ifw.h b/src/plugins/ifw/ifw.h
new file mode 100644
index 0000000..f007b0f
--- /dev/null
+++ b/src/plugins/ifw/ifw.h
@@ -0,0 +1,48 @@
+#ifndef IFW_H
+#define IFW_H
+
+#include "plugin.h"
+
+#define IFW_DBUS_PATH PLUGIN_ROOT_PATH "/ifw"
+#define IFW_DBUS_INTERFACE PLUGIN_ROOT_INTF ".ifw"
+
+#include <sys/types.h>
+#include "libnl_ifw.h"
+
+#define IFW_SYSCONF_ROOT "/etc/ifw/"
+#define IFW_BLACKLIST_FILENAME IFW_SYSCONF_ROOT "blacklist"
+#define IFW_WHITELIST_FILENAME IFW_SYSCONF_ROOT "whitelist"
+
+typedef enum {
+ IFW_MODE_AUTO,
+ IFW_MODE_INTERACTIVE
+} ifw_mode_t;
+
+typedef struct {
+ long timestamp_sec; /* date */
+ char indev_name[IFNAMSIZ]; /* input interface */
+ char prefix[PREFSIZ]; /* summary of attack */
+ int sensor; /* sensor the alert come from */
+ int protocol; /* Protocol */
+ u_int32_t s_addr; /* source address */
+ u_int16_t d_port; /* destination port UDP/TCP */
+ u_int8_t icmp_type; /* icmp type */
+} msg_usr_t;
+
+typedef struct popup_verdict {
+ int seq;
+ int bl;
+} popup_verdict_t;
+
+#include "black_list.h"
+#include "white_list.h"
+#include "report_list.h"
+
+typedef struct {
+ ifw_mode_t mode;
+ black_list_t blacklist;
+ report_list_t reports;
+ white_list_t whitelist;
+} ifw_t;
+
+#endif /* IFW_H */
diff --git a/src/plugins/ifw/ifw_dbus.c b/src/plugins/ifw/ifw_dbus.c
new file mode 100644
index 0000000..82b2675
--- /dev/null
+++ b/src/plugins/ifw/ifw_dbus.c
@@ -0,0 +1,456 @@
+#include <stdio.h>
+
+#include "ifw_dbus.h"
+
+static void ifw_dbus_notify_simple_signal(DBusConnection *bus, char *signal) {
+ DBusMessage *message;
+
+ message = dbus_message_new_signal(IFW_DBUS_PATH,
+ IFW_DBUS_INTERFACE,
+ signal);
+ dbus_connection_send(bus, message, NULL);
+ dbus_connection_flush(bus);
+ dbus_message_unref(message);
+}
+
+void ifw_dbus_apply_report_verdict(DBusConnection *connection, ifw_t *ifw, report_list_cell_t *report, int do_blacklist) {
+ if (do_blacklist) {
+ if (!black_list_find(&ifw->blacklist, report->info.s_addr)) {
+ printf("blacklisting seq %d\n", report->seq);
+ black_list_add(&ifw->blacklist, &report->info);
+ ifw_dbus_notify_blacklist(connection, &report->info);
+ } else {
+ printf("(seq %d) addr %u already in blacklist\n", report->seq, report->info.s_addr);
+ }
+ } else {
+ printf("ignoring seq %d\n", report->seq);
+ }
+ report->processed = 1;
+}
+
+/* notify frontends of a new attack with a DBus signal */
+void ifw_dbus_notify_attack(DBusConnection *bus, report_list_cell_t *report) {
+ DBusMessage *message;
+
+ message = dbus_message_new_signal(IFW_DBUS_PATH,
+ IFW_DBUS_INTERFACE,
+ "Attack");
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_UINT32,
+ report->info.timestamp_sec,
+ DBUS_TYPE_STRING,
+ report->info.indev_name,
+ DBUS_TYPE_STRING,
+ report->info.prefix,
+ DBUS_TYPE_UINT32,
+ report->info.sensor,
+ DBUS_TYPE_UINT32,
+ report->info.protocol,
+ DBUS_TYPE_UINT32,
+ report->info.s_addr,
+ DBUS_TYPE_UINT32,
+ report->info.d_port,
+ DBUS_TYPE_UINT32,
+ report->info.icmp_type,
+ DBUS_TYPE_UINT32,
+ report->seq,
+ DBUS_TYPE_UINT32,
+ report->processed,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(bus, message, NULL);
+ dbus_connection_flush(bus);
+ dbus_message_unref(message);
+}
+
+/* notify frontends of a new blacklist with a DBus signal */
+void ifw_dbus_notify_blacklist(DBusConnection *bus, msg_usr_t *attack) {
+ DBusMessage *message;
+
+ message = dbus_message_new_signal(IFW_DBUS_PATH,
+ IFW_DBUS_INTERFACE,
+ "Blacklist");
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_UINT32,
+ attack->timestamp_sec,
+ DBUS_TYPE_STRING,
+ attack->indev_name,
+ DBUS_TYPE_STRING,
+ attack->prefix,
+ DBUS_TYPE_UINT32,
+ attack->sensor,
+ DBUS_TYPE_UINT32,
+ attack->protocol,
+ DBUS_TYPE_UINT32,
+ attack->s_addr,
+ DBUS_TYPE_UINT32,
+ attack->d_port,
+ DBUS_TYPE_UINT32,
+ attack->icmp_type,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(bus, message, NULL);
+ dbus_connection_flush(bus);
+ dbus_message_unref(message);
+}
+
+/* notify frontends of a new whitelist with a DBus signal */
+void ifw_dbus_notify_whitelist(DBusConnection *bus, u_int32_t addr) {
+ DBusMessage *message;
+
+ message = dbus_message_new_signal(IFW_DBUS_PATH,
+ IFW_DBUS_INTERFACE,
+ "Whitelist");
+ dbus_message_append_args(message,
+ DBUS_TYPE_UINT32,
+ addr,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(bus, message, NULL);
+ dbus_connection_flush(bus);
+ dbus_message_unref(message);
+}
+
+/* notify frontends that ifw data isn't usable with a DBus signal */
+void ifw_dbus_notify_clear(DBusConnection *bus) {
+ ifw_dbus_notify_simple_signal(bus, "Clear");
+}
+
+/* notify frontends that ifw has just been started */
+void ifw_dbus_notify_init(DBusConnection *bus) {
+ ifw_dbus_notify_simple_signal(bus, "Init");
+}
+
+/* notify frontends that a user is aware of the attacks */
+void ifw_dbus_notify_alert_ack(DBusConnection *bus) {
+ ifw_dbus_notify_simple_signal(bus, "AlertAck");
+}
+
+/* notify frontends that a user is wants to review the attacks */
+void ifw_dbus_notify_manage_request(DBusConnection *bus) {
+ ifw_dbus_notify_simple_signal(bus, "ManageRequest");
+}
+
+DBusHandlerResult ifw_dbus_get_mode(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_UINT32,
+ ifw->mode,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult ifw_dbus_set_mode(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ DBusError error;
+ DBusMessage *reply;
+ ifw_mode_t mode;
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_UINT32,
+ &mode,
+ DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "ifw_dbus_set_mode(): failed to read D-BUS message args: %s\n", error.message);
+ dbus_error_free (&error);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_error_free (&error);
+
+ printf("setting new ifw mode : %s\n", mode == IFW_MODE_AUTO ? "auto" : mode == IFW_MODE_INTERACTIVE ? "interactive" : "unknown");
+ ifw->mode = mode;
+
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_UINT32,
+ ifw->mode,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult ifw_dbus_get_reports(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ DBusError error;
+ struct list_head *entry;
+ DBusMessage *reply;
+ char include_processed;
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_UINT32,
+ &include_processed,
+ DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "ifw_dbus_get_reports(): failed to read D-BUS message args: %s\n", error.message);
+ dbus_error_free (&error);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_error_free (&error);
+
+ reply = dbus_message_new_method_return(message);
+ __list_for_each(entry, &ifw->reports) {
+ report_list_cell_t *cell;
+ cell = list_entry(entry, report_list_cell_t, list);
+ if (cell->processed && !include_processed) {
+ continue;
+ }
+ dbus_message_append_args(reply,
+ DBUS_TYPE_UINT32,
+ cell->info.timestamp_sec,
+ DBUS_TYPE_STRING,
+ cell->info.indev_name,
+ DBUS_TYPE_STRING,
+ cell->info.prefix,
+ DBUS_TYPE_UINT32,
+ cell->info.sensor,
+ DBUS_TYPE_UINT32,
+ cell->info.protocol,
+ DBUS_TYPE_UINT32,
+ cell->info.s_addr,
+ DBUS_TYPE_UINT32,
+ cell->info.d_port,
+ DBUS_TYPE_UINT32,
+ cell->info.icmp_type,
+ DBUS_TYPE_UINT32,
+ cell->seq,
+ DBUS_TYPE_UINT32,
+ cell->processed,
+ DBUS_TYPE_INVALID);
+ }
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult ifw_dbus_get_blacklist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ struct list_head *entry;
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(message);
+ __list_for_each(entry, &ifw->blacklist) {
+ black_list_cell_t *cell;
+ cell = list_entry(entry, black_list_cell_t, list);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_UINT32,
+ cell->info.timestamp_sec,
+ DBUS_TYPE_STRING,
+ cell->info.indev_name,
+ DBUS_TYPE_STRING,
+ cell->info.prefix,
+ DBUS_TYPE_UINT32,
+ cell->info.sensor,
+ DBUS_TYPE_UINT32,
+ cell->info.protocol,
+ DBUS_TYPE_UINT32,
+ cell->info.s_addr,
+ DBUS_TYPE_UINT32,
+ cell->info.d_port,
+ DBUS_TYPE_UINT32,
+ cell->info.icmp_type,
+ DBUS_TYPE_INVALID);
+ }
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult ifw_dbus_set_blacklist_verdict(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ DBusError error;
+ DBusMessage *reply;
+ int seq, do_blacklist;
+ report_list_cell_t *report;
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_UINT32,
+ &seq,
+ DBUS_TYPE_UINT32,
+ &do_blacklist,
+ DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "ifw_dbus_blacklist(): failed to read D-BUS message args: %s\n", error.message);
+ dbus_error_free (&error);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_error_free (&error);
+
+ report = report_list_find_seq(&ifw->reports, seq);
+ if (report) {
+ ifw_dbus_apply_report_verdict(connection, ifw, report, do_blacklist);
+ } else {
+ fprintf(stderr, "unable find sequence number in report list, skipping\n");
+ }
+
+ black_list_print(&ifw->blacklist);
+ report_list_print(&ifw->reports);
+
+ reply = dbus_message_new_method_return(message);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult ifw_dbus_unblacklist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ DBusError error;
+ DBusMessage *reply;
+ u_int32_t addr;
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_UINT32,
+ &addr,
+ DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "ifw_dbus_blacklist(): failed to read D-BUS message args: %s\n", error.message);
+ dbus_error_free (&error);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_error_free (&error);
+
+ black_list_remove(&ifw->blacklist, addr);
+
+ reply = dbus_message_new_method_return(message);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult ifw_dbus_get_whitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ struct list_head *entry;
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(message);
+ __list_for_each(entry, &ifw->whitelist) {
+ white_list_cell_t *cell;
+ cell = list_entry(entry, white_list_cell_t, list);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_UINT32,
+ cell->addr,
+ DBUS_TYPE_INVALID);
+ }
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult ifw_dbus_whitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ DBusError error;
+ DBusMessage *reply;
+ u_int32_t addr;
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_UINT32,
+ &addr,
+ DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "ifw_dbus_whitelist(): failed to read D-BUS message args: %s\n", error.message);
+ dbus_error_free (&error);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_error_free (&error);
+
+ if (!white_list_find(&ifw->whitelist, addr)) {
+ printf("whitelisting addr %u\n", addr);
+ white_list_add(&ifw->whitelist, addr);
+ } else {
+ printf("addr %u already in whitelist\n", addr);
+ }
+ white_list_print(&ifw->whitelist);
+
+ reply = dbus_message_new_method_return(message);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ ifw_dbus_notify_whitelist(connection, addr);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult ifw_dbus_unwhitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ DBusError error;
+ DBusMessage *reply;
+ u_int32_t addr;
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_UINT32,
+ &addr,
+ DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "ifw_dbus_whitelist(): failed to read D-BUS message args: %s\n", error.message);
+ dbus_error_free (&error);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_error_free (&error);
+
+ printf("remove addr from whitelist %u\n", addr);
+ white_list_remove(&ifw->whitelist, addr);
+
+ white_list_print(&ifw->whitelist);
+
+ reply = dbus_message_new_method_return(message);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult ifw_dbus_clear_processed_reports(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ DBusMessage *reply;
+
+ report_list_clear_processed(&ifw->reports);
+
+ reply = dbus_message_new_method_return(message);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult ifw_dbus_send_alert_ack(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ DBusMessage *reply;
+
+ ifw_dbus_notify_alert_ack(connection);
+
+ reply = dbus_message_new_method_return(message);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult ifw_dbus_send_manage_request(DBusConnection *connection, DBusMessage *message, ifw_t *ifw) {
+ DBusMessage *reply;
+
+ ifw_dbus_notify_manage_request(connection);
+
+ reply = dbus_message_new_method_return(message);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
diff --git a/src/plugins/ifw/ifw_dbus.h b/src/plugins/ifw/ifw_dbus.h
new file mode 100644
index 0000000..a4385db
--- /dev/null
+++ b/src/plugins/ifw/ifw_dbus.h
@@ -0,0 +1,43 @@
+#ifndef IFW_DBUS_H
+#define IFW_DBUS_H
+
+#include <dbus/dbus.h>
+#include "ifw.h"
+
+void ifw_dbus_apply_report_verdict(DBusConnection *connection, ifw_t *ifw, report_list_cell_t *report, int do_blacklist);
+
+/* notify frontends of a new attack with a DBus signal */
+void ifw_dbus_notify_attack(DBusConnection *bus, report_list_cell_t *report);
+
+/* notify frontends of a new whitelist with a DBus signal */
+void ifw_dbus_notify_whitelist(DBusConnection *bus, u_int32_t addr);
+
+/* notify frontends of a new blacklist with a DBus signal */
+void ifw_dbus_notify_blacklist(DBusConnection *bus, msg_usr_t *attack);
+
+/* notify frontends that ifw data isn't usable with a DBus signal */
+void ifw_dbus_notify_clear(DBusConnection *bus);
+
+/* notify frontends that ifw has just been started */
+void ifw_dbus_notify_init(DBusConnection *bus);
+
+/* notify frontends that a user is aware of the attacks */
+void ifw_dbus_notify_alert_ack(DBusConnection *bus);
+
+/* notify frontends that a user is wants to review the attacks */
+void ifw_dbus_notify_manage_request(DBusConnection *bus);
+
+DBusHandlerResult ifw_dbus_get_mode(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+DBusHandlerResult ifw_dbus_set_mode(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+DBusHandlerResult ifw_dbus_get_reports(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+DBusHandlerResult ifw_dbus_get_blacklist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+DBusHandlerResult ifw_dbus_set_blacklist_verdict(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+DBusHandlerResult ifw_dbus_unblacklist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+DBusHandlerResult ifw_dbus_get_whitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+DBusHandlerResult ifw_dbus_whitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+DBusHandlerResult ifw_dbus_unwhitelist(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+DBusHandlerResult ifw_dbus_clear_processed_reports(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+DBusHandlerResult ifw_dbus_send_alert_ack(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+DBusHandlerResult ifw_dbus_send_manage_request(DBusConnection *connection, DBusMessage *message, ifw_t *ifw);
+
+#endif /* IFW_DBUS_H */
diff --git a/src/plugins/ifw/ipset.c b/src/plugins/ifw/ipset.c
new file mode 100644
index 0000000..74ca06e
--- /dev/null
+++ b/src/plugins/ifw/ipset.c
@@ -0,0 +1,89 @@
+#include "ipset.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+
+#define CMD_MAX_SIZE 1024
+
+#ifdef IPSET_DEBUG
+#define DPRINTF(s) printf("%s\n", s)
+#else
+#define DPRINTF(s)
+#endif
+
+void ipset_init() {
+ char cmd[CMD_MAX_SIZE];
+ snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -N " IPSET_BLACKLIST_NAME " iptree --timeout " IPSET_BLACKLIST_TIMEOUT);
+ DPRINTF(cmd);
+ system(cmd);
+ snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -N " IPSET_WHITELIST_NAME " iptree");
+ DPRINTF(cmd);
+ system(cmd);
+}
+
+void ipset_destroy() {
+ char cmd[CMD_MAX_SIZE];
+ snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -X " IPSET_BLACKLIST_NAME);
+ DPRINTF(cmd);
+ system(cmd);
+ snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -X " IPSET_WHITELIST_NAME);
+ DPRINTF(cmd);
+ system(cmd);
+}
+
+/* void ipset_blacklist_load(char *filename) { */
+/* char cmd[CMD_MAX_SIZE]; */
+/* snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -R < %s", filename); */
+/* DPRINTF(cmd); */
+/* system(cmd); */
+/* } */
+
+/* void ipset_blacklist_save(char *filename) { */
+/* char cmd[CMD_MAX_SIZE]; */
+/* snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -S " IPSET_BLACKLIST_NAME " > %s", filename); */
+/* DPRINTF(cmd); */
+/* system(cmd); */
+/* } */
+
+/* void ipset_whitelist_load(char *filename) { */
+/* char cmd[CMD_MAX_SIZE]; */
+/* snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -R < %s", filename); */
+/* DPRINTF(cmd); */
+/* system(cmd); */
+/* } */
+
+/* void ipset_whitelist_save(char *filename) { */
+/* char cmd[CMD_MAX_SIZE]; */
+/* snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -S " IPSET_WHITELIST_NAME " > %s", filename); */
+/* DPRINTF(cmd); */
+/* system(cmd); */
+/* } */
+
+void ipset_blacklist_add(u_int32_t addr) {
+ char cmd[CMD_MAX_SIZE];
+ snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -A " IPSET_BLACKLIST_NAME " %u", ntohl(addr));
+ DPRINTF(cmd);
+ system(cmd);
+}
+
+void ipset_blacklist_remove(u_int32_t addr) {
+ char cmd[CMD_MAX_SIZE];
+ snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -D " IPSET_BLACKLIST_NAME " %u", ntohl(addr));
+ DPRINTF(cmd);
+ system(cmd);
+}
+
+void ipset_whitelist_add(u_int32_t addr) {
+ char cmd[CMD_MAX_SIZE];
+ snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -A " IPSET_WHITELIST_NAME " %u", ntohl(addr));
+ DPRINTF(cmd);
+ system(cmd);
+}
+
+void ipset_whitelist_remove(u_int32_t addr) {
+ char cmd[CMD_MAX_SIZE];
+ snprintf(cmd, CMD_MAX_SIZE, IPSET_CMD " -D " IPSET_WHITELIST_NAME " %u", ntohl(addr));
+ DPRINTF(cmd);
+ system(cmd);
+}
diff --git a/src/plugins/ifw/ipset.h b/src/plugins/ifw/ipset.h
new file mode 100644
index 0000000..a78395a
--- /dev/null
+++ b/src/plugins/ifw/ipset.h
@@ -0,0 +1,22 @@
+#ifndef IPSET_H
+#define IPSET_H
+
+#define IPSET_CMD "ipset"
+#define IPSET_BLACKLIST_NAME "ifw_bl"
+#define IPSET_WHITELIST_NAME "ifw_wl"
+#define IPSET_BLACKLIST_TIMEOUT "3600"
+
+#include <sys/types.h>
+
+void ipset_init();
+void ipset_destroy();
+/* void ipset_blacklist_load(char *filename); */
+/* void ipset_blacklist_save(char *filename); */
+/* void ipset_whitelist_load(char *filename); */
+/* void ipset_whitelist_save(char *filename); */
+void ipset_blacklist_add(u_int32_t addr);
+void ipset_blacklist_remove(u_int32_t addr);
+void ipset_whitelist_add(u_int32_t addr);
+void ipset_whitelist_remove(u_int32_t addr);
+
+#endif /* IPSET_H */
diff --git a/src/plugins/ifw/libnl_ifw.c b/src/plugins/ifw/libnl_ifw.c
new file mode 100644
index 0000000..bb41363
--- /dev/null
+++ b/src/plugins/ifw/libnl_ifw.c
@@ -0,0 +1,62 @@
+/* nl_create_socket(), nl_bind_socket() and nl_read_msg()
+ * for Interactive Firewall
+ * sbellabes@mandriva.com
+ */
+
+
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "libnl_ifw.h"
+
+int nl_ifw_bind_socket(int s) {
+ struct sockaddr_nl saddr_nl;
+ int res;
+
+ memset(&saddr_nl, 0, sizeof(struct sockaddr_nl));
+ saddr_nl.nl_family = AF_NETLINK;
+ saddr_nl.nl_pid = getpid();
+ saddr_nl.nl_groups = 10;
+
+ res = bind(s, (struct sockaddr *)&saddr_nl, sizeof(saddr_nl));
+ if (res == -1) {
+ perror("nl_bind_socket");
+ return -1;
+ }
+ return 1;
+}
+
+int nl_ifw_create_socket(void) {
+ int s;
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_IFWLOG);
+ if (s < 0) {
+ perror("nl_create_socket");
+ return -1;
+ }
+
+ if (nl_ifw_bind_socket(s) < 0) {
+ close(s);
+ fprintf(stderr, "bind failed\n");
+ return -1;
+ }
+
+ return s;
+}
+
+int nl_ifw_read_msg(int s, struct nlmsghdr *nlh, struct nl_msg *msg) {
+ char buf[sizeof(struct nlmsghdr) + sizeof(struct nl_msg)];
+ int ret;
+
+ ret = recv(s, &buf, sizeof(buf), 0);
+ if (ret > 0) {
+ if (nlh) memcpy(nlh, buf, sizeof(struct nlmsghdr));
+ if (msg) memcpy(msg, NLMSG_DATA(buf), sizeof(struct nl_msg));
+ }
+
+ return ret;
+}
diff --git a/src/plugins/ifw/libnl_ifw.h b/src/plugins/ifw/libnl_ifw.h
new file mode 100644
index 0000000..896d05c
--- /dev/null
+++ b/src/plugins/ifw/libnl_ifw.h
@@ -0,0 +1,35 @@
+/*
+ * libnl_ifw.h
+ */
+
+#ifndef _LIBNL_IFW_H
+#define _LIBNL_IFW_H
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <linux/if.h>
+#include <linux/netlink.h>
+
+#define NETLINK_IFWLOG 19
+
+#define PREFSIZ 32
+
+struct nl_msg { /* Netlink kernel to user message */
+ long timestamp_sec; /* time packet */
+ char indev_name[IFNAMSIZ]; /* name of the ingoing interface */
+ char outdev_name[IFNAMSIZ]; /* name of the outgoing interface */
+ unsigned char prefix[PREFSIZ]; /* logging informations */
+ struct iphdr ip;
+ union {
+ struct tcphdr th;
+ struct udphdr uh;
+ } h;
+};
+
+int nl_ifw_bind_socket(int s);
+int nl_ifw_create_socket(void);
+int nl_ifw_read_msg(int s, struct nlmsghdr *nlh, struct nl_msg *msg);
+
+#endif /* !_LIBNL_IFW_H */
diff --git a/src/plugins/ifw/list.h b/src/plugins/ifw/list.h
new file mode 100644
index 0000000..1b55f95
--- /dev/null
+++ b/src/plugins/ifw/list.h
@@ -0,0 +1,155 @@
+#ifndef LIST_H
+#define LIST_H
+
+/* borrowed from kernel header linux/list.h */
+
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+
+/* borrowed from kernel header linux/kernel.h */
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - linux_offsetof(type,member) );})
+
+
+/* borrowed from linux/stdddef.h */
+
+#define linux_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif /* LIST_H */
diff --git a/src/plugins/ifw/plugin.c b/src/plugins/ifw/plugin.c
new file mode 100644
index 0000000..0e6ac69
--- /dev/null
+++ b/src/plugins/ifw/plugin.c
@@ -0,0 +1,224 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include "ifw.h"
+#include "ifw_dbus.h"
+#include "ipset.h"
+
+static int init(plugin_t *plugin, DBusConnection *connection);
+static void deinit(plugin_t *plugin, DBusConnection *connection);
+static void process_attack(plugin_t *plugin, DBusConnection *connection, int seq, msg_usr_t *attack);
+static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin);
+#ifdef IFW_FAKE
+static int generate_fake_attack(msg_usr_t *attack);
+static void handle_fake(plugin_t *plugin, DBusConnection *connection);
+#else
+static void handle_incoming(plugin_t *plugin, DBusConnection *connection);
+#endif
+
+static int init(plugin_t *plugin, DBusConnection *connection) {
+ ifw_t *ifw;
+
+ ifw = malloc(sizeof(ifw_t));
+ if (!ifw) {
+ fprintf(stderr, "unable to malloc ifw\n");
+ return -1;
+ }
+
+ report_list_init(&ifw->reports);
+ black_list_init(&ifw->blacklist);
+ white_list_init(&ifw->whitelist);
+ white_list_load(&ifw->whitelist, IFW_WHITELIST_FILENAME);
+
+ ifw->mode = IFW_MODE_INTERACTIVE;
+
+#ifdef IFW_FAKE
+ plugin->fd = 0;
+#else
+ plugin->fd = nl_ifw_create_socket();
+ if (plugin->fd < 0) {
+ fprintf(stderr, "unable to init netlink\n");
+ return -1;
+ }
+#endif
+
+ ifw_dbus_notify_clear(connection);
+ ifw_dbus_notify_init(connection);
+
+ plugin->priv = (void *) ifw;
+
+ return 0;
+}
+
+static void deinit(plugin_t *plugin, DBusConnection *connection) {
+ ifw_t *ifw = (ifw_t *) plugin->priv;
+
+ ifw_dbus_notify_clear(connection);
+ close(plugin->fd);
+}
+
+#ifdef IFW_FAKE
+#include <time.h>
+
+static int generate_fake_attack(msg_usr_t *attack) {
+ static int seq = 0;
+ uint32_t addr = 0xC0A86401;
+
+ time(&attack->timestamp_sec);
+ strcpy(attack->indev_name, "ppp0");
+ attack->sensor = 0;
+ attack->protocol = 0;
+ attack->icmp_type = 0;
+ attack->d_port = 0;
+ attack->s_addr = htonl(addr);
+
+ switch(seq%3) {
+ case 0:
+ strcpy(attack->prefix, "SCAN");
+ break;
+ case 1:
+ strcpy(attack->prefix, "SERV");
+ attack->d_port = 22;
+ break;
+ case 2:
+ strcpy(attack->prefix, "PASS");
+ break;
+ }
+
+ addr++;
+ seq++;
+
+ return seq;
+}
+
+static void handle_fake(plugin_t *plugin, DBusConnection *connection) {
+ msg_usr_t fake_attack;
+ int seq;
+
+ read(0, NULL, 1);
+
+ seq = generate_fake_attack(&fake_attack);
+ printf("seq : %d\n", seq);
+
+ process_attack(plugin, connection, seq, &fake_attack);
+}
+
+#else
+
+static void handle_incoming(plugin_t *plugin, DBusConnection *connection) {
+ struct nl_msg msg;
+ static int seq = 0;
+ msg_usr_t attack;
+
+ if (nl_ifw_read_msg(plugin->fd, NULL, &msg) <= 0) {
+ fprintf(stderr, "unable to read packet from netlink\n");
+ return;
+ }
+
+ attack.timestamp_sec = msg.timestamp_sec;
+ strncpy(attack.indev_name, msg.indev_name, IFNAMSIZ);
+ strncpy(attack.prefix, (char *) msg.prefix, PREFSIZ);
+ attack.sensor = 0;
+ attack.protocol = msg.ip.protocol;
+ attack.s_addr = msg.ip.saddr;
+ switch (msg.ip.protocol) {
+ case IPPROTO_TCP:
+ attack.d_port = msg.h.th.dest;
+ break;
+ case IPPROTO_UDP:
+ attack.d_port = msg.h.uh.dest;
+ break;
+ default:
+ attack.d_port = 0;
+ break;
+ }
+ attack.icmp_type = 0;
+
+ process_attack(plugin, connection, seq++, &attack);
+}
+
+#endif
+
+static void process_attack(plugin_t *plugin, DBusConnection *connection, int seq, msg_usr_t *attack) {
+ ifw_t *ifw = (ifw_t *) plugin->priv;
+ report_list_cell_t *report;
+
+ if (black_list_find(&ifw->blacklist, attack->s_addr) ||
+ white_list_find(&ifw->whitelist, attack->s_addr) ||
+ report_list_find(&ifw->reports, attack->s_addr, 0)) {
+ struct in_addr addr;
+ addr.s_addr = attack->s_addr;
+ fprintf(stderr, "skipping known address: %s\n", inet_ntoa(addr));
+ return;
+ }
+
+ if (!strcmp(attack->indev_name, "lo")) {
+ fprintf(stderr, "skipping loopback interface\n");
+ return;
+ }
+
+ report = report_list_add(&ifw->reports, seq, attack);
+ if (report) {
+ if (ifw->mode == IFW_MODE_AUTO) {
+ /* add ip address in ipset blacklist */
+ ifw_dbus_apply_report_verdict(connection, ifw, report, 1);
+ }
+
+ /* notify the attack to frontends */
+ ifw_dbus_notify_attack(connection, report);
+ }
+
+ black_list_print(&ifw->blacklist);
+ white_list_print(&ifw->whitelist);
+ report_list_print(&ifw->reports);
+}
+
+static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin) {
+ ifw_t *ifw = (ifw_t *) plugin->priv;
+ if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "GetMode")) {
+ return ifw_dbus_get_mode(connection, message, ifw);
+ } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "SetMode")) {
+ return ifw_dbus_set_mode(connection, message, ifw);
+ } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "GetReports")) {
+ return ifw_dbus_get_reports(connection, message, ifw);
+ } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "GetBlacklist")) {
+ return ifw_dbus_get_blacklist(connection, message, ifw);
+ } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "SetBlacklistVerdict")) {
+ return ifw_dbus_set_blacklist_verdict(connection, message, ifw);
+ } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "UnBlacklist")) {
+ return ifw_dbus_unblacklist(connection, message, ifw);
+ } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "GetWhitelist")) {
+ return ifw_dbus_get_whitelist(connection, message, ifw);
+ } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "Whitelist")) {
+ return ifw_dbus_whitelist(connection, message, ifw);
+ } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "UnWhitelist")) {
+ return ifw_dbus_unwhitelist(connection, message, ifw);
+ } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "ClearProcessedReports")) {
+ return ifw_dbus_clear_processed_reports(connection, message, ifw);
+ } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "SendAlertAck")) {
+ return ifw_dbus_send_alert_ack(connection, message, ifw);
+ } else if (dbus_message_is_method_call(message, IFW_DBUS_INTERFACE, "SendManageRequest")) {
+ return ifw_dbus_send_manage_request(connection, message, ifw);
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+plugin_t ifw_plugin = {
+ .name = "Interactive Firewall",
+ .path = IFW_DBUS_PATH,
+ .init = init,
+#ifdef IFW_FAKE
+ .handle_incoming = handle_fake,
+#else
+ .handle_incoming = handle_incoming,
+#endif
+ .handle_message = handle_message,
+ .deinit = deinit,
+};
diff --git a/src/plugins/ifw/report_list.c b/src/plugins/ifw/report_list.c
new file mode 100644
index 0000000..c21df7e
--- /dev/null
+++ b/src/plugins/ifw/report_list.c
@@ -0,0 +1,81 @@
+#include "report_list.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void report_list_init(report_list_t *list) {
+ INIT_LIST_HEAD(list);
+}
+
+report_list_cell_t *report_list_add(report_list_t *list, int seq, msg_usr_t *attack) {
+ report_list_cell_t *cell;
+
+ cell = malloc(sizeof(report_list_cell_t));
+ if (!cell) {
+ fprintf(stderr, "unable to alloc enough memory for report list cell, skipping\n");
+ return NULL;
+ }
+ cell->seq = seq;
+ cell->info = *attack;
+ cell->processed = 0;
+ INIT_LIST_HEAD(&cell->list);
+ list_add_tail(&cell->list, list);
+
+ return cell;
+}
+
+report_list_cell_t *report_list_find(report_list_t *list, u_int32_t addr, int include_processed) {
+ struct list_head *entry;
+
+ __list_for_each(entry, list) {
+ report_list_cell_t *cell;
+ cell = list_entry(entry, report_list_cell_t, list);
+ if (cell->info.s_addr == addr && include_processed || !cell->processed) {
+ return cell;
+ }
+ }
+
+ return NULL;
+}
+
+report_list_cell_t *report_list_find_seq(report_list_t *list, int seq) {
+ struct list_head *entry;
+
+ __list_for_each(entry, list) {
+ report_list_cell_t *cell;
+ cell = list_entry(entry, report_list_cell_t, list);
+ if (cell->seq == seq) {
+ return cell;
+ }
+ }
+
+ return NULL;
+}
+
+void report_list_remove(report_list_cell_t *cell) {
+ list_del(&cell->list);
+ free(cell);
+}
+
+void report_list_clear_processed(report_list_t *list) {
+ report_list_cell_t *cell, *n;
+
+ list_for_each_entry_safe(cell, n, list, list) {
+ if (cell->processed) {
+ report_list_remove(cell);
+ }
+ }
+}
+
+void report_list_print(report_list_t *list) {
+ struct list_head *entry;
+
+ printf("* report list {\n");
+ __list_for_each(entry, list) {
+ report_list_cell_t *cell;
+ cell = list_entry(entry, report_list_cell_t, list);
+ printf("%d,\n", cell->seq);
+ }
+ printf("} report list *\n");
+}
+
diff --git a/src/plugins/ifw/report_list.h b/src/plugins/ifw/report_list.h
new file mode 100644
index 0000000..626afed
--- /dev/null
+++ b/src/plugins/ifw/report_list.h
@@ -0,0 +1,24 @@
+#ifndef REPORT_LIST_H
+#define REPORT_LIST_H
+
+#include "list.h"
+typedef struct list_head report_list_t;
+
+#include "ifw.h"
+
+typedef struct {
+ struct list_head list;
+ int seq;
+ msg_usr_t info;
+ char processed;
+} report_list_cell_t;
+
+void report_list_init(report_list_t *list);
+report_list_cell_t *report_list_add(report_list_t *list, int seq, msg_usr_t *attack);
+report_list_cell_t *report_list_find(report_list_t *list, u_int32_t addr, int include_processed);
+report_list_cell_t *report_list_find_seq(report_list_t *list, int seq);
+void report_list_remove(report_list_cell_t *cell);
+void report_list_clear_processed(report_list_t *list);
+void report_list_print(report_list_t *list);
+
+#endif /* REPORT_LIST_H */
diff --git a/src/plugins/ifw/white_list.c b/src/plugins/ifw/white_list.c
new file mode 100644
index 0000000..4318abc
--- /dev/null
+++ b/src/plugins/ifw/white_list.c
@@ -0,0 +1,119 @@
+#include "white_list.h"
+#include "ipset.h"
+#include "ifw.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+void white_list_init(white_list_t *list) {
+ INIT_LIST_HEAD(list);
+}
+
+void white_list_add(white_list_t *list, u_int32_t addr) {
+ white_list_cell_t *cell;
+
+ cell = malloc(sizeof(white_list_cell_t));
+ if (!cell) {
+ fprintf(stderr, "unable to alloc enough memory for white list cell, skipping\n");
+ return;
+ }
+ cell->addr = addr;
+ INIT_LIST_HEAD(&cell->list);
+ list_add_tail(&cell->list, list);
+
+ ipset_whitelist_add(cell->addr);
+ white_list_save(list, IFW_WHITELIST_FILENAME);
+}
+
+white_list_cell_t *white_list_find(white_list_t *list, u_int32_t addr) {
+ struct list_head *entry;
+
+ __list_for_each(entry, list) {
+ white_list_cell_t *cell;
+ cell = list_entry(entry, white_list_cell_t, list);
+ if (cell->addr == addr) {
+ return cell;
+ }
+ }
+
+ return NULL;
+}
+
+void white_list_remove(white_list_t *list, u_int32_t addr) {
+ white_list_cell_t *cell, *n, *prev;
+
+ ipset_whitelist_remove(addr);
+
+ prev = NULL;
+ list_for_each_entry_safe(cell, n, list, list) {
+ if (prev)
+ free(prev);
+ if (cell->addr == addr) {
+ list_del(&cell->list);
+ prev = cell;
+ } else {
+ prev = NULL;
+ }
+ }
+ if (prev)
+ free(prev);
+
+ white_list_save(list, IFW_WHITELIST_FILENAME);
+}
+
+
+void white_list_print(white_list_t *list) {
+ struct list_head *entry;
+
+ printf("* white list {\n");
+ __list_for_each(entry, list) {
+ white_list_cell_t *cell;
+ struct in_addr addr;
+ cell = list_entry(entry, white_list_cell_t, list);
+ addr.s_addr = cell->addr;
+ printf("%s,\n", inet_ntoa(addr));
+ }
+ printf("} white list *\n");
+}
+
+void white_list_load(white_list_t *list, const char *filepath) {
+ FILE *fp;
+
+ fp = fopen(filepath, "r");
+ if (fp) {
+ char addr_str[16];
+ struct in_addr addr;
+ while (fscanf(fp, "%15s\n", addr_str) > 0) {
+ if (inet_aton(addr_str, &addr)) {
+ white_list_add(list, addr.s_addr);
+ printf("adding IP address in white list: %s\n", addr_str);
+ } else {
+ fprintf(stderr, "unable to parse IP address in white list: %s\n", addr_str);
+ }
+ }
+ } else {
+ fprintf(stderr, "unable to open white list file\n");
+ }
+}
+
+void white_list_save(white_list_t *list, const char *filepath) {
+ FILE *fp;
+ struct list_head *entry;
+
+ fp = fopen(filepath, "w+");
+ if (fp) {
+ __list_for_each(entry, list) {
+ white_list_cell_t *cell;
+ struct in_addr addr;
+ cell = list_entry(entry, white_list_cell_t, list);
+ addr.s_addr = cell->addr;
+ fprintf(fp, "%15s\n", inet_ntoa(addr));
+ printf("adding IP address in white list: %s\n", inet_ntoa(addr));
+ }
+ } else {
+ fprintf(stderr, "unable to write white list file\n");
+ }
+}
diff --git a/src/plugins/ifw/white_list.h b/src/plugins/ifw/white_list.h
new file mode 100644
index 0000000..564f5ee
--- /dev/null
+++ b/src/plugins/ifw/white_list.h
@@ -0,0 +1,23 @@
+#ifndef WHITE_LIST_H
+#define WHITE_LIST_H
+
+#include "list.h"
+
+#include <sys/types.h>
+
+typedef struct list_head white_list_t;
+
+typedef struct {
+ struct list_head list;
+ u_int32_t addr;
+} white_list_cell_t;
+
+void white_list_init(white_list_t *list);
+void white_list_add(white_list_t *list, u_int32_t addr);
+white_list_cell_t *white_list_find(white_list_t *list, u_int32_t addr);
+void white_list_remove(white_list_t *list, u_int32_t addr);
+void white_list_print(white_list_t *list);
+void white_list_load(white_list_t *list, const char *filepath);
+void white_list_save(white_list_t *list, const char *filepath);
+
+#endif /* WHITE_LIST_H */
diff --git a/src/plugins/wireless/plugin.c b/src/plugins/wireless/plugin.c
new file mode 100644
index 0000000..1ddeb95
--- /dev/null
+++ b/src/plugins/wireless/plugin.c
@@ -0,0 +1,148 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "wpa_ctrl.h"
+#include "plugin.h"
+
+#define WIRELESS_PATH PLUGIN_ROOT_PATH "/wireless"
+#define WIRELESS_INTERFACE PLUGIN_ROOT_INTF ".wireless"
+
+static int init(plugin_t *plugin, DBusConnection *connection);
+static void deinit(plugin_t *plugin, DBusConnection *connection);
+static void handle_incoming(plugin_t *plugin, DBusConnection *connection);
+static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin);
+static DBusHandlerResult select_network(DBusConnection *connection, DBusMessage *message, plugin_t *plugin);
+static DBusHandlerResult wpa_supplicant_request(DBusConnection *connection, DBusMessage *message, plugin_t *plugin, char *cmd);
+
+static int init(plugin_t *plugin, DBusConnection *connection) {
+ struct wpa_ctrl *ctrl_conn = NULL;
+ const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
+ DIR *dir = opendir(ctrl_iface_dir);
+
+ if (dir) {
+ struct dirent *dent;
+ while ((dent = readdir(dir))) {
+ char *cfile;
+ int flen;
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+ printf("Selected interface '%s'\n",
+ dent->d_name);
+ flen = strlen(ctrl_iface_dir) + strlen(dent->d_name) + 2;
+ cfile = malloc(flen);
+ if (cfile == NULL)
+ return -1;
+ snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, dent->d_name);
+ ctrl_conn = wpa_ctrl_open(cfile);
+ free(cfile);
+ break;
+ }
+ closedir(dir);
+ }
+
+ if (ctrl_conn != NULL) {
+ plugin->fd = wpa_ctrl_get_fd(ctrl_conn);
+ } else {
+ /* do not fail, the plugin will try to re-init when needed */
+ plugin->fd = -1;
+ }
+ plugin->priv = (void *) ctrl_conn;
+ return 0;
+}
+
+static void deinit(plugin_t *plugin, DBusConnection *connection) {
+ if (plugin->fd > 0)
+ close(plugin->fd);
+}
+
+static void handle_incoming(plugin_t *plugin, DBusConnection *connection) {
+ struct wpa_ctrl *ctrl_conn = (struct wpa_ctrl *) plugin->priv;
+ char buf[2048];
+ size_t len;
+ wpa_ctrl_recv(ctrl_conn, buf, &len);
+ buf[len] = '\0';
+ printf("received event: %s\n", buf);
+}
+
+static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin) {
+ if (dbus_message_is_method_call(message, WIRELESS_INTERFACE, "ScanResults")) {
+ return wpa_supplicant_request(connection, message, plugin, "SCAN_RESULTS");
+ } else if (dbus_message_is_method_call(message, WIRELESS_INTERFACE, "ListNetworks")) {
+ return wpa_supplicant_request(connection, message, plugin, "LIST_NETWORKS");
+ } else if (dbus_message_is_method_call(message, WIRELESS_INTERFACE, "SelectNetwork")) {
+ return select_network(connection, message, plugin);
+ }
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult select_network(DBusConnection *connection, DBusMessage *message, plugin_t *plugin) {
+ DBusError error;
+ u_int32_t net;
+ char cmd[32];
+
+ dbus_error_init (&error);
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_UINT32,
+ &net,
+ DBUS_TYPE_INVALID)) {
+ fprintf(stderr, "select_network(): failed to read D-BUS message args: %s\n", error.message);
+ dbus_error_free (&error);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_error_free (&error);
+
+ snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %u", net);
+ return wpa_supplicant_request(connection, message, plugin, cmd);
+}
+
+static DBusHandlerResult wpa_supplicant_request(DBusConnection *connection, DBusMessage *message, plugin_t *plugin, char *cmd) {
+ struct wpa_ctrl *ctrl_conn = (struct wpa_ctrl *) plugin->priv;
+ DBusMessage *reply;
+ char buf[2048];
+ size_t len;
+ int ret = -1;
+
+ len = sizeof(buf) - 1;
+ if (ctrl_conn) {
+ ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, &len, NULL);
+ }
+ if (ret == -1) {
+ fprintf(stderr, "connection to wpa_supplicant daemon lost, reconnecting\n");
+ init(plugin, connection);
+ ctrl_conn = (struct wpa_ctrl *) plugin->priv;
+ if (ctrl_conn) {
+ ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, &len, NULL);
+ }
+ }
+ if (ret != 0) {
+ fprintf(stderr, "unable to request command\n");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ buf[len] = '\0';
+
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING,
+ buf,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(connection, reply, NULL);
+ dbus_connection_flush(connection);
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+plugin_t wpa_supplicant_plugin = {
+ .name = "Wireless",
+ .path = WIRELESS_PATH,
+ .init = init,
+ .handle_incoming = handle_incoming,
+ .handle_message = handle_message,
+ .deinit = deinit,
+};
diff --git a/src/plugins/wireless/wpa_ctrl.c b/src/plugins/wireless/wpa_ctrl.c
new file mode 100644
index 0000000..1c88e69
--- /dev/null
+++ b/src/plugins/wireless/wpa_ctrl.c
@@ -0,0 +1,238 @@
+/*
+ * wpa_supplicant/hostapd control interface library
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "wpa_ctrl.h"
+#ifdef CONFIG_NATIVE_WINDOWS
+#include "common.h"
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+/**
+ * struct wpa_ctrl - Internal structure for control interface library
+ *
+ * This structure is used by the wpa_supplicant/hostapd control interface
+ * library to store internal data. Programs using the library should not touch
+ * this data directly. They can only use the pointer to the data structure as
+ * an identifier for the control interface connection and use this as one of
+ * the arguments for most of the control interface library functions.
+ */
+struct wpa_ctrl {
+ int s;
+#ifdef CONFIG_CTRL_IFACE_UDP
+ struct sockaddr_in local;
+ struct sockaddr_in dest;
+#else /* CONFIG_CTRL_IFACE_UDP */
+ struct sockaddr_un local;
+ struct sockaddr_un dest;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+};
+
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+ struct wpa_ctrl *ctrl;
+#ifndef CONFIG_CTRL_IFACE_UDP
+ static int counter = 0;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+ ctrl = malloc(sizeof(*ctrl));
+ if (ctrl == NULL)
+ return NULL;
+ memset(ctrl, 0, sizeof(*ctrl));
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+ ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (ctrl->s < 0) {
+ perror("socket");
+ free(ctrl);
+ return NULL;
+ }
+
+ ctrl->local.sin_family = AF_INET;
+ ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
+ if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+ sizeof(ctrl->local)) < 0) {
+ close(ctrl->s);
+ free(ctrl);
+ return NULL;
+ }
+
+ ctrl->dest.sin_family = AF_INET;
+ ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
+ ctrl->dest.sin_port = htons(9877);
+ if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
+ sizeof(ctrl->dest)) < 0) {
+ perror("connect");
+ close(ctrl->s);
+ free(ctrl);
+ return NULL;
+ }
+#else /* CONFIG_CTRL_IFACE_UDP */
+ ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (ctrl->s < 0) {
+ free(ctrl);
+ return NULL;
+ }
+
+ ctrl->local.sun_family = AF_UNIX;
+ snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
+ "/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
+ if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+ sizeof(ctrl->local)) < 0) {
+ close(ctrl->s);
+ free(ctrl);
+ return NULL;
+ }
+
+ ctrl->dest.sun_family = AF_UNIX;
+ snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s",
+ ctrl_path);
+ if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
+ sizeof(ctrl->dest)) < 0) {
+ close(ctrl->s);
+ unlink(ctrl->local.sun_path);
+ free(ctrl);
+ return NULL;
+ }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+ return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+#ifndef CONFIG_CTRL_IFACE_UDP
+ unlink(ctrl->local.sun_path);
+#endif /* CONFIG_CTRL_IFACE_UDP */
+ close(ctrl->s);
+ free(ctrl);
+}
+
+
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+ char *reply, size_t *reply_len,
+ void (*msg_cb)(char *msg, size_t len))
+{
+ struct timeval tv;
+ int res;
+ fd_set rfds;
+
+ if (send(ctrl->s, cmd, cmd_len, 0) < 0)
+ return -1;
+
+ for (;;) {
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ FD_ZERO(&rfds);
+ FD_SET(ctrl->s, &rfds);
+ res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+ if (FD_ISSET(ctrl->s, &rfds)) {
+ res = recv(ctrl->s, reply, *reply_len, 0);
+ if (res < 0)
+ return res;
+ if (res > 0 && reply[0] == '<') {
+ /* This is an unsolicited message from
+ * wpa_supplicant, not the reply to the
+ * request. Use msg_cb to report this to the
+ * caller. */
+ if (msg_cb) {
+ /* Make sure the message is nul
+ * terminated. */
+ if ((size_t) res == *reply_len)
+ res = (*reply_len) - 1;
+ reply[res] = '\0';
+ msg_cb(reply, res);
+ }
+ continue;
+ }
+ *reply_len = res;
+ break;
+ } else {
+ return -2;
+ }
+ }
+ return 0;
+}
+
+
+static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
+{
+ char buf[10];
+ int ret;
+ size_t len = 10;
+
+ ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
+ buf, &len, NULL);
+ if (ret < 0)
+ return ret;
+ if (len == 3 && memcmp(buf, "OK\n", 3) == 0)
+ return 0;
+ return -1;
+}
+
+
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
+{
+ return wpa_ctrl_attach_helper(ctrl, 1);
+}
+
+
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
+{
+ return wpa_ctrl_attach_helper(ctrl, 0);
+}
+
+
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+{
+ int res;
+
+ res = recv(ctrl->s, reply, *reply_len, 0);
+ if (res < 0)
+ return res;
+ *reply_len = res;
+ return 0;
+}
+
+
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
+{
+ struct timeval tv;
+ int res;
+ fd_set rfds;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ FD_ZERO(&rfds);
+ FD_SET(ctrl->s, &rfds);
+ res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+ return FD_ISSET(ctrl->s, &rfds);
+}
+
+
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
+{
+ return ctrl->s;
+}
diff --git a/src/plugins/wireless/wpa_ctrl.h b/src/plugins/wireless/wpa_ctrl.h
new file mode 100644
index 0000000..964f7ab
--- /dev/null
+++ b/src/plugins/wireless/wpa_ctrl.h
@@ -0,0 +1,179 @@
+/*
+ * wpa_supplicant/hostapd control interface library
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef WPA_CTRL_H
+#define WPA_CTRL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* wpa_supplicant control interface - fixed message prefixes */
+
+/** Interactive request for identity/password/pin */
+#define WPA_CTRL_REQ "CTRL-REQ-"
+
+/** Response to identity/password/pin request */
+#define WPA_CTRL_RSP "CTRL-RSP-"
+
+/* Event messages with fixed prefix */
+/** Authentication completed successfully and data connection enabled */
+#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
+/** Disconnected, data connection is not available */
+#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
+/** wpa_supplicant is exiting */
+#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
+/** Password change was completed successfully */
+#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
+/** EAP-Request/Notification received */
+#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
+/** EAP authentication started (EAP-Request/Identity received) */
+#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
+/** EAP method selected */
+#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
+/** EAP authentication completed successfully */
+#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
+/** EAP authentication failed (EAP-Failure received) */
+#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
+
+
+/* wpa_supplicant/hostapd control interface access */
+
+/**
+ * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
+ * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
+ * Returns: Pointer to abstract control interface data or %NULL on failure
+ *
+ * This function is used to open a control interface to wpa_supplicant/hostapd.
+ * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
+ * is configured in wpa_supplicant/hostapd and other programs using the control
+ * interface need to use matching path configuration.
+ */
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
+
+
+/**
+ * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ *
+ * This function is used to close a control interface.
+ */
+void wpa_ctrl_close(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @cmd: Command; usually, ASCII text, e.g., "PING"
+ * @cmd_len: Length of the cmd in bytes
+ * @reply: Buffer for the response
+ * @reply_len: Reply buffer length
+ * @msg_cb: Callback function for unsolicited messages or %NULL if not used
+ * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
+ *
+ * This function is used to send commands to wpa_supplicant/hostapd. Received
+ * response will be written to reply and reply_len is set to the actual length
+ * of the reply. This function will block for up to two seconds while waiting
+ * for the reply. If unsolicited messages are received, the blocking time may
+ * be longer.
+ *
+ * msg_cb can be used to register a callback function that will be called for
+ * unsolicited messages received while waiting for the command response. These
+ * messages may be received if wpa_ctrl_request() is called at the same time as
+ * wpa_supplicant/hostapd is sending such a message. This can happen only if
+ * the program has used wpa_ctrl_attach() to register itself as a monitor for
+ * event messages. Alternatively to msg_cb, programs can register two control
+ * interface connections and use one of them for commands and the other one for
+ * receiving event messages, in other words, call wpa_ctrl_attach() only for
+ * the control interface connection that will be used for event messages.
+ */
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+ char *reply, size_t *reply_len,
+ void (*msg_cb)(char *msg, size_t len));
+
+
+/**
+ * wpa_ctrl_attach - Register as an event monitor for the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function registers the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
+ * control interface connection starts receiving event messages that can be
+ * read with wpa_ctrl_recv().
+ */
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_detach - Unregister event monitor from the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function unregisters the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events, i.e., cancels the registration done with
+ * wpa_ctrl_attach().
+ */
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_recv - Receive a pending control interface message
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @reply: Buffer for the message data
+ * @reply_len: Length of the reply buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function will receive a pending control interface message. This
+ * function will block if no messages are available. The received response will
+ * be written to reply and reply_len is set to the actual length of the reply.
+ * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
+ * must have been used to register the control interface as an event monitor.
+ */
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
+
+
+/**
+ * wpa_ctrl_pending - Check whether there are pending event messages
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: Non-zero if there are pending messages
+ *
+ * This function will check whether there are any pending control interface
+ * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
+ * only used for event messages, i.e., wpa_ctrl_attach() must have been used to
+ * register the control interface as an event monitor.
+ */
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_get_fd - Get file descriptor used by the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: File descriptor used for the connection
+ *
+ * This function can be used to get the file descriptor that is used for the
+ * control interface connection. The returned value can be used, e.g., with
+ * select() while waiting for multiple events.
+ *
+ * The returned file descriptor must not be used directly for sending or
+ * receiving packets; instead, the library functions wpa_ctrl_request() and
+ * wpa_ctrl_recv() must be used for this.
+ */
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WPA_CTRL_H */