mirror of
https://gitlab.com/shorewall/code.git
synced 2024-11-27 01:53:27 +01:00
Remove Shorewall-perl from SVN
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@9507 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
parent
46b9aa2d57
commit
7130579749
@ -1,340 +0,0 @@
|
|||||||
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) 19yy <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) 19yy 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.
|
|
@ -1,2 +0,0 @@
|
|||||||
This is the Shorewall-perl stable 4.2 branch of SVN.
|
|
||||||
|
|
@ -1,220 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.2 -- /usr/share/shorewall-perl/Shorewall/Accounting.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007,2008 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# This module contains the code that handles the /etc/shorewall/accounting
|
|
||||||
# file.
|
|
||||||
#
|
|
||||||
package Shorewall::Accounting;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Config qw(:DEFAULT :internal);
|
|
||||||
use Shorewall::IPAddrs;
|
|
||||||
use Shorewall::Zones;
|
|
||||||
use Shorewall::Chains qw(:DEFAULT :internal);
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw( setup_accounting );
|
|
||||||
our @EXPORT_OK = qw( );
|
|
||||||
our $VERSION = 4.2.4;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
||||||
# the compiler to run multiple times in the same process. The
|
|
||||||
# initialize() function does globals initialization for this
|
|
||||||
# module and is called from an INIT block below. The function is
|
|
||||||
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
||||||
# the second and subsequent calls to that function.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub initialize() {
|
|
||||||
our $jumpchainref;
|
|
||||||
$jumpchainref = undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT {
|
|
||||||
initialize;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Accounting
|
|
||||||
#
|
|
||||||
sub process_accounting_rule( $$$$$$$$$ ) {
|
|
||||||
|
|
||||||
our $jumpchainref;
|
|
||||||
|
|
||||||
my ($action, $chain, $source, $dest, $proto, $ports, $sports, $user, $mark ) = @_;
|
|
||||||
|
|
||||||
our $disposition = '';
|
|
||||||
|
|
||||||
sub check_chain( $ ) {
|
|
||||||
my $chainref = shift;
|
|
||||||
fatal_error "A non-accounting chain ($chainref->{name}) may not appear in the accounting file" if $chainref->{policy};
|
|
||||||
}
|
|
||||||
|
|
||||||
sub accounting_error() {
|
|
||||||
fatal_error "Invalid Accounting rule";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub jump_to_chain( $ ) {
|
|
||||||
my $jumpchain = $_[0];
|
|
||||||
$jumpchainref = ensure_accounting_chain( $jumpchain );
|
|
||||||
check_chain( $jumpchainref );
|
|
||||||
$disposition = $jumpchain;
|
|
||||||
"-j $jumpchain";
|
|
||||||
}
|
|
||||||
|
|
||||||
my $target = '';
|
|
||||||
|
|
||||||
$proto = '' if $proto eq 'any';
|
|
||||||
$ports = '' if $ports eq 'any' || $ports eq 'all';
|
|
||||||
$sports = '' if $sports eq 'any' || $sports eq 'all';
|
|
||||||
|
|
||||||
my $rule = do_proto( $proto, $ports, $sports ) . do_user ( $user ) . do_test ( $mark, 0xFF );
|
|
||||||
my $rule2 = 0;
|
|
||||||
|
|
||||||
unless ( $action eq 'COUNT' ) {
|
|
||||||
if ( $action eq 'DONE' ) {
|
|
||||||
$target = '-j RETURN';
|
|
||||||
} else {
|
|
||||||
( $action, my $cmd ) = split /:/, $action;
|
|
||||||
if ( $cmd ) {
|
|
||||||
if ( $cmd eq 'COUNT' ) {
|
|
||||||
$rule2=1;
|
|
||||||
} elsif ( $cmd ne 'JUMP' ) {
|
|
||||||
accounting_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$target = jump_to_chain $action;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my $restriction = NO_RESTRICT;
|
|
||||||
|
|
||||||
$source = ALLIP if $source eq 'any' || $source eq 'all';
|
|
||||||
|
|
||||||
if ( have_bridges ) {
|
|
||||||
my $fw = firewall_zone;
|
|
||||||
|
|
||||||
if ( $source =~ /^$fw:?(.*)$/ ) {
|
|
||||||
$source = $1 ? $1 : ALLIP;
|
|
||||||
$restriction = OUTPUT_RESTRICT;
|
|
||||||
$chain = 'accountout' unless $chain and $chain ne '-';
|
|
||||||
$dest = ALLIP if $dest eq 'any' || $dest eq 'all';
|
|
||||||
} else {
|
|
||||||
$chain = 'accounting' unless $chain and $chain ne '-';
|
|
||||||
if ( $dest eq 'any' || $dest eq 'all' || $dest eq ALLIP ) {
|
|
||||||
expand_rule(
|
|
||||||
ensure_filter_chain( 'accountout' , 0 ) ,
|
|
||||||
OUTPUT_RESTRICT ,
|
|
||||||
$rule ,
|
|
||||||
$source ,
|
|
||||||
$dest = ALLIP ,
|
|
||||||
'' ,
|
|
||||||
'' ,
|
|
||||||
$target ,
|
|
||||||
'' ,
|
|
||||||
$disposition ,
|
|
||||||
'' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$chain = 'accounting' unless $chain and $chain ne '-';
|
|
||||||
$dest = ALLIP if $dest eq 'any' || $dest eq 'all';
|
|
||||||
}
|
|
||||||
|
|
||||||
my $chainref = ensure_accounting_chain $chain;
|
|
||||||
|
|
||||||
expand_rule
|
|
||||||
$chainref ,
|
|
||||||
$restriction ,
|
|
||||||
$rule ,
|
|
||||||
$source ,
|
|
||||||
$dest ,
|
|
||||||
'' ,
|
|
||||||
'' ,
|
|
||||||
$target ,
|
|
||||||
'' ,
|
|
||||||
$disposition ,
|
|
||||||
'' ;
|
|
||||||
|
|
||||||
if ( $rule2 ) {
|
|
||||||
expand_rule
|
|
||||||
$jumpchainref ,
|
|
||||||
$restriction ,
|
|
||||||
$rule ,
|
|
||||||
$source ,
|
|
||||||
$dest ,
|
|
||||||
'' ,
|
|
||||||
'' ,
|
|
||||||
'' ,
|
|
||||||
'' ,
|
|
||||||
'' ,
|
|
||||||
'' ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_accounting() {
|
|
||||||
|
|
||||||
my $fn = open_file 'accounting';
|
|
||||||
|
|
||||||
first_entry "$doing $fn...";
|
|
||||||
|
|
||||||
my $nonEmpty = 0;
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $action, $chain, $source, $dest, $proto, $ports, $sports, $user, $mark ) = split_line1 1, 9, 'Accounting File';
|
|
||||||
|
|
||||||
if ( $action eq 'COMMENT' ) {
|
|
||||||
process_comment;
|
|
||||||
} else {
|
|
||||||
$nonEmpty = 1;
|
|
||||||
process_accounting_rule $action, $chain, $source, $dest, $proto, $ports, $sports, $user, $mark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Accounring rules are isolated" if $nonEmpty && ! $filter_table->{accounting};
|
|
||||||
|
|
||||||
clear_comment;
|
|
||||||
|
|
||||||
if ( have_bridges ) {
|
|
||||||
if ( $filter_table->{accounting} ) {
|
|
||||||
for my $chain ( qw/INPUT FORWARD/ ) {
|
|
||||||
insert_rule1 $filter_table->{$chain}, 0, '-j accounting';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $filter_table->{accountout} ) {
|
|
||||||
insert_rule1 $filter_table->{OUTPUT}, 0, '-j accountout';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ( $filter_table->{accounting} ) {
|
|
||||||
for my $chain ( qw/INPUT FORWARD OUTPUT/ ) {
|
|
||||||
insert_rule1 $filter_table->{$chain}, 0, '-j accounting';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,897 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.2 -- /usr/share/shorewall-perl/Shorewall/Actions.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007,2008 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# This module contains the code for dealing with actions (built-in,
|
|
||||||
# standard and user-defined) and Macros.
|
|
||||||
#
|
|
||||||
package Shorewall::Actions;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Config qw(:DEFAULT :internal);
|
|
||||||
use Shorewall::Zones;
|
|
||||||
use Shorewall::Chains qw(:DEFAULT :internal);
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw( merge_levels
|
|
||||||
isolate_basic_target
|
|
||||||
get_target_param
|
|
||||||
add_requiredby
|
|
||||||
createactionchain
|
|
||||||
find_logactionchain
|
|
||||||
process_actions1
|
|
||||||
process_actions2
|
|
||||||
process_actions3
|
|
||||||
|
|
||||||
find_macro
|
|
||||||
split_action
|
|
||||||
substitute_param
|
|
||||||
merge_macro_source_dest
|
|
||||||
merge_macro_column
|
|
||||||
|
|
||||||
%usedactions
|
|
||||||
%default_actions
|
|
||||||
%actions
|
|
||||||
|
|
||||||
%macros
|
|
||||||
$macro_commands
|
|
||||||
);
|
|
||||||
our @EXPORT_OK = qw( initialize );
|
|
||||||
our $VERSION = 4.2.4;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Used Actions. Each action that is actually used has an entry with value 1.
|
|
||||||
#
|
|
||||||
our %usedactions;
|
|
||||||
#
|
|
||||||
# Default actions for each policy.
|
|
||||||
#
|
|
||||||
our %default_actions;
|
|
||||||
|
|
||||||
# Action Table
|
|
||||||
#
|
|
||||||
# %actions{ <action1> => { requires => { <requisite1> = 1,
|
|
||||||
# <requisite2> = 1,
|
|
||||||
# ...
|
|
||||||
# } ,
|
|
||||||
# actchain => <action chain number> # Used for generating unique chain names for each <level>:<tag> pair.
|
|
||||||
#
|
|
||||||
our %actions;
|
|
||||||
#
|
|
||||||
# Contains an entry for each used <action>:<level>[:<tag>] that maps to the associated chain.
|
|
||||||
#
|
|
||||||
our %logactionchains;
|
|
||||||
|
|
||||||
our %macros;
|
|
||||||
|
|
||||||
our $family;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Commands that can be embedded in a macro file and how many total tokens on the line (0 => unlimited).
|
|
||||||
#
|
|
||||||
our $macro_commands = { COMMENT => 0, FORMAT => 2 };
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
||||||
# the compiler to run multiple times in the same process. The
|
|
||||||
# initialize() function does globals initialization for this
|
|
||||||
# module and is called from an INIT block below. The function is
|
|
||||||
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
||||||
# the second and subsequent calls to that function.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub initialize( $ ) {
|
|
||||||
|
|
||||||
$family = shift;
|
|
||||||
%usedactions = ();
|
|
||||||
%default_actions = ( DROP => 'none' ,
|
|
||||||
REJECT => 'none' ,
|
|
||||||
ACCEPT => 'none' ,
|
|
||||||
QUEUE => 'none' );
|
|
||||||
%actions = ();
|
|
||||||
%logactionchains = ();
|
|
||||||
%macros = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT {
|
|
||||||
initialize( F_IPV4 );
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# This function determines the logging for a subordinate action or a rule within a superior action
|
|
||||||
#
|
|
||||||
sub merge_levels ($$) {
|
|
||||||
my ( $superior, $subordinate ) = @_;
|
|
||||||
|
|
||||||
my @supparts = split /:/, $superior;
|
|
||||||
my @subparts = split /:/, $subordinate;
|
|
||||||
|
|
||||||
my $subparts = @subparts;
|
|
||||||
|
|
||||||
my $target = $subparts[0];
|
|
||||||
|
|
||||||
push @subparts, '' while @subparts < 3; #Avoid undefined values
|
|
||||||
|
|
||||||
my $level = $supparts[1];
|
|
||||||
my $tag = $supparts[2];
|
|
||||||
|
|
||||||
if ( @supparts == 3 ) {
|
|
||||||
return "$target:none!:$tag" if $level eq 'none!';
|
|
||||||
return "$target:$level:$tag" if $level =~ /!$/;
|
|
||||||
return $subordinate if $subparts >= 2;
|
|
||||||
return "$target:$level:$tag";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( @supparts == 2 ) {
|
|
||||||
return "$target:none!" if $level eq 'none!';
|
|
||||||
return "$target:$level" if ($level =~ /!$/) || ($subparts < 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
$subordinate;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Try to find a macro file -- RETURNS false if the file doesn't exist or MACRO if it does.
|
|
||||||
# If the file exists, the macro is entered into the 'targets' table and the fully-qualified
|
|
||||||
# name of the file is stored in the 'macro' table.
|
|
||||||
#
|
|
||||||
sub find_macro( $ )
|
|
||||||
{
|
|
||||||
my $macro = $_[0];
|
|
||||||
my $macrofile = find_file "macro.$macro";
|
|
||||||
|
|
||||||
if ( -f $macrofile ) {
|
|
||||||
$macros{$macro} = $macrofile;
|
|
||||||
$targets{$macro} = MACRO;
|
|
||||||
} else {
|
|
||||||
0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Return ( action, level[:tag] ) from passed full action
|
|
||||||
#
|
|
||||||
sub split_action ( $ ) {
|
|
||||||
my $action = $_[0];
|
|
||||||
my @a = split( /:/ , $action, 4 );
|
|
||||||
fatal_error "Invalid ACTION ($action)" if ( $action =~ /::/ ) || ( @a > 3 );
|
|
||||||
( shift @a, join ":", @a );
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# This function substitutes the second argument for the first part of the first argument up to the first colon (":")
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
#
|
|
||||||
# substitute_param DNAT PARAM:info:FTP
|
|
||||||
#
|
|
||||||
# produces "DNAT:info:FTP"
|
|
||||||
#
|
|
||||||
sub substitute_param( $$ ) {
|
|
||||||
my ( $param, $action ) = @_;
|
|
||||||
|
|
||||||
if ( $action =~ /:/ ) {
|
|
||||||
my $logpart = (split_action $action)[1];
|
|
||||||
$logpart =~ s!/$!!;
|
|
||||||
return "$param:$logpart";
|
|
||||||
}
|
|
||||||
|
|
||||||
$param;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Combine fields from a macro body with one from the macro invocation
|
|
||||||
#
|
|
||||||
sub merge_macro_source_dest( $$ ) {
|
|
||||||
my ( $body, $invocation ) = @_;
|
|
||||||
|
|
||||||
if ( $invocation ) {
|
|
||||||
if ( $body ) {
|
|
||||||
return $body if $invocation eq '-';
|
|
||||||
return "$body:$invocation" if $invocation =~ /.*?\.*?\.|^\+|^~|^!~/;
|
|
||||||
return "$invocation:$body";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $invocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
$body || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
sub merge_macro_column( $$ ) {
|
|
||||||
my ( $body, $invocation ) = @_;
|
|
||||||
|
|
||||||
if ( defined $invocation && $invocation ne '' && $invocation ne '-' ) {
|
|
||||||
$invocation;
|
|
||||||
} else {
|
|
||||||
$body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Get Macro Name -- strips away trailing /* and :* from the first column in a rule, macro or action.
|
|
||||||
#
|
|
||||||
sub isolate_basic_target( $ ) {
|
|
||||||
my $target = ( split '[/:]', $_[0])[0];
|
|
||||||
|
|
||||||
$target =~ /^(\w+)[(].*[)]$/ ? $1 : $target;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Split the passed target into the basic target and parameter
|
|
||||||
#
|
|
||||||
sub get_target_param( $ ) {
|
|
||||||
my ( $target, $param ) = split '/', $_[0];
|
|
||||||
|
|
||||||
unless ( defined $param ) {
|
|
||||||
( $target, $param ) = ( $1, $2 ) if $target =~ /^(.*?)[(](.*)[)]$/;
|
|
||||||
}
|
|
||||||
|
|
||||||
( $target, $param );
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Define an Action
|
|
||||||
#
|
|
||||||
sub new_action( $ ) {
|
|
||||||
|
|
||||||
my $action = $_[0];
|
|
||||||
|
|
||||||
$actions{$action} = { actchain => '', requires => {} };
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Record a 'requires' relationship between a pair of actions.
|
|
||||||
#
|
|
||||||
sub add_requiredby ( $$ ) {
|
|
||||||
my ($requiredby , $requires ) = @_;
|
|
||||||
$actions{$requires}{requires}{$requiredby} = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Create and record a log action chain -- Log action chains have names
|
|
||||||
# that are formed from the action name by prepending a "%" and appending
|
|
||||||
# a 1- or 2-digit sequence number. In the functions that follow,
|
|
||||||
# the CHAIN, LEVEL and TAG variable serves as arguments to the user's
|
|
||||||
# exit. We call the exit corresponding to the name of the action but we
|
|
||||||
# set CHAIN to the name of the iptables chain where rules are to be added.
|
|
||||||
# Similarly, LEVEL and TAG contain the log level and log tag respectively.
|
|
||||||
#
|
|
||||||
# The maximum length of a chain name is 30 characters -- since the log
|
|
||||||
# action chain name is 2-3 characters longer than the base chain name,
|
|
||||||
# this function truncates the original chain name where necessary before
|
|
||||||
# it adds the leading "%" and trailing sequence number.
|
|
||||||
#
|
|
||||||
sub createlogactionchain( $$ ) {
|
|
||||||
my ( $action, $level ) = @_;
|
|
||||||
my $chain = $action;
|
|
||||||
my $actionref = $actions{$action};
|
|
||||||
my $chainref;
|
|
||||||
|
|
||||||
my ($lev, $tag) = split ':', $level;
|
|
||||||
|
|
||||||
validate_level $lev;
|
|
||||||
|
|
||||||
$actionref = new_action $action unless $actionref;
|
|
||||||
|
|
||||||
$chain = substr $chain, 0, 28 if ( length $chain ) > 28;
|
|
||||||
|
|
||||||
CHECKDUP:
|
|
||||||
{
|
|
||||||
$actionref->{actchain}++ while $chain_table{filter}{'%' . $chain . $actionref->{actchain}};
|
|
||||||
$chain = substr( $chain, 0, 27 ), redo CHECKDUP if ( $actionref->{actchain} || 0 ) >= 10 and length $chain == 28;
|
|
||||||
}
|
|
||||||
|
|
||||||
$logactionchains{"$action:$level"} = $chainref = new_standard_chain '%' . $chain . $actionref->{actchain}++;
|
|
||||||
|
|
||||||
fatal_error "Too many invocations of Action $action" if $actionref->{actchain} > 99;
|
|
||||||
|
|
||||||
unless ( $targets{$action} & STANDARD ) {
|
|
||||||
|
|
||||||
my $file = find_file $chain;
|
|
||||||
|
|
||||||
if ( -f $file ) {
|
|
||||||
progress_message "Processing $file...";
|
|
||||||
|
|
||||||
( $level, my $tag ) = split /:/, $level;
|
|
||||||
|
|
||||||
$tag = $tag || '';
|
|
||||||
|
|
||||||
unless ( my $return = eval `cat $file` ) {
|
|
||||||
fatal_error "Couldn't parse $file: $@" if $@;
|
|
||||||
fatal_error "Couldn't do $file: $!" unless defined $return;
|
|
||||||
fatal_error "Couldn't run $file" unless $return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub createsimpleactionchain( $ ) {
|
|
||||||
my $action = shift;
|
|
||||||
my $chainref = new_standard_chain $action;
|
|
||||||
|
|
||||||
$logactionchains{"$action:none"} = $chainref;
|
|
||||||
|
|
||||||
unless ( $targets{$action} & STANDARD ) {
|
|
||||||
|
|
||||||
my $file = find_file $action;
|
|
||||||
|
|
||||||
if ( -f $file ) {
|
|
||||||
progress_message "Processing $file...";
|
|
||||||
|
|
||||||
my ( $level, $tag ) = ( '', '' );
|
|
||||||
|
|
||||||
unless ( my $return = eval `cat $file` ) {
|
|
||||||
fatal_error "Couldn't parse $file: $@" if $@;
|
|
||||||
fatal_error "Couldn't do $file: $!" unless defined $return;
|
|
||||||
fatal_error "Couldn't run $file" unless $return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Create an action chain and run it's associated user exit
|
|
||||||
#
|
|
||||||
sub createactionchain( $ ) {
|
|
||||||
my ( $action , $level ) = split_action $_[0];
|
|
||||||
|
|
||||||
my $chainref;
|
|
||||||
|
|
||||||
if ( defined $level && $level ne '' ) {
|
|
||||||
if ( $level eq 'none' ) {
|
|
||||||
createsimpleactionchain $action;
|
|
||||||
} else {
|
|
||||||
createlogactionchain $action , $level;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
createsimpleactionchain $action;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Find the chain that handles the passed action. If the chain cannot be found,
|
|
||||||
# a fatal error is generated and the function does not return.
|
|
||||||
#
|
|
||||||
sub find_logactionchain( $ ) {
|
|
||||||
my $fullaction = $_[0];
|
|
||||||
my ( $action, $level ) = split_action $fullaction;
|
|
||||||
|
|
||||||
$level = 'none' unless $level;
|
|
||||||
|
|
||||||
fatal_error "Fatal error in find_logactionchain" unless $logactionchains{"$action:$level"};
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# The functions process_actions1-3() implement the three phases of action processing.
|
|
||||||
#
|
|
||||||
# The first phase (process_actions1) occurs before the rules file is processed. ${SHAREDIR}/actions.std
|
|
||||||
# and ${CONFDIR}/actions are scanned (in that order) and for each action:
|
|
||||||
#
|
|
||||||
# a) The related action definition file is located and scanned.
|
|
||||||
# b) Forward and unresolved action references are trapped as errors.
|
|
||||||
# c) A dependency graph is created using the 'requires' field in the 'actions' table.
|
|
||||||
#
|
|
||||||
# As the rules file is scanned, each action[:level[:tag]] is merged onto the 'usedactions' hash. When an <action>
|
|
||||||
# is merged into the hash, its action chain is created. Where logging is specified, a chain with the name
|
|
||||||
# %<action>n is used where the <action> name is truncated on the right where necessary to ensure that the total
|
|
||||||
# length of the chain name does not exceed 30 characters.
|
|
||||||
#
|
|
||||||
# The second phase (process_actions2) occurs after the rules file is scanned. The transitive closure of
|
|
||||||
# %usedactions is generated; again, as new actions are merged into the hash, their action chains are created.
|
|
||||||
#
|
|
||||||
# The final phase (process_actions3) is to traverse the keys of %usedactions populating each chain appropriately
|
|
||||||
# by reading the action definition files and creating rules. Note that a given action definition file is
|
|
||||||
# processed once for each unique [:level[:tag]] applied to an invocation of the action.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub process_macro1 ( $$ ) {
|
|
||||||
my ( $action, $macrofile ) = @_;
|
|
||||||
|
|
||||||
progress_message " ..Expanding Macro $macrofile...";
|
|
||||||
|
|
||||||
push_open( $macrofile );
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
my ( $mtarget, $msource, $mdest, $mproto, $mports, $msports, $morigdest, $mrate, $muser ) = split_line1 1, 9, 'macro file', $macro_commands;
|
|
||||||
|
|
||||||
next if $mtarget eq 'COMMENT' || $mtarget eq 'FORMAT';
|
|
||||||
|
|
||||||
$mtarget =~ s/:.*$//;
|
|
||||||
|
|
||||||
$mtarget = (split '/' , $mtarget)[0];
|
|
||||||
|
|
||||||
my $targettype = $targets{$mtarget};
|
|
||||||
|
|
||||||
$targettype = 0 unless defined $targettype;
|
|
||||||
|
|
||||||
fatal_error "Invalid target ($mtarget)"
|
|
||||||
unless ( $targettype == STANDARD ) || ( $mtarget eq 'PARAM' ) || ( $targettype & ( LOGRULE | NFQ | CHAIN ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
progress_message " ..End Macro $macrofile";
|
|
||||||
|
|
||||||
pop_open;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub process_action1 ( $$ ) {
|
|
||||||
my ( $action, $wholetarget ) = @_;
|
|
||||||
|
|
||||||
my ( $target, $level ) = split_action $wholetarget;
|
|
||||||
|
|
||||||
$level = 'none' unless $level;
|
|
||||||
|
|
||||||
my $targettype = $targets{$target};
|
|
||||||
|
|
||||||
if ( defined $targettype ) {
|
|
||||||
return if ( $targettype == STANDARD ) || ( $targettype & ( MACRO | LOGRULE | NFQ | CHAIN ) );
|
|
||||||
|
|
||||||
fatal_error "Invalid TARGET ($target)" if $targettype & STANDARD;
|
|
||||||
|
|
||||||
fatal_error "An action may not invoke itself" if $target eq $action;
|
|
||||||
|
|
||||||
add_requiredby $wholetarget, $action if $targettype & ACTION;
|
|
||||||
} elsif ( $target eq 'COMMENT' ) {
|
|
||||||
fatal_error "Invalid TARGET ($wholetarget)" unless $wholetarget eq $target;
|
|
||||||
} else {
|
|
||||||
( $target, my $param ) = get_target_param $target;
|
|
||||||
|
|
||||||
return if $target eq 'NFQUEUE';
|
|
||||||
|
|
||||||
if ( defined $param ) {
|
|
||||||
my $paramtype = $targets{$param} || 0;
|
|
||||||
|
|
||||||
fatal_error "Parameter value not allowed in action files ($param)" if $paramtype & NATRULE;
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Invalid or missing ACTION ($wholetarget)" unless defined $target;
|
|
||||||
|
|
||||||
if ( find_macro $target ) {
|
|
||||||
process_macro1( $action, $macros{$target} );
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid TARGET ($target)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub process_actions1() {
|
|
||||||
|
|
||||||
progress_message2 "Preprocessing Action Files...";
|
|
||||||
|
|
||||||
for my $act ( grep $targets{$_} & ACTION , keys %targets ) {
|
|
||||||
new_action $act;
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $file ( qw/actions.std actions/ ) {
|
|
||||||
open_file $file;
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
my ( $action ) = split_line 1, 1, 'action file';
|
|
||||||
|
|
||||||
if ( $action =~ /:/ ) {
|
|
||||||
warning_message 'Default Actions are now specified in /etc/shorewall/shorewall.conf';
|
|
||||||
$action =~ s/:.*$//;
|
|
||||||
}
|
|
||||||
|
|
||||||
next unless $action;
|
|
||||||
|
|
||||||
if ( $targets{$action} ) {
|
|
||||||
warning_message "Duplicate Action Name ($action) Ignored" unless $targets{$action} & ACTION;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
$targets{$action} = ACTION;
|
|
||||||
|
|
||||||
fatal_error "Invalid Action Name ($action)" unless "\L$action" =~ /^[a-z]\w*$/;
|
|
||||||
|
|
||||||
new_action $action;
|
|
||||||
|
|
||||||
my $actionfile = find_file "action.$action";
|
|
||||||
|
|
||||||
fatal_error "Missing Action File ($actionfile)" unless -f $actionfile;
|
|
||||||
|
|
||||||
progress_message2 " Pre-processing $actionfile...";
|
|
||||||
|
|
||||||
push_open( $actionfile );
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ($wholetarget, $source, $dest, $proto, $ports, $sports, $rate, $users ) = split_line 1, 8, 'action file';
|
|
||||||
|
|
||||||
process_action1( $action, $wholetarget );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pop_open;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub process_actions2 () {
|
|
||||||
progress_message2 'Generating Transitive Closure of Used-action List...';
|
|
||||||
|
|
||||||
my $changed = 1;
|
|
||||||
|
|
||||||
while ( $changed ) {
|
|
||||||
$changed = 0;
|
|
||||||
for my $target (keys %usedactions) {
|
|
||||||
my ($action, $level) = split_action $target;
|
|
||||||
my $actionref = $actions{$action};
|
|
||||||
fatal_error "Null Action Reference in process_actions2" unless $actionref;
|
|
||||||
for my $action1 ( keys %{$actionref->{requires}} ) {
|
|
||||||
my $action2 = merge_levels $target, $action1;
|
|
||||||
unless ( $usedactions{ $action2 } ) {
|
|
||||||
$usedactions{ $action2 } = 1;
|
|
||||||
createactionchain $action2;
|
|
||||||
$changed = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# This function is called to process each rule generated from an action file.
|
|
||||||
#
|
|
||||||
sub process_action( $$$$$$$$$$ ) {
|
|
||||||
my ($chainref, $actionname, $target, $source, $dest, $proto, $ports, $sports, $rate, $user ) = @_;
|
|
||||||
|
|
||||||
my ( $action , $level ) = split_action $target;
|
|
||||||
|
|
||||||
if ( $action eq 'REJECT' ) {
|
|
||||||
$action = 'reject';
|
|
||||||
} elsif ( $action eq 'CONTINUE' ) {
|
|
||||||
$action = 'RETURN';
|
|
||||||
} elsif ( $action =~ /^NFQUEUE/ ) {
|
|
||||||
( $action, my $param ) = get_target_param $action;
|
|
||||||
$param = 1 unless defined $param;
|
|
||||||
$action = "NFQUEUE --queue-num $param";
|
|
||||||
} elsif ( $action eq 'COUNT' ) {
|
|
||||||
$action = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
expand_rule ( $chainref ,
|
|
||||||
NO_RESTRICT ,
|
|
||||||
do_proto( $proto, $ports, $sports ) . do_ratelimit( $rate, $action ) . do_user $user ,
|
|
||||||
$source ,
|
|
||||||
$dest ,
|
|
||||||
'', #Original Dest
|
|
||||||
'', #Original Dest port
|
|
||||||
$action ? "-j $action" : '',
|
|
||||||
$level ,
|
|
||||||
$action ,
|
|
||||||
'' );
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Expand Macro in action files.
|
|
||||||
#
|
|
||||||
sub process_macro3( $$$$$$$$$$$ ) {
|
|
||||||
my ( $macro, $param, $chainref, $action, $source, $dest, $proto, $ports, $sports, $rate, $user ) = @_;
|
|
||||||
|
|
||||||
my $nocomment = no_comment;
|
|
||||||
|
|
||||||
my $format = 1;
|
|
||||||
|
|
||||||
macro_comment $macro;
|
|
||||||
|
|
||||||
my $fn = $macros{$macro};
|
|
||||||
|
|
||||||
progress_message "..Expanding Macro $fn...";
|
|
||||||
|
|
||||||
push_open $fn;
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $mtarget, $msource, $mdest, $mproto, $mports, $msports, $morigdest, $mrate, $muser );
|
|
||||||
|
|
||||||
if ( $format == 1 ) {
|
|
||||||
( $mtarget, $msource, $mdest, $mproto, $mports, $msports, $mrate, $muser, $morigdest ) = split_line1 1, 9, 'macro file', $macro_commands;
|
|
||||||
} else {
|
|
||||||
( $mtarget, $msource, $mdest, $mproto, $mports, $msports, $morigdest, $mrate, $muser ) = split_line1 1, 9, 'macro file', $macro_commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $mtarget eq 'COMMENT' ) {
|
|
||||||
process_comment unless $nocomment;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $mtarget eq 'FORMAT' ) {
|
|
||||||
fatal_error "Invalid FORMAT ($msource)" unless $msource =~ /^[12]$/;
|
|
||||||
$format = $msource;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Invalid macro file entry (too many columns)" if $morigdest ne '-' && $format == 1;
|
|
||||||
|
|
||||||
if ( $mtarget =~ /^PARAM:?/ ) {
|
|
||||||
fatal_error 'PARAM requires that a parameter be supplied in macro invocation' unless $param;
|
|
||||||
$mtarget = substitute_param $param, $mtarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Macros used within Actions may not specify an ORIGINAL DEST " if $morigdest ne '-';
|
|
||||||
|
|
||||||
if ( $msource ) {
|
|
||||||
if ( ( $msource eq '-' ) || ( $msource eq 'SOURCE' ) ) {
|
|
||||||
$msource = $source || '';
|
|
||||||
} elsif ( $msource eq 'DEST' ) {
|
|
||||||
$msource = $dest || '';
|
|
||||||
} else {
|
|
||||||
$msource = merge_macro_source_dest $msource, $source;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$msource = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$msource = '' if $msource eq '-';
|
|
||||||
|
|
||||||
if ( $mdest ) {
|
|
||||||
if ( ( $mdest eq '-' ) || ( $mdest eq 'DEST' ) ) {
|
|
||||||
$mdest = $dest || '';
|
|
||||||
} elsif ( $mdest eq 'SOURCE' ) {
|
|
||||||
$mdest = $source || '';
|
|
||||||
} else {
|
|
||||||
$mdest = merge_macro_source_dest $mdest, $dest;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$mdest = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$mdest = '' if $mdest eq '-';
|
|
||||||
|
|
||||||
$mproto = merge_macro_column $mproto, $proto;
|
|
||||||
$mports = merge_macro_column $mports, $ports;
|
|
||||||
$msports = merge_macro_column $msports, $sports;
|
|
||||||
$mrate = merge_macro_column $mrate, $rate;
|
|
||||||
$muser = merge_macro_column $muser, $user;
|
|
||||||
|
|
||||||
process_action $chainref, $action, $mtarget, $msource, $mdest, $mproto, $mports, $msports, $mrate, $muser;
|
|
||||||
}
|
|
||||||
|
|
||||||
pop_open;
|
|
||||||
|
|
||||||
progress_message '..End Macro';
|
|
||||||
|
|
||||||
clear_comment unless $nocomment;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Generate chain for non-builtin action invocation
|
|
||||||
#
|
|
||||||
sub process_action3( $$$$$ ) {
|
|
||||||
my ( $chainref, $wholeaction, $action, $level, $tag ) = @_;
|
|
||||||
my $actionfile = find_file "action.$action";
|
|
||||||
|
|
||||||
fatal_error "Missing Action File ($actionfile)" unless -f $actionfile;
|
|
||||||
|
|
||||||
progress_message2 "Processing $actionfile for chain $chainref->{name}...";
|
|
||||||
|
|
||||||
open_file $actionfile;
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ($target, $source, $dest, $proto, $ports, $sports, $rate, $user ) = split_line1 1, 8, 'action file';
|
|
||||||
|
|
||||||
if ( $target eq 'COMMENT' ) {
|
|
||||||
process_comment;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $target2 = merge_levels $wholeaction, $target;
|
|
||||||
|
|
||||||
my ( $action2 , $level2 ) = split_action $target2;
|
|
||||||
|
|
||||||
( $action2 , my $param ) = get_target_param $action2;
|
|
||||||
|
|
||||||
my $action2type = $targets{$action2} || 0;
|
|
||||||
|
|
||||||
unless ( $action2type == STANDARD ) {
|
|
||||||
if ( $action2type & ACTION ) {
|
|
||||||
$target2 = (find_logactionchain ( $target = $target2 ))->{name};
|
|
||||||
} else {
|
|
||||||
fatal_error "Internal Error" unless $action2type & ( MACRO | LOGRULE | NFQ | CHAIN );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $action2type == MACRO ) {
|
|
||||||
process_macro3( $action2, $param, $chainref, $action, $source, $dest, $proto, $ports, $sports, $rate, $user );
|
|
||||||
} else {
|
|
||||||
process_action $chainref, $action, $target2, $source, $dest, $proto, $ports, $sports, $rate, $user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub process_actions3 () {
|
|
||||||
#
|
|
||||||
# The following small functions generate rules for the builtin actions of the same name
|
|
||||||
#
|
|
||||||
sub dropBcast( $$$ ) {
|
|
||||||
my ($chainref, $level, $tag) = @_;
|
|
||||||
|
|
||||||
if ( $capabilities{ADDRTYPE} ) {
|
|
||||||
if ( $level ne '' ) {
|
|
||||||
log_rule_limit $level, $chainref, 'dropBcast' , 'DROP', '', $tag, 'add', ' -m addrtype --dst-type BROADCAST ';
|
|
||||||
log_rule_limit $level, $chainref, 'dropBcast' , 'DROP', '', $tag, 'add', ' -d 224.0.0.0/4 ';
|
|
||||||
}
|
|
||||||
|
|
||||||
add_rule $chainref, '-m addrtype --dst-type BROADCAST -j DROP';
|
|
||||||
} else {
|
|
||||||
if ( $family == F_IPV4 ) {
|
|
||||||
add_command $chainref, 'for address in $ALL_BCASTS; do';
|
|
||||||
} else {
|
|
||||||
add_command $chainref, 'for address in $ALL_ACASTS; do';
|
|
||||||
}
|
|
||||||
|
|
||||||
incr_cmd_level $chainref;
|
|
||||||
log_rule_limit $level, $chainref, 'dropBcast' , 'DROP', '', $tag, 'add', ' -d $address ' if $level ne '';
|
|
||||||
add_rule $chainref, '-d $address -j DROP';
|
|
||||||
decr_cmd_level $chainref;
|
|
||||||
add_command $chainref, 'done';
|
|
||||||
|
|
||||||
log_rule_limit $level, $chainref, 'dropBcast' , 'DROP', '', $tag, 'add', ' -d 224.0.0.0/4 ' if $level ne '';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if ( $family == F_IPV4 ) {
|
|
||||||
add_rule $chainref, '-d 224.0.0.0/4 -j DROP';
|
|
||||||
} else {
|
|
||||||
add_rule $chainref, '-d ff00::/10 -j DROP';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub allowBcast( $$$ ) {
|
|
||||||
my ($chainref, $level, $tag) = @_;
|
|
||||||
|
|
||||||
if ( $family == F_IPV4 && $capabilities{ADDRTYPE} ) {
|
|
||||||
if ( $level ne '' ) {
|
|
||||||
log_rule_limit $level, $chainref, 'allowBcast' , 'ACCEPT', '', $tag, 'add', ' -m addrtype --dst-type BROADCAST ';
|
|
||||||
log_rule_limit $level, $chainref, 'allowBcast' , 'ACCEPT', '', $tag, 'add', ' -d 224.0.0.0/4 ';
|
|
||||||
}
|
|
||||||
|
|
||||||
add_rule $chainref, '-m addrtype --dst-type BROADCAST -j ACCEPT';
|
|
||||||
add_rule $chainref, '-d 224.0.0.0/4 -j ACCEPT';
|
|
||||||
} else {
|
|
||||||
if ( $family == F_IPV4 ) {
|
|
||||||
add_command $chainref, 'for address in $ALL_BCASTS; do';
|
|
||||||
} else {
|
|
||||||
add_command $chainref, 'for address in $ALL_MACASTS; do';
|
|
||||||
}
|
|
||||||
|
|
||||||
incr_cmd_level $chainref;
|
|
||||||
log_rule_limit $level, $chainref, 'allowBcast' , 'ACCEPT', '', $tag, 'add', ' -d $address ' if $level ne '';
|
|
||||||
add_rule $chainref, '-d $address -j ACCEPT';
|
|
||||||
decr_cmd_level $chainref;
|
|
||||||
add_command $chainref, 'done';
|
|
||||||
|
|
||||||
if ( $family == F_IPV4 ) {
|
|
||||||
log_rule_limit $level, $chainref, 'allowBcast' , 'ACCEPT', '', $tag, 'add', ' -d 224.0.0.0/4 ' if $level ne '';
|
|
||||||
add_rule $chainref, '-d 224.0.0.0/4 -j ACCEPT';
|
|
||||||
} else {
|
|
||||||
log_rule_limit $level, $chainref, 'allowBcast' , 'ACCEPT', '', $tag, 'add', ' -d ff00::/10 ' if $level ne '';
|
|
||||||
add_rule $chainref, '-d ff00:/10 -j ACCEPT';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub dropNotSyn ( $$$ ) {
|
|
||||||
my ($chainref, $level, $tag) = @_;
|
|
||||||
|
|
||||||
log_rule_limit $level, $chainref, 'dropNotSyn' , 'DROP', '', $tag, 'add', '-p tcp ! --syn ' if $level ne '';
|
|
||||||
add_rule $chainref , '-p tcp ! --syn -j DROP';
|
|
||||||
}
|
|
||||||
|
|
||||||
sub rejNotSyn ( $$$ ) {
|
|
||||||
my ($chainref, $level, $tag) = @_;
|
|
||||||
|
|
||||||
log_rule_limit $level, $chainref, 'rejNotSyn' , 'REJECT', '', $tag, 'add', '-p tcp ! --syn ' if $level ne '';
|
|
||||||
add_rule $chainref , '-p tcp ! --syn -j REJECT --reject-with tcp-reset';
|
|
||||||
}
|
|
||||||
|
|
||||||
sub dropInvalid ( $$$ ) {
|
|
||||||
my ($chainref, $level, $tag) = @_;
|
|
||||||
|
|
||||||
log_rule_limit $level, $chainref, 'dropInvalid' , 'DROP', '', $tag, 'add', '-m state --state INVALID ' if $level ne '';
|
|
||||||
add_rule $chainref , '-m state --state INVALID -j DROP';
|
|
||||||
}
|
|
||||||
|
|
||||||
sub allowInvalid ( $$$ ) {
|
|
||||||
my ($chainref, $level, $tag) = @_;
|
|
||||||
|
|
||||||
log_rule_limit $level, $chainref, 'allowInvalid' , 'ACCEPT', '', $tag, 'add', '-m state --state INVALID ' if $level ne '';
|
|
||||||
add_rule $chainref , '-m state --state INVALID -j ACCEPT';
|
|
||||||
}
|
|
||||||
|
|
||||||
sub forwardUPnP ( $$$ ) {
|
|
||||||
}
|
|
||||||
|
|
||||||
sub allowinUPnP ( $$$ ) {
|
|
||||||
my ($chainref, $level, $tag) = @_;
|
|
||||||
|
|
||||||
if ( $level ne '' ) {
|
|
||||||
log_rule_limit $level, $chainref, 'allowinUPnP' , 'ACCEPT', '', $tag, 'add', '-p udp --dport 1900 ';
|
|
||||||
log_rule_limit $level, $chainref, 'allowinUPnP' , 'ACCEPT', '', $tag, 'add', '-p tcp --dport 49152 ';
|
|
||||||
}
|
|
||||||
|
|
||||||
add_rule $chainref, '-p udp --dport 1900 -j ACCEPT';
|
|
||||||
add_rule $chainref, '-p tcp --dport 49152 -j ACCEPT';
|
|
||||||
}
|
|
||||||
|
|
||||||
sub Limit( $$$ ) {
|
|
||||||
my ($chainref, $level, $tag) = @_;
|
|
||||||
|
|
||||||
my @tag = split /,/, $tag;
|
|
||||||
|
|
||||||
fatal_error 'Limit rules must include <set name>,<max connections>,<interval> as the log tag (' . join( ':', 'Limit', $level eq '' ? 'none' : $level , $tag ) . ')' unless @tag == 3;
|
|
||||||
|
|
||||||
my $set = $tag[0];
|
|
||||||
|
|
||||||
for ( @tag[1,2] ) {
|
|
||||||
fatal_error 'Max connections and interval in Limit rules must be numeric (' . join( ':', 'Limit', $level eq '' ? 'none' : $level, $tag ) . ')' unless /^\d+$/
|
|
||||||
}
|
|
||||||
|
|
||||||
my $count = $tag[1] + 1;
|
|
||||||
|
|
||||||
require_capability( 'RECENT_MATCH' , 'Limit rules' , '' );
|
|
||||||
|
|
||||||
add_rule $chainref, "-m recent --name $set --set";
|
|
||||||
|
|
||||||
if ( $level ne '' ) {
|
|
||||||
my $xchainref = new_chain 'filter' , "$chainref->{name}%";
|
|
||||||
log_rule_limit $level, $xchainref, $tag[0], 'DROP', '', '', 'add', '';
|
|
||||||
add_rule $xchainref, '-j DROP';
|
|
||||||
add_rule $chainref, "-m recent --name $set --update --seconds $tag[2] --hitcount $count -j $xchainref->{name}";
|
|
||||||
} else {
|
|
||||||
add_rule $chainref, "-m recent --update --name $set --seconds $tag[2] --hitcount $count -j DROP";
|
|
||||||
}
|
|
||||||
|
|
||||||
add_rule $chainref, '-j ACCEPT';
|
|
||||||
}
|
|
||||||
|
|
||||||
my %builtinops = ( 'dropBcast' => \&dropBcast,
|
|
||||||
'allowBcast' => \&allowBcast,
|
|
||||||
'dropNotSyn' => \&dropNotSyn,
|
|
||||||
'rejNotSyn' => \&rejNotSyn,
|
|
||||||
'dropInvalid' => \&dropInvalid,
|
|
||||||
'allowInvalid' => \&allowInvalid,
|
|
||||||
'allowinUPnP' => \&allowinUPnP,
|
|
||||||
'forwardUPnP' => \&forwardUPnP,
|
|
||||||
'Limit' => \&Limit, );
|
|
||||||
|
|
||||||
for my $wholeaction ( keys %usedactions ) {
|
|
||||||
my $chainref = find_logactionchain $wholeaction;
|
|
||||||
my ( $action, $level, $tag ) = split /:/, $wholeaction;
|
|
||||||
|
|
||||||
$level = '' unless defined $level;
|
|
||||||
$tag = '' unless defined $tag;
|
|
||||||
|
|
||||||
if ( $targets{$action} & BUILTIN ) {
|
|
||||||
$level = '' if $level =~ /none!?/;
|
|
||||||
$builtinops{$action}->($chainref, $level, $tag);
|
|
||||||
} else {
|
|
||||||
process_action3 $chainref, $wholeaction, $action, $level, $tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,661 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.2 -- /usr/share/shorewall-perl/Shorewall/IPAddrs.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# This module provides interfaces for dealing with IPv4 addresses, protocol names, and
|
|
||||||
# port names. It also exports functions for validating protocol- and port- (service)
|
|
||||||
# related constructs.
|
|
||||||
#
|
|
||||||
package Shorewall::IPAddrs;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Config qw( :DEFAULT split_list require_capability in_hex8 F_IPV4 F_IPV6 );
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw( ALLIPv4
|
|
||||||
ALLIPv6
|
|
||||||
IPv6_MULTICAST
|
|
||||||
IPv6_LINKLOCAL
|
|
||||||
IPv6_SITELOCAL
|
|
||||||
IPv6_LINKLOCAL
|
|
||||||
IPv6_LOOPBACK
|
|
||||||
IPv6_LINK_ALLNODES
|
|
||||||
IPv6_LINK_ALLRTRS
|
|
||||||
IPv6_SITE_ALLNODES
|
|
||||||
IPv6_SITE_ALLRTRS
|
|
||||||
ALLIP
|
|
||||||
ALL
|
|
||||||
TCP
|
|
||||||
UDP
|
|
||||||
ICMP
|
|
||||||
DCCP
|
|
||||||
IPv6_ICMP
|
|
||||||
SCTP
|
|
||||||
|
|
||||||
validate_address
|
|
||||||
validate_net
|
|
||||||
decompose_net
|
|
||||||
validate_host
|
|
||||||
validate_range
|
|
||||||
ip_range_explicit
|
|
||||||
expand_port_range
|
|
||||||
allipv4
|
|
||||||
allipv6
|
|
||||||
allip
|
|
||||||
rfc1918_networks
|
|
||||||
resolve_proto
|
|
||||||
proto_name
|
|
||||||
validate_port
|
|
||||||
validate_portpair
|
|
||||||
validate_port_list
|
|
||||||
validate_icmp
|
|
||||||
validate_icmp6
|
|
||||||
);
|
|
||||||
our @EXPORT_OK = qw( );
|
|
||||||
our $VERSION = 4.2.4;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Some IPv4/6 useful stuff
|
|
||||||
#
|
|
||||||
our @allipv4 = ( '0.0.0.0/0' );
|
|
||||||
our @allipv6 = ( '::/0' );
|
|
||||||
our $family;
|
|
||||||
|
|
||||||
use constant { ALLIPv4 => '0.0.0.0/0' ,
|
|
||||||
ALLIPv6 => '::/0' ,
|
|
||||||
IPv6_MULTICAST => 'FF00::/10' ,
|
|
||||||
IPv6_LINKLOCAL => 'FF80::/10' ,
|
|
||||||
IPv6_SITELOCAL => 'FFC0::/10' ,
|
|
||||||
IPv6_LINKLOCAL => 'FF80::/10' ,
|
|
||||||
IPv6_LOOPBACK => '::1' ,
|
|
||||||
IPv6_LINK_ALLNODES => 'FF01::1' ,
|
|
||||||
IPv6_LINK_ALLRTRS => 'FF01::2' ,
|
|
||||||
IPv6_SITE_ALLNODES => 'FF02::1' ,
|
|
||||||
IPv6_SITE_ALLRTRS => 'FF02::2' ,
|
|
||||||
ICMP => 1,
|
|
||||||
TCP => 6,
|
|
||||||
UDP => 17,
|
|
||||||
DCCP => 33,
|
|
||||||
IPv6_ICMP => 58,
|
|
||||||
SCTP => 132 };
|
|
||||||
|
|
||||||
our @rfc1918_networks = ( "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" );
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
||||||
# the compiler to run multiple times in the same process. The
|
|
||||||
# initialize() function does globals initialization for this
|
|
||||||
# module and is called from an INIT block below. The function is
|
|
||||||
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
||||||
# the second and subsequent calls to that function.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub initialize( $ ) {
|
|
||||||
$family = shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT {
|
|
||||||
initialize( F_IPV4 );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub vlsm_to_mask( $ ) {
|
|
||||||
my $vlsm = $_[0];
|
|
||||||
|
|
||||||
in_hex8 ( ( 0xFFFFFFFF << ( 32 - $vlsm ) ) && 0xFFFFFFFF );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub valid_4address( $ ) {
|
|
||||||
my $address = $_[0];
|
|
||||||
|
|
||||||
my @address = split /\./, $address;
|
|
||||||
return 0 unless @address == 4;
|
|
||||||
for my $a ( @address ) {
|
|
||||||
return 0 unless $a =~ /^\d+$/ && $a < 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_4address( $$ ) {
|
|
||||||
my ( $addr, $allow_name ) = @_;
|
|
||||||
|
|
||||||
my @addrs = ( $addr );
|
|
||||||
|
|
||||||
unless ( valid_4address $addr ) {
|
|
||||||
fatal_error "Invalid IP Address ($addr)" unless $allow_name;
|
|
||||||
fatal_error "Unknown Host ($addr)" unless (@addrs = gethostbyname $addr);
|
|
||||||
|
|
||||||
if ( defined wantarray ) {
|
|
||||||
shift @addrs for (1..4);
|
|
||||||
for ( @addrs ) {
|
|
||||||
$_ = inet_htoa $_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defined wantarray ? wantarray ? @addrs : $addrs[0] : undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub decodeaddr( $ ) {
|
|
||||||
my $address = $_[0];
|
|
||||||
|
|
||||||
my @address = split /\./, $address;
|
|
||||||
|
|
||||||
my $result = shift @address;
|
|
||||||
|
|
||||||
for my $a ( @address ) {
|
|
||||||
$result = ( $result << 8 ) | $a;
|
|
||||||
}
|
|
||||||
|
|
||||||
$result;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub encodeaddr( $ ) {
|
|
||||||
my $addr = $_[0];
|
|
||||||
my $result = $addr & 0xff;
|
|
||||||
|
|
||||||
for my $i ( 1..3 ) {
|
|
||||||
my $a = ($addr = $addr >> 8) & 0xff;
|
|
||||||
$result = "$a.$result";
|
|
||||||
}
|
|
||||||
|
|
||||||
$result;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_4net( $$ ) {
|
|
||||||
my ($net, $vlsm, $rest) = split( '/', $_[0], 3 );
|
|
||||||
my $allow_name = $_[1];
|
|
||||||
|
|
||||||
$net = '' unless defined $net;
|
|
||||||
|
|
||||||
fatal_error "Missing address" if $net eq '';
|
|
||||||
fatal_error "An ipset name ($net) is not allowed in this context" if substr( $net, 0, 1 ) eq '+';
|
|
||||||
|
|
||||||
if ( defined $vlsm ) {
|
|
||||||
fatal_error "Invalid VLSM ($vlsm)" unless $vlsm =~ /^\d+$/ && $vlsm <= 32;
|
|
||||||
fatal_error "Invalid Network address ($_[0])" if defined $rest;
|
|
||||||
fatal_error "Invalid IP address ($net)" unless valid_4address $net;
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid Network address ($_[0])" if $_[0] =~ '/' || ! defined $net;
|
|
||||||
validate_4address $net, $_[1];
|
|
||||||
$vlsm = 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( defined wantarray ) {
|
|
||||||
fatal_error "Internal Error in validate_net()" if $allow_name;
|
|
||||||
if ( wantarray ) {
|
|
||||||
( decodeaddr( $net ) , $vlsm );
|
|
||||||
} else {
|
|
||||||
"$net/$vlsm";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_4range( $$ ) {
|
|
||||||
my ( $low, $high ) = @_;
|
|
||||||
|
|
||||||
validate_4address $low, 0;
|
|
||||||
validate_4address $high, 0;
|
|
||||||
|
|
||||||
my $first = decodeaddr $low;
|
|
||||||
my $last = decodeaddr $high;
|
|
||||||
|
|
||||||
fatal_error "Invalid IP Range ($low-$high)" unless $first <= $last;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_4host( $$ ) {
|
|
||||||
my ( $host, $allow_name ) = $_[0];
|
|
||||||
|
|
||||||
if ( $host =~ /^(\d+\.\d+\.\d+\.\d+)-(\d+\.\d+\.\d+\.\d+)$/ ) {
|
|
||||||
validate_4range $1, $2;
|
|
||||||
} else {
|
|
||||||
validate_4net( $host, $allow_name );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub ip_range_explicit( $ ) {
|
|
||||||
my $range = $_[0];
|
|
||||||
my @result;
|
|
||||||
|
|
||||||
my ( $low, $high ) = split /-/, $range;
|
|
||||||
|
|
||||||
validate_4address $low, 0;
|
|
||||||
|
|
||||||
push @result, $low;
|
|
||||||
|
|
||||||
if ( defined $high ) {
|
|
||||||
validate_4address $high, 0;
|
|
||||||
|
|
||||||
my $first = decodeaddr $low;
|
|
||||||
my $last = decodeaddr $high;
|
|
||||||
my $diff = $last - $first;
|
|
||||||
|
|
||||||
fatal_error "Invalid IP Range ($range)" unless $diff >= 0 && $diff <= 256;
|
|
||||||
|
|
||||||
while ( ++$first <= $last ) {
|
|
||||||
push @result, encodeaddr( $first );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@result;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub decompose_net( $ ) {
|
|
||||||
my $net = $_[0];
|
|
||||||
|
|
||||||
return ( qw/0x00000000 0x00000000/ ) if $net eq '-';
|
|
||||||
|
|
||||||
( $net, my $vlsm ) = validate_net( $net , 0 );
|
|
||||||
|
|
||||||
( in_hex8( $net ) , vlsm_to_mask( $vlsm ) );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub allipv4() {
|
|
||||||
@allipv4;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub allipv6() {
|
|
||||||
@allipv6;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub rfc1918_networks() {
|
|
||||||
@rfc1918_networks
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Protocol/port validation
|
|
||||||
#
|
|
||||||
|
|
||||||
our %nametoproto = ( all => 0, ALL => 0, icmp => 1, ICMP => 1, tcp => 6, TCP => 6, udp => 17, UDP => 17 );
|
|
||||||
our @prototoname = ( 'all', 'icmp', '', '', '', '', 'tcp', '', '', '', '', '', '', '', '', '', '', 'udp' );
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the protocol number if the passed argument is a valid protocol number or name. Returns undef otherwise
|
|
||||||
#
|
|
||||||
sub resolve_proto( $ ) {
|
|
||||||
my $proto = $_[0];
|
|
||||||
my $number;
|
|
||||||
|
|
||||||
$proto =~ /^(\d+)$/ ? $proto <= 65535 ? $proto : undef : defined( $number = $nametoproto{$proto} ) ? $number : scalar getprotobyname $proto;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub proto_name( $ ) {
|
|
||||||
my $proto = $_[0];
|
|
||||||
|
|
||||||
$proto =~ /^(\d+)$/ ? $prototoname[ $proto ] || scalar getprotobynumber $proto : $proto
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_port( $$ ) {
|
|
||||||
my ($proto, $port) = @_;
|
|
||||||
|
|
||||||
my $value;
|
|
||||||
|
|
||||||
if ( $port =~ /^(\d+)$/ ) {
|
|
||||||
return $port if $port <= 65535;
|
|
||||||
} else {
|
|
||||||
$proto = proto_name $proto if $proto =~ /^(\d+)$/;
|
|
||||||
$value = getservbyname( $port, $proto );
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Invalid/Unknown $proto port/service ($port)" unless defined $value;
|
|
||||||
|
|
||||||
$value;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_portpair( $$ ) {
|
|
||||||
my ($proto, $portpair) = @_;
|
|
||||||
|
|
||||||
fatal_error "Invalid port range ($portpair)" if $portpair =~ tr/:/:/ > 1;
|
|
||||||
|
|
||||||
$portpair = "0$portpair" if substr( $portpair, 0, 1 ) eq ':';
|
|
||||||
$portpair = "${portpair}65535" if substr( $portpair, -1, 1 ) eq ':';
|
|
||||||
|
|
||||||
my @ports = split /:/, $portpair, 2;
|
|
||||||
|
|
||||||
$_ = validate_port( $proto, $_) for ( @ports );
|
|
||||||
|
|
||||||
if ( @ports == 2 ) {
|
|
||||||
fatal_error "Invalid port range ($portpair)" unless $ports[0] < $ports[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
join ':', @ports;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_port_list( $$ ) {
|
|
||||||
my $result = '';
|
|
||||||
my ( $proto, $list ) = @_;
|
|
||||||
my @list = split_list( $list, 'port' );
|
|
||||||
|
|
||||||
if ( @list > 1 && $list =~ /:/ ) {
|
|
||||||
require_capability( 'XMULTIPORT' , 'Port ranges in a port list', '' );
|
|
||||||
}
|
|
||||||
|
|
||||||
$proto = proto_name $proto;
|
|
||||||
|
|
||||||
for ( @list ) {
|
|
||||||
my $value = validate_portpair( $proto , $_ );
|
|
||||||
$result = $result ? join ',', $result, $value : $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
$result;
|
|
||||||
}
|
|
||||||
|
|
||||||
my %icmp_types = ( any => 'any',
|
|
||||||
'echo-reply' => 0,
|
|
||||||
'destination-unreachable' => 3,
|
|
||||||
'network-unreachable' => '3/0',
|
|
||||||
'host-unreachable' => '3/1',
|
|
||||||
'protocol-unreachable' => '3/2',
|
|
||||||
'port-unreachable' => '3/3',
|
|
||||||
'fragmentation-needed' => '3/4',
|
|
||||||
'source-route-failed' => '3/5',
|
|
||||||
'network-unknown' => '3/6',
|
|
||||||
'host-unknown' => '3/7',
|
|
||||||
'network-prohibited' => '3/9',
|
|
||||||
'host-prohibited' => '3/10',
|
|
||||||
'TOS-network-unreachable' => '3/11',
|
|
||||||
'TOS-host-unreachable' => '3/12',
|
|
||||||
'communication-prohibited' => '3/13',
|
|
||||||
'host-precedence-violation' => '3/14',
|
|
||||||
'precedence-cutoff' => '3/15',
|
|
||||||
'source-quench' => 4,
|
|
||||||
'redirect' => 5,
|
|
||||||
'network-redirect' => '5/0',
|
|
||||||
'host-redirect' => '5/1',
|
|
||||||
'TOS-network-redirect' => '5/2',
|
|
||||||
'TOS-host-redirect' => '5/3',
|
|
||||||
'echo-request' => '8',
|
|
||||||
'router-advertisement' => 9,
|
|
||||||
'router-solicitation' => 10,
|
|
||||||
'time-exceeded' => 11,
|
|
||||||
'ttl-zero-during-transit' => '11/0',
|
|
||||||
'ttl-zero-during-reassembly' => '11/1',
|
|
||||||
'parameter-problem' => 12,
|
|
||||||
'ip-header-bad' => '12/0',
|
|
||||||
'required-option-missing' => '12/1',
|
|
||||||
'timestamp-request' => 13,
|
|
||||||
'timestamp-reply' => 14,
|
|
||||||
'address-mask-request' => 17,
|
|
||||||
'address-mask-reply' => 18 );
|
|
||||||
|
|
||||||
sub validate_icmp( $ ) {
|
|
||||||
fatal_error "IPv4 ICMP not allowed in an IPv6 Rule" unless $family == F_IPV4;
|
|
||||||
|
|
||||||
my $type = $_[0];
|
|
||||||
|
|
||||||
my $value = $icmp_types{$type};
|
|
||||||
|
|
||||||
return $value if defined $value;
|
|
||||||
|
|
||||||
if ( $type =~ /^(\d+)(\/(\d+))?$/ ) {
|
|
||||||
return $type if $1 < 256 && ( ! $2 || $3 < 256 );
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Invalid ICMP Type ($type)"
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Expands a port range into a minimal list of ( port, mask ) pairs.
|
|
||||||
# Each port and mask are expressed as 4 hex nibbles without a leading '0x'.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
#
|
|
||||||
# DB<3> @foo = Shorewall::IPAddrs::expand_port_range( 6, '110:' ); print "@foo\n"
|
|
||||||
# 006e fffe 0070 fff0 0080 ff80 0100 ff00 0200 fe00 0400 fc00 0800 f800 1000 f000 2000 e000 4000 c000 8000 8000
|
|
||||||
#
|
|
||||||
sub expand_port_range( $$ ) {
|
|
||||||
my ( $proto, $range ) = @_;
|
|
||||||
|
|
||||||
if ( $range =~ /^(.*):(.*)$/ ) {
|
|
||||||
my ( $first, $last ) = ( $1, $2);
|
|
||||||
my @result;
|
|
||||||
|
|
||||||
fatal_error "Invalid port range ($range)" unless $first ne '' or $last ne '';
|
|
||||||
#
|
|
||||||
# Supply missing first/last port number
|
|
||||||
#
|
|
||||||
$first = 0 if $first eq '';
|
|
||||||
$last = 65535 if $last eq '';
|
|
||||||
#
|
|
||||||
# Validate the ports
|
|
||||||
#
|
|
||||||
( $first , $last ) = ( validate_port( $proto, $first ) , validate_port( $proto, $last ) );
|
|
||||||
|
|
||||||
$last++; #Increment last address for limit testing.
|
|
||||||
#
|
|
||||||
# Break the range into groups:
|
|
||||||
#
|
|
||||||
# - If the first port in the remaining range is odd, then the next group is ( <first>, ffff ).
|
|
||||||
# - Otherwise, find the largest power of two P that divides the first address such that
|
|
||||||
# the remaining range has less than or equal to P ports. The next group is
|
|
||||||
# ( <first> , ~( P-1 ) ).
|
|
||||||
#
|
|
||||||
while ( ( my $ports = ( $last - $first ) ) > 0 ) {
|
|
||||||
my $mask = 0xffff; #Mask for current ports in group.
|
|
||||||
my $y = 2; #Next power of two to test
|
|
||||||
my $z = 1; #Number of ports in current group (Previous value of $y).
|
|
||||||
|
|
||||||
while ( ( ! ( $first % $y ) ) && ( $y <= $ports ) ) {
|
|
||||||
$mask <<= 1;
|
|
||||||
$z = $y;
|
|
||||||
$y <<= 1;
|
|
||||||
}
|
|
||||||
#
|
|
||||||
#
|
|
||||||
push @result, sprintf( '%04x', $first ) , sprintf( '%04x' , $mask & 0xffff );
|
|
||||||
$first += $z;
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Invalid port range ($range)" unless @result; # first port > last port
|
|
||||||
|
|
||||||
@result;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
( sprintf( '%04x' , validate_port( $proto, $range ) ) , 'ffff' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub valid_6address( $ ) {
|
|
||||||
my $address = $_[0];
|
|
||||||
|
|
||||||
my @address = split /:/, $address;
|
|
||||||
my $max;
|
|
||||||
|
|
||||||
if ( $address[-1] && $address[-1] =~ /^\d+\.\d+\.\d+\.\d+$/ ) {
|
|
||||||
return 0 unless valid_4address pop @address;
|
|
||||||
$max = 6;
|
|
||||||
$address = join ':', @address;
|
|
||||||
} else {
|
|
||||||
$max = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0 if @address > $max;
|
|
||||||
return 0 unless ( @address == $max ) || $address =~ /::/;
|
|
||||||
return 0 if $address =~ /:::/ || $address =~ /::.*::/;
|
|
||||||
|
|
||||||
if ( $address =~ /^:/ ) {
|
|
||||||
unless ( $address eq '::' ) {
|
|
||||||
return 0 if $address =~ /:$/ || $address =~ /^:.*::/;
|
|
||||||
}
|
|
||||||
} elsif ( $address =~ /:$/ ) {
|
|
||||||
return 0 if $address =~ /::.*:$/;
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $a ( @address ) {
|
|
||||||
return 0 unless $a eq '' || ( $a =~ /^[a-fA-f\d]+$/ && oct "0x$a" < 65536 );
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_6address( $$ ) {
|
|
||||||
my ( $addr, $allow_name ) = @_;
|
|
||||||
|
|
||||||
my @addrs = ( $addr );
|
|
||||||
|
|
||||||
unless ( valid_6address $addr ) {
|
|
||||||
fatal_error "Invalid IPv6 Address ($addr)" unless $allow_name;
|
|
||||||
require Socket6;
|
|
||||||
fatal_error "Unknown Host ($addr)" unless (@addrs = Socket6::gethostbyname2( $addr, Socket6::AF_INET6()));
|
|
||||||
|
|
||||||
if ( defined wantarray ) {
|
|
||||||
shift @addrs for (1..4);
|
|
||||||
for ( @addrs ) {
|
|
||||||
$_ = Socket6::inet_ntop( Socket6::AF_INET6(), $_ );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defined wantarray ? wantarray ? @addrs : $addrs[0] : undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_6net( $$ ) {
|
|
||||||
my ($net, $vlsm, $rest) = split( '/', $_[0], 3 );
|
|
||||||
my $allow_name = $_[1];
|
|
||||||
|
|
||||||
fatal_error "An ipset name ($net) is not allowed in this context" if substr( $net, 0, 1 ) eq '+';
|
|
||||||
|
|
||||||
if ( defined $vlsm ) {
|
|
||||||
fatal_error "Invalid VLSM ($vlsm)" unless $vlsm =~ /^\d+$/ && $vlsm <= 128;
|
|
||||||
fatal_error "Invalid Network address ($_[0])" if defined $rest;
|
|
||||||
fatal_error "Invalid IPv6 address ($net)" unless valid_6address $net;
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid Network address ($_[0])" if $_[0] =~ '/' || ! defined $net;
|
|
||||||
validate_6address $net, $allow_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Note: the input is assumed to be a valid IPv6 address
|
|
||||||
#
|
|
||||||
sub normalize_6addr( $ ) {
|
|
||||||
my $addr = shift;
|
|
||||||
|
|
||||||
while ( $addr =~ tr/:/:/ < 6 ) {
|
|
||||||
$addr =~ s/::/:0::/;
|
|
||||||
}
|
|
||||||
|
|
||||||
$addr =~ s/::/:0:/;
|
|
||||||
|
|
||||||
$addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_6range( $$ ) {
|
|
||||||
my ( $low, $high ) = @_;
|
|
||||||
|
|
||||||
validate_6address $low, 0;
|
|
||||||
validate_6address $high, 0;
|
|
||||||
|
|
||||||
my @low = split ":", normalize_6addr( $low );
|
|
||||||
my @high = split ":", normalize_6addr( $high );
|
|
||||||
|
|
||||||
|
|
||||||
while ( @low ) {
|
|
||||||
my ( $l, $h) = ( shift @low, shift @high );
|
|
||||||
next if hex "0x$l" == hex "0x$h";
|
|
||||||
return 1 if hex "0x$l" < hex "0x$h";
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Invalid IPv6 Range ($low-$high)";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_6host( $$ ) {
|
|
||||||
my ( $host, $allow_name ) = $_[0];
|
|
||||||
|
|
||||||
if ( $host =~ /^(.*:.*)-(.*:.*)$/ ) {
|
|
||||||
validate_6range $1, $2;
|
|
||||||
} else {
|
|
||||||
validate_6net( $host, $allow_name );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my %ipv6_icmp_types = ( any => 'any',
|
|
||||||
'destination-unreachable' => 1,
|
|
||||||
'no-route' => '1/0',
|
|
||||||
'communication-prohibited' => '1/1',
|
|
||||||
'address-unreachable' => '1/2',
|
|
||||||
'port-unreachable' => '1/3',
|
|
||||||
'packet-too-big' => 2,
|
|
||||||
'time-exceeded' => 3,
|
|
||||||
'ttl-exceeded' => 3,
|
|
||||||
'ttl-zero-during-transit' => '3/0',
|
|
||||||
'ttl-zero-during-reassembly' => '3/1',
|
|
||||||
'parameter-problem' => 4,
|
|
||||||
'bad-header' => '4/0',
|
|
||||||
'unknown-header-type' => '4/1',
|
|
||||||
'unknown-option' => '4/2',
|
|
||||||
'echo-request' => 128,
|
|
||||||
'echo-reply' => 129,
|
|
||||||
'router-solicitation' => 133,
|
|
||||||
'router-advertisement' => 134,
|
|
||||||
'neighbour-solicitation' => 135,
|
|
||||||
'neighbour-advertisement' => 136,
|
|
||||||
redirect => 137 );
|
|
||||||
|
|
||||||
|
|
||||||
sub validate_icmp6( $ ) {
|
|
||||||
fatal_error "IPv6 ICMP not allowed in an IPv4 Rule" unless $family == F_IPV6;
|
|
||||||
my $type = $_[0];
|
|
||||||
|
|
||||||
my $value = $ipv6_icmp_types{$type};
|
|
||||||
|
|
||||||
return $value if defined $value;
|
|
||||||
|
|
||||||
if ( $type =~ /^(\d+)(\/(\d+))?$/ ) {
|
|
||||||
return $type if $1 < 256 && ( ! $2 || $3 < 256 );
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Invalid IPv6 ICMP Type ($type)"
|
|
||||||
}
|
|
||||||
|
|
||||||
sub ALLIP() {
|
|
||||||
$family == F_IPV4 ? ALLIPv4 : ALLIPv6;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub allip() {
|
|
||||||
$family == F_IPV4 ? ALLIPv4 : ALLIPv6;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub valid_address ( $ ) {
|
|
||||||
$family == F_IPV4 ? valid_4address( $_[0] ) : valid_6address( $_[0] );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_address ( $$ ) {
|
|
||||||
$family == F_IPV4 ? validate_4address( $_[0], $_[1] ) : validate_6address( $_[0], $_[1] );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_net ( $$ ) {
|
|
||||||
$family == F_IPV4 ? validate_4net( $_[0], $_[1] ) : validate_6net( $_[0], $_[1] );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_range ($$ ) {
|
|
||||||
$family == F_IPV4 ? validate_4range( $_[0], $_[1] ) : validate_6range( $_[0], $_[1] );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_host ($$ ) {
|
|
||||||
$family == F_IPV4 ? validate_4host( $_[0], $_[1] ) : validate_6host( $_[0], $_[1] );
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,518 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.2 -- /usr/share/shorewall-perl/Shorewall/Nat.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007,2008 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# This module contains code for dealing with the /etc/shorewall/masq,
|
|
||||||
# /etc/shorewall/nat and /etc/shorewall/netmap files.
|
|
||||||
#
|
|
||||||
package Shorewall::Nat;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Config qw(:DEFAULT :internal);
|
|
||||||
use Shorewall::IPAddrs;
|
|
||||||
use Shorewall::Zones;
|
|
||||||
use Shorewall::Chains qw(:DEFAULT :internal);
|
|
||||||
use Shorewall::IPAddrs;
|
|
||||||
use Shorewall::Providers qw( lookup_provider );
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw( setup_masq setup_nat setup_netmap add_addresses );
|
|
||||||
our @EXPORT_OK = ();
|
|
||||||
our $VERSION = 4.2.4;
|
|
||||||
|
|
||||||
our @addresses_to_add;
|
|
||||||
our %addresses_to_add;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
||||||
# the compiler to run multiple times in the same process. The
|
|
||||||
# initialize() function does globals initialization for this
|
|
||||||
# module and is called from an INIT block below. The function is
|
|
||||||
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
||||||
# the second and subsequent calls to that function.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub initialize() {
|
|
||||||
@addresses_to_add = ();
|
|
||||||
%addresses_to_add = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT {
|
|
||||||
initialize;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Handle IPSEC Options in a masq record
|
|
||||||
#
|
|
||||||
sub do_ipsec_options($)
|
|
||||||
{
|
|
||||||
my %validoptions = ( strict => NOTHING,
|
|
||||||
next => NOTHING,
|
|
||||||
reqid => NUMERIC,
|
|
||||||
spi => NUMERIC,
|
|
||||||
proto => IPSECPROTO,
|
|
||||||
mode => IPSECMODE,
|
|
||||||
"tunnel-src" => NETWORK,
|
|
||||||
"tunnel-dst" => NETWORK,
|
|
||||||
);
|
|
||||||
my $list=$_[0];
|
|
||||||
my $options = '-m policy --pol ipsec --dir out ';
|
|
||||||
my $fmt;
|
|
||||||
|
|
||||||
for my $e ( split_list $list, 'option' ) {
|
|
||||||
my $val = undef;
|
|
||||||
my $invert = '';
|
|
||||||
|
|
||||||
if ( $e =~ /([\w-]+)!=(.+)/ ) {
|
|
||||||
$val = $2;
|
|
||||||
$e = $1;
|
|
||||||
$invert = '! ';
|
|
||||||
} elsif ( $e =~ /([\w-]+)=(.+)/ ) {
|
|
||||||
$val = $2;
|
|
||||||
$e = $1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$fmt = $validoptions{$e};
|
|
||||||
|
|
||||||
fatal_error "Invalid Option ($e)" unless $fmt;
|
|
||||||
|
|
||||||
if ( $fmt eq NOTHING ) {
|
|
||||||
fatal_error "Option \"$e\" does not take a value" if defined $val;
|
|
||||||
} else {
|
|
||||||
fatal_error "Missing value for option \"$e\"" unless defined $val;
|
|
||||||
fatal_error "Invalid value ($val) for option \"$e\"" unless $val =~ /^($fmt)$/;
|
|
||||||
}
|
|
||||||
|
|
||||||
$options .= $invert;
|
|
||||||
$options .= "--$e ";
|
|
||||||
$options .= "$val " if defined $val;
|
|
||||||
}
|
|
||||||
|
|
||||||
$options;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Process a single rule from the the masq file
|
|
||||||
#
|
|
||||||
sub setup_one_masq($$$$$$$)
|
|
||||||
{
|
|
||||||
my ($interfacelist, $networks, $addresses, $proto, $ports, $ipsec, $mark) = @_;
|
|
||||||
|
|
||||||
my $pre_nat;
|
|
||||||
my $add_snat_aliases = $config{ADD_SNAT_ALIASES};
|
|
||||||
my $destnets = '';
|
|
||||||
my $baserule = '';
|
|
||||||
|
|
||||||
#
|
|
||||||
# Leading '+'
|
|
||||||
#
|
|
||||||
$pre_nat = 1 if $interfacelist =~ s/^\+//;
|
|
||||||
#
|
|
||||||
# Parse the remaining part of the INTERFACE column
|
|
||||||
#
|
|
||||||
if ( $interfacelist =~ /^([^:]+)::([^:]*)$/ ) {
|
|
||||||
$add_snat_aliases = 0;
|
|
||||||
$destnets = $2;
|
|
||||||
$interfacelist = $1;
|
|
||||||
} elsif ( $interfacelist =~ /^([^:]+:[^:]+):([^:]+)$/ ) {
|
|
||||||
$destnets = $2;
|
|
||||||
$interfacelist = $1;
|
|
||||||
} elsif ( $interfacelist =~ /^([^:]+):$/ ) {
|
|
||||||
$add_snat_aliases = 0;
|
|
||||||
$interfacelist = $1;
|
|
||||||
} elsif ( $interfacelist =~ /^([^:]+):([^:]*)$/ ) {
|
|
||||||
my ( $one, $two ) = ( $1, $2 );
|
|
||||||
if ( $2 =~ /\./ ) {
|
|
||||||
$interfacelist = $one;
|
|
||||||
$destnets = $two;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#
|
|
||||||
# If there is no source or destination then allow all addresses
|
|
||||||
#
|
|
||||||
$networks = ALLIPv4 if $networks eq '-';
|
|
||||||
$destnets = ALLIPv4 if $destnets eq '-';
|
|
||||||
|
|
||||||
#
|
|
||||||
# Handle IPSEC options, if any
|
|
||||||
#
|
|
||||||
if ( $ipsec ne '-' ) {
|
|
||||||
fatal_error "Non-empty IPSEC column requires policy match support in your kernel and iptables" unless $globals{ORIGINAL_POLICY_MATCH};
|
|
||||||
|
|
||||||
if ( $ipsec =~ /^yes$/i ) {
|
|
||||||
$baserule .= '-m policy --pol ipsec --dir out ';
|
|
||||||
} elsif ( $ipsec =~ /^no$/i ) {
|
|
||||||
$baserule .= '-m policy --pol none --dir out ';
|
|
||||||
} else {
|
|
||||||
$baserule .= do_ipsec_options $ipsec;
|
|
||||||
}
|
|
||||||
} elsif ( $capabilities{POLICY_MATCH} ) {
|
|
||||||
$baserule .= '-m policy --pol none --dir out ';
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Handle Protocol and Ports
|
|
||||||
#
|
|
||||||
$baserule .= do_proto $proto, $ports, '';
|
|
||||||
|
|
||||||
#
|
|
||||||
# Handle Mark
|
|
||||||
#
|
|
||||||
$baserule .= do_test( $mark, 0xFF) if $mark ne '-';
|
|
||||||
|
|
||||||
for my $fullinterface (split_list $interfacelist, 'interface' ) {
|
|
||||||
my $rule = '';
|
|
||||||
my $target = '-j MASQUERADE ';
|
|
||||||
#
|
|
||||||
# Isolate and verify the interface part
|
|
||||||
#
|
|
||||||
( my $interface = $fullinterface ) =~ s/:.*//;
|
|
||||||
|
|
||||||
if ( $interface =~ /(.*)[(](\w*)[)]$/ ) {
|
|
||||||
$interface = $1;
|
|
||||||
my $provider = $2;
|
|
||||||
$fullinterface =~ s/[(]\w*[)]//;
|
|
||||||
my $realm = lookup_provider( $provider ) unless $provider =~ /^\d+$/;
|
|
||||||
|
|
||||||
fatal_error "$provider is not a shared-interface provider" unless $realm;
|
|
||||||
|
|
||||||
$rule .= "-m realm --realm $realm ";
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Unknown interface ($interface)" unless my $interfaceref = known_interface( $interface );
|
|
||||||
|
|
||||||
unless ( $interfaceref->{root} ) {
|
|
||||||
$rule .= "-o $interface ";
|
|
||||||
$interface = $interfaceref->{name};
|
|
||||||
}
|
|
||||||
|
|
||||||
my $chainref = ensure_chain('nat', $pre_nat ? snat_chain $interface : masq_chain $interface);
|
|
||||||
|
|
||||||
my $detectaddress = 0;
|
|
||||||
my $exceptionrule = '';
|
|
||||||
my $randomize = '';
|
|
||||||
#
|
|
||||||
# Parse the ADDRESSES column
|
|
||||||
#
|
|
||||||
if ( $addresses ne '-' ) {
|
|
||||||
if ( $addresses eq 'random' ) {
|
|
||||||
$randomize = '--random ';
|
|
||||||
} else {
|
|
||||||
$addresses =~ s/:random$// and $randomize = '--random ';
|
|
||||||
|
|
||||||
if ( $addresses =~ /^SAME:nodst:/ ) {
|
|
||||||
fatal_error "':random' is not supported by the SAME target" if $randomize;
|
|
||||||
$target = '-j SAME --nodst ';
|
|
||||||
$addresses =~ s/.*://;
|
|
||||||
for my $addr ( split_list $addresses, 'address' ) {
|
|
||||||
$target .= "--to $addr ";
|
|
||||||
}
|
|
||||||
} elsif ( $addresses =~ /^SAME:/ ) {
|
|
||||||
fatal_error "':random' is not supported by the SAME target" if $randomize;
|
|
||||||
$target = '-j SAME ';
|
|
||||||
$addresses =~ s/.*://;
|
|
||||||
for my $addr ( split_list $addresses, 'address' ) {
|
|
||||||
$target .= "--to $addr ";
|
|
||||||
}
|
|
||||||
} elsif ( $addresses eq 'detect' ) {
|
|
||||||
my $variable = get_interface_address $interface;
|
|
||||||
$target = "-j SNAT --to-source $variable";
|
|
||||||
|
|
||||||
if ( interface_is_optional $interface ) {
|
|
||||||
add_commands( $chainref,
|
|
||||||
'',
|
|
||||||
"if [ \"$variable\" != 0.0.0.0 ]; then" );
|
|
||||||
incr_cmd_level( $chainref );
|
|
||||||
$detectaddress = 1;
|
|
||||||
}
|
|
||||||
} elsif ( $addresses eq 'NONAT' ) {
|
|
||||||
$target = '-j RETURN';
|
|
||||||
$add_snat_aliases = 0;
|
|
||||||
} else {
|
|
||||||
my $addrlist = '';
|
|
||||||
for my $addr ( split_list $addresses , 'address' ) {
|
|
||||||
if ( $addr =~ /^.*\..*\..*\./ ) {
|
|
||||||
$target = '-j SNAT ';
|
|
||||||
$addrlist .= "--to-source $addr ";
|
|
||||||
$exceptionrule = do_proto( $proto, '', '' ) if $addr =~ /:/;
|
|
||||||
} else {
|
|
||||||
$addr =~ s/^://;
|
|
||||||
$addrlist .= "--to-ports $addr ";
|
|
||||||
$exceptionrule = do_proto( $proto, '', '' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$target .= $addrlist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$target .= $randomize;
|
|
||||||
} else {
|
|
||||||
$add_snat_aliases = 0;
|
|
||||||
}
|
|
||||||
#
|
|
||||||
# And Generate the Rule(s)
|
|
||||||
#
|
|
||||||
expand_rule( $chainref ,
|
|
||||||
POSTROUTE_RESTRICT ,
|
|
||||||
$baserule . $rule ,
|
|
||||||
$networks ,
|
|
||||||
$destnets ,
|
|
||||||
'' ,
|
|
||||||
'' ,
|
|
||||||
$target ,
|
|
||||||
'' ,
|
|
||||||
'' ,
|
|
||||||
$exceptionrule );
|
|
||||||
|
|
||||||
if ( $detectaddress ) {
|
|
||||||
decr_cmd_level( $chainref );
|
|
||||||
add_command( $chainref , 'fi' );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $add_snat_aliases ) {
|
|
||||||
my ( $interface, $alias , $remainder ) = split( /:/, $fullinterface, 3 );
|
|
||||||
fatal_error "Invalid alias ($alias:$remainder)" if defined $remainder;
|
|
||||||
for my $address ( split_list $addresses, 'address' ) {
|
|
||||||
my ( $addrs, $port ) = split /:/, $address;
|
|
||||||
next unless $addrs;
|
|
||||||
next if $addrs eq 'detect';
|
|
||||||
for my $addr ( ip_range_explicit $addrs ) {
|
|
||||||
unless ( $addresses_to_add{$addr} ) {
|
|
||||||
emit "del_ip_addr $addr $interface" unless $config{RETAIN_ALIASES};
|
|
||||||
$addresses_to_add{$addr} = 1;
|
|
||||||
if ( defined $alias ) {
|
|
||||||
push @addresses_to_add, $addr, "$interface:$alias";
|
|
||||||
$alias++;
|
|
||||||
} else {
|
|
||||||
push @addresses_to_add, $addr, $interface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
progress_message " Masq record \"$currentline\" $done";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Process the masq file
|
|
||||||
#
|
|
||||||
sub setup_masq()
|
|
||||||
{
|
|
||||||
my $fn = open_file 'masq';
|
|
||||||
|
|
||||||
first_entry( sub { progress_message2 "$doing $fn..."; require_capability 'NAT_ENABLED' , 'a non-empty masq file' , 's'; } );
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ($fullinterface, $networks, $addresses, $proto, $ports, $ipsec, $mark ) = split_line1 2, 7, 'masq file';
|
|
||||||
|
|
||||||
if ( $fullinterface eq 'COMMENT' ) {
|
|
||||||
process_comment;
|
|
||||||
} else {
|
|
||||||
setup_one_masq $fullinterface, $networks, $addresses, $proto, $ports, $ipsec, $mark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_comment;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Validate the ALL INTERFACES or LOCAL column in the NAT file
|
|
||||||
#
|
|
||||||
sub validate_nat_column( $$ ) {
|
|
||||||
my $ref = $_[1];
|
|
||||||
my $val = $$ref;
|
|
||||||
|
|
||||||
if ( defined $val ) {
|
|
||||||
unless ( ( $val = "\L$val" ) eq 'yes' ) {
|
|
||||||
if ( ( $val eq 'no' ) || ( $val eq '-' ) ) {
|
|
||||||
$$ref = '';
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid value ($val) for $_[0]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$$ref = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Process a record from the NAT file
|
|
||||||
#
|
|
||||||
sub do_one_nat( $$$$$ )
|
|
||||||
{
|
|
||||||
my ( $external, $fullinterface, $internal, $allints, $localnat ) = @_;
|
|
||||||
|
|
||||||
my ( $interface, $alias, $remainder ) = split( /:/, $fullinterface, 3 );
|
|
||||||
|
|
||||||
fatal_error "Invalid alias ($alias:$remainder)" if defined $remainder;
|
|
||||||
|
|
||||||
sub add_nat_rule( $$ ) {
|
|
||||||
add_rule ensure_chain( 'nat', $_[0] ) , $_[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
my $add_ip_aliases = $config{ADD_IP_ALIASES};
|
|
||||||
|
|
||||||
my $policyin = '';
|
|
||||||
my $policyout = '';
|
|
||||||
my $rulein = '';
|
|
||||||
my $ruleout = '';
|
|
||||||
|
|
||||||
fatal_error "Unknown interface ($interface)" unless my $interfaceref = known_interface( $interface );
|
|
||||||
|
|
||||||
unless ( $interfaceref->{root} ) {
|
|
||||||
$rulein = "-i $interface ";
|
|
||||||
$ruleout = "-o $interface ";
|
|
||||||
$interface = $interfaceref->{name};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $capabilities{POLICY_MATCH} ) {
|
|
||||||
$policyin = ' -m policy --pol none --dir in';
|
|
||||||
$policyout = '-m policy --pol none --dir out';
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Invalid nat file entry" unless defined $interface && defined $internal;
|
|
||||||
|
|
||||||
if ( $add_ip_aliases ) {
|
|
||||||
if ( defined( $alias ) && $alias eq '' ) {
|
|
||||||
$add_ip_aliases = '';
|
|
||||||
} else {
|
|
||||||
emit "del_ip_addr $external $interface" unless $config{RETAIN_ALIASES};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
validate_nat_column 'ALL INTERFACES', \$allints;
|
|
||||||
validate_nat_column 'LOCAL' , \$localnat;
|
|
||||||
|
|
||||||
if ( $allints ) {
|
|
||||||
add_nat_rule 'nat_in' , "-d $external $policyin -j DNAT --to-destination $internal";
|
|
||||||
add_nat_rule 'nat_out' , "-s $internal $policyout -j SNAT --to-source $external";
|
|
||||||
} else {
|
|
||||||
add_nat_rule input_chain( $interface ) , $rulein . "-d $external $policyin -j DNAT --to-destination $internal";
|
|
||||||
add_nat_rule output_chain( $interface ) , $ruleout . "-s $internal $policyout -j SNAT --to-source $external";
|
|
||||||
}
|
|
||||||
|
|
||||||
add_nat_rule 'OUTPUT' , "-d $external $policyout -j DNAT --to-destination $internal " if $localnat;
|
|
||||||
|
|
||||||
if ( $add_ip_aliases ) {
|
|
||||||
unless ( $addresses_to_add{$external} ) {
|
|
||||||
$addresses_to_add{$external} = 1;
|
|
||||||
push @addresses_to_add, ( $external , $fullinterface );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Process NAT file
|
|
||||||
#
|
|
||||||
sub setup_nat() {
|
|
||||||
|
|
||||||
my $fn = open_file 'nat';
|
|
||||||
|
|
||||||
first_entry( sub { progress_message2 "$doing $fn..."; require_capability 'NAT_ENABLED' , 'a non-empty nat file' , 's'; } );
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $external, $interfacelist, $internal, $allints, $localnat ) = split_line1 3, 5, 'nat file';
|
|
||||||
|
|
||||||
if ( $external eq 'COMMENT' ) {
|
|
||||||
process_comment;
|
|
||||||
} else {
|
|
||||||
( $interfacelist, my $digit ) = split /:/, $interfacelist;
|
|
||||||
|
|
||||||
$digit = defined $digit ? ":$digit" : '';
|
|
||||||
|
|
||||||
for my $interface ( split_list $interfacelist , 'interface' ) {
|
|
||||||
fatal_error "Invalid Interface List ($interfacelist)" unless defined $interface && $interface ne '';
|
|
||||||
do_one_nat $external, "${interface}${digit}", $internal, $allints, $localnat;
|
|
||||||
}
|
|
||||||
|
|
||||||
progress_message " NAT entry \"$currentline\" $done";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Setup Network Mapping
|
|
||||||
#
|
|
||||||
sub setup_netmap() {
|
|
||||||
|
|
||||||
my $fn = open_file 'netmap';
|
|
||||||
|
|
||||||
first_entry( sub { progress_message2 "$doing $fn..."; require_capability 'NAT_ENABLED' , 'a non-empty netmap file' , 's'; } );
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $type, $net1, $interfacelist, $net2 ) = split_line 4, 4, 'netmap file';
|
|
||||||
|
|
||||||
for my $interface ( split_list $interfacelist, 'interface' ) {
|
|
||||||
|
|
||||||
my $rulein = '';
|
|
||||||
my $ruleout = '';
|
|
||||||
my $iface = $interface;
|
|
||||||
|
|
||||||
fatal_error "Unknown interface ($interface)" unless my $interfaceref = find_interface( $interface );
|
|
||||||
|
|
||||||
unless ( $interfaceref->{root} ) {
|
|
||||||
$rulein = "-i $interface ";
|
|
||||||
$ruleout = "-o $interface ";
|
|
||||||
$interface = $interfaceref->{name};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $type eq 'DNAT' ) {
|
|
||||||
add_rule ensure_chain( 'nat' , input_chain $interface ) , $rulein . "-d $net1 -j NETMAP --to $net2";
|
|
||||||
} elsif ( $type eq 'SNAT' ) {
|
|
||||||
add_rule ensure_chain( 'nat' , output_chain $interface ) , $ruleout . "-s $net1 -j NETMAP --to $net2";
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid type ($type)";
|
|
||||||
}
|
|
||||||
|
|
||||||
progress_message " Network $net1 on $iface mapped to $net2 ($type)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub add_addresses () {
|
|
||||||
if ( @addresses_to_add ) {
|
|
||||||
my $arg = '';
|
|
||||||
|
|
||||||
while ( @addresses_to_add ) {
|
|
||||||
my $addr = shift @addresses_to_add;
|
|
||||||
my $interface = shift @addresses_to_add;
|
|
||||||
$arg = "$arg $addr $interface";
|
|
||||||
}
|
|
||||||
|
|
||||||
emit "add_ip_aliases $arg";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,480 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.2 -- /usr/share/shorewall-perl/Shorewall/Policy.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007,2008 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# This module deals with the /etc/shorewall/policy file.
|
|
||||||
#
|
|
||||||
package Shorewall::Policy;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Config qw(:DEFAULT :internal);
|
|
||||||
use Shorewall::Zones;
|
|
||||||
use Shorewall::Chains qw( :DEFAULT :internal) ;
|
|
||||||
use Shorewall::Actions;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw( validate_policy apply_policy_rules complete_standard_chain setup_syn_flood_chains );
|
|
||||||
our @EXPORT_OK = qw( );
|
|
||||||
our $VERSION = 4.2.4;
|
|
||||||
|
|
||||||
# @policy_chains is a list of references to policy chains in the filter table
|
|
||||||
|
|
||||||
our @policy_chains;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
||||||
# the compiler to run multiple times in the same process. The
|
|
||||||
# initialize() function does globals initialization for this
|
|
||||||
# module and is called from an INIT block below. The function is
|
|
||||||
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
||||||
# the second and subsequent calls to that function.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub initialize() {
|
|
||||||
@policy_chains = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT {
|
|
||||||
initialize;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Convert a chain into a policy chain.
|
|
||||||
#
|
|
||||||
sub convert_to_policy_chain($$$$$)
|
|
||||||
{
|
|
||||||
my ($chainref, $source, $dest, $policy, $optional ) = @_;
|
|
||||||
|
|
||||||
$chainref->{is_policy} = 1;
|
|
||||||
$chainref->{policy} = $policy;
|
|
||||||
$chainref->{is_optional} = $optional;
|
|
||||||
$chainref->{policychain} = $chainref->{name};
|
|
||||||
$chainref->{policypair} = [ $source, $dest ];
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Create a new policy chain and return a reference to it.
|
|
||||||
#
|
|
||||||
sub new_policy_chain($$$$)
|
|
||||||
{
|
|
||||||
my ($source, $dest, $policy, $optional) = @_;
|
|
||||||
|
|
||||||
my $chainref = new_chain( 'filter', "${source}2${dest}" );
|
|
||||||
|
|
||||||
convert_to_policy_chain( $chainref, $source, $dest, $policy, $optional );
|
|
||||||
|
|
||||||
$chainref;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Set the passed chain's policychain and policy to the passed values.
|
|
||||||
#
|
|
||||||
sub set_policy_chain($$$$$)
|
|
||||||
{
|
|
||||||
my ($source, $dest, $chain1, $chainref, $policy ) = @_;
|
|
||||||
|
|
||||||
my $chainref1 = $filter_table->{$chain1};
|
|
||||||
|
|
||||||
$chainref1 = new_chain 'filter', $chain1 unless $chainref1;
|
|
||||||
|
|
||||||
unless ( $chainref1->{policychain} ) {
|
|
||||||
if ( $config{EXPAND_POLICIES} ) {
|
|
||||||
#
|
|
||||||
# We convert the canonical chain into a policy chain, using the settings of the
|
|
||||||
# passed policy chain.
|
|
||||||
#
|
|
||||||
$chainref1->{policychain} = $chain1;
|
|
||||||
$chainref1->{loglevel} = $chainref->{loglevel} if defined $chainref->{loglevel};
|
|
||||||
|
|
||||||
if ( defined $chainref->{synparams} ) {
|
|
||||||
$chainref1->{synparams} = $chainref->{synparams};
|
|
||||||
$chainref1->{synchain} = $chainref->{synchain};
|
|
||||||
}
|
|
||||||
|
|
||||||
$chainref1->{default} = $chainref->{default} if defined $chainref->{default};
|
|
||||||
$chainref1->{is_policy} = 1;
|
|
||||||
push @policy_chains, $chainref1;
|
|
||||||
} else {
|
|
||||||
$chainref1->{policychain} = $chainref->{name};
|
|
||||||
}
|
|
||||||
|
|
||||||
$chainref1->{policy} = $policy;
|
|
||||||
$chainref1->{policypair} = [ $source, $dest ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Process the policy file
|
|
||||||
#
|
|
||||||
use constant { OPTIONAL => 1 };
|
|
||||||
|
|
||||||
sub add_or_modify_policy_chain( $$ ) {
|
|
||||||
my ( $zone, $zone1 ) = @_;
|
|
||||||
my $chain = "${zone}2${zone1}";
|
|
||||||
my $chainref = $filter_table->{$chain};
|
|
||||||
|
|
||||||
if ( $chainref ) {
|
|
||||||
unless( $chainref->{is_policy} ) {
|
|
||||||
convert_to_policy_chain( $chainref, $zone, $zone1, 'CONTINUE', OPTIONAL );
|
|
||||||
push @policy_chains, $chainref;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
push @policy_chains, ( new_policy_chain $zone, $zone1, 'CONTINUE', OPTIONAL );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub print_policy($$$$) {
|
|
||||||
my ( $source, $dest, $policy , $chain ) = @_;
|
|
||||||
unless ( ( $source eq 'all' ) || ( $dest eq 'all' ) ) {
|
|
||||||
if ( $policy eq 'CONTINUE' ) {
|
|
||||||
my ( $sourceref, $destref ) = ( find_zone($source) ,find_zone( $dest ) );
|
|
||||||
warning_message "CONTINUE policy between two un-nested zones ($source, $dest)" if ! ( @{$sourceref->{parents}} || @{$destref->{parents}} );
|
|
||||||
}
|
|
||||||
progress_message_nocompress " Policy for $source to $dest is $policy using chain $chain" unless $source eq $dest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_policy()
|
|
||||||
{
|
|
||||||
my %validpolicies = (
|
|
||||||
ACCEPT => undef,
|
|
||||||
REJECT => undef,
|
|
||||||
DROP => undef,
|
|
||||||
CONTINUE => undef,
|
|
||||||
QUEUE => undef,
|
|
||||||
NFQUEUE => undef,
|
|
||||||
NONE => undef
|
|
||||||
);
|
|
||||||
|
|
||||||
my %map = ( DROP_DEFAULT => 'DROP' ,
|
|
||||||
REJECT_DEFAULT => 'REJECT' ,
|
|
||||||
ACCEPT_DEFAULT => 'ACCEPT' ,
|
|
||||||
QUEUE_DEFAULT => 'QUEUE' ,
|
|
||||||
NFQUEUE_DEFAULT => 'NFQUEUE' );
|
|
||||||
|
|
||||||
my $zone;
|
|
||||||
my @zonelist = $config{EXPAND_POLICIES} ? all_zones : ( all_zones, 'all' );
|
|
||||||
|
|
||||||
for my $option qw/DROP_DEFAULT REJECT_DEFAULT ACCEPT_DEFAULT QUEUE_DEFAULT NFQUEUE_DEFAULT/ {
|
|
||||||
my $action = $config{$option};
|
|
||||||
next if $action eq 'none';
|
|
||||||
my $actiontype = $targets{$action};
|
|
||||||
|
|
||||||
if ( defined $actiontype ) {
|
|
||||||
fatal_error "Invalid setting ($action) for $option" unless $actiontype & ACTION;
|
|
||||||
} else {
|
|
||||||
fatal_error "Default Action $option=$action not found";
|
|
||||||
}
|
|
||||||
|
|
||||||
unless ( $usedactions{$action} ) {
|
|
||||||
$usedactions{$action} = 1;
|
|
||||||
createactionchain $action;
|
|
||||||
}
|
|
||||||
|
|
||||||
$default_actions{$map{$option}} = $action;
|
|
||||||
}
|
|
||||||
|
|
||||||
for $zone ( all_zones ) {
|
|
||||||
push @policy_chains, ( new_policy_chain $zone, $zone, 'ACCEPT', OPTIONAL );
|
|
||||||
|
|
||||||
if ( $config{IMPLICIT_CONTINUE} && ( @{find_zone( $zone )->{parents}} ) ) {
|
|
||||||
for my $zone1 ( all_zones ) {
|
|
||||||
unless( $zone eq $zone1 ) {
|
|
||||||
add_or_modify_policy_chain( $zone, $zone1 );
|
|
||||||
add_or_modify_policy_chain( $zone1, $zone );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my $fn = open_file 'policy';
|
|
||||||
|
|
||||||
first_entry "$doing $fn...";
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $client, $server, $originalpolicy, $loglevel, $synparams, $connlimit ) = split_line 3, 6, 'policy file';
|
|
||||||
|
|
||||||
$loglevel = '' if $loglevel eq '-';
|
|
||||||
$synparams = '' if $synparams eq '-';
|
|
||||||
$connlimit = '' if $connlimit eq '-';
|
|
||||||
|
|
||||||
my $clientwild = ( "\L$client" eq 'all' );
|
|
||||||
|
|
||||||
fatal_error "Undefined zone ($client)" unless $clientwild || defined_zone( $client );
|
|
||||||
|
|
||||||
my $serverwild = ( "\L$server" eq 'all' );
|
|
||||||
|
|
||||||
fatal_error "Undefined zone ($server)" unless $serverwild || defined_zone( $server );
|
|
||||||
|
|
||||||
my ( $policy, $default, $remainder ) = split( /:/, $originalpolicy, 3 );
|
|
||||||
|
|
||||||
fatal_error "Invalid or missing POLICY ($originalpolicy)" unless $policy;
|
|
||||||
|
|
||||||
fatal_error "Invalid default action ($default:$remainder)" if defined $remainder;
|
|
||||||
|
|
||||||
( $policy , my $queue ) = get_target_param $policy;
|
|
||||||
|
|
||||||
if ( $default ) {
|
|
||||||
if ( "\L$default" eq 'none' ) {
|
|
||||||
$default = 'none';
|
|
||||||
} else {
|
|
||||||
my $defaulttype = $targets{$default} || 0;
|
|
||||||
|
|
||||||
if ( $defaulttype & ACTION ) {
|
|
||||||
unless ( $usedactions{$default} ) {
|
|
||||||
$usedactions{$default} = 1;
|
|
||||||
createactionchain $default;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fatal_error "Unknown Default Action ($default)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$default = $default_actions{$policy} || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Invalid policy ($policy)" unless exists $validpolicies{$policy};
|
|
||||||
|
|
||||||
if ( defined $queue ) {
|
|
||||||
fatal_error "Invalid policy ($policy($queue))" unless $policy eq 'NFQUEUE';
|
|
||||||
require_capability( 'NFQUEUE_TARGET', 'An NFQUEUE Policy', 's' );
|
|
||||||
my $queuenum = numeric_value( $queue );
|
|
||||||
fatal_error "Invalid NFQUEUE queue number ($queue)" unless defined( $queuenum) && $queuenum <= 65535;
|
|
||||||
$policy = "NFQUEUE --queue-num $queuenum";
|
|
||||||
} elsif ( $policy eq 'NONE' ) {
|
|
||||||
fatal_error "NONE policy not allowed with \"all\""
|
|
||||||
if $clientwild || $serverwild;
|
|
||||||
fatal_error "NONE policy not allowed to/from firewall zone"
|
|
||||||
if ( zone_type( $client ) eq 'firewall' ) || ( zone_type( $server ) eq 'firewall' );
|
|
||||||
}
|
|
||||||
|
|
||||||
unless ( $clientwild || $serverwild ) {
|
|
||||||
if ( zone_type( $server ) eq 'bport' ) {
|
|
||||||
fatal_error "Invalid policy - DEST zone is a Bridge Port zone but the SOURCE zone is not associated with the same bridge"
|
|
||||||
unless find_zone( $client )->{bridge} eq find_zone( $server)->{bridge} || single_interface( $client ) eq find_zone( $server )->{bridge};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my $chain = "${client}2${server}";
|
|
||||||
my $chainref;
|
|
||||||
|
|
||||||
if ( defined $filter_table->{$chain} ) {
|
|
||||||
$chainref = $filter_table->{$chain};
|
|
||||||
|
|
||||||
if ( $chainref->{is_policy} ) {
|
|
||||||
if ( $chainref->{is_optional} ) {
|
|
||||||
$chainref->{is_optional} = 0;
|
|
||||||
$chainref->{policy} = $policy;
|
|
||||||
} else {
|
|
||||||
fatal_error qq(Policy "$client $server $policy" duplicates earlier policy "@{$chainref->{policypair}} $chainref->{policy}");
|
|
||||||
}
|
|
||||||
} elsif ( $chainref->{policy} ) {
|
|
||||||
fatal_error qq(Policy "$client $server $policy" duplicates earlier policy "@{$chainref->{policypair}} $chainref->{policy}");
|
|
||||||
} else {
|
|
||||||
convert_to_policy_chain( $chainref, $client, $server, $policy, 0 );
|
|
||||||
push @policy_chains, ( $chainref ) unless $config{EXPAND_POLICIES} && ( $clientwild || $serverwild );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$chainref = new_policy_chain $client, $server, $policy, 0;
|
|
||||||
push @policy_chains, ( $chainref ) unless $config{EXPAND_POLICIES} && ( $clientwild || $serverwild );
|
|
||||||
}
|
|
||||||
|
|
||||||
$chainref->{loglevel} = validate_level( $loglevel ) if defined $loglevel && $loglevel ne '';
|
|
||||||
|
|
||||||
if ( $synparams ne '' || $connlimit ne '' ) {
|
|
||||||
my $value = '';
|
|
||||||
fatal_error "Invalid CONNLIMIT ($connlimit)" if $connlimit =~ /^!/;
|
|
||||||
$value = do_ratelimit $synparams, 'ACCEPT' if $synparams ne '';
|
|
||||||
$value .= do_connlimit $connlimit if $connlimit ne '';
|
|
||||||
$chainref->{synparams} = $value;
|
|
||||||
$chainref->{synchain} = $chain
|
|
||||||
}
|
|
||||||
|
|
||||||
$chainref->{default} = $default if $default;
|
|
||||||
|
|
||||||
if ( $clientwild ) {
|
|
||||||
if ( $serverwild ) {
|
|
||||||
for my $zone ( @zonelist ) {
|
|
||||||
for my $zone1 ( @zonelist ) {
|
|
||||||
set_policy_chain $client, $server, "${zone}2${zone1}", $chainref, $policy;
|
|
||||||
print_policy $zone, $zone1, $policy, $chain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for my $zone ( all_zones ) {
|
|
||||||
set_policy_chain $client, $server, "${zone}2${server}", $chainref, $policy;
|
|
||||||
print_policy $zone, $server, $policy, $chain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elsif ( $serverwild ) {
|
|
||||||
for my $zone ( @zonelist ) {
|
|
||||||
set_policy_chain $client, $server, "${client}2${zone}", $chainref, $policy;
|
|
||||||
print_policy $client, $zone, $policy, $chain;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
print_policy $client, $server, $policy, $chain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for $zone ( all_zones ) {
|
|
||||||
for my $zone1 ( all_zones ) {
|
|
||||||
fatal_error "No policy defined from zone $zone to zone $zone1" unless $filter_table->{"${zone}2${zone1}"}{policy};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Policy Rule application
|
|
||||||
#
|
|
||||||
sub policy_rules( $$$$$ ) {
|
|
||||||
my ( $chainref , $target, $loglevel, $default, $dropmulticast ) = @_;
|
|
||||||
|
|
||||||
unless ( $target eq 'NONE' ) {
|
|
||||||
add_rule $chainref, "-d 224.0.0.0/24 -j RETURN" if $dropmulticast && $target ne 'CONTINUE';
|
|
||||||
add_rule $chainref, "-j $default" if $default && $default ne 'none';
|
|
||||||
log_rule $loglevel , $chainref , $target , '' if $loglevel ne '';
|
|
||||||
fatal_error "Null target in policy_rules()" unless $target;
|
|
||||||
|
|
||||||
add_jump( $chainref , $target eq 'REJECT' ? 'reject' : $target, 1 ) unless $target eq 'CONTINUE';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub report_syn_flood_protection() {
|
|
||||||
progress_message_nocompress ' Enabled SYN flood protection';
|
|
||||||
}
|
|
||||||
|
|
||||||
sub default_policy( $$$ ) {
|
|
||||||
my $chainref = $_[0];
|
|
||||||
my $policyref = $filter_table->{$chainref->{policychain}};
|
|
||||||
my $synparams = $policyref->{synparams};
|
|
||||||
my $default = $policyref->{default};
|
|
||||||
my $policy = $policyref->{policy};
|
|
||||||
my $loglevel = $policyref->{loglevel};
|
|
||||||
|
|
||||||
fatal_error "Internal error in default_policy()" unless $policyref;
|
|
||||||
|
|
||||||
if ( $chainref eq $policyref ) {
|
|
||||||
policy_rules $chainref , $policy, $loglevel , $default, $config{MULTICAST};
|
|
||||||
} else {
|
|
||||||
if ( $policy eq 'ACCEPT' || $policy eq 'QUEUE' || $policy =~ /^NFQUEUE/ ) {
|
|
||||||
if ( $synparams ) {
|
|
||||||
report_syn_flood_protection;
|
|
||||||
policy_rules $chainref , $policy , $loglevel , $default, $config{MULTICAST};
|
|
||||||
} else {
|
|
||||||
add_jump $chainref, $policyref, 1;
|
|
||||||
$chainref = $policyref;
|
|
||||||
}
|
|
||||||
} elsif ( $policy eq 'CONTINUE' ) {
|
|
||||||
report_syn_flood_protection if $synparams;
|
|
||||||
policy_rules $chainref , $policy , $loglevel , $default, $config{MULTICAST};
|
|
||||||
} else {
|
|
||||||
report_syn_flood_protection if $synparams;
|
|
||||||
add_jump $chainref , $policyref, 1;
|
|
||||||
$chainref = $policyref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
progress_message_nocompress " Policy $policy from $_[1] to $_[2] using chain $chainref->{name}";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub apply_policy_rules() {
|
|
||||||
progress_message2 'Applying Policies...';
|
|
||||||
|
|
||||||
for my $chainref ( @policy_chains ) {
|
|
||||||
my $policy = $chainref->{policy};
|
|
||||||
my $loglevel = $chainref->{loglevel};
|
|
||||||
my $optional = $chainref->{is_optional};
|
|
||||||
my $default = $chainref->{default};
|
|
||||||
my $name = $chainref->{name};
|
|
||||||
|
|
||||||
if ( $policy ne 'NONE' ) {
|
|
||||||
if ( ! $chainref->{referenced} && ( ! $optional && $policy ne 'CONTINUE' ) ) {
|
|
||||||
ensure_filter_chain $name, 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $name =~ /^all2|2all$/ ) {
|
|
||||||
run_user_exit $chainref;
|
|
||||||
policy_rules $chainref , $policy, $loglevel , $default, $config{MULTICAST};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $zone ( all_zones ) {
|
|
||||||
for my $zone1 ( all_zones ) {
|
|
||||||
my $chainref = $filter_table->{"${zone}2${zone1}"};
|
|
||||||
|
|
||||||
if ( $chainref->{referenced} ) {
|
|
||||||
run_user_exit $chainref;
|
|
||||||
default_policy $chainref, $zone, $zone1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Complete a standard chain
|
|
||||||
#
|
|
||||||
# - run any supplied user exit
|
|
||||||
# - search the policy file for an applicable policy and add rules as
|
|
||||||
# appropriate
|
|
||||||
# - If no applicable policy is found, add rules for an assummed
|
|
||||||
# policy of DROP INFO
|
|
||||||
#
|
|
||||||
sub complete_standard_chain ( $$$$ ) {
|
|
||||||
my ( $stdchainref, $zone, $zone2, $default ) = @_;
|
|
||||||
|
|
||||||
add_rule $stdchainref, '-m state --state ESTABLISHED,RELATED -j ACCEPT' unless $config{FASTACCEPT};
|
|
||||||
|
|
||||||
run_user_exit $stdchainref;
|
|
||||||
|
|
||||||
my $ruleschainref = $filter_table->{"${zone}2${zone2}"};
|
|
||||||
my ( $policy, $loglevel, $defaultaction ) = ( $default , 6, $config{$default . '_DEFAULT'} );
|
|
||||||
my $policychainref;
|
|
||||||
|
|
||||||
$policychainref = $filter_table->{$ruleschainref->{policychain}} if $ruleschainref;
|
|
||||||
|
|
||||||
( $policy, $loglevel, $defaultaction ) = @{$policychainref}{'policy', 'loglevel', 'default' } if $policychainref;
|
|
||||||
|
|
||||||
policy_rules $stdchainref , $policy , $loglevel, $defaultaction, 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Create and populate the synflood chains corresponding to entries in /etc/shorewall/policy
|
|
||||||
#
|
|
||||||
sub setup_syn_flood_chains() {
|
|
||||||
for my $chainref ( @policy_chains ) {
|
|
||||||
my $limit = $chainref->{synparams};
|
|
||||||
if ( $limit && ! $filter_table->{syn_flood_chain $chainref} ) {
|
|
||||||
my $level = $chainref->{loglevel};
|
|
||||||
my $synchainref = new_chain 'filter' , syn_flood_chain $chainref;
|
|
||||||
add_rule $synchainref , "${limit}-j RETURN";
|
|
||||||
log_rule_limit $level , $synchainref , $chainref->{name} , 'DROP', '-m limit --limit 5/min --limit-burst 5 ' , '' , 'add' , ''
|
|
||||||
if $level ne '';
|
|
||||||
add_rule $synchainref, '-j DROP';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,252 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall 4.2 -- /usr/share/shorewall-perl/Shorewall/Proc.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# This module contains the code that deals with entries in /proc.
|
|
||||||
#
|
|
||||||
# Note: The /proc/sys/net/ipv4/conf/x/proxy_arp flag is handled
|
|
||||||
# in the Proxyarp module.
|
|
||||||
#
|
|
||||||
package Shorewall::Proc;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Config qw(:DEFAULT :internal);
|
|
||||||
use Shorewall::Zones;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw(
|
|
||||||
setup_arp_filtering
|
|
||||||
setup_route_filtering
|
|
||||||
setup_martian_logging
|
|
||||||
setup_source_routing
|
|
||||||
setup_forwarding
|
|
||||||
);
|
|
||||||
our @EXPORT_OK = qw( );
|
|
||||||
our $VERSION = 4.2.4;
|
|
||||||
|
|
||||||
#
|
|
||||||
# ARP Filtering
|
|
||||||
#
|
|
||||||
sub setup_arp_filtering() {
|
|
||||||
save_progress_message "Setting up ARP filtering...";
|
|
||||||
|
|
||||||
my $interfaces = find_interfaces_by_option 'arp_filter';
|
|
||||||
my $interfaces1 = find_interfaces_by_option 'arp_ignore';
|
|
||||||
|
|
||||||
if ( @$interfaces || @$interfaces1 ) {
|
|
||||||
progress_message2 "$doing ARP Filtering...";
|
|
||||||
|
|
||||||
for my $interface ( @$interfaces ) {
|
|
||||||
my $file = "/proc/sys/net/ipv4/conf/$interface/arp_filter";
|
|
||||||
my $value = get_interface_option $interface, 'arp_filter';
|
|
||||||
|
|
||||||
emit ( '',
|
|
||||||
"if [ -f $file ]; then",
|
|
||||||
" echo $value > $file");
|
|
||||||
emit ( 'else',
|
|
||||||
" error_message \"WARNING: Cannot set ARP filtering on $interface\"" ) unless interface_is_optional( $interface );
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $interface ( @$interfaces1 ) {
|
|
||||||
my $file = "/proc/sys/net/ipv4/conf/$interface/arp_ignore";
|
|
||||||
my $value = get_interface_option $interface, 'arp_ignore';
|
|
||||||
|
|
||||||
fatal_error "Internal Error in setup_arp_filtering()" unless defined $value;
|
|
||||||
|
|
||||||
emit ( "if [ -f $file ]; then",
|
|
||||||
" echo $value > $file");
|
|
||||||
emit ( 'else',
|
|
||||||
" error_message \"WARNING: Cannot set ARP filtering on $interface\"" ) unless interface_is_optional( $interface );
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Route Filtering
|
|
||||||
#
|
|
||||||
sub setup_route_filtering() {
|
|
||||||
|
|
||||||
my $interfaces = find_interfaces_by_option 'routefilter';
|
|
||||||
|
|
||||||
if ( @$interfaces || $config{ROUTE_FILTER} ) {
|
|
||||||
|
|
||||||
progress_message2 "$doing Kernel Route Filtering...";
|
|
||||||
|
|
||||||
save_progress_message "Setting up Route Filtering...";
|
|
||||||
|
|
||||||
|
|
||||||
if ( $config{ROUTE_FILTER} ) {
|
|
||||||
my $val = $config{ROUTE_FILTER} eq 'on' ? 1 : 0;
|
|
||||||
|
|
||||||
emit ( 'for file in /proc/sys/net/ipv4/conf/*; do',
|
|
||||||
" [ -f \$file/rp_filter ] && echo $val > \$file/rp_filter",
|
|
||||||
'done' );
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $interface ( @$interfaces ) {
|
|
||||||
my $file = "/proc/sys/net/ipv4/conf/$interface/rp_filter";
|
|
||||||
my $value = get_interface_option $interface, 'routefilter';
|
|
||||||
|
|
||||||
emit ( "if [ -f $file ]; then" ,
|
|
||||||
" echo $value > $file" );
|
|
||||||
emit ( 'else' ,
|
|
||||||
" error_message \"WARNING: Cannot set route filtering on $interface\"" ) unless interface_is_optional( $interface);
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
emit 'echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter';
|
|
||||||
|
|
||||||
if ( $config{ROUTE_FILTER} eq 'on' ) {
|
|
||||||
emit 'echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter';
|
|
||||||
} elsif ( $config{ROUTE_FILTER} eq 'off' ) {
|
|
||||||
emit 'echo 0 > /proc/sys/net/ipv4/conf/default/rp_filter';
|
|
||||||
}
|
|
||||||
|
|
||||||
emit "[ -n \"\$NOROUTES\" ] || ip -4 route flush cache";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Martian Logging
|
|
||||||
#
|
|
||||||
|
|
||||||
sub setup_martian_logging() {
|
|
||||||
my $interfaces = find_interfaces_by_option 'logmartians';
|
|
||||||
|
|
||||||
if ( @$interfaces || $config{LOG_MARTIANS} ) {
|
|
||||||
|
|
||||||
progress_message2 "$doing Martian Logging...";
|
|
||||||
|
|
||||||
save_progress_message "Setting up Martian Logging...";
|
|
||||||
|
|
||||||
if ( $config{LOG_MARTIANS} ) {
|
|
||||||
my $val = $config{LOG_MARTIANS} eq 'on' ? 1 : 0;
|
|
||||||
|
|
||||||
emit ( 'for file in /proc/sys/net/ipv4/conf/*; do',
|
|
||||||
" [ -f \$file/log_martians ] && echo $val > \$file/log_martians",
|
|
||||||
'done' );
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $interface ( @$interfaces ) {
|
|
||||||
my $file = "/proc/sys/net/ipv4/conf/$interface/log_martians";
|
|
||||||
my $value = get_interface_option $interface, 'logmartians';
|
|
||||||
|
|
||||||
emit ( "if [ -f $file ]; then" ,
|
|
||||||
" echo $value > $file" );
|
|
||||||
|
|
||||||
emit ( 'else' ,
|
|
||||||
" error_message \"WARNING: Cannot set Martian logging on $interface\"") unless interface_is_optional( $interface);
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $config{LOG_MARTIANS} eq 'on' ) {
|
|
||||||
emit 'echo 1 > /proc/sys/net/ipv4/conf/all/log_martians';
|
|
||||||
emit 'echo 1 > /proc/sys/net/ipv4/conf/default/log_martians';
|
|
||||||
} elsif ( $config{LOG_MARTIANS} eq 'off' ) {
|
|
||||||
emit 'echo 0 > /proc/sys/net/ipv4/conf/all/log_martians';
|
|
||||||
emit 'echo 0 > /proc/sys/net/ipv4/conf/default/log_martians';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Source Routing
|
|
||||||
#
|
|
||||||
sub setup_source_routing( $ ) {
|
|
||||||
my $family = shift;
|
|
||||||
|
|
||||||
save_progress_message 'Setting up Accept Source Routing...';
|
|
||||||
|
|
||||||
my $interfaces = find_interfaces_by_option 'sourceroute';
|
|
||||||
|
|
||||||
if ( @$interfaces ) {
|
|
||||||
progress_message2 "$doing Accept Source Routing...";
|
|
||||||
|
|
||||||
save_progress_message 'Setting up Source Routing...';
|
|
||||||
|
|
||||||
for my $interface ( @$interfaces ) {
|
|
||||||
my $file = "/proc/sys/net/ipv$family/conf/$interface/accept_source_route";
|
|
||||||
my $value = get_interface_option $interface, 'sourceroute';
|
|
||||||
|
|
||||||
emit ( "if [ -f $file ]; then" ,
|
|
||||||
" echo $value > $file" );
|
|
||||||
emit ( 'else' ,
|
|
||||||
" error_message \"WARNING: Cannot set Accept Source Routing on $interface\"" ) unless interface_is_optional( $interface);
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_forwarding( $ ) {
|
|
||||||
my $family = shift;
|
|
||||||
|
|
||||||
if ( $family == F_IPV4 ) {
|
|
||||||
if ( $config{IP_FORWARDING} eq 'on' ) {
|
|
||||||
emit ' echo 1 > /proc/sys/net/ipv4/ip_forward';
|
|
||||||
emit ' progress_message2 IPv4 Forwarding Enabled';
|
|
||||||
} elsif ( $config{IP_FORWARDING} eq 'off' ) {
|
|
||||||
emit ' echo 0 > /proc/sys/net/ipv4/ip_forward';
|
|
||||||
emit ' progress_message2 IPv4 Forwarding Disabled!';
|
|
||||||
}
|
|
||||||
|
|
||||||
emit '';
|
|
||||||
} else {
|
|
||||||
if ( $config{IP_FORWARDING} eq 'on' ) {
|
|
||||||
emit ' echo 1 > /proc/sys/net/ipv6/conf/all/forwarding';
|
|
||||||
emit ' progress_message2 IPv6 Forwarding Enabled';
|
|
||||||
} elsif ( $config{IP_FORWARDING} eq 'off' ) {
|
|
||||||
emit ' echo 0 > /proc/sys/net/ipv6/conf/all/forwarding';
|
|
||||||
emit ' progress_message2 IPv6 Forwarding Disabled!';
|
|
||||||
}
|
|
||||||
|
|
||||||
emit '';
|
|
||||||
|
|
||||||
my $interfaces = find_interfaces_by_option 'forward';
|
|
||||||
|
|
||||||
if ( @$interfaces ) {
|
|
||||||
progress_message2 "$doing Interface forwarding...";
|
|
||||||
|
|
||||||
push_indent;
|
|
||||||
push_indent;
|
|
||||||
|
|
||||||
save_progress_message 'Setting up IPv6 Interface Forwarding...';
|
|
||||||
|
|
||||||
for my $interface ( @$interfaces ) {
|
|
||||||
my $file = "/proc/sys/net/ipv6/conf/$interface/forwarding";
|
|
||||||
my $value = get_interface_option $interface, 'forward';
|
|
||||||
|
|
||||||
emit ( "if [ -f $file ]; then" ,
|
|
||||||
" echo $value > $file" );
|
|
||||||
emit ( 'else' ,
|
|
||||||
" error_message \"WARNING: Cannot set IPv6 forwarding on $interface\"" ) unless interface_is_optional( $interface);
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
pop_indent;
|
|
||||||
pop_indent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,757 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.2 -- /usr/share/shorewall-perl/Shorewall/Providers.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007,2008 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# This module deals with the /etc/shorewall/providers and
|
|
||||||
# /etc/shorewall/route_rules files.
|
|
||||||
#
|
|
||||||
package Shorewall::Providers;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Config qw(:DEFAULT :internal);
|
|
||||||
use Shorewall::IPAddrs;
|
|
||||||
use Shorewall::Zones;
|
|
||||||
use Shorewall::Chains qw(:DEFAULT :internal);
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw( setup_providers @routemarked_interfaces);
|
|
||||||
our @EXPORT_OK = qw( initialize lookup_provider );
|
|
||||||
our $VERSION = 4.2.4;
|
|
||||||
|
|
||||||
use constant { LOCAL_TABLE => 255,
|
|
||||||
MAIN_TABLE => 254,
|
|
||||||
DEFAULT_TABLE => 253,
|
|
||||||
UNSPEC_TABLE => 0
|
|
||||||
};
|
|
||||||
|
|
||||||
our @routemarked_providers;
|
|
||||||
our %routemarked_interfaces;
|
|
||||||
our @routemarked_interfaces;
|
|
||||||
|
|
||||||
our $balancing;
|
|
||||||
our $fallback;
|
|
||||||
our $first_default_route;
|
|
||||||
our $first_fallback_route;
|
|
||||||
|
|
||||||
our %providers;
|
|
||||||
|
|
||||||
our @providers;
|
|
||||||
|
|
||||||
our $family;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
||||||
# the compiler to run multiple times in the same process. The
|
|
||||||
# initialize() function does globals initialization for this
|
|
||||||
# module and is called from an INIT block below. The function is
|
|
||||||
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
||||||
# the second and subsequent calls to that function.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub initialize( $ ) {
|
|
||||||
$family = shift;
|
|
||||||
|
|
||||||
@routemarked_providers = ();
|
|
||||||
%routemarked_interfaces = ();
|
|
||||||
@routemarked_interfaces = ();
|
|
||||||
$balancing = 0;
|
|
||||||
$fallback = 0;
|
|
||||||
$first_default_route = 1;
|
|
||||||
$first_fallback_route = 1;
|
|
||||||
|
|
||||||
%providers = ( local => { number => LOCAL_TABLE , mark => 0 , optional => 0 } ,
|
|
||||||
main => { number => MAIN_TABLE , mark => 0 , optional => 0 } ,
|
|
||||||
default => { number => DEFAULT_TABLE , mark => 0 , optional => 0 } ,
|
|
||||||
unspec => { number => UNSPEC_TABLE , mark => 0 , optional => 0 } );
|
|
||||||
@providers = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT {
|
|
||||||
initialize( F_IPV4 );
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Set up marking for 'tracked' interfaces.
|
|
||||||
#
|
|
||||||
sub setup_route_marking() {
|
|
||||||
my $mask = $config{HIGH_ROUTE_MARKS} ? '0xFF00' : '0xFF';
|
|
||||||
|
|
||||||
require_capability( 'CONNMARK_MATCH' , 'the provider \'track\' option' , 's' );
|
|
||||||
require_capability( 'CONNMARK' , 'the provider \'track\' option' , 's' );
|
|
||||||
|
|
||||||
add_rule $mangle_table->{PREROUTING} , "-m connmark ! --mark 0/$mask -j CONNMARK --restore-mark --mask $mask";
|
|
||||||
add_rule $mangle_table->{OUTPUT} , "-m connmark ! --mark 0/$mask -j CONNMARK --restore-mark --mask $mask";
|
|
||||||
|
|
||||||
my $chainref = new_chain 'mangle', 'routemark';
|
|
||||||
|
|
||||||
my %marked_interfaces;
|
|
||||||
|
|
||||||
for my $providerref ( @routemarked_providers ) {
|
|
||||||
my $interface = $providerref->{interface};
|
|
||||||
my $base = uc chain_base $interface;
|
|
||||||
|
|
||||||
add_command( $chainref, qq(if [ -n "\$${base}_IS_UP" ]; then) ), incr_cmd_level( $chainref ) if $providerref->{optional};
|
|
||||||
|
|
||||||
unless ( $marked_interfaces{$interface} ) {
|
|
||||||
add_rule $mangle_table->{PREROUTING} , "-i $interface -m mark --mark 0/$mask -j routemark";
|
|
||||||
$marked_interfaces{$interface} = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $providerref->{shared} ) {
|
|
||||||
add_rule $chainref, " -i $interface -m mac --mac-source $providerref->{mac} -j MARK --set-mark $providerref->{mark}";
|
|
||||||
} else {
|
|
||||||
add_rule $chainref, " -i $interface -j MARK --set-mark $providerref->{mark}";
|
|
||||||
}
|
|
||||||
|
|
||||||
decr_cmd_level( $chainref), add_command( $chainref, "fi" ) if $providerref->{optional};
|
|
||||||
}
|
|
||||||
|
|
||||||
add_rule $chainref, "-m mark ! --mark 0/$mask -j CONNMARK --save-mark --mask $mask";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub copy_table( $$$ ) {
|
|
||||||
my ( $duplicate, $number, $realm ) = @_;
|
|
||||||
|
|
||||||
if ( $realm ) {
|
|
||||||
emit ( "ip -$family route show table $duplicate | sed -r 's/ realm [[:alnum:]_]+//' | while read net route; do" )
|
|
||||||
} else {
|
|
||||||
emit ( "ip -$family route show table $duplicate | while read net route; do" )
|
|
||||||
}
|
|
||||||
|
|
||||||
emit ( ' case $net in',
|
|
||||||
' default|nexthop)',
|
|
||||||
' ;;',
|
|
||||||
' *)',
|
|
||||||
" run_ip route add table $number \$net \$route $realm",
|
|
||||||
' ;;',
|
|
||||||
' esac',
|
|
||||||
"done\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub copy_and_edit_table( $$$$ ) {
|
|
||||||
my ( $duplicate, $number, $copy, $realm) = @_;
|
|
||||||
|
|
||||||
if ( $realm ) {
|
|
||||||
emit ( "ip -$family route show table $duplicate | sed -r 's/ realm [[:alnum:]_]+//' | while read net route; do" )
|
|
||||||
} else {
|
|
||||||
emit ( "ip -$family route show table $duplicate | while read net route; do" )
|
|
||||||
}
|
|
||||||
|
|
||||||
emit ( ' case $net in',
|
|
||||||
' default|nexthop)',
|
|
||||||
' ;;',
|
|
||||||
' *)',
|
|
||||||
' case $(find_device $route) in',
|
|
||||||
" $copy)",
|
|
||||||
" run_ip route add table $number \$net \$route $realm",
|
|
||||||
' ;;',
|
|
||||||
' esac',
|
|
||||||
' ;;',
|
|
||||||
' esac',
|
|
||||||
"done\n" );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub balance_default_route( $$$$ ) {
|
|
||||||
my ( $weight, $gateway, $interface, $realm ) = @_;
|
|
||||||
|
|
||||||
$balancing = 1;
|
|
||||||
|
|
||||||
emit '';
|
|
||||||
|
|
||||||
if ( $first_default_route ) {
|
|
||||||
if ( $gateway ) {
|
|
||||||
emit "DEFAULT_ROUTE=\"nexthop via $gateway dev $interface weight $weight $realm\"";
|
|
||||||
} else {
|
|
||||||
emit "DEFAULT_ROUTE=\"nexthop dev $interface weight $weight $realm\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
$first_default_route = 0;
|
|
||||||
} else {
|
|
||||||
if ( $gateway ) {
|
|
||||||
emit "DEFAULT_ROUTE=\"\$DEFAULT_ROUTE nexthop via $gateway dev $interface weight $weight $realm\"";
|
|
||||||
} else {
|
|
||||||
emit "DEFAULT_ROUTE=\"\$DEFAULT_ROUTE nexthop dev $interface weight $weight $realm\"";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub balance_fallback_route( $$$$ ) {
|
|
||||||
my ( $weight, $gateway, $interface, $realm ) = @_;
|
|
||||||
|
|
||||||
$fallback = 1;
|
|
||||||
|
|
||||||
emit '';
|
|
||||||
|
|
||||||
if ( $first_fallback_route ) {
|
|
||||||
if ( $gateway ) {
|
|
||||||
emit "FALLBACK_ROUTE=\"nexthop via $gateway dev $interface weight $weight $realm\"";
|
|
||||||
} else {
|
|
||||||
emit "FALLBACK_ROUTE=\"nexthop dev $interface weight $weight $realm\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
$first_fallback_route = 0;
|
|
||||||
} else {
|
|
||||||
if ( $gateway ) {
|
|
||||||
emit "FALLBACK_ROUTE=\"\$FALLBACK_ROUTE nexthop via $gateway dev $interface weight $weight $realm\"";
|
|
||||||
} else {
|
|
||||||
emit "FALLBACK_ROUTE=\"\$FALLBACK_ROUTE nexthop dev $interface weight $weight $realm\"";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub start_provider( $$$ ) {
|
|
||||||
my ($table, $number, $test ) = @_;
|
|
||||||
|
|
||||||
emit $test;
|
|
||||||
push_indent;
|
|
||||||
|
|
||||||
emit "#\n# Add Provider $table ($number)\n#";
|
|
||||||
|
|
||||||
emit "qt ip -$family route flush table $number";
|
|
||||||
emit "echo \"qt ip -$family route flush table $number\" >> \${VARDIR}/undo_routing";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub add_a_provider( $$$$$$$$ ) {
|
|
||||||
|
|
||||||
my ($table, $number, $mark, $duplicate, $interface, $gateway, $options, $copy) = @_;
|
|
||||||
|
|
||||||
fatal_error "Duplicate provider ($table)" if $providers{$table};
|
|
||||||
|
|
||||||
my $num = numeric_value $number;
|
|
||||||
|
|
||||||
fatal_error "Invalid Provider number ($number)" unless defined $num;
|
|
||||||
|
|
||||||
$number = $num;
|
|
||||||
|
|
||||||
for my $providerref ( values %providers ) {
|
|
||||||
fatal_error "Duplicate provider number ($number)" if $providerref->{number} == $number;
|
|
||||||
}
|
|
||||||
|
|
||||||
( $interface, my $address ) = split /:/, $interface;
|
|
||||||
|
|
||||||
my $shared = 0;
|
|
||||||
|
|
||||||
if ( defined $address ) {
|
|
||||||
validate_address $address, 0;
|
|
||||||
$shared = 1;
|
|
||||||
require_capability 'REALM_MATCH', "Configuring multiple providers through one interface", "s";
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Unknown Interface ($interface)" unless known_interface $interface;
|
|
||||||
|
|
||||||
my $provider = chain_base $table;
|
|
||||||
my $base = uc chain_base $interface;
|
|
||||||
|
|
||||||
if ( $gateway eq 'detect' ) {
|
|
||||||
fatal_error "Configuring multiple providers through one interface requires an explicit gateway" if $shared;
|
|
||||||
$gateway = get_interface_gateway $interface;
|
|
||||||
start_provider( $table, $number, qq(if interface_is_usable $interface && [ -n "$gateway" ]; then) );
|
|
||||||
} else {
|
|
||||||
start_provider( $table, $number, "if interface_is_usable $interface; then" );
|
|
||||||
|
|
||||||
if ( $gateway && $gateway ne '-' ) {
|
|
||||||
validate_address $gateway, 0;
|
|
||||||
} else {
|
|
||||||
fatal_error "Configuring multiple providers through one interface requires a gateway" if $shared;
|
|
||||||
$gateway = '';
|
|
||||||
emit "run_ip route add default dev $interface table $number";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my $val = 0;
|
|
||||||
|
|
||||||
if ( $mark ne '-' ) {
|
|
||||||
|
|
||||||
$val = numeric_value $mark;
|
|
||||||
|
|
||||||
fatal_error "Invalid Mark Value ($mark)" unless defined $val;
|
|
||||||
|
|
||||||
verify_mark $mark;
|
|
||||||
|
|
||||||
if ( $val < 256) {
|
|
||||||
fatal_error "Invalid Mark Value ($mark) with HIGH_ROUTE_MARKS=Yes" if $config{HIGH_ROUTE_MARKS};
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid Mark Value ($mark) with HIGH_ROUTE_MARKS=No" if ! $config{HIGH_ROUTE_MARKS};
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $providerref ( values %providers ) {
|
|
||||||
fatal_error "Duplicate mark value ($mark)" if $providerref->{mark} == $val;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $pref = 10000 + $number - 1;
|
|
||||||
|
|
||||||
emit ( "qt ip -$family rule del fwmark $mark" ) if $config{DELETE_THEN_ADD};
|
|
||||||
|
|
||||||
emit ( "run_ip rule add fwmark $mark pref $pref table $number",
|
|
||||||
"echo \"qt ip -$family rule del fwmark $mark\" >> \${VARDIR}/undo_routing"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
my ( $loose, $track, $balance , $default, $default_balance, $optional, $mtu ) = (0,0,0,0,$config{USE_DEFAULT_RT} ? 1 : 0,interface_is_optional( $interface ), '' );
|
|
||||||
|
|
||||||
unless ( $options eq '-' ) {
|
|
||||||
for my $option ( split_list $options, 'option' ) {
|
|
||||||
if ( $option eq 'track' ) {
|
|
||||||
$track = 1;
|
|
||||||
} elsif ( $option =~ /^balance=(\d+)$/ ) {
|
|
||||||
fatal_error q('balance' is not available in IPv6) if $family == F_IPV6;
|
|
||||||
$balance = $1;
|
|
||||||
} elsif ( $option eq 'balance' ) {
|
|
||||||
fatal_error q('balance' is not available in IPv6) if $family == F_IPV6;
|
|
||||||
$balance = 1;
|
|
||||||
} elsif ( $option eq 'loose' ) {
|
|
||||||
$loose = 1;
|
|
||||||
$default_balance = 0;
|
|
||||||
} elsif ( $option eq 'optional' ) {
|
|
||||||
set_interface_option $interface, 'optional', 1;
|
|
||||||
$optional = 1;
|
|
||||||
} elsif ( $option =~ /^src=(.*)$/ ) {
|
|
||||||
fatal_error "OPTION 'src' not allowed on shared interface" if $shared;
|
|
||||||
$address = validate_address( $1 , 1 );
|
|
||||||
} elsif ( $option =~ /^mtu=(\d+)$/ ) {
|
|
||||||
$mtu = "mtu $1 ";
|
|
||||||
} elsif ( $option =~ /^fallback=(\d+)$/ ) {
|
|
||||||
fatal_error q('fallback' is not available in IPv6) if $family == F_IPV6;
|
|
||||||
if ( $config{USE_DEFAULT_RT} ) {
|
|
||||||
warning_message "'fallback' is ignored when USE_DEFAULT_RT=Yes";
|
|
||||||
} else {
|
|
||||||
$default = $1;
|
|
||||||
fatal_error 'fallback must be non-zero' unless $default;
|
|
||||||
}
|
|
||||||
} elsif ( $option eq 'fallback' ) {
|
|
||||||
fatal_error q('fallback' is not available in IPv6) if $family == F_IPV6;
|
|
||||||
if ( $config{USE_DEFAULT_RT} ) {
|
|
||||||
warning_message "'fallback' is ignored when USE_DEFAULT_RT=Yes";
|
|
||||||
} else {
|
|
||||||
$default = -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid option ($option)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$balance = $default_balance unless $balance;
|
|
||||||
|
|
||||||
$providers{$table} = { provider => $table,
|
|
||||||
number => $number ,
|
|
||||||
mark => $val ,
|
|
||||||
interface => $interface ,
|
|
||||||
optional => $optional ,
|
|
||||||
gateway => $gateway ,
|
|
||||||
shared => $shared ,
|
|
||||||
default => $default };
|
|
||||||
|
|
||||||
if ( $track ) {
|
|
||||||
fatal_error "The 'track' option requires a numeric value in the MARK column" if $mark eq '-';
|
|
||||||
|
|
||||||
if ( $routemarked_interfaces{$interface} ) {
|
|
||||||
fatal_error "Interface $interface is tracked through an earlier provider" if $routemarked_interfaces{$interface} > 1;
|
|
||||||
fatal_error "Multiple providers through the same interface must their IP address specified in the INTERFACES" unless $shared;
|
|
||||||
} else {
|
|
||||||
$routemarked_interfaces{$interface} = $shared ? 1 : 2;
|
|
||||||
push @routemarked_interfaces, $interface;
|
|
||||||
}
|
|
||||||
|
|
||||||
push @routemarked_providers, $providers{$table};
|
|
||||||
}
|
|
||||||
|
|
||||||
my $realm = '';
|
|
||||||
|
|
||||||
if ( $shared ) {
|
|
||||||
$providers{$table}{mac} = get_interface_mac( $gateway, $interface , $table );
|
|
||||||
$realm = "realm $number";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $duplicate ne '-' ) {
|
|
||||||
fatal_error "The DUPLICATE column must be empty when USE_DEFAULT_RT=Yes" if $config{USE_DEFAULT_RT};
|
|
||||||
if ( $copy eq '-' ) {
|
|
||||||
copy_table ( $duplicate, $number, $realm );
|
|
||||||
} else {
|
|
||||||
if ( $copy eq 'none' ) {
|
|
||||||
$copy = $interface;
|
|
||||||
} else {
|
|
||||||
$copy =~ tr/,/|/;
|
|
||||||
$copy = "$interface|$copy";
|
|
||||||
}
|
|
||||||
|
|
||||||
copy_and_edit_table( $duplicate, $number ,$copy , $realm);
|
|
||||||
}
|
|
||||||
} elsif ( $copy ne '-' ) {
|
|
||||||
fatal_error "The COPY column must be empty when USE_DEFAULT_RT=Yes" if $config{USE_DEFAULT_RT};
|
|
||||||
fatal_error 'A non-empty COPY column requires that a routing table be specified in the DUPLICATE column';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $gateway ) {
|
|
||||||
$address = get_interface_address $interface unless $address;
|
|
||||||
emit "run_ip route replace $gateway src $address dev $interface ${mtu}table $number $realm";
|
|
||||||
emit "run_ip route add default via $gateway src $address dev $interface ${mtu}table $number $realm";
|
|
||||||
}
|
|
||||||
|
|
||||||
balance_default_route $balance , $gateway, $interface, $realm if $balance;
|
|
||||||
|
|
||||||
if ( $default > 0 ) {
|
|
||||||
balance_fallback_route $default , $gateway, $interface, $realm;
|
|
||||||
} elsif ( $default ) {
|
|
||||||
emit '';
|
|
||||||
if ( $gateway ) {
|
|
||||||
emit qq(run_ip route replace default via $gateway src $address dev $interface table ) . DEFAULT_TABLE . qq( dev $interface metric $number);
|
|
||||||
emit qq(echo "qt ip route del default via $gateway table ) . DEFAULT_TABLE . qq(" >> \${VARDIR}/undo_routing);
|
|
||||||
} else {
|
|
||||||
emit qq(run_ip route add default table ) . DEFAULT_TABLE . qq( dev $interface metric $number);
|
|
||||||
emit qq(echo "qt ip route del default dev $interface table ) . DEFAULT_TABLE . qq(" >> \${VARDIR}/undo_routing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $loose ) {
|
|
||||||
if ( $config{DELETE_THEN_ADD} ) {
|
|
||||||
emit ( "\nfind_interface_addresses $interface | while read address; do",
|
|
||||||
" qt ip -$family rule del from \$address",
|
|
||||||
'done'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} elsif ( $shared ) {
|
|
||||||
emit "qt ip -$family rule del from $address" if $config{DELETE_THEN_ADD};
|
|
||||||
emit( "run_ip rule add from $address pref 20000 table $number" ,
|
|
||||||
"echo \"qt ip -$family rule del from $address\" >> \${VARDIR}/undo_routing" );
|
|
||||||
} else {
|
|
||||||
my $rulebase = 20000 + ( 256 * ( $number - 1 ) );
|
|
||||||
|
|
||||||
emit "\nrulenum=0\n";
|
|
||||||
|
|
||||||
emit ( "find_interface_addresses $interface | while read address; do" );
|
|
||||||
emit ( " qt ip -$family rule del from \$address" ) if $config{DELETE_THEN_ADD};
|
|
||||||
emit ( " run_ip rule add from \$address pref \$(( $rulebase + \$rulenum )) table $number",
|
|
||||||
" echo \"qt ip -$family rule del from \$address\" >> \${VARDIR}/undo_routing",
|
|
||||||
' rulenum=$(($rulenum + 1))',
|
|
||||||
'done'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit qq(\nprogress_message " Provider $table ($number) Added"\n);
|
|
||||||
|
|
||||||
emit ( "${base}_IS_UP=Yes" ) if $optional;
|
|
||||||
|
|
||||||
pop_indent;
|
|
||||||
emit 'else';
|
|
||||||
|
|
||||||
if ( $optional ) {
|
|
||||||
emit ( " error_message \"WARNING: Interface $interface is not usable -- Provider $table ($number) not Added\"",
|
|
||||||
" ${base}_IS_UP=" );
|
|
||||||
} else {
|
|
||||||
emit( " fatal_error \"Interface $interface is not usable -- Provider $table ($number) Cannot be Added\"" );
|
|
||||||
}
|
|
||||||
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub add_an_rtrule( $$$$ ) {
|
|
||||||
my ( $source, $dest, $provider, $priority ) = @_;
|
|
||||||
|
|
||||||
unless ( $providers{$provider} ) {
|
|
||||||
my $found = 0;
|
|
||||||
|
|
||||||
if ( "\L$provider" =~ /^(0x[a-f0-9]+|0[0-7]*|[0-9]*)$/ ) {
|
|
||||||
my $provider_number = numeric_value $provider;
|
|
||||||
|
|
||||||
for ( keys %providers ) {
|
|
||||||
if ( $providers{$_}{number} == $provider_number ) {
|
|
||||||
$provider = $_;
|
|
||||||
$found = 1;
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Unknown provider ($provider)" unless $found;
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "You must specify either the source or destination in a route_rules entry" if $source eq '-' && $dest eq '-';
|
|
||||||
|
|
||||||
if ( $dest eq '-' ) {
|
|
||||||
$dest = 'to ' . ALLIP;
|
|
||||||
} else {
|
|
||||||
validate_net( $dest, 0 );
|
|
||||||
$dest = "to $dest";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $source eq '-' ) {
|
|
||||||
$source = 'from ' . ALLIP;
|
|
||||||
} elsif ( $family == F_IPV4 ) {
|
|
||||||
if ( $source =~ /:/ ) {
|
|
||||||
( my $interface, $source , my $remainder ) = split( /:/, $source, 3 );
|
|
||||||
fatal_error "Invalid SOURCE" if defined $remainder;
|
|
||||||
validate_net ( $source, 0 );
|
|
||||||
$source = "iif $interface from $source";
|
|
||||||
} elsif ( $source =~ /\..*\..*/ ) {
|
|
||||||
validate_net ( $source, 0 );
|
|
||||||
$source = "from $source";
|
|
||||||
} else {
|
|
||||||
$source = "iif $source";
|
|
||||||
}
|
|
||||||
} elsif ( $source =~ /^(.+?):<(.+)>\s*$/ ) {
|
|
||||||
my ($interface, $source ) = ($1, $2);
|
|
||||||
validate_net ($source, 0);
|
|
||||||
$source = "iif $interface from $source";
|
|
||||||
} elsif ( $source =~ /:.*:/ || $source =~ /\..*\..*/ ) {
|
|
||||||
validate_net ( $source, 0 );
|
|
||||||
$source = "from $source";
|
|
||||||
} else {
|
|
||||||
$source = "iif $source";
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Invalid priority ($priority)" unless $priority && $priority =~ /^\d{1,5}$/;
|
|
||||||
|
|
||||||
$priority = "priority $priority";
|
|
||||||
|
|
||||||
emit ( "qt ip -$family rule del $source $dest $priority" ) if $config{DELETE_THEN_ADD};
|
|
||||||
|
|
||||||
my ( $optional, $number ) = ( $providers{$provider}{optional} , $providers{$provider}{number} );
|
|
||||||
|
|
||||||
if ( $optional ) {
|
|
||||||
my $base = uc chain_base( $providers{$provider}{interface} );
|
|
||||||
emit ( '', "if [ -n \$${base}_IS_UP ]; then" );
|
|
||||||
push_indent;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit ( "run_ip rule add $source $dest $priority table $number",
|
|
||||||
"echo \"qt ip -$family rule del $source $dest $priority\" >> \${VARDIR}/undo_routing" );
|
|
||||||
|
|
||||||
pop_indent, emit ( "fi\n" ) if $optional;
|
|
||||||
|
|
||||||
progress_message " Routing rule \"$currentline\" $done";
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# This probably doesn't belong here but looking forward to the day when we get Shorewall out of the routing business,
|
|
||||||
# it makes sense to keep all of the routing code together
|
|
||||||
#
|
|
||||||
sub setup_null_routing() {
|
|
||||||
save_progress_message "Null Routing the RFC 1918 subnets";
|
|
||||||
for ( rfc1918_networks ) {
|
|
||||||
emit( "run_ip route replace unreachable $_" );
|
|
||||||
emit( "echo \"qt ip -$family route del unreachable $_\" >> \${VARDIR}/undo_routing" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_providers() {
|
|
||||||
my $providers = 0;
|
|
||||||
|
|
||||||
my $fn = open_file 'providers';
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
unless ( $providers ) {
|
|
||||||
progress_message2 "$doing $fn ...";
|
|
||||||
|
|
||||||
require_capability( 'MANGLE_ENABLED' , 'a non-empty providers file' , 's' );
|
|
||||||
|
|
||||||
fatal_error "A non-empty providers file is not permitted with MANGLE_ENABLED=No" unless $config{MANGLE_ENABLED};
|
|
||||||
|
|
||||||
emit "\nif [ -z \"\$NOROUTES\" ]; then";
|
|
||||||
|
|
||||||
push_indent;
|
|
||||||
|
|
||||||
emit ( '#',
|
|
||||||
'# Undo any changes made since the last time that we [re]started -- this will not restore the default route',
|
|
||||||
'#',
|
|
||||||
'undo_routing' );
|
|
||||||
|
|
||||||
unless ( $config{KEEP_RT_TABLES} ) {
|
|
||||||
emit (
|
|
||||||
'#',
|
|
||||||
'# Save current routing table database so that it can be restored later',
|
|
||||||
'#',
|
|
||||||
'cp /etc/iproute2/rt_tables ${VARDIR}/' );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
emit ( '#',
|
|
||||||
'# Capture the default route(s) if we don\'t have it (them) already.',
|
|
||||||
'#',
|
|
||||||
'[ -f ${VARDIR}/default_route ] || ip -' . $family . ' route list | grep -E \'^\s*(default |nexthop )\' > ${VARDIR}/default_route',
|
|
||||||
'#',
|
|
||||||
'# Initialize the file that holds \'undo\' commands',
|
|
||||||
'#',
|
|
||||||
'> ${VARDIR}/undo_routing' );
|
|
||||||
|
|
||||||
save_progress_message 'Adding Providers...';
|
|
||||||
|
|
||||||
emit 'DEFAULT_ROUTE=';
|
|
||||||
emit 'FALLBACK_ROUTE=';
|
|
||||||
emit '';
|
|
||||||
}
|
|
||||||
|
|
||||||
my ( $table, $number, $mark, $duplicate, $interface, $gateway, $options, $copy ) = split_line 6, 8, 'providers file';
|
|
||||||
|
|
||||||
add_a_provider( $table, $number, $mark, $duplicate, $interface, $gateway, $options, $copy );
|
|
||||||
|
|
||||||
push @providers, $table;
|
|
||||||
|
|
||||||
$providers++;
|
|
||||||
|
|
||||||
progress_message " Provider \"$currentline\" $done";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $providers ) {
|
|
||||||
if ( $balancing ) {
|
|
||||||
my $table = MAIN_TABLE;
|
|
||||||
|
|
||||||
if ( $config{USE_DEFAULT_RT} ) {
|
|
||||||
emit ( 'run_ip rule add from all table ' . MAIN_TABLE . ' pref 999',
|
|
||||||
"ip -$family rule del from all table " . MAIN_TABLE . ' pref 32766',
|
|
||||||
qq(echo "qt ip -$family rule add from all table ) . MAIN_TABLE . ' pref 32766" >> ${VARDIR}/undo_routing',
|
|
||||||
qq(echo "qt ip -$family rule del from all table ) . MAIN_TABLE . ' pref 999" >> ${VARDIR}/undo_routing',
|
|
||||||
'' );
|
|
||||||
$table = DEFAULT_TABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit ( 'if [ -n "$DEFAULT_ROUTE" ]; then' );
|
|
||||||
emit ( " run_ip route replace default scope global table $table \$DEFAULT_ROUTE" );
|
|
||||||
emit ( " qt ip -$family route del default table " . MAIN_TABLE ) if $config{USE_DEFAULT_RT};
|
|
||||||
emit ( " progress_message \"Default route '\$(echo \$DEFAULT_ROUTE | sed 's/\$\\s*//')' Added\"",
|
|
||||||
'else',
|
|
||||||
' error_message "WARNING: No Default route added (all \'balance\' providers are down)"' );
|
|
||||||
|
|
||||||
if ( $config{RESTORE_DEFAULT_ROUTE} ) {
|
|
||||||
emit ' restore_default_route && error_message "NOTICE: Default route restored"'
|
|
||||||
} else {
|
|
||||||
emit qq( qt ip -$family route del default table $table && error_message "WARNING: Default route deleted from table $table");
|
|
||||||
}
|
|
||||||
|
|
||||||
emit( 'fi',
|
|
||||||
'' );
|
|
||||||
} else {
|
|
||||||
emit ( '#',
|
|
||||||
'# We don\'t have any \'balance\' providers so we restore any default route that we\'ve saved',
|
|
||||||
'#',
|
|
||||||
'restore_default_route' ,
|
|
||||||
'' );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $fallback ) {
|
|
||||||
emit ( 'if [ -n "$FALLBACK_ROUTE" ]; then' ,
|
|
||||||
" run_ip route replace default scope global table " . DEFAULT_TABLE . " \$FALLBACK_ROUTE" ,
|
|
||||||
" progress_message \"Fallback route '\$(echo \$FALLBACK_ROUTE | sed 's/\$\\s*//')' Added\"",
|
|
||||||
'fi',
|
|
||||||
'' );
|
|
||||||
}
|
|
||||||
|
|
||||||
unless ( $config{KEEP_RT_TABLES} ) {
|
|
||||||
emit( 'if [ -w /etc/iproute2/rt_tables ]; then',
|
|
||||||
' cat > /etc/iproute2/rt_tables <<EOF' );
|
|
||||||
|
|
||||||
push_indent;
|
|
||||||
|
|
||||||
emit_unindented join( "\n",
|
|
||||||
'#',
|
|
||||||
'# reserved values',
|
|
||||||
'#',
|
|
||||||
LOCAL_TABLE . "\tlocal",
|
|
||||||
MAIN_TABLE . "\tmain",
|
|
||||||
DEFAULT_TABLE . "\tdefault",
|
|
||||||
"0\tunspec",
|
|
||||||
'#',
|
|
||||||
'# local',
|
|
||||||
'#',
|
|
||||||
"EOF\n" );
|
|
||||||
|
|
||||||
emit "echocommand=\$(find_echo)\n";
|
|
||||||
|
|
||||||
for my $table ( @providers ) {
|
|
||||||
emit "\$echocommand \"$providers{$table}{number}\\t$table\" >> /etc/iproute2/rt_tables";
|
|
||||||
}
|
|
||||||
|
|
||||||
pop_indent;
|
|
||||||
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
my $fn = open_file 'route_rules';
|
|
||||||
|
|
||||||
if ( $fn ) {
|
|
||||||
|
|
||||||
first_entry "$doing $fn...";
|
|
||||||
|
|
||||||
emit '';
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $source, $dest, $provider, $priority ) = split_line 4, 4, 'route_rules file';
|
|
||||||
|
|
||||||
add_an_rtrule( $source, $dest, $provider , $priority );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_null_routing if $config{NULL_ROUTE_RFC1918};
|
|
||||||
emit "\nrun_ip route flush cache";
|
|
||||||
pop_indent;
|
|
||||||
emit "fi\n";
|
|
||||||
|
|
||||||
setup_route_marking if @routemarked_interfaces;
|
|
||||||
} else {
|
|
||||||
emit "\nundo_routing";
|
|
||||||
emit 'restore_default_route';
|
|
||||||
if ( $config{NULL_ROUTE_RFC1918} ) {
|
|
||||||
emit "\nif [ -z \"\$NOROUTES\" ]; then";
|
|
||||||
|
|
||||||
push_indent;
|
|
||||||
|
|
||||||
emit ( '#',
|
|
||||||
'# Initialize the file that holds \'undo\' commands',
|
|
||||||
'#',
|
|
||||||
'> ${VARDIR}/undo_routing' );
|
|
||||||
setup_null_routing;
|
|
||||||
emit "\nrun_ip route flush cache";
|
|
||||||
|
|
||||||
pop_indent;
|
|
||||||
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub lookup_provider( $ ) {
|
|
||||||
my $provider = $_[0];
|
|
||||||
my $providerref = $providers{ $provider };
|
|
||||||
|
|
||||||
unless ( $providerref ) {
|
|
||||||
fatal_error "Unknown provider ($provider)" unless $provider =~ /^(0x[a-f0-9]+|0[0-7]*|[0-9]*)$/;
|
|
||||||
|
|
||||||
my $provider_number = numeric_value $provider;
|
|
||||||
|
|
||||||
for ( keys %providers ) {
|
|
||||||
if ( $providers{$_}{number} == $provider_number ) {
|
|
||||||
$providerref = $providers{$_};
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "Unknown provider ($provider)" unless $providerref;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$providerref->{shared} ? $providerref->{number} : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,180 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.2 -- /usr/share/shorewall-perl/Shorewall/Proxyarp.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
package Shorewall::Proxyarp;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Config qw(:DEFAULT :internal);
|
|
||||||
use Shorewall::Zones;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw(
|
|
||||||
setup_proxy_arp
|
|
||||||
dump_proxy_arp
|
|
||||||
);
|
|
||||||
|
|
||||||
our @EXPORT_OK = qw( initialize );
|
|
||||||
our $VERSION = 4.2.4;
|
|
||||||
|
|
||||||
our @proxyarp;
|
|
||||||
|
|
||||||
our $family;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
||||||
# the compiler to run multiple times in the same process. The
|
|
||||||
# initialize() function does globals initialization for this
|
|
||||||
# module and is called from an INIT block below. The function is
|
|
||||||
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
||||||
# the second and subsequent calls to that function.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub initialize( $ ) {
|
|
||||||
$family = shift;
|
|
||||||
@proxyarp = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT {
|
|
||||||
initialize( F_IPV4 );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_one_proxy_arp( $$$$$ ) {
|
|
||||||
my ( $address, $interface, $external, $haveroute, $persistent) = @_;
|
|
||||||
|
|
||||||
if ( "\L$haveroute" eq 'no' || $haveroute eq '-' ) {
|
|
||||||
$haveroute = '';
|
|
||||||
} elsif ( "\L$haveroute" eq 'yes' ) {
|
|
||||||
$haveroute = 'yes';
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid value ($haveroute) for HAVEROUTE";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( "\L$persistent" eq 'no' || $persistent eq '-' ) {
|
|
||||||
$persistent = '';
|
|
||||||
} elsif ( "\L$persistent" eq 'yes' ) {
|
|
||||||
$persistent = 'yes';
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid value ($persistent) for PERSISTENT";
|
|
||||||
}
|
|
||||||
|
|
||||||
unless ( $haveroute ) {
|
|
||||||
emit "[ -n \"\$NOROUTES\" ] || run_ip route replace $address dev $interface";
|
|
||||||
$haveroute = 1 if $persistent;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit ( "if ! arp -i $external -Ds $address $external pub; then",
|
|
||||||
" fatal_error \"Command 'arp -i $external -Ds $address $external pub' failed\"" ,
|
|
||||||
'fi' ,
|
|
||||||
'',
|
|
||||||
"progress_message \" Host $address connected to $interface added to ARP on $external\"\n" );
|
|
||||||
|
|
||||||
push @proxyarp, "$address $interface $external $haveroute";
|
|
||||||
|
|
||||||
progress_message " Host $address connected to $interface added to ARP on $external";
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Setup Proxy ARP
|
|
||||||
#
|
|
||||||
sub setup_proxy_arp() {
|
|
||||||
if ( $family == F_IPV4 ) {
|
|
||||||
|
|
||||||
my $interfaces= find_interfaces_by_option 'proxyarp';
|
|
||||||
my $fn = open_file 'proxyarp';
|
|
||||||
|
|
||||||
if ( @$interfaces || $fn ) {
|
|
||||||
|
|
||||||
my $first_entry = 1;
|
|
||||||
|
|
||||||
save_progress_message "Setting up Proxy ARP...";
|
|
||||||
|
|
||||||
my ( %set, %reset );
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $address, $interface, $external, $haveroute, $persistent ) = split_line 3, 5, 'proxyarp file';
|
|
||||||
|
|
||||||
if ( $first_entry ) {
|
|
||||||
progress_message2 "$doing $fn...";
|
|
||||||
$first_entry = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$set{$interface} = 1;
|
|
||||||
$reset{$external} = 1 unless $set{$external};
|
|
||||||
|
|
||||||
setup_one_proxy_arp( $address, $interface, $external, $haveroute, $persistent );
|
|
||||||
}
|
|
||||||
|
|
||||||
emit '';
|
|
||||||
|
|
||||||
for my $interface ( keys %reset ) {
|
|
||||||
unless ( $set{interface} ) {
|
|
||||||
emit ( "if [ -f /proc/sys/net/ipv4/conf/$interface/proxy_arp ]; then" ,
|
|
||||||
" echo 0 > /proc/sys/net/ipv4/conf/$interface/proxy_arp" );
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $interface ( keys %set ) {
|
|
||||||
emit ( "if [ -f /proc/sys/net/ipv4/conf/$interface/proxy_arp ]; then" ,
|
|
||||||
" echo 1 > /proc/sys/net/ipv4/conf/$interface/proxy_arp" );
|
|
||||||
emit ( 'else' ,
|
|
||||||
" error_message \" WARNING: Cannot set the 'proxy_arp' option for interface $interface\"" ) unless interface_is_optional( $interface );
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $interface ( @$interfaces ) {
|
|
||||||
my $value = get_interface_option $interface, 'proxyarp';
|
|
||||||
emit ( "if [ -f /proc/sys/net/ipv4/conf/$interface/proxy_arp ] ; then" ,
|
|
||||||
" echo $value > /proc/sys/net/ipv4/conf/$interface/proxy_arp" );
|
|
||||||
emit ( 'else' ,
|
|
||||||
" error_message \"WARNING: Unable to set/reset proxy ARP on $interface\"" ) unless interface_is_optional( $interface );
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
my $interfaces= find_interfaces_by_option 'proxyndp';
|
|
||||||
|
|
||||||
if ( @$interfaces ) {
|
|
||||||
save_progress_message "Setting up Proxy NDP...";
|
|
||||||
|
|
||||||
for my $interface ( @$interfaces ) {
|
|
||||||
my $value = get_interface_option $interface, 'proxyndp';
|
|
||||||
emit ( "if [ -f /proc/sys/net/ipv6/conf/$interface/proxy_ndp ] ; then" ,
|
|
||||||
" echo $value > /proc/sys/net/ipv6/conf/$interface/proxy_ndp" );
|
|
||||||
emit ( 'else' ,
|
|
||||||
" error_message \"WARNING: Unable to set/reset Proxy NDP on $interface\"" ) unless interface_is_optional( $interface );
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub dump_proxy_arp() {
|
|
||||||
for ( @proxyarp ) {
|
|
||||||
emit_unindented $_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
File diff suppressed because it is too large
Load Diff
@ -1,971 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.2 -- /usr/share/shorewall-perl/Shorewall/Tc.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007,2008 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Traffic Control is from tc4shorewall Version 0.5
|
|
||||||
# (c) 2005 Arne Bernin <arne@ucbering.de>
|
|
||||||
# Modified by Tom Eastep for integration into the Shorewall distribution
|
|
||||||
# published under GPL Version 2#
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# This module deals with Traffic Shaping and the tcrules file.
|
|
||||||
#
|
|
||||||
package Shorewall::Tc;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Config qw(:DEFAULT :internal);
|
|
||||||
use Shorewall::IPAddrs;
|
|
||||||
use Shorewall::Zones;
|
|
||||||
use Shorewall::Chains qw(:DEFAULT :internal);
|
|
||||||
use Shorewall::Providers;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw( setup_tc );
|
|
||||||
our @EXPORT_OK = qw( process_tc_rule initialize );
|
|
||||||
our $VERSION = 4.2.4;
|
|
||||||
|
|
||||||
our %tcs = ( T => { chain => 'tcpost',
|
|
||||||
connmark => 0,
|
|
||||||
fw => 1
|
|
||||||
} ,
|
|
||||||
CT => { chain => 'tcpost' ,
|
|
||||||
target => 'CONNMARK --set-mark' ,
|
|
||||||
connmark => 1 ,
|
|
||||||
fw => 1
|
|
||||||
} ,
|
|
||||||
C => { target => 'CONNMARK --set-mark' ,
|
|
||||||
connmark => 1 ,
|
|
||||||
fw => 1
|
|
||||||
} ,
|
|
||||||
P => { chain => 'tcpre' ,
|
|
||||||
connmark => 0 ,
|
|
||||||
fw => 0
|
|
||||||
} ,
|
|
||||||
CP => { chain => 'tcpre' ,
|
|
||||||
target => 'CONNMARK --set-mark' ,
|
|
||||||
connmark => 1 ,
|
|
||||||
fw => 0
|
|
||||||
} ,
|
|
||||||
F => { chain => 'tcfor' ,
|
|
||||||
connmark => 0 ,
|
|
||||||
fw => 0
|
|
||||||
} ,
|
|
||||||
CF => { chain => 'tcfor' ,
|
|
||||||
connmark => 1 ,
|
|
||||||
fw => 0 ,
|
|
||||||
} ,
|
|
||||||
);
|
|
||||||
|
|
||||||
use constant { NOMARK => 0 ,
|
|
||||||
SMALLMARK => 1 ,
|
|
||||||
HIGHMARK => 2
|
|
||||||
};
|
|
||||||
|
|
||||||
our @tccmd = ( { match => sub ( $ ) { $_[0] eq 'SAVE' } ,
|
|
||||||
target => 'CONNMARK --save-mark --mask' ,
|
|
||||||
mark => SMALLMARK ,
|
|
||||||
mask => '0xFF' ,
|
|
||||||
connmark => 1
|
|
||||||
} ,
|
|
||||||
{ match => sub ( $ ) { $_[0] eq 'RESTORE' },
|
|
||||||
target => 'CONNMARK --restore-mark --mask' ,
|
|
||||||
mark => SMALLMARK ,
|
|
||||||
mask => '0xFF' ,
|
|
||||||
connmark => 1
|
|
||||||
} ,
|
|
||||||
{ match => sub ( $ ) { $_[0] eq 'CONTINUE' },
|
|
||||||
target => 'RETURN' ,
|
|
||||||
mark => NOMARK ,
|
|
||||||
mask => '' ,
|
|
||||||
connmark => 0
|
|
||||||
} ,
|
|
||||||
{ match => sub ( $ ) { $_[0] =~ '\|.*'} ,
|
|
||||||
target => 'MARK --or-mark' ,
|
|
||||||
mark => HIGHMARK ,
|
|
||||||
mask => '' } ,
|
|
||||||
{ match => sub ( $ ) { $_[0] =~ '&.*' },
|
|
||||||
target => 'MARK --and-mark ' ,
|
|
||||||
mark => HIGHMARK ,
|
|
||||||
mask => '' ,
|
|
||||||
connmark => 0
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
our %flow_keys = ( 'src' => 1,
|
|
||||||
'dst' => 1,
|
|
||||||
'proto' => 1,
|
|
||||||
'proto-src' => 1,
|
|
||||||
'proto-dst' => 1,
|
|
||||||
'iif' => 1,
|
|
||||||
'priority' => 1,
|
|
||||||
'mark' => 1,
|
|
||||||
'nfct' => 1,
|
|
||||||
'nfct-src' => 1,
|
|
||||||
'nfct-dst' => 1,
|
|
||||||
'nfct-proto-src' => 1,
|
|
||||||
'nfct-proto-dst' => 1,
|
|
||||||
'rt-classid' => 1,
|
|
||||||
'sk-uid' => 1,
|
|
||||||
'sk-gid' => 1,
|
|
||||||
'vlan-tag' => 1 );
|
|
||||||
|
|
||||||
our %classids;
|
|
||||||
|
|
||||||
our @deferred_rules;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Perl version of Arn Bernin's 'tc4shorewall'.
|
|
||||||
#
|
|
||||||
# TCDevices Table
|
|
||||||
#
|
|
||||||
# %tcdevices { <interface> -> {in_bandwidth => <value> ,
|
|
||||||
# out_bandwidth => <value> ,
|
|
||||||
# number => <number>,
|
|
||||||
# classify => 0|1
|
|
||||||
# tablenumber => <next u32 table to be allocated for this device>
|
|
||||||
# default => <default class mark value>
|
|
||||||
# redirected => [ <dev1>, <dev2>, ... ]
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
our @tcdevices;
|
|
||||||
our %tcdevices;
|
|
||||||
our @devnums;
|
|
||||||
our $devnum;
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# TCClasses Table
|
|
||||||
#
|
|
||||||
# %tcclasses { device => <device> ,
|
|
||||||
# mark => <mark> ,
|
|
||||||
# number => <number> ,
|
|
||||||
# rate => <rate> ,
|
|
||||||
# ceiling => <ceiling> ,
|
|
||||||
# priority => <priority> ,
|
|
||||||
# options => { tos => [ <value1> , <value2> , ... ];
|
|
||||||
# tcp_ack => 1 ,
|
|
||||||
# ...
|
|
||||||
#
|
|
||||||
|
|
||||||
our @tcclasses;
|
|
||||||
our %tcclasses;
|
|
||||||
|
|
||||||
our %restrictions = ( tcpre => PREROUTE_RESTRICT ,
|
|
||||||
tcpost => POSTROUTE_RESTRICT ,
|
|
||||||
tcfor => NO_RESTRICT ,
|
|
||||||
tcout => OUTPUT_RESTRICT );
|
|
||||||
|
|
||||||
our $family;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
||||||
# the compiler to run multiple times in the same process. The
|
|
||||||
# initialize() function does globals initialization for this
|
|
||||||
# module and is called from an INIT block below. The function is
|
|
||||||
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
||||||
# the second and subsequent calls to that function.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub initialize( $ ) {
|
|
||||||
$family = shift;
|
|
||||||
%classids = ();
|
|
||||||
@deferred_rules = ();
|
|
||||||
@tcdevices = ();
|
|
||||||
%tcdevices = ();
|
|
||||||
@tcclasses = ();
|
|
||||||
%tcclasses = ();
|
|
||||||
@devnums = ();
|
|
||||||
$devnum = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT {
|
|
||||||
initialize( F_IPV4 );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub process_tc_rule( $$$$$$$$$$$$ ) {
|
|
||||||
my ( $originalmark, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos , $connbytes , $helper ) = @_;
|
|
||||||
|
|
||||||
my ( $mark, $designator, $remainder ) = split( /:/, $originalmark, 3 );
|
|
||||||
|
|
||||||
fatal_error "Invalid MARK ($originalmark)" if defined $remainder || ! defined $mark || $mark eq '';
|
|
||||||
|
|
||||||
my $chain = $globals{MARKING_CHAIN};
|
|
||||||
my $target = 'MARK --set-mark';
|
|
||||||
my $tcsref;
|
|
||||||
my $connmark = 0;
|
|
||||||
my $classid = 0;
|
|
||||||
my $device = '';
|
|
||||||
my $fw = firewall_zone;
|
|
||||||
|
|
||||||
if ( $source ) {
|
|
||||||
if ( $source eq $fw ) {
|
|
||||||
$chain = 'tcout';
|
|
||||||
$source = '';
|
|
||||||
} else {
|
|
||||||
$chain = 'tcout' if $source =~ s/^($fw)://;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $designator ) {
|
|
||||||
$tcsref = $tcs{$designator};
|
|
||||||
|
|
||||||
if ( $tcsref ) {
|
|
||||||
if ( $chain eq 'tcout' ) {
|
|
||||||
fatal_error "Invalid chain designator for source $fw" unless $tcsref->{fw};
|
|
||||||
}
|
|
||||||
|
|
||||||
$chain = $tcsref->{chain} if $tcsref->{chain};
|
|
||||||
$target = $tcsref->{target} if $tcsref->{target};
|
|
||||||
$mark = "$mark/0xFF" if $connmark = $tcsref->{connmark};
|
|
||||||
|
|
||||||
require_capability ('CONNMARK' , "CONNMARK Rules", '' ) if $connmark;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid MARK ($originalmark)" unless $mark =~ /^([0-9]+|0x[0-9a-f]+)$/ and $designator =~ /^([0-9]+|0x[0-9a-f]+)$/;
|
|
||||||
|
|
||||||
if ( $config{TC_ENABLED} eq 'Internal' ) {
|
|
||||||
fatal_error "Unknown Class ($originalmark)}" unless ( $device = $classids{$originalmark} );
|
|
||||||
}
|
|
||||||
|
|
||||||
$chain = 'tcpost';
|
|
||||||
$classid = 1;
|
|
||||||
$mark = $originalmark;
|
|
||||||
$target = 'CLASSIFY --set-class';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my $mask = 0xffff;
|
|
||||||
|
|
||||||
my ($cmd, $rest) = split( '/', $mark, 2 );
|
|
||||||
|
|
||||||
unless ( $classid ) {
|
|
||||||
MARK:
|
|
||||||
{
|
|
||||||
for my $tccmd ( @tccmd ) {
|
|
||||||
if ( $tccmd->{match}($cmd) ) {
|
|
||||||
fatal_error "$mark not valid with :C[FPT]" if $connmark;
|
|
||||||
|
|
||||||
require_capability ('CONNMARK' , "SAVE/RESTORE Rules", '' ) if $tccmd->{connmark};
|
|
||||||
|
|
||||||
$target = "$tccmd->{target} ";
|
|
||||||
my $marktype = $tccmd->{mark};
|
|
||||||
|
|
||||||
if ( $marktype == NOMARK ) {
|
|
||||||
$mark = ''
|
|
||||||
} else {
|
|
||||||
$mark =~ s/^[|&]//;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $rest ) {
|
|
||||||
fatal_error "Invalid MARK ($originalmark)" if $marktype == NOMARK;
|
|
||||||
|
|
||||||
$mark = $rest if $tccmd->{mask};
|
|
||||||
|
|
||||||
if ( $marktype == SMALLMARK ) {
|
|
||||||
verify_small_mark $mark;
|
|
||||||
} else {
|
|
||||||
validate_mark $mark;
|
|
||||||
}
|
|
||||||
} elsif ( $tccmd->{mask} ) {
|
|
||||||
$mark = $tccmd->{mask};
|
|
||||||
}
|
|
||||||
|
|
||||||
last MARK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
validate_mark $mark;
|
|
||||||
|
|
||||||
if ( $config{HIGH_ROUTE_MARKS} ) {
|
|
||||||
my $val = numeric_value( $cmd );
|
|
||||||
fatal_error "Invalid MARK/CLASSIFY ($cmd)" unless defined $val;
|
|
||||||
fatal_error 'Marks < 256 may not be set in the PREROUTING or OUTPUT chains when HIGH_ROUTE_MARKS=Yes'
|
|
||||||
if $cmd && ( $chain eq 'tcpre' || $chain eq 'tcout' ) && $val <= 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ( my $result = expand_rule( ensure_chain( 'mangle' , $chain ) ,
|
|
||||||
$restrictions{$chain} ,
|
|
||||||
do_proto( $proto, $ports, $sports) .
|
|
||||||
do_user( $user ) .
|
|
||||||
do_test( $testval, $mask ) .
|
|
||||||
do_length( $length ) .
|
|
||||||
do_tos( $tos ) .
|
|
||||||
do_connbytes( $connbytes ) .
|
|
||||||
do_helper( $helper ),
|
|
||||||
$source ,
|
|
||||||
$dest ,
|
|
||||||
'' ,
|
|
||||||
'' ,
|
|
||||||
"-j $target $mark" ,
|
|
||||||
'' ,
|
|
||||||
'' ,
|
|
||||||
'' ) )
|
|
||||||
&& $device ) {
|
|
||||||
#
|
|
||||||
# expand_rule() returns destination device if any
|
|
||||||
#
|
|
||||||
fatal_error "Class Id $originalmark is not associated with device $result" if $device ne $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
progress_message " TC Rule \"$currentline\" $done";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub rate_to_kbit( $ ) {
|
|
||||||
my $rate = $_[0];
|
|
||||||
|
|
||||||
return 0 if $rate eq '-';
|
|
||||||
return $1 if $rate =~ /^(\d+)kbit$/i;
|
|
||||||
return $1 * 1000 if $rate =~ /^(\d+)mbit$/i;
|
|
||||||
return $1 * 8000 if $rate =~ /^(\d+)mbps$/i;
|
|
||||||
return $1 * 8 if $rate =~ /^(\d+)kbps$/i;
|
|
||||||
return int($1/125) if $rate =~ /^(\d+)(bps)?$/;
|
|
||||||
fatal_error "Invalid Rate ($rate)";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub calculate_r2q( $ ) {
|
|
||||||
my $rate = rate_to_kbit $_[0];
|
|
||||||
my $r2q= $rate / 200 ;
|
|
||||||
$r2q <= 5 ? 5 : $r2q;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub calculate_quantum( $$ ) {
|
|
||||||
my ( $rate, $r2q ) = @_;
|
|
||||||
$rate = rate_to_kbit $rate;
|
|
||||||
int( ( $rate * 125 ) / $r2q );
|
|
||||||
}
|
|
||||||
|
|
||||||
sub process_flow($) {
|
|
||||||
my $flow = shift;
|
|
||||||
|
|
||||||
$flow =~ s/^\(// if $flow =~ s/\)$//;
|
|
||||||
|
|
||||||
my @flow = split /,/, $flow;
|
|
||||||
|
|
||||||
for ( @flow ) {
|
|
||||||
fatal_error "Invalid flow key ($_)" unless $flow_keys{$_};
|
|
||||||
}
|
|
||||||
|
|
||||||
$flow;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_tc_device( $$$$$ ) {
|
|
||||||
my ( $device, $inband, $outband , $options , $redirected ) = @_;
|
|
||||||
|
|
||||||
my $devnumber;
|
|
||||||
|
|
||||||
if ( $device =~ /:/ ) {
|
|
||||||
( my $number, $device, my $rest ) = split /:/, $device, 3;
|
|
||||||
|
|
||||||
fatal_error "Invalid NUMBER:INTERFACE ($device:$number:$rest)" if defined $rest;
|
|
||||||
|
|
||||||
if ( defined $number ) {
|
|
||||||
$devnumber = numeric_value( $number );
|
|
||||||
fatal_error "Invalid interface NUMBER ($number)" unless defined $devnumber && $devnumber;
|
|
||||||
fatal_error "Duplicate interface number ($number)" if defined $devnums[ $devnumber ];
|
|
||||||
$devnum = $devnumber if $devnumber > $devnum;
|
|
||||||
} else {
|
|
||||||
fatal_error "Missing interface NUMBER";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$devnumber = ++$devnum;
|
|
||||||
}
|
|
||||||
|
|
||||||
$devnums[ $devnumber ] = $device;
|
|
||||||
|
|
||||||
fatal_error "Duplicate INTERFACE ($device)" if $tcdevices{$device};
|
|
||||||
fatal_error "Invalid INTERFACE name ($device)" if $device =~ /[:+]/;
|
|
||||||
|
|
||||||
my ( $classify, $pfifo, $flow) = (0, 0, '' );
|
|
||||||
|
|
||||||
if ( $options ne '-' ) {
|
|
||||||
for my $option ( split_list1 $options, 'option' ) {
|
|
||||||
if ( $option eq 'classify' ) {
|
|
||||||
$classify = 1;
|
|
||||||
} elsif ( $option =~ /^flow=(.*)$/ ) {
|
|
||||||
fatal_error "The 'flow' option is not allowed with 'pfifo'" if $pfifo;
|
|
||||||
$flow = process_flow $1;
|
|
||||||
} elsif ( $option eq 'pfifo' ) {
|
|
||||||
fatal_error "The 'pfifo'' option is not allowed with 'flow='" if $flow;
|
|
||||||
$pfifo = 1;
|
|
||||||
} else {
|
|
||||||
fatal_error "Unknown device option ($option)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my @redirected = ();
|
|
||||||
|
|
||||||
@redirected = split_list( $redirected , 'device' ) if defined $redirected && $redirected ne '-';
|
|
||||||
|
|
||||||
if ( @redirected ) {
|
|
||||||
fatal_error "IFB devices may not have IN-BANDWIDTH" if $inband ne '-' && $inband;
|
|
||||||
$classify = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $rdevice ( @redirected ) {
|
|
||||||
fatal_error "Invalid device name ($rdevice)" if $rdevice =~ /[:+]/;
|
|
||||||
my $rdevref = $tcdevices{$rdevice};
|
|
||||||
fatal_error "REDIRECTED device ($rdevice) has not been defined in this file" unless $rdevref;
|
|
||||||
fatal_error "IN-BANDWIDTH must be zero for REDIRECTED devices" if $rdevref->{in_bandwidth} ne '0kbit';
|
|
||||||
}
|
|
||||||
|
|
||||||
$tcdevices{$device} = { in_bandwidth => rate_to_kbit( $inband ) . 'kbit' ,
|
|
||||||
out_bandwidth => rate_to_kbit( $outband ) . 'kbit' ,
|
|
||||||
number => $devnumber,
|
|
||||||
classify => $classify ,
|
|
||||||
flow => $flow ,
|
|
||||||
pfifo => $pfifo ,
|
|
||||||
tablenumber => 1 ,
|
|
||||||
redirected => \@redirected ,
|
|
||||||
} ,
|
|
||||||
|
|
||||||
push @tcdevices, $device;
|
|
||||||
|
|
||||||
progress_message " Tcdevice \"$currentline\" $done.";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub convert_rate( $$$ ) {
|
|
||||||
my ($full, $rate, $column) = @_;
|
|
||||||
|
|
||||||
if ( $rate =~ /\bfull\b/ ) {
|
|
||||||
$rate =~ s/\bfull\b/$full/g;
|
|
||||||
fatal_error "Invalid $column ($_[1])" if $rate =~ m{[^0-9*/+()-]};
|
|
||||||
no warnings;
|
|
||||||
$rate = eval "int( $rate )";
|
|
||||||
use warnings;
|
|
||||||
fatal_error "Invalid $column ($_[1])" unless defined $rate;
|
|
||||||
} else {
|
|
||||||
$rate = rate_to_kbit $rate
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal_error "$column may not be zero" unless $rate;
|
|
||||||
fatal_error "$column ($_[1]) exceeds OUT-BANDWIDTH" if $rate > $full;
|
|
||||||
|
|
||||||
$rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub dev_by_number( $ ) {
|
|
||||||
my $dev = $_[0];
|
|
||||||
my $devnum = numeric_value( $dev );
|
|
||||||
my $devref;
|
|
||||||
|
|
||||||
if ( defined $devnum ) {
|
|
||||||
$dev = $devnums[ $devnum ];
|
|
||||||
fatal_error "Undefined INTERFACE number ($_[0])" unless defined $dev;
|
|
||||||
$devref = $tcdevices{$dev};
|
|
||||||
fatal_error "Internal Error in dev_by_number()" unless $devref;
|
|
||||||
} else {
|
|
||||||
$devref = $tcdevices{$dev};
|
|
||||||
fatal_error "Unknown INTERFACE ($dev)" unless $devref;
|
|
||||||
}
|
|
||||||
|
|
||||||
( $dev , $devref );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub validate_tc_class( $$$$$$ ) {
|
|
||||||
my ( $devclass, $mark, $rate, $ceil, $prio, $options ) = @_;
|
|
||||||
|
|
||||||
my %tosoptions = ( 'tos-minimize-delay' => 'tos=0x10/0x10' ,
|
|
||||||
'tos-maximize-throughput' => 'tos=0x08/0x08' ,
|
|
||||||
'tos-maximize-reliability' => 'tos=0x04/0x04' ,
|
|
||||||
'tos-minimize-cost' => 'tos=0x02/0x02' ,
|
|
||||||
'tos-normal-service' => 'tos=0x00/0x1e' );
|
|
||||||
|
|
||||||
my $classnumber = 0;
|
|
||||||
my $devref;
|
|
||||||
my $device = $devclass;
|
|
||||||
|
|
||||||
if ( $devclass =~ /:/ ) {
|
|
||||||
( $device, my ($number, $rest ) ) = split /:/, $device, 3;
|
|
||||||
fatal_error "Invalid INTERFACE:CLASS ($devclass)" if defined $rest;
|
|
||||||
|
|
||||||
( $device , $devref) = dev_by_number( $device );
|
|
||||||
|
|
||||||
if ( defined $number ) {
|
|
||||||
if ( $devref->{classify} ) {
|
|
||||||
$classnumber = numeric_value( $number );
|
|
||||||
fatal_error "Invalid interface NUMBER ($number)" unless defined $classnumber && $classnumber;
|
|
||||||
fatal_error "Duplicate interface/class number ($number)" if defined $devnums[ $classnumber ];
|
|
||||||
} else {
|
|
||||||
warning_message "Class NUMBER ignored -- INTERFACE $device does not have the 'classify' option";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fatal_error "Missing interface NUMBER";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
($device, $devref ) = dev_by_number( $device );
|
|
||||||
fatal_error "Missing class NUMBER" if $devref->{classify};
|
|
||||||
}
|
|
||||||
|
|
||||||
my $full = rate_to_kbit $devref->{out_bandwidth};
|
|
||||||
|
|
||||||
$tcclasses{$device} = {} unless $tcclasses{$device};
|
|
||||||
my $tcref = $tcclasses{$device};
|
|
||||||
|
|
||||||
my $markval = 0;
|
|
||||||
|
|
||||||
if ( $mark ne '-' ) {
|
|
||||||
if ( $devref->{classify} ) {
|
|
||||||
warning_message "INTERFACE $device has the 'classify' option - MARK value ($mark) ignored";
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid Mark ($mark)" unless $mark =~ /^([0-9]+|0x[0-9a-fA-F]+)$/ && numeric_value( $mark ) <= 0xff;
|
|
||||||
|
|
||||||
$markval = numeric_value( $mark );
|
|
||||||
fatal_error "Invalid MARK ($markval)" unless defined $markval;
|
|
||||||
fatal_error "Duplicate MARK ($mark)" if $tcref->{$classnumber};
|
|
||||||
$classnumber = $devnum . $mark;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fatal_error "Missing MARK" unless $devref->{classify};
|
|
||||||
fatal_error "Duplicate Class NUMBER ($classnumber)" if $tcref->{$classnumber};
|
|
||||||
}
|
|
||||||
|
|
||||||
$tcref->{$classnumber} = { tos => [] ,
|
|
||||||
rate => convert_rate( $full, $rate, 'RATE' ) ,
|
|
||||||
ceiling => convert_rate( $full, $ceil, 'CEIL' ) ,
|
|
||||||
priority => $prio eq '-' ? 1 : $prio ,
|
|
||||||
mark => $markval ,
|
|
||||||
flow => '' ,
|
|
||||||
pfifo => 0
|
|
||||||
};
|
|
||||||
|
|
||||||
$tcref = $tcref->{$classnumber};
|
|
||||||
|
|
||||||
fatal_error "RATE ($tcref->{rate}) exceeds CEIL ($tcref->{ceiling})" if $tcref->{rate} > $tcref->{ceiling};
|
|
||||||
|
|
||||||
unless ( $options eq '-' ) {
|
|
||||||
for my $option ( split_list1 "\L$options", 'option' ) {
|
|
||||||
my $optval = $tosoptions{$option};
|
|
||||||
|
|
||||||
$option = $optval if $optval;
|
|
||||||
|
|
||||||
if ( $option eq 'default' ) {
|
|
||||||
fatal_error "Only one default class may be specified for device $device" if $devref->{default};
|
|
||||||
$devref->{default} = $classnumber;
|
|
||||||
} elsif ( $option eq 'tcp-ack' ) {
|
|
||||||
$tcref->{tcp_ack} = 1;
|
|
||||||
} elsif ( $option =~ /^tos=0x[0-9a-f]{2}$/ ) {
|
|
||||||
( undef, $option ) = split /=/, $option;
|
|
||||||
push @{$tcref->{tos}}, "$option/0xff";
|
|
||||||
} elsif ( $option =~ /^tos=0x[0-9a-f]{2}\/0x[0-9a-f]{2}$/ ) {
|
|
||||||
( undef, $option ) = split /=/, $option;
|
|
||||||
push @{$tcref->{tos}}, $option;
|
|
||||||
} elsif ( $option =~ /^flow=(.*)$/ ) {
|
|
||||||
fatal_error "The 'flow' option is not allowed with 'pfifo'" if $tcref->{pfifo};
|
|
||||||
$tcref->{flow} = process_flow $1;
|
|
||||||
} elsif ( $option eq 'pfifo' ) {
|
|
||||||
fatal_error "The 'pfifo'' option is not allowed with 'flow='" if $tcref->{flow};
|
|
||||||
$tcref->{pfifo} = 1;
|
|
||||||
} else {
|
|
||||||
fatal_error "Unknown option ($option)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$tcref->{flow} = $devref->{flow} unless $tcref->{flow};
|
|
||||||
$tcref->{pfifo} = $devref->{pfifo} unless $tcref->{flow} || $tcref->{pfifo};
|
|
||||||
|
|
||||||
push @tcclasses, "$device:$classnumber";
|
|
||||||
progress_message " Tcclass \"$currentline\" $done.";
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Process a record from the tcfilters file
|
|
||||||
#
|
|
||||||
sub process_tc_filter( $$$$$$ ) {
|
|
||||||
my ($devclass , $source, $dest , $proto, $portlist , $sportlist ) = @_;
|
|
||||||
|
|
||||||
my ($device, $class, $rest ) = split /:/, $devclass, 3;
|
|
||||||
|
|
||||||
fatal_error "Invalid INTERFACE:CLASS ($devclass)" if defined $rest || ! ($device && $class );
|
|
||||||
|
|
||||||
( $device , my $devref ) = dev_by_number( $device );
|
|
||||||
|
|
||||||
my $devnum = $devref->{number};
|
|
||||||
|
|
||||||
my $tcref = $tcclasses{$device};
|
|
||||||
|
|
||||||
fatal_error "No Classes were defined for INTERFACE $device" unless $tcref;
|
|
||||||
|
|
||||||
$tcref = $tcref->{$class};
|
|
||||||
|
|
||||||
fatal_error "Unknown CLASS ($devclass)" unless $tcref;
|
|
||||||
|
|
||||||
my $rule = "filter add dev $device protocol ip parent $devnum:0 pref 10 u32";
|
|
||||||
|
|
||||||
my ( $net , $mask ) = decompose_net( $source );
|
|
||||||
|
|
||||||
$rule .= "\\\n match u32 $net $mask at 12" unless $mask eq '0x00000000';
|
|
||||||
|
|
||||||
( $net , $mask ) = decompose_net( $dest );
|
|
||||||
|
|
||||||
$rule .= "\\\n match u32 $net $mask at 16" unless $mask eq '0x00000000';
|
|
||||||
|
|
||||||
my $protonumber = 0;
|
|
||||||
|
|
||||||
unless ( $proto eq '-' ) {
|
|
||||||
$protonumber = resolve_proto $proto;
|
|
||||||
fatal_error "Unknown PROTO ($proto)" unless defined $protonumber;
|
|
||||||
|
|
||||||
if ( $protonumber ) {
|
|
||||||
my $pnumber = in_hex2 $protonumber;
|
|
||||||
$rule .= "\\\n match u8 $pnumber 0xff at 9";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $portlist eq '-' && $sportlist eq '-' ) {
|
|
||||||
emit( "\nrun_tc $rule\\" ,
|
|
||||||
" flowid $devref->{number}:$class" ,
|
|
||||||
'' );
|
|
||||||
} else {
|
|
||||||
our $lastrule;
|
|
||||||
our $lasttnum;
|
|
||||||
#
|
|
||||||
# In order to be able to access the protocol header, we must create another hash table and link to it.
|
|
||||||
#
|
|
||||||
# Create the Table.
|
|
||||||
#
|
|
||||||
my $tnum;
|
|
||||||
|
|
||||||
if ( $lastrule eq $rule ) {
|
|
||||||
#
|
|
||||||
# The source, dest and protocol are the same as the last rule that specified a port
|
|
||||||
# Use the same table
|
|
||||||
#
|
|
||||||
$tnum = $lasttnum
|
|
||||||
} else {
|
|
||||||
$tnum = in_hex3 $devref->{tablenumber}++;
|
|
||||||
$lasttnum = $tnum;
|
|
||||||
$lastrule = $rule;
|
|
||||||
|
|
||||||
emit( "\nrun_tc filter add dev $device parent $devnum:0 protocol ip pref 10 handle $tnum: u32 divisor 1" );
|
|
||||||
}
|
|
||||||
#
|
|
||||||
# And link to it using the current contents of $rule
|
|
||||||
#
|
|
||||||
emit( "\nrun_tc $rule\\" ,
|
|
||||||
" link $tnum:0 offset at 0 mask 0x0F00 shift 6 plus 0 eat" );
|
|
||||||
#
|
|
||||||
# The rule to match the port(s) will be inserted into the new table
|
|
||||||
#
|
|
||||||
$rule = "filter add dev $device protocol ip parent $devnum:0 pref 10 u32 ht $tnum:0";
|
|
||||||
|
|
||||||
if ( $portlist eq '-' ) {
|
|
||||||
fatal_error "Only TCP, UDP and SCTP may specify SOURCE PORT"
|
|
||||||
unless $protonumber == TCP || $protonumber == UDP || $protonumber == SCTP;
|
|
||||||
|
|
||||||
for my $sportrange ( split_list $sportlist , 'port list' ) {
|
|
||||||
my @sportlist = expand_port_range $protonumber , $sportrange;
|
|
||||||
|
|
||||||
while ( @sportlist ) {
|
|
||||||
my ( $sport, $smask ) = ( shift @sportlist, shift @sportlist );
|
|
||||||
emit( "\nrun_tc $rule\\" ,
|
|
||||||
" match u32 0x${sport}0000 0x${smask}0000 at nexthdr+0\\" ,
|
|
||||||
" flowid $devref->{number}:$class" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fatal_error "Only TCP, UDP, SCTP and ICMP may specify DEST PORT"
|
|
||||||
unless $protonumber == TCP || $protonumber == UDP || $protonumber == SCTP || $protonumber == ICMP;
|
|
||||||
|
|
||||||
for my $portrange ( split_list $portlist, 'port list' ) {
|
|
||||||
if ( $protonumber == ICMP ) {
|
|
||||||
fatal_error "SOURCE PORT(S) are not allowed with ICMP" if $sportlist ne '-';
|
|
||||||
|
|
||||||
my ( $icmptype , $icmpcode ) = split '//', validate_icmp( $portrange );
|
|
||||||
|
|
||||||
$icmptype = in_hex2 numeric_value1 $icmptype;
|
|
||||||
$icmpcode = in_hex2 numeric_value1 $icmpcode if defined $icmpcode;
|
|
||||||
|
|
||||||
my $rule1 = " match u8 $icmptype 0xff at nexthdr+0";
|
|
||||||
$rule1 .= "\\\n match u8 $icmpcode 0xff at nexthdr+1" if defined $icmpcode;
|
|
||||||
emit( "\nrun_tc ${rule}\\" ,
|
|
||||||
"$rule1\\" ,
|
|
||||||
" flowid $devref->{number}:$class" );
|
|
||||||
} else {
|
|
||||||
my @portlist = expand_port_range $protonumber , $portrange;
|
|
||||||
|
|
||||||
while ( @portlist ) {
|
|
||||||
my ( $port, $mask ) = ( shift @portlist, shift @portlist );
|
|
||||||
|
|
||||||
my $rule1 = "match u32 0x0000${port} 0x0000${mask} at nexthdr+0";
|
|
||||||
|
|
||||||
if ( $sportlist eq '-' ) {
|
|
||||||
emit( "\nrun_tc ${rule}\\" ,
|
|
||||||
" $rule1\\" ,
|
|
||||||
" flowid $devref->{number}:$class" );
|
|
||||||
} else {
|
|
||||||
for my $sportrange ( split_list $sportlist , 'port list' ) {
|
|
||||||
my @sportlist = expand_port_range $protonumber , $sportrange;
|
|
||||||
|
|
||||||
while ( @sportlist ) {
|
|
||||||
my ( $sport, $smask ) = ( shift @sportlist, shift @sportlist );
|
|
||||||
|
|
||||||
emit( "\nrun_tc ${rule}\\",
|
|
||||||
" $rule1\\" ,
|
|
||||||
" match u32 0x${sport}0000 0x${smask}0000 at nexthdr+0\\" ,
|
|
||||||
" flowid $devref->{number}:$class" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emit '';
|
|
||||||
|
|
||||||
progress_message " TC Filter \"$currentline\" $done";
|
|
||||||
|
|
||||||
$currentline =~ s/\s+/ /g;
|
|
||||||
|
|
||||||
save_progress_message_short qq(" TC Filter \"$currentline\" defined.");
|
|
||||||
|
|
||||||
emit '';
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_traffic_shaping() {
|
|
||||||
our $lastrule = '';
|
|
||||||
|
|
||||||
save_progress_message "Setting up Traffic Control...";
|
|
||||||
|
|
||||||
my $fn = open_file 'tcdevices';
|
|
||||||
|
|
||||||
if ( $fn ) {
|
|
||||||
first_entry "$doing $fn...";
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $device, $inband, $outband, $options , $redirected ) = split_line 3, 5, 'tcdevices';
|
|
||||||
|
|
||||||
fatal_error "Invalid tcdevices entry" if $outband eq '-';
|
|
||||||
validate_tc_device( $device, $inband, $outband , $options , $redirected );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$devnum = $devnum > 10 ? 10 : 1;
|
|
||||||
|
|
||||||
$fn = open_file 'tcclasses';
|
|
||||||
|
|
||||||
if ( $fn ) {
|
|
||||||
first_entry "$doing $fn...";
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $device, $mark, $rate, $ceil, $prio, $options ) = split_line 4, 6, 'tcclasses file';
|
|
||||||
|
|
||||||
validate_tc_class( $device, $mark, $rate, $ceil, $prio, $options );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $device ( @tcdevices ) {
|
|
||||||
my $dev = chain_base( $device );
|
|
||||||
my $devref = $tcdevices{$device};
|
|
||||||
my $defmark = $devref->{default} || 0;
|
|
||||||
my $devnum = $devref->{number};
|
|
||||||
|
|
||||||
emit "if interface_is_up $device; then";
|
|
||||||
|
|
||||||
push_indent;
|
|
||||||
|
|
||||||
emit ( "${dev}_exists=Yes",
|
|
||||||
"qt tc qdisc del dev $device root",
|
|
||||||
"qt tc qdisc del dev $device ingress",
|
|
||||||
"run_tc qdisc add dev $device root handle $devnum: htb default $defmark",
|
|
||||||
"${dev}_mtu=\$(get_device_mtu $device)",
|
|
||||||
"${dev}_mtu1=\$(get_device_mtu1 $device)",
|
|
||||||
"run_tc class add dev $device parent $devnum: classid $devnum:1 htb rate $devref->{out_bandwidth} \$${dev}_mtu1"
|
|
||||||
);
|
|
||||||
|
|
||||||
my $inband = rate_to_kbit $devref->{in_bandwidth};
|
|
||||||
|
|
||||||
if ( $inband ) {
|
|
||||||
emit ( "run_tc qdisc add dev $device handle ffff: ingress",
|
|
||||||
"run_tc filter add dev $device parent ffff: protocol ip pref 10 u32 match ip src 0.0.0.0/0 police rate ${inband}kbit burst 10k drop flowid :1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $rdev ( @{$devref->{redirected}} ) {
|
|
||||||
emit ( "run_tc qdisc add dev $rdev handle ffff: ingress" );
|
|
||||||
emit( "run_tc filter add dev $rdev parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $device > /dev/null" );
|
|
||||||
}
|
|
||||||
|
|
||||||
save_progress_message_short " TC Device $device defined.";
|
|
||||||
|
|
||||||
pop_indent;
|
|
||||||
emit 'else';
|
|
||||||
push_indent;
|
|
||||||
|
|
||||||
emit qq(error_message "WARNING: Device $device is not in the UP state -- traffic-shaping configuration skipped");
|
|
||||||
emit "${dev}_exists=";
|
|
||||||
pop_indent;
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
my $lastdevice = '';
|
|
||||||
|
|
||||||
for my $class ( @tcclasses ) {
|
|
||||||
my ( $device, $classnum ) = split /:/, $class;
|
|
||||||
my $devref = $tcdevices{$device};
|
|
||||||
my $tcref = $tcclasses{$device}{$classnum};
|
|
||||||
my $mark = $tcref->{mark};
|
|
||||||
my $devicenumber = $devref->{number};
|
|
||||||
my $classid = join( '', $devicenumber, ':', $classnum);
|
|
||||||
my $rate = "$tcref->{rate}kbit";
|
|
||||||
my $quantum = calculate_quantum $rate, calculate_r2q( $devref->{out_bandwidth} );
|
|
||||||
my $dev = chain_base $device;
|
|
||||||
|
|
||||||
$classids{$classid}=$device;
|
|
||||||
|
|
||||||
if ( $lastdevice ne $device ) {
|
|
||||||
if ( $lastdevice ) {
|
|
||||||
pop_indent;
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
emit qq(if [ -n "\$${dev}_exists" ]; then);
|
|
||||||
push_indent;
|
|
||||||
$lastdevice = $device;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit ( "[ \$${dev}_mtu -gt $quantum ] && quantum=\$${dev}_mtu || quantum=$quantum",
|
|
||||||
"run_tc class add dev $device parent $devref->{number}:1 classid $classid htb rate $rate ceil $tcref->{ceiling}kbit prio $tcref->{priority} \$${dev}_mtu1 quantum \$quantum" );
|
|
||||||
|
|
||||||
emit( "run_tc qdisc add dev $device parent $classid handle ${classnum}: sfq quantum \$quantum limit 127 perturb 10" ) unless $tcref->{pfifo};
|
|
||||||
#
|
|
||||||
# add filters
|
|
||||||
#
|
|
||||||
emit "run_tc filter add dev $device protocol ip parent $devicenumber:0 prio 1 handle $mark fw classid $classid" unless $devref->{classify};
|
|
||||||
emit "run_tc filter add dev $device protocol ip pref 1 parent $classnum: handle 1 flow hash keys $tcref->{flow} divisor 1024" if $tcref->{flow};
|
|
||||||
#
|
|
||||||
#options
|
|
||||||
#
|
|
||||||
emit "run_tc filter add dev $device parent $devref->{number}:0 protocol ip prio 10 u32 match ip protocol 6 0xff match u8 0x05 0x0f at 0 match u16 0x0000 0xffc0 at 2 match u8 0x10 0xff at 33 flowid $classid" if $tcref->{tcp_ack};
|
|
||||||
|
|
||||||
for my $tospair ( @{$tcref->{tos}} ) {
|
|
||||||
my ( $tos, $mask ) = split q(/), $tospair;
|
|
||||||
emit "run_tc filter add dev $device parent $devicenumber:0 protocol ip prio 10 u32 match ip tos $tos $mask flowid $classid";
|
|
||||||
}
|
|
||||||
|
|
||||||
save_progress_message_short qq(" TC Class $class defined.");
|
|
||||||
emit '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $lastdevice ) {
|
|
||||||
pop_indent;
|
|
||||||
emit "fi\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $family == F_IPV4 ) {
|
|
||||||
$fn = open_file 'tcfilters';
|
|
||||||
|
|
||||||
if ( $fn ) {
|
|
||||||
first_entry( sub { progress_message2 "$doing $fn..."; save_progress_message "Adding TC Filters"; } );
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $devclass, $source, $dest, $proto, $port, $sport ) = split_line 2, 6, 'tcfilters file';
|
|
||||||
|
|
||||||
process_tc_filter( $devclass, $source, $dest, $proto, $port, $sport );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Process the tcrules file and setup traffic shaping
|
|
||||||
#
|
|
||||||
sub setup_tc() {
|
|
||||||
|
|
||||||
if ( $capabilities{MANGLE_ENABLED} && $config{MANGLE_ENABLED} ) {
|
|
||||||
ensure_mangle_chain 'tcpre';
|
|
||||||
ensure_mangle_chain 'tcout';
|
|
||||||
|
|
||||||
if ( $capabilities{MANGLE_FORWARD} ) {
|
|
||||||
ensure_mangle_chain 'tcfor';
|
|
||||||
ensure_mangle_chain 'tcpost';
|
|
||||||
}
|
|
||||||
|
|
||||||
my $mark_part = '';
|
|
||||||
|
|
||||||
if ( @routemarked_interfaces && ! $config{TC_EXPERT} ) {
|
|
||||||
$mark_part = $config{HIGH_ROUTE_MARKS} ? '-m mark --mark 0/0xFF00' : '-m mark --mark 0/0xFF';
|
|
||||||
|
|
||||||
for my $interface ( @routemarked_interfaces ) {
|
|
||||||
add_rule $mangle_table->{PREROUTING} , "-i $interface -j tcpre";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add_rule $mangle_table->{PREROUTING} , "$mark_part -j tcpre";
|
|
||||||
add_rule $mangle_table->{OUTPUT} , "$mark_part -j tcout";
|
|
||||||
|
|
||||||
if ( $capabilities{MANGLE_FORWARD} ) {
|
|
||||||
add_rule $mangle_table->{FORWARD} , '-j tcfor';
|
|
||||||
add_rule $mangle_table->{POSTROUTING} , '-j tcpost';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $config{HIGH_ROUTE_MARKS} ) {
|
|
||||||
for my $chain qw(INPUT FORWARD POSTROUTING) {
|
|
||||||
insert_rule1 $mangle_table->{$chain}, 0, '-j MARK --and-mark 0xFF';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $globals{TC_SCRIPT} ) {
|
|
||||||
save_progress_message 'Setting up Traffic Control...';
|
|
||||||
append_file $globals{TC_SCRIPT};
|
|
||||||
} elsif ( $config{TC_ENABLED} eq 'Internal' ) {
|
|
||||||
setup_traffic_shaping;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $config{TC_ENABLED} ) {
|
|
||||||
if ( my $fn = open_file 'tcrules' ) {
|
|
||||||
|
|
||||||
first_entry( sub { progress_message2 "$doing $fn..."; require_capability 'MANGLE_ENABLED' , 'a non-empty tcrules file' , 's'; } );
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $mark, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos , $connbytes, $helper ) = split_line1 2, 12, 'tcrules file';
|
|
||||||
|
|
||||||
if ( $mark eq 'COMMENT' ) {
|
|
||||||
process_comment;
|
|
||||||
} else {
|
|
||||||
process_tc_rule $mark, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos, $connbytes, $helper;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_comment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( @deferred_rules ) {
|
|
||||||
add_rule ensure_chain( 'mangle' , 'tcpost' ), $_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,298 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.2 -- /usr/share/shorewall-perl/Shorewall/Tunnels.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# This module handles the /etc/shorewall/tunnels file.
|
|
||||||
#
|
|
||||||
package Shorewall::Tunnels;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Config qw(:DEFAULT :internal);
|
|
||||||
use Shorewall::Zones;
|
|
||||||
use Shorewall::IPAddrs;
|
|
||||||
use Shorewall::Chains qw(:DEFAULT :internal);
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw( setup_tunnels );
|
|
||||||
our @EXPORT_OK = ( );
|
|
||||||
our $VERSION = 4.2.4;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Here starts the tunnel stuff -- we really should get rid of this crap...
|
|
||||||
#
|
|
||||||
sub setup_tunnels() {
|
|
||||||
|
|
||||||
our $fw = firewall_zone;
|
|
||||||
|
|
||||||
sub setup_one_ipsec {
|
|
||||||
my ($inchainref, $outchainref, $kind, $source, $dest, $gatewayzones) = @_;
|
|
||||||
|
|
||||||
( $kind, my ( $qualifier , $remainder ) ) = split( /:/, $kind, 3 );
|
|
||||||
|
|
||||||
my $noah = 1;
|
|
||||||
|
|
||||||
fatal_error "Invalid IPSEC modifier ($qualifier:$remainder)" if defined $remainder;
|
|
||||||
|
|
||||||
if ( defined $qualifier ) {
|
|
||||||
if ( $qualifier eq 'ah' ) {
|
|
||||||
fatal_error ":ah not allowed with ipsecnat tunnels" if $kind eq 'ipsecnat';
|
|
||||||
$noah = 0;
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid IPSEC modifier ($qualifier)" if $qualifier ne 'noah';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my $options = $globals{UNTRACKED} ? '-m state --state NEW,UNTRACKED -j ACCEPT' : '-m state --state NEW -j ACCEPT';
|
|
||||||
|
|
||||||
add_tunnel_rule $inchainref, "-p 50 $source -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref, "-p 50 $dest -j ACCEPT";
|
|
||||||
|
|
||||||
unless ( $noah ) {
|
|
||||||
add_tunnel_rule $inchainref, "-p 51 $source -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref, "-p 51 $dest -j ACCEPT";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $kind eq 'ipsec' ) {
|
|
||||||
add_tunnel_rule $inchainref, "-p udp $source --dport 500 $options";
|
|
||||||
add_tunnel_rule $outchainref, "-p udp $dest --dport 500 $options";
|
|
||||||
} else {
|
|
||||||
add_tunnel_rule $inchainref, "-p udp $source -m multiport --dports 500,4500 $options";
|
|
||||||
add_tunnel_rule $outchainref, "-p udp $dest -m multiport --dports 500,4500 $options";
|
|
||||||
}
|
|
||||||
|
|
||||||
unless ( $gatewayzones eq '-' ) {
|
|
||||||
for my $zone ( split_list $gatewayzones, 'zone' ) {
|
|
||||||
my $type = zone_type( $zone );
|
|
||||||
fatal_error "Invalid zone ($zone) for GATEWAY ZONE" if $type eq 'firewall' || $type eq 'bport';
|
|
||||||
$inchainref = ensure_filter_chain "${zone}2${fw}", 1;
|
|
||||||
$outchainref = ensure_filter_chain "${fw}2${zone}", 1;
|
|
||||||
|
|
||||||
unless ( $capabilities{POLICY_MATCH} ) {
|
|
||||||
add_tunnel_rule $inchainref, "-p 50 $source -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref, "-p 50 $dest -j ACCEPT";
|
|
||||||
|
|
||||||
unless ( $noah ) {
|
|
||||||
add_tunnel_rule $inchainref, "-p 51 $source -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref, "-p 51 $dest -j ACCEPT";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $kind eq 'ipsec' ) {
|
|
||||||
add_tunnel_rule $inchainref, "-p udp $source --dport 500 $options";
|
|
||||||
add_tunnel_rule $outchainref, "-p udp $dest --dport 500 $options";
|
|
||||||
} else {
|
|
||||||
add_tunnel_rule $inchainref, "-p udp $source -m multiport --dports 500,4500 $options";
|
|
||||||
add_tunnel_rule $outchainref, "-p udp $dest -m multiport --dports 500,4500 $options";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_one_other {
|
|
||||||
my ($inchainref, $outchainref, $source, $dest , $protocol) = @_;
|
|
||||||
|
|
||||||
add_tunnel_rule $inchainref , "-p $protocol $source -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref , "-p $protocol $dest -j ACCEPT";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_pptp_client {
|
|
||||||
my ($inchainref, $outchainref, $kind, $source, $dest ) = @_;
|
|
||||||
|
|
||||||
add_tunnel_rule $outchainref, "-p 47 $dest -j ACCEPT";
|
|
||||||
add_tunnel_rule $inchainref, "-p 47 $source -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref, "-p tcp --dport 1723 $dest -j ACCEPT"
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_pptp_server {
|
|
||||||
my ($inchainref, $outchainref, $kind, $source, $dest ) = @_;
|
|
||||||
|
|
||||||
add_tunnel_rule $inchainref, "-p 47 $dest -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref, "-p 47 $source -j ACCEPT";
|
|
||||||
add_tunnel_rule $inchainref, "-p tcp --dport 1723 $dest -j ACCEPT"
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_one_openvpn {
|
|
||||||
my ($inchainref, $outchainref, $kind, $source, $dest) = @_;
|
|
||||||
|
|
||||||
my $protocol = 'udp';
|
|
||||||
my $port = 1194;
|
|
||||||
|
|
||||||
( $kind, my ( $proto, $p, $remainder ) ) = split( /:/, $kind, 4 );
|
|
||||||
|
|
||||||
fatal_error "Invalid port ($p:$remainder)" if defined $remainder;
|
|
||||||
|
|
||||||
if ( defined $p && $p ne '' ) {
|
|
||||||
$port = $p;
|
|
||||||
$protocol = $proto;
|
|
||||||
} elsif ( defined $proto && $proto ne '' ) {
|
|
||||||
if ( "\L$proto" =~ /udp|tcp/ ) {
|
|
||||||
$protocol = $proto;
|
|
||||||
} else {
|
|
||||||
$port = $proto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add_tunnel_rule $inchainref, "-p $protocol $source --dport $port -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref, "-p $protocol $dest --dport $port -j ACCEPT";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_one_openvpn_client {
|
|
||||||
my ($inchainref, $outchainref, $kind, $source, $dest) = @_;
|
|
||||||
|
|
||||||
my $protocol = 'udp';
|
|
||||||
my $port = 1194;
|
|
||||||
|
|
||||||
( $kind, my ( $proto, $p , $remainder ) ) = split( /:/, $kind, 4 );
|
|
||||||
|
|
||||||
fatal_error "Invalid port ($p:$remainder)" if defined $remainder;
|
|
||||||
|
|
||||||
if ( defined $p && $p ne '' ) {
|
|
||||||
$port = $p;
|
|
||||||
$protocol = $proto;
|
|
||||||
} elsif ( defined $proto && $proto ne '' ) {
|
|
||||||
if ( "\L$proto" =~ /udp|tcp/ ) {
|
|
||||||
$protocol = $proto;
|
|
||||||
} else {
|
|
||||||
$port = $proto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add_tunnel_rule $inchainref, "-p $protocol $source --sport $port -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref, "-p $protocol $dest --dport $port -j ACCEPT";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_one_openvpn_server {
|
|
||||||
my ($inchainref, $outchainref, $kind, $source, $dest) = @_;
|
|
||||||
|
|
||||||
my $protocol = 'udp';
|
|
||||||
my $port = 1194;
|
|
||||||
|
|
||||||
( $kind, my ( $proto, $p , $remainder ) ) = split( /:/, $kind, 4 );
|
|
||||||
|
|
||||||
fatal_error "Invalid port ($p:$remainder)" if defined $remainder;
|
|
||||||
|
|
||||||
if ( defined $p && $p ne '' ) {
|
|
||||||
$port = $p;
|
|
||||||
$protocol = $proto;
|
|
||||||
} elsif ( defined $proto && $proto ne '' ) {
|
|
||||||
if ( "\L$proto" =~ /udp|tcp/ ) {
|
|
||||||
$protocol = $proto;
|
|
||||||
} else {
|
|
||||||
$port = $proto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add_tunnel_rule $inchainref, "-p $protocol $source --dport $port -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref, "-p $protocol $dest --sport $port -j ACCEPT";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_one_l2tp {
|
|
||||||
my ($inchainref, $outchainref, $kind, $source, $dest) = @_;
|
|
||||||
|
|
||||||
fatal_error "Unknown option ($1)" if $kind =~ /^.*?:(.*)$/;
|
|
||||||
|
|
||||||
add_tunnel_rule $inchainref, "-p udp $source --sport 1701 --dport 1701 -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref, "-p udp $dest --sport 1701 --dport 1701 -j ACCEPT";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_one_generic {
|
|
||||||
my ($inchainref, $outchainref, $kind, $source, $dest) = @_;
|
|
||||||
|
|
||||||
my $protocol = 'udp';
|
|
||||||
my $port = '--dport 5000';
|
|
||||||
|
|
||||||
if ( $kind =~ /.*:.*:.*/ ) {
|
|
||||||
( $kind, $protocol, $port) = split /:/, $kind;
|
|
||||||
$port = "--dport $port";
|
|
||||||
} else {
|
|
||||||
$port = '';
|
|
||||||
( $kind, $protocol ) = split /:/ , $kind if $kind =~ /.*:.*/;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_tunnel_rule $inchainref, "-p $protocol $source $port -j ACCEPT";
|
|
||||||
add_tunnel_rule $outchainref, "-p $protocol $dest $port -j ACCEPT";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_one_tunnel($$$$) {
|
|
||||||
my ( $kind , $zone, $gateway, $gatewayzones ) = @_;
|
|
||||||
|
|
||||||
my $zonetype = zone_type( $zone );
|
|
||||||
|
|
||||||
fatal_error "Invalid tunnel ZONE ($zone)" if $zonetype eq 'firewall' || $zonetype eq 'bport';
|
|
||||||
|
|
||||||
my $inchainref = ensure_filter_chain "${zone}2${fw}", 1;
|
|
||||||
my $outchainref = ensure_filter_chain "${fw}2${zone}", 1;
|
|
||||||
|
|
||||||
$gateway = ALLIP if $gateway eq '-';
|
|
||||||
|
|
||||||
my $source = match_source_net $gateway;
|
|
||||||
my $dest = match_dest_net $gateway;
|
|
||||||
|
|
||||||
my %tunneltypes = ( 'ipsec' => { function => \&setup_one_ipsec , params => [ $kind, $source, $dest , $gatewayzones ] } ,
|
|
||||||
'ipsecnat' => { function => \&setup_one_ipsec , params => [ $kind, $source, $dest , $gatewayzones ] } ,
|
|
||||||
'ipip' => { function => \&setup_one_other, params => [ $source, $dest , 4 ] } ,
|
|
||||||
'gre' => { function => \&setup_one_other, params => [ $source, $dest , 47 ] } ,
|
|
||||||
'6to4' => { function => \&setup_one_other, params => [ $source, $dest , 41 ] } ,
|
|
||||||
'pptpclient' => { function => \&setup_pptp_client, params => [ $kind, $source, $dest ] } ,
|
|
||||||
'pptpserver' => { function => \&setup_pptp_server, params => [ $kind, $source, $dest ] } ,
|
|
||||||
'openvpn' => { function => \&setup_one_openvpn, params => [ $kind, $source, $dest ] } ,
|
|
||||||
'openvpnclient' => { function => \&setup_one_openvpn_client, params => [ $kind, $source, $dest ] } ,
|
|
||||||
'openvpnserver' => { function => \&setup_one_openvpn_server, params => [ $kind, $source, $dest ] } ,
|
|
||||||
'l2tp' => { function => \&setup_one_l2tp , params => [ $kind, $source, $dest ] } ,
|
|
||||||
'generic' => { function => \&setup_one_generic , params => [ $kind, $source, $dest ] } ,
|
|
||||||
);
|
|
||||||
|
|
||||||
$kind = "\L$kind";
|
|
||||||
|
|
||||||
(my $type) = split /:/, $kind;
|
|
||||||
|
|
||||||
my $tunnelref = $tunneltypes{ $type };
|
|
||||||
|
|
||||||
fatal_error "Tunnels of type $type are not supported" unless $tunnelref;
|
|
||||||
|
|
||||||
$tunnelref->{function}->( $inchainref, $outchainref, @{$tunnelref->{params}} );
|
|
||||||
|
|
||||||
progress_message " Tunnel \"$currentline\" $done";
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Setup_Tunnels() Starts Here
|
|
||||||
#
|
|
||||||
my $fn = open_file 'tunnels';
|
|
||||||
|
|
||||||
first_entry "$doing $fn...";
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
my ( $kind, $zone, $gateway, $gatewayzones ) = split_line1 2, 4, 'tunnels file';
|
|
||||||
|
|
||||||
if ( $kind eq 'COMMENT' ) {
|
|
||||||
process_comment;
|
|
||||||
} else {
|
|
||||||
setup_one_tunnel $kind, $zone, $gateway, $gatewayzones;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
File diff suppressed because it is too large
Load Diff
@ -1,115 +0,0 @@
|
|||||||
#! /usr/bin/perl -w
|
|
||||||
#
|
|
||||||
# The Shoreline Firewall4 (Shorewall-perl) Packet Filtering Firewall Compiler - V4.2
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007,2008 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
#
|
|
||||||
# compiler.pl [ <option> ... ] [ <filename> ]
|
|
||||||
#
|
|
||||||
# Options:
|
|
||||||
#
|
|
||||||
# --export # Compile for export
|
|
||||||
# --verbosity=<number> # Set VERBOSITY range -1 to 2
|
|
||||||
# --directory=<directory> # Directory where configuration resides (default is /etc/shorewall)
|
|
||||||
# --timestamp # Timestamp all progress messages
|
|
||||||
# --debug # Print stack trace on warnings and fatal error.
|
|
||||||
# --refresh=<chainlist> # Make the 'refresh' command refresh a comma-separated list of chains rather than 'blacklst'.
|
|
||||||
# --log=<filename> # Log file
|
|
||||||
# --log_verbosity=<number> # Log Verbosity range -1 to 2
|
|
||||||
# --family=<number> # IP family; 4 = IPv4 (default), 6 = IPv6
|
|
||||||
#
|
|
||||||
use strict;
|
|
||||||
use FindBin;
|
|
||||||
use lib "$FindBin::Bin";
|
|
||||||
use Shorewall::Compiler;
|
|
||||||
use Getopt::Long;
|
|
||||||
|
|
||||||
sub usage( $ ) {
|
|
||||||
print STDERR 'usage: compiler.pl [ <option> ... ] [ <filename> ]
|
|
||||||
|
|
||||||
options are:
|
|
||||||
[ --export ]
|
|
||||||
[ --directory=<directory> ]
|
|
||||||
[ --verbose={-1|0-2} ]
|
|
||||||
[ --timestamp ]
|
|
||||||
[ --debug ]
|
|
||||||
[ --refresh=<chainlist> ]
|
|
||||||
[ --log=<filename> ]
|
|
||||||
[ --log-verbose={-1|0-2} ]
|
|
||||||
[ --test ]
|
|
||||||
[ --family={1|2} ]
|
|
||||||
';
|
|
||||||
exit shift @_;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# E x e c u t i o n B e g i n s H e r e
|
|
||||||
#
|
|
||||||
my $export = 0;
|
|
||||||
my $shorewall_dir = '';
|
|
||||||
my $verbose = 0;
|
|
||||||
my $timestamp = 0;
|
|
||||||
my $debug = 0;
|
|
||||||
my $chains = '';
|
|
||||||
my $log = '';
|
|
||||||
my $log_verbose = 0;
|
|
||||||
my $help = 0;
|
|
||||||
my $test = 0;
|
|
||||||
my $family = 4; # F_IPV4
|
|
||||||
|
|
||||||
Getopt::Long::Configure ('bundling');
|
|
||||||
|
|
||||||
my $result = GetOptions('h' => \$help,
|
|
||||||
'--help' => \$help,
|
|
||||||
'export' => \$export,
|
|
||||||
'e' => \$export,
|
|
||||||
'directory=s' => \$shorewall_dir,
|
|
||||||
'd=s' => \$shorewall_dir,
|
|
||||||
'verbose=i' => \$verbose,
|
|
||||||
'v=i' => \$verbose,
|
|
||||||
'timestamp' => \$timestamp,
|
|
||||||
't' => \$timestamp,
|
|
||||||
'debug' => \$debug,
|
|
||||||
'r=s' => \$chains,
|
|
||||||
'refresh=s' => \$chains,
|
|
||||||
'log=s' => \$log,
|
|
||||||
'l=s' => \$log,
|
|
||||||
'log_verbosity=i' => \$log_verbose,
|
|
||||||
'test' => \$test,
|
|
||||||
'f=i' => \$family,
|
|
||||||
'family=i' => \$family,
|
|
||||||
);
|
|
||||||
|
|
||||||
usage(1) unless $result && @ARGV < 2;
|
|
||||||
usage(0) if $help;
|
|
||||||
|
|
||||||
compiler( object => defined $ARGV[0] ? $ARGV[0] : '',
|
|
||||||
directory => $shorewall_dir,
|
|
||||||
verbosity => $verbose,
|
|
||||||
timestamp => $timestamp,
|
|
||||||
debug => $debug,
|
|
||||||
export => $export,
|
|
||||||
chains => $chains,
|
|
||||||
log => $log,
|
|
||||||
log_verbosity => $log_verbose,
|
|
||||||
test => $test,
|
|
||||||
family => $family );
|
|
@ -1,198 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Script to install Shorewall-perl.
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 2007,2008 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Shorewall documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
|
|
||||||
VERSION=4.3.5
|
|
||||||
|
|
||||||
usage() # $1 = exit status
|
|
||||||
{
|
|
||||||
ME=$(basename $0)
|
|
||||||
echo "usage: $ME"
|
|
||||||
echo " $ME -v"
|
|
||||||
echo " $ME -h"
|
|
||||||
echo " $ME -n"
|
|
||||||
exit $1
|
|
||||||
}
|
|
||||||
|
|
||||||
split() {
|
|
||||||
local ifs
|
|
||||||
ifs=$IFS
|
|
||||||
IFS=:
|
|
||||||
set -- $1
|
|
||||||
echo $*
|
|
||||||
IFS=$ifs
|
|
||||||
}
|
|
||||||
|
|
||||||
qt()
|
|
||||||
{
|
|
||||||
"$@" >/dev/null 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
mywhich() {
|
|
||||||
local dir
|
|
||||||
|
|
||||||
for dir in $(split $PATH); do
|
|
||||||
if [ -x $dir/$1 ]; then
|
|
||||||
echo $dir/$1
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
|
|
||||||
run_install()
|
|
||||||
{
|
|
||||||
if ! install $*; then
|
|
||||||
echo
|
|
||||||
echo "ERROR: Failed to install $*" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
delete_file() # $1 = file to delete
|
|
||||||
{
|
|
||||||
rm -f $1
|
|
||||||
}
|
|
||||||
|
|
||||||
install_file() # $1 = source $2 = target $3 = mode
|
|
||||||
{
|
|
||||||
run_install $OWNERSHIP -m $3 $1 ${2}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Parse the run line
|
|
||||||
#
|
|
||||||
# DEST is the SysVInit script directory
|
|
||||||
# INIT is the name of the script in the $DEST directory
|
|
||||||
# RUNLEVELS is the chkconfig parmeters for firewall
|
|
||||||
# ARGS is "yes" if we've already parsed an argument
|
|
||||||
#
|
|
||||||
ARGS=""
|
|
||||||
|
|
||||||
if [ -z "$DEST" ] ; then
|
|
||||||
DEST="/etc/init.d"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$INIT" ] ; then
|
|
||||||
INIT="shorewall"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$RUNLEVELS" ] ; then
|
|
||||||
RUNLEVELS=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
case $(uname) in
|
|
||||||
CYGWIN*)
|
|
||||||
DEST=
|
|
||||||
INIT=
|
|
||||||
OWNER=$(id -un)
|
|
||||||
GROUP=$(id -gn)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
[ -z "$OWNER" ] && OWNER=root
|
|
||||||
[ -z "$GROUP" ] && GROUP=root
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
NOBACKUP=
|
|
||||||
|
|
||||||
while [ $# -gt 0 ] ; do
|
|
||||||
case "$1" in
|
|
||||||
-h|help|?)
|
|
||||||
usage 0
|
|
||||||
;;
|
|
||||||
-v)
|
|
||||||
echo "Shorewall-perl Installer Version $VERSION"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
-n)
|
|
||||||
NOBACKUP=Yes
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
ARGS="yes"
|
|
||||||
done
|
|
||||||
|
|
||||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin
|
|
||||||
|
|
||||||
OWNERSHIP="-o $OWNER -g $GROUP"
|
|
||||||
|
|
||||||
if [ -n "$PREFIX" ]; then
|
|
||||||
if [ `id -u` != 0 ] ; then
|
|
||||||
echo "Not setting file owner/group permissions, not running as root."
|
|
||||||
OWNERSHIP=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
install -d $OWNERSHIP -m 755 ${PREFIX}/sbin
|
|
||||||
install -d $OWNERSHIP -m 755 ${PREFIX}${DEST}
|
|
||||||
fi
|
|
||||||
|
|
||||||
#
|
|
||||||
# Change to the directory containing this script
|
|
||||||
#
|
|
||||||
cd "$(dirname $0)"
|
|
||||||
|
|
||||||
echo "Installing Shorewall-perl Version $VERSION"
|
|
||||||
|
|
||||||
#
|
|
||||||
# /usr/share/shorewall-perl if needed
|
|
||||||
#
|
|
||||||
mkdir -p ${PREFIX}/usr/share/shorewall-perl/Shorewall
|
|
||||||
|
|
||||||
chmod 755 ${PREFIX}/usr/share/shorewall-perl
|
|
||||||
chmod 755 ${PREFIX}/usr/share/shorewall-perl/Shorewall
|
|
||||||
|
|
||||||
#
|
|
||||||
# Install the Compiler
|
|
||||||
#
|
|
||||||
|
|
||||||
install_file compiler.pl ${PREFIX}/usr/share/shorewall-perl/compiler.pl 0755
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "Compiler installed in ${PREFIX}/usr/share/shorewall-perl/compiler.pl"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Install the libraries
|
|
||||||
#
|
|
||||||
for f in Shorewall/*.pm ; do
|
|
||||||
install_file $f ${PREFIX}/usr/share/shorewall-perl/$f 0644
|
|
||||||
echo "Module ${f%.*} installed as ${PREFIX}/usr/share/shorewall-perl/$f"
|
|
||||||
done
|
|
||||||
|
|
||||||
#
|
|
||||||
# Install the program skeleton files
|
|
||||||
#
|
|
||||||
for f in prog.* ; do
|
|
||||||
install_file $f ${PREFIX}/usr/share/shorewall-perl/$f 0644
|
|
||||||
echo "Program skeleton file ${f#*.} installed as ${PREFIX}/usr/share/shorewall-perl/$f"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo $VERSION > ${PREFIX}/usr/share/shorewall-perl/version
|
|
||||||
#
|
|
||||||
# Report Success
|
|
||||||
#
|
|
||||||
echo "Shorewall-perl Version $VERSION Installed"
|
|
@ -1,201 +0,0 @@
|
|||||||
#
|
|
||||||
# Give Usage Information
|
|
||||||
#
|
|
||||||
usage() {
|
|
||||||
echo "Usage: $0 [ -q ] [ -v ] [ -n ] [ start|stop|clear|reset|refresh|restart|status|version ]"
|
|
||||||
exit $1
|
|
||||||
}
|
|
||||||
################################################################################
|
|
||||||
# E X E C U T I O N B E G I N S H E R E #
|
|
||||||
################################################################################
|
|
||||||
#
|
|
||||||
# Start trace if first arg is "debug" or "trace"
|
|
||||||
#
|
|
||||||
if [ $# -gt 1 ]; then
|
|
||||||
if [ "x$1" = "xtrace" ]; then
|
|
||||||
set -x
|
|
||||||
shift
|
|
||||||
elif [ "x$1" = "xdebug" ]; then
|
|
||||||
DEBUG=Yes
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
initialize
|
|
||||||
|
|
||||||
finished=0
|
|
||||||
|
|
||||||
while [ $finished -eq 0 -a $# -gt 0 ]; do
|
|
||||||
option=$1
|
|
||||||
case $option in
|
|
||||||
-*)
|
|
||||||
option=${option#-}
|
|
||||||
|
|
||||||
[ -z "$option" ] && usage 1
|
|
||||||
|
|
||||||
while [ -n "$option" ]; do
|
|
||||||
case $option in
|
|
||||||
v*)
|
|
||||||
VERBOSE=$(($VERBOSE + 1 ))
|
|
||||||
option=${option#v}
|
|
||||||
;;
|
|
||||||
q*)
|
|
||||||
VERBOSE=$(($VERBOSE - 1 ))
|
|
||||||
option=${option#q}
|
|
||||||
;;
|
|
||||||
n*)
|
|
||||||
NOROUTES=Yes
|
|
||||||
option=${option#n}
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
finished=1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
COMMAND="$1"
|
|
||||||
|
|
||||||
[ -n "${PRODUCT:=Shorewall}" ]
|
|
||||||
|
|
||||||
case "$COMMAND" in
|
|
||||||
start)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
if shorewall_is_started; then
|
|
||||||
error_message "$PRODUCT is already Running"
|
|
||||||
status=0
|
|
||||||
else
|
|
||||||
progress_message3 "Starting $PRODUCT...."
|
|
||||||
define_firewall
|
|
||||||
status=$?
|
|
||||||
[ -n "$SUBSYSLOCK" -a $status -eq 0 ] && touch $SUBSYSLOCK
|
|
||||||
progress_message3 "done."
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
progress_message3 "Stopping $PRODUCT...."
|
|
||||||
stop_firewall
|
|
||||||
status=0
|
|
||||||
[ -n "$SUBSYSLOCK" ] && rm -f $SUBSYSLOCK
|
|
||||||
progress_message3 "done."
|
|
||||||
;;
|
|
||||||
reset)
|
|
||||||
if ! shorewall_is_started ; then
|
|
||||||
error_message "$PRODUCT is not running"
|
|
||||||
status=2
|
|
||||||
elif [ $# -eq 1 ]; then
|
|
||||||
$IPTABLES -Z
|
|
||||||
$IPTABLES -t nat -Z
|
|
||||||
$IPTABLES -t mangle -Z
|
|
||||||
date > ${VARDIR}/restarted
|
|
||||||
status=0
|
|
||||||
progress_message3 "$PRODUCT Counters Reset"
|
|
||||||
else
|
|
||||||
shift
|
|
||||||
status=0
|
|
||||||
for chain in $@; do
|
|
||||||
if chain_exists $chain; then
|
|
||||||
if qt $IPTABLES -Z $chain; then
|
|
||||||
progress_message3 "Filter $chain Counters Reset"
|
|
||||||
else
|
|
||||||
error_message "ERROR: Reset of chain $chain failed"
|
|
||||||
status=2
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
error_message "WARNING: Filter Chain $chain does not exist"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
if shorewall_is_started; then
|
|
||||||
progress_message3 "Restarting $PRODUCT...."
|
|
||||||
else
|
|
||||||
error_message "$PRODUCT is not running"
|
|
||||||
progress_message3 "Starting $PRODUCT...."
|
|
||||||
fi
|
|
||||||
|
|
||||||
define_firewall
|
|
||||||
status=$?
|
|
||||||
if [ -n "$SUBSYSLOCK" ]; then
|
|
||||||
[ $status -eq 0 ] && touch $SUBSYSLOCK || rm -f $SUBSYSLOCK
|
|
||||||
fi
|
|
||||||
progress_message3 "done."
|
|
||||||
;;
|
|
||||||
refresh)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
if shorewall_is_started; then
|
|
||||||
progress_message3 "Refreshing $PRODUCT...."
|
|
||||||
define_firewall
|
|
||||||
status=$?
|
|
||||||
progress_message3 "done."
|
|
||||||
else
|
|
||||||
echo "$PRODUCT is not running" >&2
|
|
||||||
status=2
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
restore)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
define_firewall
|
|
||||||
status=$?
|
|
||||||
if [ -n "$SUBSYSLOCK" ]; then
|
|
||||||
[ $status -eq 0 ] && touch $SUBSYSLOCK || rm -f $SUBSYSLOCK
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
clear)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
progress_message3 "Clearing $PRODUCT...."
|
|
||||||
clear_firewall
|
|
||||||
status=0
|
|
||||||
[ -n "$SUBSYSLOCK" ] && rm -f $SUBSYSLOCK
|
|
||||||
progress_message3 "done."
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
echo "$PRODUCT-$VERSION Status at $HOSTNAME - $(date)"
|
|
||||||
echo
|
|
||||||
if shorewall_is_started; then
|
|
||||||
echo "$PRODUCT is running"
|
|
||||||
status=0
|
|
||||||
else
|
|
||||||
echo "$PRODUCT is stopped"
|
|
||||||
status=4
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f ${VARDIR}/state ]; then
|
|
||||||
state="$(cat ${VARDIR}/state)"
|
|
||||||
case $state in
|
|
||||||
Stopped*|Clear*)
|
|
||||||
status=3
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
state=Unknown
|
|
||||||
fi
|
|
||||||
echo "State:$state"
|
|
||||||
echo
|
|
||||||
;;
|
|
||||||
version)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
echo $VERSION
|
|
||||||
status=0
|
|
||||||
;;
|
|
||||||
help)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
usage 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage 2
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
exit $status
|
|
@ -1,206 +0,0 @@
|
|||||||
#
|
|
||||||
# Give Usage Information
|
|
||||||
#
|
|
||||||
usage() {
|
|
||||||
echo "Usage: $0 [ -q ] [ -v ] [ -n ] [ start|stop|clear|reset|refresh|restart|status|version ]"
|
|
||||||
exit $1
|
|
||||||
}
|
|
||||||
################################################################################
|
|
||||||
# E X E C U T I O N B E G I N S H E R E #
|
|
||||||
################################################################################
|
|
||||||
#
|
|
||||||
# Start trace if first arg is "debug" or "trace"
|
|
||||||
#
|
|
||||||
if [ $# -gt 1 ]; then
|
|
||||||
if [ "x$1" = "xtrace" ]; then
|
|
||||||
set -x
|
|
||||||
shift
|
|
||||||
elif [ "x$1" = "xdebug" ]; then
|
|
||||||
DEBUG=Yes
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
initialize
|
|
||||||
|
|
||||||
finished=0
|
|
||||||
|
|
||||||
while [ $finished -eq 0 -a $# -gt 0 ]; do
|
|
||||||
option=$1
|
|
||||||
case $option in
|
|
||||||
-*)
|
|
||||||
option=${option#-}
|
|
||||||
|
|
||||||
[ -z "$option" ] && usage 1
|
|
||||||
|
|
||||||
while [ -n "$option" ]; do
|
|
||||||
case $option in
|
|
||||||
v*)
|
|
||||||
VERBOSE=$(($VERBOSE + 1 ))
|
|
||||||
option=${option#v}
|
|
||||||
;;
|
|
||||||
q*)
|
|
||||||
VERBOSE=$(($VERBOSE - 1 ))
|
|
||||||
option=${option#q}
|
|
||||||
;;
|
|
||||||
n*)
|
|
||||||
NOROUTES=Yes
|
|
||||||
option=${option#n}
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
finished=1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
COMMAND="$1"
|
|
||||||
|
|
||||||
[ -n "${PRODUCT:=Shorewall6}" ]
|
|
||||||
|
|
||||||
kernel=$(printf "%2d%02d%02d\n" $(echo $(uname -r) 2> /dev/null | sed 's/-.*//' | tr '.' ' ' ) | head -n1)
|
|
||||||
if [ $kernel -lt 20625 ]; then
|
|
||||||
error_message "ERROR: $PRODUCT requires Linux kernel 2.6.25 or later"
|
|
||||||
status=2
|
|
||||||
else
|
|
||||||
case "$COMMAND" in
|
|
||||||
start)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
if shorewall6_is_started; then
|
|
||||||
error_message "$PRODUCT is already Running"
|
|
||||||
status=0
|
|
||||||
else
|
|
||||||
progress_message3 "Starting $PRODUCT...."
|
|
||||||
define_firewall
|
|
||||||
status=$?
|
|
||||||
[ -n "$SUBSYSLOCK" -a $status -eq 0 ] && touch $SUBSYSLOCK
|
|
||||||
progress_message3 "done."
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
progress_message3 "Stopping $PRODUCT...."
|
|
||||||
stop_firewall
|
|
||||||
status=0
|
|
||||||
[ -n "$SUBSYSLOCK" ] && rm -f $SUBSYSLOCK
|
|
||||||
progress_message3 "done."
|
|
||||||
;;
|
|
||||||
reset)
|
|
||||||
if ! shorewall6_is_started ; then
|
|
||||||
error_message "$PRODUCT is not running"
|
|
||||||
status=2
|
|
||||||
elif [ $# -eq 1 ]; then
|
|
||||||
$IP6TABLES -Z
|
|
||||||
$IP6TABLES -t mangle -Z
|
|
||||||
date > ${VARDIR}/restarted
|
|
||||||
status=0
|
|
||||||
progress_message3 "$PRODUCT Counters Reset"
|
|
||||||
else
|
|
||||||
shift
|
|
||||||
status=0
|
|
||||||
for chain in $@; do
|
|
||||||
if chain_exists $chain; then
|
|
||||||
if qt $IP6TABLES -Z $chain; then
|
|
||||||
progress_message3 "Filter $chain Counters Reset"
|
|
||||||
else
|
|
||||||
error_message "ERROR: Reset of chain $chain failed"
|
|
||||||
status=2
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
error_message "WARNING: Filter Chain $chain does not exist"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
if shorewall6_is_started; then
|
|
||||||
progress_message3 "Restarting $PRODUCT...."
|
|
||||||
else
|
|
||||||
error_message "$PRODUCT is not running"
|
|
||||||
progress_message3 "Starting $PRODUCT...."
|
|
||||||
fi
|
|
||||||
|
|
||||||
define_firewall
|
|
||||||
status=$?
|
|
||||||
if [ -n "$SUBSYSLOCK" ]; then
|
|
||||||
[ $status -eq 0 ] && touch $SUBSYSLOCK || rm -f $SUBSYSLOCK
|
|
||||||
fi
|
|
||||||
progress_message3 "done."
|
|
||||||
;;
|
|
||||||
refresh)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
if shorewall6_is_started; then
|
|
||||||
progress_message3 "Refreshing $PRODUCT...."
|
|
||||||
define_firewall
|
|
||||||
status=$?
|
|
||||||
progress_message3 "done."
|
|
||||||
else
|
|
||||||
echo "$PRODUCT is not running" >&2
|
|
||||||
status=2
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
restore)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
define_firewall
|
|
||||||
status=$?
|
|
||||||
if [ -n "$SUBSYSLOCK" ]; then
|
|
||||||
[ $status -eq 0 ] && touch $SUBSYSLOCK || rm -f $SUBSYSLOCK
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
clear)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
progress_message3 "Clearing $PRODUCT...."
|
|
||||||
clear_firewall
|
|
||||||
status=0
|
|
||||||
[ -n "$SUBSYSLOCK" ] && rm -f $SUBSYSLOCK
|
|
||||||
progress_message3 "done."
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
echo "$PRODUCT-$VERSION Status at $HOSTNAME - $(date)"
|
|
||||||
echo
|
|
||||||
if shorewall6_is_started; then
|
|
||||||
echo "$PRODUCT is running"
|
|
||||||
status=0
|
|
||||||
else
|
|
||||||
echo "$PRODUCT is stopped"
|
|
||||||
status=4
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f ${VARDIR}/state ]; then
|
|
||||||
state="$(cat ${VARDIR}/state)"
|
|
||||||
case $state in
|
|
||||||
Stopped*|Clear*)
|
|
||||||
status=3
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
state=Unknown
|
|
||||||
fi
|
|
||||||
echo "State:$state"
|
|
||||||
echo
|
|
||||||
;;
|
|
||||||
version)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
echo $VERSION
|
|
||||||
status=0
|
|
||||||
;;
|
|
||||||
help)
|
|
||||||
[ $# -ne 1 ] && usage 2
|
|
||||||
usage 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage 2
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit $status
|
|
@ -1,273 +0,0 @@
|
|||||||
#
|
|
||||||
# Clear Proxy Arp
|
|
||||||
#
|
|
||||||
delete_proxyarp() {
|
|
||||||
if [ -f ${VARDIR}/proxyarp ]; then
|
|
||||||
while read address interface external haveroute; do
|
|
||||||
qt arp -i $external -d $address pub
|
|
||||||
[ -z "${haveroute}${NOROUTES}" ] && qt ip -4 route del $address dev $interface
|
|
||||||
f=/proc/sys/net/ipv4/conf/$interface/proxy_arp
|
|
||||||
[ -f $f ] && echo 0 > $f
|
|
||||||
done < ${VARDIR}/proxyarp
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f ${VARDIR}/proxyarp
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Remove all Shorewall-added rules
|
|
||||||
#
|
|
||||||
clear_firewall() {
|
|
||||||
stop_firewall
|
|
||||||
|
|
||||||
setpolicy INPUT ACCEPT
|
|
||||||
setpolicy FORWARD ACCEPT
|
|
||||||
setpolicy OUTPUT ACCEPT
|
|
||||||
|
|
||||||
run_iptables -F
|
|
||||||
|
|
||||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
|
||||||
|
|
||||||
if [ -n "$DISABLE_IPV6" ]; then
|
|
||||||
if qt mywhich ip6tables; then
|
|
||||||
ip6tables -P INPUT ACCEPT 2> /dev/null
|
|
||||||
ip6tables -P OUTPUT ACCEPT 2> /dev/null
|
|
||||||
ip6tables -P FORWARD ACCEPT 2> /dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
run_clear_exit
|
|
||||||
|
|
||||||
set_state "Cleared"
|
|
||||||
|
|
||||||
logger -p kern.info "$PRODUCT Cleared"
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Issue a message and stop/restore the firewall
|
|
||||||
#
|
|
||||||
fatal_error()
|
|
||||||
{
|
|
||||||
echo " ERROR: $@" >&2
|
|
||||||
|
|
||||||
if [ $LOG_VERBOSE -gt 1 ]; then
|
|
||||||
timestamp="$(date +'%_b %d %T') "
|
|
||||||
echo "${timestamp} ERROR: $@" >> $STARTUP_LOG
|
|
||||||
fi
|
|
||||||
|
|
||||||
stop_firewall
|
|
||||||
[ -n "$TEMPFILE" ] && rm -f $TEMPFILE
|
|
||||||
exit 2
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Issue a message and stop
|
|
||||||
#
|
|
||||||
startup_error() # $* = Error Message
|
|
||||||
{
|
|
||||||
echo " ERROR: $@" >&2
|
|
||||||
case $COMMAND in
|
|
||||||
start)
|
|
||||||
logger -p kern.err "ERROR:$PRODUCT start failed"
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
logger -p kern.err "ERROR:$PRODUCT restart failed"
|
|
||||||
;;
|
|
||||||
restore)
|
|
||||||
logger -p kern.err "ERROR:$PRODUCT restore failed"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ $LOG_VERBOSE -gt 1 ]; then
|
|
||||||
timestamp="$(date +'%_b %d %T') "
|
|
||||||
|
|
||||||
case $COMMAND in
|
|
||||||
start)
|
|
||||||
echo "${timestamp} ERROR:$PRODUCT start failed" >> $STARTUP_LOG
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
echo "${timestamp} ERROR:$PRODUCT restart failed" >> $STARTUP_LOG
|
|
||||||
;;
|
|
||||||
restore)
|
|
||||||
echo "${timestamp} ERROR:$PRODUCT restore failed" >> $STARTUP_LOG
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
kill $$
|
|
||||||
exit 2
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run iptables and if an error occurs, stop/restore the firewall
|
|
||||||
#
|
|
||||||
run_iptables()
|
|
||||||
{
|
|
||||||
local status
|
|
||||||
|
|
||||||
while [ 1 ]; do
|
|
||||||
$IPTABLES $@
|
|
||||||
status=$?
|
|
||||||
[ $status -ne 4 ] && break
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ $status -ne 0 ]; then
|
|
||||||
error_message "ERROR: Command \"$IPTABLES $@\" Failed"
|
|
||||||
stop_firewall
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run iptables retrying exit status 4
|
|
||||||
#
|
|
||||||
do_iptables()
|
|
||||||
{
|
|
||||||
local status
|
|
||||||
|
|
||||||
while [ 1 ]; do
|
|
||||||
$IPTABLES $@
|
|
||||||
status=$?
|
|
||||||
[ $status -ne 4 ] && return $status;
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run iptables and if an error occurs, stop/restore the firewall
|
|
||||||
#
|
|
||||||
run_ip()
|
|
||||||
{
|
|
||||||
if ! ip -4 $@; then
|
|
||||||
error_message "ERROR: Command \"ip -4 $@\" Failed"
|
|
||||||
stop_firewall
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run tc and if an error occurs, stop/restore the firewall
|
|
||||||
#
|
|
||||||
run_tc() {
|
|
||||||
if ! tc $@ ; then
|
|
||||||
error_message "ERROR: Command \"tc $@\" Failed"
|
|
||||||
stop_firewall
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
restore_dynamic_rules() {
|
|
||||||
if [ -f ${VARDIR}/save ]; then
|
|
||||||
progress_message2 "Setting up dynamic rules..."
|
|
||||||
rangematch='source IP range'
|
|
||||||
while read target ignore1 ignore2 address ignore3 rest; do
|
|
||||||
case $target in
|
|
||||||
DROP|reject|logdrop|logreject)
|
|
||||||
case $rest in
|
|
||||||
$rangematch*)
|
|
||||||
run_iptables -A dynamic -m iprange --src-range ${rest#source IP range} -j $target
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [ -z "$rest" ]; then
|
|
||||||
run_iptables -A dynamic -s $address -j $target
|
|
||||||
else
|
|
||||||
error_message "WARNING: Unable to restore dynamic rule \"$target $ignore1 $ignore2 $address $ignore3 $rest\""
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done < ${VARDIR}/save
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Get a list of all configured broadcast addresses on the system
|
|
||||||
#
|
|
||||||
get_all_bcasts()
|
|
||||||
{
|
|
||||||
ip -f inet addr show 2> /dev/null | grep 'inet.*brd' | sed 's/inet.*brd //; s/scope.*//;' | sort -u
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run the .iptables_restore_input as a set of discrete iptables commands
|
|
||||||
#
|
|
||||||
debug_restore_input() {
|
|
||||||
local first second rest table chain
|
|
||||||
#
|
|
||||||
# Clear the ruleset
|
|
||||||
#
|
|
||||||
qt1 $IPTABLES -t mangle -F
|
|
||||||
qt1 $IPTABLES -t mangle -X
|
|
||||||
|
|
||||||
for chain in PREROUTING INPUT FORWARD POSTROUTING; do
|
|
||||||
qt1 $IPTABLES -t mangle -P $chain ACCEPT
|
|
||||||
done
|
|
||||||
|
|
||||||
qt1 $IPTABLES -t raw -F
|
|
||||||
qt1 $IPTABLES -t raw -X
|
|
||||||
|
|
||||||
for chain in PREROUTING OUTPUT; do
|
|
||||||
qt1 $IPTABLES -t raw -P $chain ACCEPT
|
|
||||||
done
|
|
||||||
|
|
||||||
run_iptables -t nat -F
|
|
||||||
run_iptables -t nat -X
|
|
||||||
|
|
||||||
for chain in PREROUTING POSTROUTING OUTPUT; do
|
|
||||||
qt1 $IPTABLES -t nat -P $chain ACCEPT
|
|
||||||
done
|
|
||||||
|
|
||||||
qt1 $IPTABLES -t filter -F
|
|
||||||
qt1 $IPTABLES -t filter -X
|
|
||||||
|
|
||||||
for chain in INPUT FORWARD OUTPUT; do
|
|
||||||
qt1 $IPTABLES -t filter -P $chain -P ACCEPT
|
|
||||||
done
|
|
||||||
|
|
||||||
while read first second rest; do
|
|
||||||
case $first in
|
|
||||||
-*)
|
|
||||||
#
|
|
||||||
# We can't call run_iptables() here because the rules may contain quoted strings
|
|
||||||
#
|
|
||||||
eval $IPTABLES -t $table $first $second $rest
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
error_message "ERROR: Command \"$IPTABLES $first $second $rest\" Failed"
|
|
||||||
stop_firewall
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
:*)
|
|
||||||
chain=${first#:}
|
|
||||||
|
|
||||||
if [ "x$second" = x- ]; then
|
|
||||||
do_iptables -t $table -N $chain
|
|
||||||
else
|
|
||||||
do_iptables -t $table -P $chain $second
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
error_message "ERROR: Command \"$IPTABLES $first $second $rest\" Failed"
|
|
||||||
stop_firewall
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
#
|
|
||||||
# This grotesque hack with the table names works around a bug/feature with ash
|
|
||||||
#
|
|
||||||
'*'raw)
|
|
||||||
table=raw
|
|
||||||
;;
|
|
||||||
'*'mangle)
|
|
||||||
table=mangle
|
|
||||||
;;
|
|
||||||
'*'nat)
|
|
||||||
table=nat
|
|
||||||
;;
|
|
||||||
'*'filter)
|
|
||||||
table=filter
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
@ -1,234 +0,0 @@
|
|||||||
#
|
|
||||||
# Remove all Shorewall-added rules
|
|
||||||
#
|
|
||||||
clear_firewall() {
|
|
||||||
stop_firewall
|
|
||||||
|
|
||||||
setpolicy INPUT ACCEPT
|
|
||||||
setpolicy FORWARD ACCEPT
|
|
||||||
setpolicy OUTPUT ACCEPT
|
|
||||||
|
|
||||||
run_iptables -F
|
|
||||||
|
|
||||||
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
|
|
||||||
|
|
||||||
run_clear_exit
|
|
||||||
|
|
||||||
set_state "Cleared"
|
|
||||||
|
|
||||||
logger -p kern.info "$PRODUCT Cleared"
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Issue a message and stop/restore the firewall
|
|
||||||
#
|
|
||||||
fatal_error()
|
|
||||||
{
|
|
||||||
echo " ERROR: $@" >&2
|
|
||||||
|
|
||||||
if [ $LOG_VERBOSE -gt 1 ]; then
|
|
||||||
timestamp="$(date +'%_b %d %T') "
|
|
||||||
echo "${timestamp} ERROR: $@" >> $STARTUP_LOG
|
|
||||||
fi
|
|
||||||
|
|
||||||
stop_firewall
|
|
||||||
[ -n "$TEMPFILE" ] && rm -f $TEMPFILE
|
|
||||||
exit 2
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Issue a message and stop
|
|
||||||
#
|
|
||||||
startup_error() # $* = Error Message
|
|
||||||
{
|
|
||||||
echo " ERROR: $@" >&2
|
|
||||||
case $COMMAND in
|
|
||||||
start)
|
|
||||||
logger -p kern.err "ERROR:$PRODUCT start failed"
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
logger -p kern.err "ERROR:$PRODUCT restart failed"
|
|
||||||
;;
|
|
||||||
restore)
|
|
||||||
logger -p kern.err "ERROR:$PRODUCT restore failed"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ $LOG_VERBOSE -gt 1 ]; then
|
|
||||||
timestamp="$(date +'%_b %d %T') "
|
|
||||||
|
|
||||||
case $COMMAND in
|
|
||||||
start)
|
|
||||||
echo "${timestamp} ERROR:$PRODUCT start failed" >> $STARTUP_LOG
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
echo "${timestamp} ERROR:$PRODUCT restart failed" >> $STARTUP_LOG
|
|
||||||
;;
|
|
||||||
restore)
|
|
||||||
echo "${timestamp} ERROR:$PRODUCT restore failed" >> $STARTUP_LOG
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
kill $$
|
|
||||||
exit 2
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run iptables and if an error occurs, stop/restore the firewall
|
|
||||||
#
|
|
||||||
run_iptables()
|
|
||||||
{
|
|
||||||
local status
|
|
||||||
|
|
||||||
while [ 1 ]; do
|
|
||||||
$IP6TABLES $@
|
|
||||||
status=$?
|
|
||||||
[ $status -ne 4 ] && break
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ $status -ne 0 ]; then
|
|
||||||
error_message "ERROR: Command \"$IP6TABLES $@\" Failed"
|
|
||||||
stop_firewall
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run iptables retrying exit status 4
|
|
||||||
#
|
|
||||||
do_iptables()
|
|
||||||
{
|
|
||||||
local status
|
|
||||||
|
|
||||||
while [ 1 ]; do
|
|
||||||
$IP6TABLES $@
|
|
||||||
status=$?
|
|
||||||
[ $status -ne 4 ] && return $status;
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run iptables and if an error occurs, stop/restore the firewall
|
|
||||||
#
|
|
||||||
run_ip()
|
|
||||||
{
|
|
||||||
if ! ip -6 $@; then
|
|
||||||
error_message "ERROR: Command \"ip -6 $@\" Failed"
|
|
||||||
stop_firewall
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run tc and if an error occurs, stop/restore the firewall
|
|
||||||
#
|
|
||||||
run_tc() {
|
|
||||||
if ! tc $@ ; then
|
|
||||||
error_message "ERROR: Command \"tc $@\" Failed"
|
|
||||||
stop_firewall
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
restore_dynamic_rules() {
|
|
||||||
if [ -f ${VARDIR}/save ]; then
|
|
||||||
progress_message2 "Setting up dynamic rules..."
|
|
||||||
rangematch='source IP range'
|
|
||||||
while read target ignore1 ignore2 address ignore3 rest; do
|
|
||||||
case $target in
|
|
||||||
DROP|reject|logdrop|logreject)
|
|
||||||
case $rest in
|
|
||||||
$rangematch*)
|
|
||||||
run_iptables -A dynamic -m iprange --src-range ${rest#source IP range} -j $target
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [ -z "$rest" ]; then
|
|
||||||
run_iptables -A dynamic -s $address -j $target
|
|
||||||
else
|
|
||||||
error_message "WARNING: Unable to restore dynamic rule \"$target $ignore1 $ignore2 $address $ignore3 $rest\""
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done < ${VARDIR}/save
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run the .iptables_restore_input as a set of discrete iptables commands
|
|
||||||
#
|
|
||||||
debug_restore_input() {
|
|
||||||
local first second rest table chain
|
|
||||||
#
|
|
||||||
# Clear the ruleset
|
|
||||||
#
|
|
||||||
qt1 $IP6TABLES -t mangle -F
|
|
||||||
qt1 $IP6TABLES -t mangle -X
|
|
||||||
|
|
||||||
for chain in PREROUTING INPUT FORWARD POSTROUTING; do
|
|
||||||
qt1 $IP6TABLES -t mangle -P $chain ACCEPT
|
|
||||||
done
|
|
||||||
|
|
||||||
qt1 $IP6TABLES -t raw -F
|
|
||||||
qt1 $IP6TABLES -t raw -X
|
|
||||||
|
|
||||||
for chain in PREROUTING OUTPUT; do
|
|
||||||
qt1 $IP6TABLES -t raw -P $chain ACCEPT
|
|
||||||
done
|
|
||||||
|
|
||||||
qt1 $IP6TABLES -t filter -F
|
|
||||||
qt1 $IP6TABLES -t filter -X
|
|
||||||
|
|
||||||
for chain in INPUT FORWARD OUTPUT; do
|
|
||||||
qt1 $IP6TABLES -t filter -P $chain -P ACCEPT
|
|
||||||
done
|
|
||||||
|
|
||||||
while read first second rest; do
|
|
||||||
case $first in
|
|
||||||
-*)
|
|
||||||
#
|
|
||||||
# We can't call run_iptables() here because the rules may contain quoted strings
|
|
||||||
#
|
|
||||||
eval $IP6TABLES -t $table $first $second $rest
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
error_message "ERROR: Command \"$IP6TABLES $first $second $rest\" Failed"
|
|
||||||
stop_firewall
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
:*)
|
|
||||||
chain=${first#:}
|
|
||||||
|
|
||||||
if [ "x$second" = x- ]; then
|
|
||||||
do_iptables -t $table -N $chain
|
|
||||||
else
|
|
||||||
do_iptables -t $table -P $chain $second
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
error_message "ERROR: Command \"$IP6TABLES $first $second $rest\" Failed"
|
|
||||||
stop_firewall
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
#
|
|
||||||
# This grotesque hack with the table names works around a bug/feature with ash
|
|
||||||
#
|
|
||||||
'*'raw)
|
|
||||||
table=raw
|
|
||||||
;;
|
|
||||||
'*'mangle)
|
|
||||||
table=mangle
|
|
||||||
;;
|
|
||||||
'*'nat)
|
|
||||||
table=nat
|
|
||||||
;;
|
|
||||||
'*'filter)
|
|
||||||
table=filter
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,954 +0,0 @@
|
|||||||
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
||||||
#
|
|
||||||
# (c) 1999-2009 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Options are:
|
|
||||||
#
|
|
||||||
# -n Don't alter Routing
|
|
||||||
# -v and -q Standard Shorewall Verbosity control
|
|
||||||
#
|
|
||||||
# Commands are:
|
|
||||||
#
|
|
||||||
# start Starts the firewall
|
|
||||||
# refresh Refresh the firewall
|
|
||||||
# restart Restarts the firewall
|
|
||||||
# reload Reload the firewall
|
|
||||||
# clear Removes all firewall rules
|
|
||||||
# stop Stops the firewall
|
|
||||||
# status Displays firewall status
|
|
||||||
# version Displays the version of Shorewall that
|
|
||||||
# generated this program
|
|
||||||
#
|
|
||||||
################################################################################
|
|
||||||
# Functions imported from /usr/share/shorewall/lib.base
|
|
||||||
################################################################################
|
|
||||||
#
|
|
||||||
# Message to stderr
|
|
||||||
#
|
|
||||||
error_message() # $* = Error Message
|
|
||||||
{
|
|
||||||
echo " $@" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Conditionally produce message
|
|
||||||
#
|
|
||||||
progress_message() # $* = Message
|
|
||||||
{
|
|
||||||
local timestamp
|
|
||||||
timestamp=
|
|
||||||
|
|
||||||
if [ $VERBOSE -gt 1 ]; then
|
|
||||||
[ -n "$TIMESTAMP" ] && timestamp="$(date +%H:%M:%S) "
|
|
||||||
echo "${timestamp}$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $LOG_VERBOSE -gt 1 ]; then
|
|
||||||
timestamp="$(date +'%b %_d %T') "
|
|
||||||
echo "${timestamp}$@" >> $STARTUP_LOG
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
progress_message2() # $* = Message
|
|
||||||
{
|
|
||||||
local timestamp
|
|
||||||
timestamp=
|
|
||||||
|
|
||||||
if [ $VERBOSE -gt 0 ]; then
|
|
||||||
[ -n "$TIMESTAMP" ] && timestamp="$(date +%H:%M:%S) "
|
|
||||||
echo "${timestamp}$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $LOG_VERBOSE -gt 0 ]; then
|
|
||||||
timestamp="$(date +'%b %_d %T') "
|
|
||||||
echo "${timestamp}$@" >> $STARTUP_LOG
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
progress_message3() # $* = Message
|
|
||||||
{
|
|
||||||
local timestamp
|
|
||||||
timestamp=
|
|
||||||
|
|
||||||
if [ $VERBOSE -ge 0 ]; then
|
|
||||||
[ -n "$TIMESTAMP" ] && timestamp="$(date +%H:%M:%S) "
|
|
||||||
echo "${timestamp}$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $LOG_VERBOSE -ge 0 ]; then
|
|
||||||
timestamp="$(date +'%b %_d %T') "
|
|
||||||
echo "${timestamp}$@" >> $STARTUP_LOG
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Split a colon-separated list into a space-separated list
|
|
||||||
#
|
|
||||||
split() {
|
|
||||||
local ifs
|
|
||||||
ifs=$IFS
|
|
||||||
IFS=:
|
|
||||||
echo $*
|
|
||||||
IFS=$ifs
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Undo the effect of 'split()'
|
|
||||||
#
|
|
||||||
join()
|
|
||||||
{
|
|
||||||
local f
|
|
||||||
local o
|
|
||||||
o=
|
|
||||||
|
|
||||||
for f in $* ; do
|
|
||||||
o="${o:+$o:}$f"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo $o
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Return the number of elements in a list
|
|
||||||
#
|
|
||||||
list_count() # $* = list
|
|
||||||
{
|
|
||||||
return $#
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Search a list looking for a match -- returns zero if a match found
|
|
||||||
# 1 otherwise
|
|
||||||
#
|
|
||||||
list_search() # $1 = element to search for , $2-$n = list
|
|
||||||
{
|
|
||||||
local e
|
|
||||||
e=$1
|
|
||||||
|
|
||||||
while [ $# -gt 1 ]; do
|
|
||||||
shift
|
|
||||||
[ "x$e" = "x$1" ] && return 0
|
|
||||||
done
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Suppress all output for a command
|
|
||||||
#
|
|
||||||
qt()
|
|
||||||
{
|
|
||||||
"$@" >/dev/null 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
qt1()
|
|
||||||
{
|
|
||||||
local status
|
|
||||||
|
|
||||||
while [ 1 ]; do
|
|
||||||
"$@" >/dev/null 2>&1
|
|
||||||
status=$?
|
|
||||||
[ $status -ne 4 ] && return $status
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Determine if Shorewall is "running"
|
|
||||||
#
|
|
||||||
shorewall6_is_started() {
|
|
||||||
qt1 $IP6TABLES -L shorewall -n
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Echos the fully-qualified name of the calling shell program
|
|
||||||
#
|
|
||||||
my_pathname() {
|
|
||||||
cd $(dirname $0)
|
|
||||||
echo $PWD/$(basename $0)
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Source a user exit file if it exists
|
|
||||||
#
|
|
||||||
run_user_exit() # $1 = file name
|
|
||||||
{
|
|
||||||
local user_exit
|
|
||||||
user_exit=$(find_file $1)
|
|
||||||
|
|
||||||
if [ -f $user_exit ]; then
|
|
||||||
progress_message "Processing $user_exit ..."
|
|
||||||
. $user_exit
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Set a standard chain's policy
|
|
||||||
#
|
|
||||||
setpolicy() # $1 = name of chain, $2 = policy
|
|
||||||
{
|
|
||||||
run_iptables -P $1 $2
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Set a standard chain to enable established and related connections
|
|
||||||
#
|
|
||||||
setcontinue() # $1 = name of chain
|
|
||||||
{
|
|
||||||
run_iptables -A $1 -m state --state ESTABLISHED,RELATED -j ACCEPT
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Flush one of the Mangle table chains
|
|
||||||
#
|
|
||||||
flushmangle() # $1 = name of chain
|
|
||||||
{
|
|
||||||
run_iptables -t mangle -F $1
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Flush and delete all user-defined chains in the filter table
|
|
||||||
#
|
|
||||||
deleteallchains() {
|
|
||||||
run_iptables -F
|
|
||||||
run_iptables -X
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Load a Kernel Module -- assumes that the variable 'moduledirectories' contains
|
|
||||||
# a space-separated list of directories to search for
|
|
||||||
# the module and that 'moduleloader' contains the
|
|
||||||
# module loader command.
|
|
||||||
#
|
|
||||||
loadmodule() # $1 = module name, $2 - * arguments
|
|
||||||
{
|
|
||||||
local modulename
|
|
||||||
modulename=$1
|
|
||||||
local modulefile
|
|
||||||
local suffix
|
|
||||||
|
|
||||||
if ! list_search $modulename $DONT_LOAD $MODULES; then
|
|
||||||
shift
|
|
||||||
|
|
||||||
for suffix in $MODULE_SUFFIX ; do
|
|
||||||
for directory in $moduledirectories; do
|
|
||||||
modulefile=$directory/${modulename}.${suffix}
|
|
||||||
|
|
||||||
if [ -f $modulefile ]; then
|
|
||||||
case $moduleloader in
|
|
||||||
insmod)
|
|
||||||
insmod $modulefile $*
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
modprobe $modulename $*
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
break 2
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Reload the Modules
|
|
||||||
#
|
|
||||||
reload_kernel_modules() {
|
|
||||||
|
|
||||||
local save_modules_dir
|
|
||||||
save_modules_dir=$MODULESDIR
|
|
||||||
local directory
|
|
||||||
local moduledirectories
|
|
||||||
moduledirectories=
|
|
||||||
local moduleloader
|
|
||||||
moduleloader=modprobe
|
|
||||||
|
|
||||||
if ! qt mywhich modprobe; then
|
|
||||||
moduleloader=insmod
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ -n "${MODULE_SUFFIX:=o gz ko o.gz ko.gz}" ]
|
|
||||||
|
|
||||||
[ -z "$MODULESDIR" ] && MODULESDIR=/lib/modules/$(uname -r)/kernel/net/ipv6/netfilter:/lib/modules/$(uname -r)/kernel/net/netfilter
|
|
||||||
MODULES=$(lsmod | cut -d ' ' -f1)
|
|
||||||
|
|
||||||
for directory in $(split $MODULESDIR); do
|
|
||||||
[ -d $directory ] && moduledirectories="$moduledirectories $directory"
|
|
||||||
done
|
|
||||||
|
|
||||||
[ -n "$moduledirectories" ] && while read command; do
|
|
||||||
eval $command
|
|
||||||
done
|
|
||||||
|
|
||||||
MODULESDIR=$save_modules_dir
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Load kernel modules required for Shorewall6
|
|
||||||
#
|
|
||||||
load_kernel_modules() # $1 = Yes, if we are to save moduleinfo in $VARDIR
|
|
||||||
{
|
|
||||||
local save_modules_dir
|
|
||||||
save_modules_dir=$MODULESDIR
|
|
||||||
local directory
|
|
||||||
local moduledirectories
|
|
||||||
moduledirectories=
|
|
||||||
local moduleloader
|
|
||||||
moduleloader=modprobe
|
|
||||||
local savemoduleinfo
|
|
||||||
savemoduleinfo=${1:-Yes} # So old compiled scripts still work
|
|
||||||
|
|
||||||
if ! qt mywhich modprobe; then
|
|
||||||
moduleloader=insmod
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ -n "${MODULE_SUFFIX:=o gz ko o.gz ko.gz}" ]
|
|
||||||
|
|
||||||
[ -z "$MODULESDIR" ] && \
|
|
||||||
MODULESDIR=/lib/modules/$(uname -r)/kernel/net/ipv6/netfilter:/lib/modules/$(uname -r)/kernel/net/netfilter
|
|
||||||
|
|
||||||
for directory in $(split $MODULESDIR); do
|
|
||||||
[ -d $directory ] && moduledirectories="$moduledirectories $directory"
|
|
||||||
done
|
|
||||||
|
|
||||||
modules=$(find_file modules)
|
|
||||||
|
|
||||||
if [ -f $modules -a -n "$moduledirectories" ]; then
|
|
||||||
MODULES=$(lsmod | cut -d ' ' -f1)
|
|
||||||
progress_message "Loading Modules..."
|
|
||||||
. $modules
|
|
||||||
if [ $savemoduleinfo = Yes ]; then
|
|
||||||
[ -d ${VARDIR} ] || mkdir -p ${VARDIR}
|
|
||||||
echo MODULESDIR="$MODULESDIR" > ${VARDIR}/.modulesdir
|
|
||||||
cp -f $modules ${VARDIR}/.modules
|
|
||||||
fi
|
|
||||||
elif [ $savemoduleinfo = Yes ]; then
|
|
||||||
[ -d ${VARDIR} ] || mkdir -p ${VARDIR}
|
|
||||||
> ${VARDIR}/.modulesdir
|
|
||||||
> ${VARDIR}/.modules
|
|
||||||
fi
|
|
||||||
|
|
||||||
MODULESDIR=$save_modules_dir
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Query NetFilter about the existence of a filter chain
|
|
||||||
#
|
|
||||||
chain_exists() # $1 = chain name
|
|
||||||
{
|
|
||||||
qt1 $IP6TABLES -L $1 -n
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Find the value 'dev' in the passed arguments then echo the next value
|
|
||||||
#
|
|
||||||
|
|
||||||
find_device() {
|
|
||||||
while [ $# -gt 1 ]; do
|
|
||||||
[ "x$1" = xdev ] && echo $2 && return
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Find the value 'via' in the passed arguments then echo the next value
|
|
||||||
#
|
|
||||||
|
|
||||||
find_gateway() {
|
|
||||||
while [ $# -gt 1 ]; do
|
|
||||||
[ "x$1" = xvia ] && echo $2 && return
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Find the value 'mtu' in the passed arguments then echo the next value
|
|
||||||
#
|
|
||||||
|
|
||||||
find_mtu() {
|
|
||||||
while [ $# -gt 1 ]; do
|
|
||||||
[ "x$1" = xmtu ] && echo $2 && return
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Find the value 'peer' in the passed arguments then echo the next value up to
|
|
||||||
# "/"
|
|
||||||
#
|
|
||||||
|
|
||||||
find_peer() {
|
|
||||||
while [ $# -gt 1 ]; do
|
|
||||||
[ "x$1" = xpeer ] && echo ${2%/*} && return
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Try to find the gateway through an interface looking for 'nexthop'
|
|
||||||
|
|
||||||
find_nexthop() # $1 = interface
|
|
||||||
{
|
|
||||||
echo $(find_gateway `ip -6 route list | grep "[[:space:]]nexthop.* $1"`)
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Find the default route's interface
|
|
||||||
#
|
|
||||||
find_default_interface() {
|
|
||||||
ip -6 route list | while read first rest; do
|
|
||||||
[ "$first" = default ] && echo $(find_device $rest) && return
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Find the interface with the passed MAC address
|
|
||||||
#
|
|
||||||
|
|
||||||
find_interface_by_mac() {
|
|
||||||
local mac
|
|
||||||
mac=$1
|
|
||||||
local first
|
|
||||||
local second
|
|
||||||
local rest
|
|
||||||
local dev
|
|
||||||
|
|
||||||
ip link list | while read first second rest; do
|
|
||||||
case $first in
|
|
||||||
*:)
|
|
||||||
dev=$second
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [ "$second" = $mac ]; then
|
|
||||||
echo ${dev%:}
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Determine if Interface is up
|
|
||||||
#
|
|
||||||
interface_is_up() {
|
|
||||||
[ -n "$(ip link list dev $1 2> /dev/null | grep -e '[<,]UP[,>]')" ]
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Find interface address--returns the first IP address assigned to the passed
|
|
||||||
# device
|
|
||||||
#
|
|
||||||
find_first_interface_address() # $1 = interface
|
|
||||||
{
|
|
||||||
#
|
|
||||||
# get the line of output containing the first IP address
|
|
||||||
#
|
|
||||||
addr=$(ip -f inet6 addr show $1 2> /dev/null | grep 'inet6 .* global' | head -n1)
|
|
||||||
#
|
|
||||||
# If there wasn't one, bail out now
|
|
||||||
#
|
|
||||||
[ -n "$addr" ] || fatal_error "Can't determine the IPv6 address of $1"
|
|
||||||
#
|
|
||||||
# Strip off the trailing VLSM mask (or the peer IP in case of a P-t-P link)
|
|
||||||
# along with everything else on the line
|
|
||||||
#
|
|
||||||
echo $addr | sed 's/\s*inet6 //;s/\/.*//;s/ peer.*//'
|
|
||||||
}
|
|
||||||
|
|
||||||
find_first_interface_address_if_any() # $1 = interface
|
|
||||||
{
|
|
||||||
#
|
|
||||||
# get the line of output containing the first IP address
|
|
||||||
#
|
|
||||||
addr=$(ip -f inet6 addr show $1 2> /dev/null | grep 'inet6 2.* global' | head -n1)
|
|
||||||
#
|
|
||||||
# Strip off the trailing VLSM mask (or the peer IP in case of a P-t-P link)
|
|
||||||
# along with everything else on the line
|
|
||||||
#
|
|
||||||
[ -n "$addr" ] && echo $addr | sed 's/\s*inet6 //;s/\/.*//;s/ peer.*//' || echo ::
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Determine if interface is usable from a Netfilter prespective
|
|
||||||
#
|
|
||||||
interface_is_usable() # $1 = interface
|
|
||||||
{
|
|
||||||
interface_is_up $1 && [ "$(find_first_interface_address_if_any $1)" != :: ] && run_isusable_exit $1
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Find interface addresses--returns the set of addresses assigned to the passed
|
|
||||||
# device
|
|
||||||
#
|
|
||||||
find_interface_addresses() # $1 = interface
|
|
||||||
{
|
|
||||||
ip -f inet6 addr show $1 2> /dev/null | grep 'inet6 2' | sed 's/\s*inet6 //;s/\/.*//;s/ peer.*//'
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Get all interface addresses with VLSMs
|
|
||||||
#
|
|
||||||
|
|
||||||
find_interface_full_addresses() # $1 = interface
|
|
||||||
{
|
|
||||||
ip -f inet6 addr show $1 2> /dev/null | grep 'inet6 ' | sed 's/\s*inet6 //;s/ scope.*//;s/ peer.*//'
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# echo the list of networks routed out of a given interface
|
|
||||||
#
|
|
||||||
get_routed_networks() # $1 = interface name, $2-n = Fatal error message
|
|
||||||
{
|
|
||||||
local address
|
|
||||||
local rest
|
|
||||||
|
|
||||||
ip -6 route show dev $1 2> /dev/null |
|
|
||||||
while read address rest; do
|
|
||||||
case "$address" in
|
|
||||||
default)
|
|
||||||
if [ $# -gt 1 ]; then
|
|
||||||
shift
|
|
||||||
fatal_error "$@"
|
|
||||||
else
|
|
||||||
echo "WARNING: default route ignored on interface $1" >&2
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
multicast|broadcast|prohibit|nat|throw|nexthop)
|
|
||||||
;;
|
|
||||||
2*)
|
|
||||||
[ "$address" = "${address%/*}" ] && address="${address}/128"
|
|
||||||
echo $address
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
normalize_address() # $1 = valid IPv6 Address
|
|
||||||
{
|
|
||||||
local address
|
|
||||||
address=$1
|
|
||||||
local j
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
case $address in
|
|
||||||
::*)
|
|
||||||
address=0$address
|
|
||||||
;;
|
|
||||||
*::*)
|
|
||||||
list_count $(split $address)
|
|
||||||
|
|
||||||
j=$?
|
|
||||||
|
|
||||||
if [ $j -eq 7 ]; then
|
|
||||||
address=${address%::*}:0:${address#*::}
|
|
||||||
elif [ $j -eq 8 ]; then
|
|
||||||
$address=${address%::*}:${address#*::}
|
|
||||||
break 2
|
|
||||||
else
|
|
||||||
address=${address%::*}:0::${address#*::}
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo $address
|
|
||||||
break 2
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Reads correctly-formed and fully-qualified host and subnet addresses from STDIN. For each
|
|
||||||
# that defines a /120 or larger network, it sends to STDOUT:
|
|
||||||
#
|
|
||||||
# The corresponding subnet-router anycast address (all host address bits are zero)
|
|
||||||
# The corresponding anycast addresses defined by RFC 2526 (the last 128 addresses in the subnet)
|
|
||||||
#
|
|
||||||
convert_to_anycast() {
|
|
||||||
local address
|
|
||||||
local badress
|
|
||||||
local vlsm
|
|
||||||
local host
|
|
||||||
local o
|
|
||||||
local m
|
|
||||||
m=
|
|
||||||
local z
|
|
||||||
z=65535
|
|
||||||
local l
|
|
||||||
|
|
||||||
while read address; do
|
|
||||||
case $address in
|
|
||||||
2*|3*)
|
|
||||||
vlsm=${address#*/}
|
|
||||||
vlsm=${vlsm:=128}
|
|
||||||
|
|
||||||
if [ $vlsm -le 120 ]; then
|
|
||||||
#
|
|
||||||
# Defines a viable subnet -- first get the subnet-router anycast address
|
|
||||||
#
|
|
||||||
host=$((128 - $vlsm))
|
|
||||||
|
|
||||||
address=$(normalize_address ${address%/*})
|
|
||||||
|
|
||||||
while [ $host -ge 16 ]; do
|
|
||||||
address=${address%:*}
|
|
||||||
host=$(($host - 16))
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ $host -gt 0 ]; then
|
|
||||||
#
|
|
||||||
# VLSM is not a multiple of 16
|
|
||||||
#
|
|
||||||
host=$((16 - $host))
|
|
||||||
o=$((0x${address##*:}))
|
|
||||||
m=0
|
|
||||||
while [ $host -gt 0 ]; do
|
|
||||||
m=$((($m >> 1) | 0x8000))
|
|
||||||
z=$(($z >> 1))
|
|
||||||
host=$(($host - 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
o=$(($o & $m))
|
|
||||||
|
|
||||||
badress=${address%:*}
|
|
||||||
|
|
||||||
address=$badress:$(printf %04x $o)
|
|
||||||
|
|
||||||
z=$(($o | $z))
|
|
||||||
|
|
||||||
if [ $vlsm -gt 112 ]; then
|
|
||||||
z=$(($z & 0xff80))
|
|
||||||
fi
|
|
||||||
|
|
||||||
badress=$badress:$(printf %04x $z)
|
|
||||||
else
|
|
||||||
badress=$address
|
|
||||||
fi
|
|
||||||
#
|
|
||||||
# Note: at this point $address and $badress are the same except possibly for
|
|
||||||
# the contents of the last half-word
|
|
||||||
#
|
|
||||||
list_count $(split $address)
|
|
||||||
|
|
||||||
l=$?
|
|
||||||
#
|
|
||||||
# Now generate the anycast addresses defined by RFC 2526
|
|
||||||
#
|
|
||||||
if [ $l -lt 8 ]; then
|
|
||||||
#
|
|
||||||
# The subnet-router address
|
|
||||||
#
|
|
||||||
echo $address::
|
|
||||||
|
|
||||||
while [ $l -lt 8 ]; do
|
|
||||||
badress=$badress:ffff
|
|
||||||
l=$(($l + 1 ))
|
|
||||||
done
|
|
||||||
else
|
|
||||||
#
|
|
||||||
# The subnet-router address
|
|
||||||
#
|
|
||||||
echo $address
|
|
||||||
fi
|
|
||||||
#
|
|
||||||
# And the RFC 2526 addresses
|
|
||||||
#
|
|
||||||
echo $badress/121
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Generate a list of anycast addresses for a given interface
|
|
||||||
#
|
|
||||||
|
|
||||||
get_interface_acasts() # $1 = interface
|
|
||||||
{
|
|
||||||
local addresses
|
|
||||||
addresses=
|
|
||||||
|
|
||||||
find_interface_full_addresses $1 | convert_to_anycast | sort -u
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Get a list of all configured anycast addresses on the system
|
|
||||||
#
|
|
||||||
get_all_acasts()
|
|
||||||
{
|
|
||||||
find_interface_full_addresses | convert_to_anycast | sort -u
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Internal version of 'which'
|
|
||||||
#
|
|
||||||
mywhich() {
|
|
||||||
local dir
|
|
||||||
|
|
||||||
for dir in $(split $PATH); do
|
|
||||||
if [ -x $dir/$1 ]; then
|
|
||||||
echo $dir/$1
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Find a File -- For relative file name, look in each ${CONFIG_PATH} then ${CONFDIR}
|
|
||||||
#
|
|
||||||
find_file()
|
|
||||||
{
|
|
||||||
local saveifs
|
|
||||||
saveifs=
|
|
||||||
local directory
|
|
||||||
|
|
||||||
case $1 in
|
|
||||||
/*)
|
|
||||||
echo $1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
for directory in $(split $CONFIG_PATH); do
|
|
||||||
if [ -f $directory/$1 ]; then
|
|
||||||
echo $directory/$1
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo ${CONFDIR}/$1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Set the Shorewall state
|
|
||||||
#
|
|
||||||
set_state () # $1 = state
|
|
||||||
{
|
|
||||||
echo "$1 ($(date))" > ${VARDIR}/state
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Perform variable substitution on the passed argument and echo the result
|
|
||||||
#
|
|
||||||
expand() # $@ = contents of variable which may be the name of another variable
|
|
||||||
{
|
|
||||||
eval echo \"$@\"
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Function for including one file into another
|
|
||||||
#
|
|
||||||
INCLUDE() {
|
|
||||||
. $(find_file $(expand $@))
|
|
||||||
}
|
|
||||||
|
|
||||||
detect_gateway() # $1 = interface
|
|
||||||
{
|
|
||||||
local interface
|
|
||||||
interface=$1
|
|
||||||
#
|
|
||||||
# First assume that this is some sort of point-to-point interface
|
|
||||||
#
|
|
||||||
gateway=$( find_peer $(ip -6 addr list $interface ) )
|
|
||||||
#
|
|
||||||
# Maybe there's a default route through this gateway already
|
|
||||||
#
|
|
||||||
[ -n "$gateway" ] || gateway=$(find_gateway $(ip -6 route list dev $interface | grep '^default'))
|
|
||||||
#
|
|
||||||
# Last hope -- is there a load-balancing route through the interface?
|
|
||||||
#
|
|
||||||
[ -n "$gateway" ] || gateway=$(find_nexthop $interface)
|
|
||||||
#
|
|
||||||
# Be sure we found one
|
|
||||||
#
|
|
||||||
[ -n "$gateway" ] && echo $gateway
|
|
||||||
}
|
|
||||||
|
|
||||||
truncate() # $1 = length
|
|
||||||
{
|
|
||||||
cut -b -${1}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete_tc1()
|
|
||||||
{
|
|
||||||
clear_one_tc() {
|
|
||||||
tc qdisc del dev $1 root 2> /dev/null
|
|
||||||
tc qdisc del dev $1 ingress 2> /dev/null
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
run_tcclear_exit
|
|
||||||
|
|
||||||
run_ip link list | \
|
|
||||||
while read inx interface details; do
|
|
||||||
case $inx in
|
|
||||||
[0-9]*)
|
|
||||||
clear_one_tc ${interface%:}
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Detect a device's MTU -- echos the passed device's MTU
|
|
||||||
#
|
|
||||||
get_device_mtu() # $1 = device
|
|
||||||
{
|
|
||||||
local output
|
|
||||||
output="$(ip link list dev $1 2> /dev/null)" # quotes required for /bin/ash
|
|
||||||
|
|
||||||
if [ -n "$output" ]; then
|
|
||||||
echo $(find_mtu $output)
|
|
||||||
else
|
|
||||||
echo 1500
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Version of the above that doesn't generate any output for MTU 1500.
|
|
||||||
# Generates 'mtu <mtu+>' otherwise, where <mtu+> is the device's MTU + 100
|
|
||||||
#
|
|
||||||
get_device_mtu1() # $1 = device
|
|
||||||
{
|
|
||||||
local output
|
|
||||||
output="$(ip link list dev $1 2> /dev/null)" # quotes required for /bin/ash
|
|
||||||
local mtu
|
|
||||||
|
|
||||||
if [ -n "$output" ]; then
|
|
||||||
mtu=$(find_mtu $output)
|
|
||||||
if [ -n "$mtu" ]; then
|
|
||||||
[ $mtu = 1500 ] || echo mtu $(($mtu + 100))
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Undo changes to routing
|
|
||||||
#
|
|
||||||
undo_routing() {
|
|
||||||
|
|
||||||
if [ -z "$NOROUTES" ]; then
|
|
||||||
#
|
|
||||||
# Restore rt_tables database
|
|
||||||
#
|
|
||||||
if [ -f ${VARDIR}/rt_tables ]; then
|
|
||||||
[ -w /etc/iproute2/rt_table -a -z "$KEEP_RT_TABLES" ] && cp -f ${VARDIR}/rt_tables /etc/iproute2/ && progress_message "/etc/iproute2/rt_tables database restored"
|
|
||||||
rm -f ${VARDIR}/rt_tables
|
|
||||||
fi
|
|
||||||
#
|
|
||||||
# Restore the rest of the routing table
|
|
||||||
#
|
|
||||||
if [ -f ${VARDIR}/undo_routing ]; then
|
|
||||||
. ${VARDIR}/undo_routing
|
|
||||||
progress_message "Shorewall-generated routing tables and routing rules removed"
|
|
||||||
rm -f ${VARDIR}/undo_routing
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
restore_default_route() {
|
|
||||||
if [ -z "$NOROUTES" -a -f ${VARDIR}/default_route ]; then
|
|
||||||
local default_route
|
|
||||||
default_route=
|
|
||||||
local route
|
|
||||||
local result
|
|
||||||
result=1
|
|
||||||
|
|
||||||
while read route ; do
|
|
||||||
case $route in
|
|
||||||
default)
|
|
||||||
if [ -n "$default_route" ]; then
|
|
||||||
case "$default_route" in
|
|
||||||
*metric*)
|
|
||||||
#
|
|
||||||
# Don't restore a route with a metric -- we only replace the one with metric == 0
|
|
||||||
#
|
|
||||||
qt ip -6 route delete default metric 0 && \
|
|
||||||
progress_message "Default Route with metric 0 deleted"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
qt ip -6 route replace $default_route && \
|
|
||||||
result=0 && \
|
|
||||||
progress_message "Default Route (${default_route# }) restored"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
|
|
||||||
default_route="$default_route $route"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
default_route="$default_route $route"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done < ${VARDIR}/default_route
|
|
||||||
|
|
||||||
rm -f ${VARDIR}/default_route
|
|
||||||
fi
|
|
||||||
|
|
||||||
return $result
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Determine how to do "echo -e"
|
|
||||||
#
|
|
||||||
|
|
||||||
find_echo() {
|
|
||||||
local result
|
|
||||||
|
|
||||||
result=$(echo "a\tb")
|
|
||||||
[ ${#result} -eq 3 ] && { echo echo; return; }
|
|
||||||
|
|
||||||
result=$(echo -e "a\tb")
|
|
||||||
[ ${#result} -eq 3 ] && { echo "echo -e"; return; }
|
|
||||||
|
|
||||||
result=$(which echo)
|
|
||||||
[ -n "$result" ] && { echo "$result -e"; return; }
|
|
||||||
|
|
||||||
echo echo
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Determine the MAC address of the passed IP through the passed interface
|
|
||||||
#
|
|
||||||
find_mac() # $1 = IP address, $2 = interface
|
|
||||||
{
|
|
||||||
if interface_is_usable $2 ; then
|
|
||||||
qt ping -nc 1 -t 2 -I $2 $1
|
|
||||||
|
|
||||||
local result
|
|
||||||
result=$(ip neigh list | awk "/^$1 / {print \$5}")
|
|
||||||
|
|
||||||
case $result in
|
|
||||||
\<*\>)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
[ -n "$result" ] && echo $result
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Flush the conntrack table if $PURGE is non-empty
|
|
||||||
#
|
|
||||||
conditionally_flush_conntrack() {
|
|
||||||
|
|
||||||
if [ -n "$PURGE" ]; then
|
|
||||||
if [ -n $(which conntrack) ]; then
|
|
||||||
conntrack -F
|
|
||||||
else
|
|
||||||
error_message "WARNING: The '-p' option requires the conntrack utility which does not appear to be installed on this system"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# End of functions imported from /usr/share/shorewall/lib.base
|
|
||||||
################################################################################
|
|
@ -1,193 +0,0 @@
|
|||||||
%define name shorewall-perl
|
|
||||||
%define version 4.3.5
|
|
||||||
%define release 0base
|
|
||||||
|
|
||||||
Summary: Shoreline Firewall Perl-based compiler.
|
|
||||||
Name: %{name}
|
|
||||||
Version: %{version}
|
|
||||||
Release: %{release}
|
|
||||||
License: GPL
|
|
||||||
Packager: Tom Eastep <teastep@shorewall.net>
|
|
||||||
Group: Networking/Utilities
|
|
||||||
Source: %{name}-%{version}.tgz
|
|
||||||
URL: http://www.shorewall.net/
|
|
||||||
BuildArch: noarch
|
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-root
|
|
||||||
Requires: perl shorewall-common >= 4.0.0
|
|
||||||
Conflicts: shorewall < 3.4.2
|
|
||||||
Provides: shorewall_compiler = %{version}-%{release}
|
|
||||||
Provides: shorewall = %{version}-%{release}
|
|
||||||
|
|
||||||
%description
|
|
||||||
|
|
||||||
The Shoreline Firewall, more commonly known as "Shorewall", is a Netfilter
|
|
||||||
(iptables) based firewall that can be used on a dedicated firewall system,
|
|
||||||
a multi-function gateway/ router/server or on a standalone GNU/Linux system.
|
|
||||||
|
|
||||||
Shorewall-perl is a part of Shorewall that allows faster compilation and
|
|
||||||
execution than the legacy shorewall-shell compiler.
|
|
||||||
|
|
||||||
%prep
|
|
||||||
|
|
||||||
%setup
|
|
||||||
|
|
||||||
%build
|
|
||||||
|
|
||||||
%install
|
|
||||||
export PREFIX=$RPM_BUILD_ROOT ; \
|
|
||||||
export OWNER=`id -n -u` ; \
|
|
||||||
export GROUP=`id -n -g` ;\
|
|
||||||
./install.sh -n
|
|
||||||
|
|
||||||
%clean
|
|
||||||
rm -rf $RPM_BUILD_ROOT
|
|
||||||
|
|
||||||
%pre
|
|
||||||
|
|
||||||
%post
|
|
||||||
|
|
||||||
%preun
|
|
||||||
|
|
||||||
%files
|
|
||||||
%defattr(0644,root,root,0755)
|
|
||||||
|
|
||||||
%attr(0755,root,root) %dir /usr/share/shorewall-perl
|
|
||||||
%attr(0755,root,root) %dir /usr/share/shorewall-perl/Shorewall
|
|
||||||
|
|
||||||
%attr(755,root,root) /usr/share/shorewall-perl/compiler.pl
|
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/prog.*
|
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/version
|
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/*.pm
|
|
||||||
|
|
||||||
%doc COPYING releasenotes.txt
|
|
||||||
|
|
||||||
%changelog
|
|
||||||
* Sun Feb 22 2009 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.3.5-0base
|
|
||||||
* Sat Feb 21 2009 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.7-0base
|
|
||||||
* Wed Feb 04 2009 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.6-0base
|
|
||||||
* Thu Jan 29 2009 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.6-0base
|
|
||||||
* Tue Jan 06 2009 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.5-0base
|
|
||||||
* Thu Dec 25 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.4-0base
|
|
||||||
* Sun Dec 21 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.4-0RC2
|
|
||||||
* Wed Dec 17 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.4-0RC1
|
|
||||||
* Tue Dec 16 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.3.4-0base
|
|
||||||
* Sat Dec 13 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.3.3-0base
|
|
||||||
* Fri Dec 12 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.3.2-0base
|
|
||||||
* Thu Dec 11 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.3.1-0base
|
|
||||||
* Thu Dec 11 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.3.1-0base
|
|
||||||
* Wed Dec 10 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.3.0-0base
|
|
||||||
* Wed Dec 10 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 2.3.0-0base
|
|
||||||
* Fri Dec 05 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.3-0base
|
|
||||||
* Wed Nov 05 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.2-0base
|
|
||||||
* Wed Oct 08 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.1-0base
|
|
||||||
* Fri Oct 03 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.0-0base
|
|
||||||
* Tue Sep 23 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.0-0RC4
|
|
||||||
* Mon Sep 15 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.0-0RC3
|
|
||||||
* Mon Sep 08 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.0-0RC2
|
|
||||||
* Tue Aug 19 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.0-0RC1
|
|
||||||
* Thu Jul 03 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.0-0Beta3
|
|
||||||
* Mon Jun 02 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.0-0Beta2
|
|
||||||
* Wed May 07 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.2.0-0Beta1
|
|
||||||
* Mon Apr 28 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.1.8-0base
|
|
||||||
* Mon Mar 24 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.1.7-0base
|
|
||||||
* Thu Mar 13 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.1.6-0base
|
|
||||||
* Tue Feb 05 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.1.5-0base
|
|
||||||
* Fri Jan 04 2008 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.1.4-0base
|
|
||||||
* Wed Dec 12 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.1.3-0base
|
|
||||||
* Fri Dec 07 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.1.3-1
|
|
||||||
* Tue Nov 27 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.1.2-1
|
|
||||||
* Wed Nov 21 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.1.1-1
|
|
||||||
* Mon Nov 19 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.1.0-1
|
|
||||||
* Thu Nov 15 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.6-1
|
|
||||||
* Sat Nov 10 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.6-0RC3
|
|
||||||
* Wed Nov 07 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.6-0RC2
|
|
||||||
* Thu Oct 25 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.6-0RC1
|
|
||||||
* Tue Oct 03 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.5-1
|
|
||||||
* Wed Sep 05 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.4-1
|
|
||||||
* Mon Aug 13 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.3-1
|
|
||||||
* Thu Aug 09 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.2-1
|
|
||||||
* Sat Jul 21 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.1-1
|
|
||||||
* Wed Jul 11 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.0-1
|
|
||||||
* Sun Jul 08 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.0-0RC2
|
|
||||||
* Fri Jun 29 2007 Tom EAstep tom@shorewall.net
|
|
||||||
- Updated to 4.0.0-0RC1
|
|
||||||
* Sun Jun 24 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.0-0Beta7
|
|
||||||
* Wed Jun 20 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.0-0Beta6
|
|
||||||
- Add new components.
|
|
||||||
* Thu Jun 14 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.0-0Beta5
|
|
||||||
* Fri Jun 08 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.0-0Beta4
|
|
||||||
* Tue Jun 05 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.0-0Beta3
|
|
||||||
* Sat May 26 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.0-0Beta2
|
|
||||||
* Tue May 15 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 4.0.0-0Beta1
|
|
||||||
* Fri May 11 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 3.9.7-1
|
|
||||||
* Sat May 05 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 3.9.6-1
|
|
||||||
* Mon Apr 30 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 3.9.5-1
|
|
||||||
* Mon Apr 23 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 3.9.4-1
|
|
||||||
* Wed Apr 18 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 3.9.3-1
|
|
||||||
* Sat Apr 14 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Updated to 3.9.2-1
|
|
||||||
* Sat Apr 07 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Initial version 3.9.1-1
|
|
||||||
* Sat Mar 24 2007 Tom Eastep tom@shorewall.net
|
|
||||||
- Initial version 3.9.0-1
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user