Configure fail2ban with firewalld in CentOS 7 and send mail notification to Admin

1. Install fail2ban from EPEL repo.

yum install y epelrelease
yum install y fail2ban fail2bansystemd

2. Deal with SELinux, there are two options to choose from.

2.1 Update SELinux Policy : yum update y selinuxpolicy*
2.2 Disable SELinux: Modify line SELINUX=enforcing to SELINUX=disabled

3.Configure fail2ban.

Create the file sshd.local in the path /etc/fail2ban/jail.d with the content below:
[sshd]
enabled = true
port = ssh                                              # change ssh port at here
logpath = %(sshd_log)s
maxretry = 5
bantime = 259200                               # count second (259200 = 3 days)
destemail = admin@gmail.com    # change your email at here
action = %(action_mw)s                  #  ban & send an e-mail with whois report to the destemail
Note: This configuration will overwrite the one in /etc/fail2ban/jail.conf, mta (mail transfer agent) is used by “sendmail” default.

4. Enable and Start fail2ban.

systemctl enable fail2ban
systemctl start fail2ban

5. Check and Test.

fail2ban-client status
Status
|- Number of jail: 1
`- Jail list: sshd
# ipset list
Name: fail2ban-sshd
Type: hash:ip
Revision: 1
Header: family inet hashsize 1024 maxelem 65536 timeout 259200
Size in memory: 16592
References: 1
Members:
192.168.100.202 timeout 245657

6. Unban ip address:

# fail2ban-client set sshd unbanip 192.168.100.202
Recheck: # ipset list
Name: fail2ban-sshd
Type: hash:ip
Revision: 1
Header: family inet hashsize 1024 maxelem 65536 timeout 259200
Size in memory: 16592
References: 1
Members:
Testing system: CentOS7 with fail2ban (v0.9.3) and firewalld (0.3.9)

C shell programming

The need for shell programming
------------------------------

Do you ever find that you often do a number of UNIX commands together and
you would like to "bundle" them up into one name?  You can do this, in effect,
creating a brand new command.  Other operating systems permit this convenience,
most notably MS-DOS, which calls such files "BAT" or batch files.  In UNIX,
such a file is called a shell script.

First, make sure you know about the various UNIX shells (Bourne and C-shell).
There is information in the glossary menu.

Both the Bourne shell and the C shell permit you to create and use shell
scripts, but because the syntax of the commands that these two shells use is
slightly different, your shell script must match the shell that is interpret-
ing it, or you will get errors.

A shell script is just a readable file that you create and into which you put
shell commands.  The first line determines which shell program will interpret
or execute a shell script.

   * If the first line begins with a C-shell comment (starting with # in
     position 1) then this will be interpreted by the C-shell and must use
     C-shell syntax.

   * Otherwise, the file will be considered a Bourne shell script.

You can have comments in either type of shell script, although the syntax
differs.  Bourne shell comments begin with a colon, whereas C-shell comments
commence with the pound sign (#).

For the rest of this tutorial, we will concentrate on the C-shell.


How to create simple scripts
----------------------------

Most shell scripts that you write will be very simple.  They will consist of
a number of UNIX commands that you would have typed at the prompt, possibly
substituting a different file name.  These substitutions are called positional
parameters.

To create a shell script that has no parameters and does the same thing every
time it is called, just put the commands in a file.  Change the permissions on 
the file so that it is executable and then use it.  The name of the file should
be something that you can easily remember and which makes sense given the 
operation that you are performing.

Let's make one that clears the screen, prints out the date, time, hostname,
current working directory, current username, and how many people are logged on.
The name of the script will be "status".  So edit a file called "status" and
put the following lines into it:  (Don't type the "frame" of dashes and vertical
bars -- these are meant to show you what the file looks like.)

   +----------------------------------------------------------
   | #
   | clear
   | echo -n "It is currently: ";date
   | echo -n "I am logged on as ";who am i
   | echo -n "This computer is called ";hostname
   | echo -n "I am currently in the directory ";pwd
   | echo -n "The number of people currently logged on is:"
   | who | wc -l
   +----------------------------------------------------------


How to make a file executable and put it in your path
-----------------------------------------------------

Make sure that you put the # in line 1.  Now set the permissions:

     % chmod 0700 status

This makes it executable and readable, both of which are necessary.
To use, just type

     % status

If you see a cryptic command saying "command not found", it is probably
because your path does not include the current directory.  To remedy this,
put the dot and a slash in front of the name:

     % ./status

or you can modify your path:

     % set path=($path .)

Note the space in front of the period.

Let's explain just a few things in the shell script above.  Note that 
echo -n is used a lot.  The echo command just prints lines to the screen,
and normally it puts a newline after the thing it prints.  -n inhibits
this, so that the output looks better.

You can string together more than one command on a line by using a semicolon.
Thus, clear;date;whoami;pwd could be put all on one line and all four of
the commands would be executed, one after the other.  This is similar to the
vertical bar (the pipe), although it is simpler.


Parameters
----------

Now let's get more complicated by adding positional parameters.  Parameters
are given after the name of the file when you start the shell script.  Each
parameter has a position, first, second, etc.  When the shell interpreter
reads and executes each line of the shell script file, it looks for symbols
like $1, $2, etc and it substitutes for these symbols the positional parameters.

Let's do a very simple example.  Our shell script will attempt to find the
word "unix" (irrespective of case) in a file that we give as a positional
parameter:

   +----------------------------------------------------------
   | #
   | grep -i unix $1
   +----------------------------------------------------------

The -i option says ignore case.  Since we are always looking for the word
unix (or UNIX, or Unix, etc.), all we need to vary is the file name.  Suppose
that we called this file "funix" for "find unix", and we made it executable
using chmod.  Now to use it on a file, we would type

     % funix myjunk

and it would search file "myjunk" for the word unix (or Unix, or UNIX, etc.),
printing out each line that it found.

You can have any number of parameters.  The second is $2, the third is $3,
etc.  

Another common variation is to refer to all the parameters at once by using
$*.  Our little shell script only looks at one file at a time.  If we typed

   funix myjunk yourjunk theirjunk ourjunk

it would only search the first file "myjunk".  To make it search all, we
could do

   +----------------------------------------------------------
   | #
   | foreach i ($*)
   |     grep -i unix $i
   | end
   +----------------------------------------------------------

"foreach" is one of the many control structures of C-shell scripts.  It takes
a list of items ($*) and assigns each one to the shell variable i in turn.
Then this shell variable is referenced (i.e., used) in the grep command by
saying $i.  All shell variables must have a $ in front when they are used.
The end keyword says that this is the end of the foreach construct, not the
end of the shell script.

In many situations, UNIX commands themselves are set up to accept multiple
filenames, and grep is one of these.  So you could have done

   +----------------------------------------------------------
   | #
   | grep -i unix $*
   +----------------------------------------------------------

instead.  But not all cases work this easily.  You just have to know your
UNIX commands.

Let us review the syntax of parameters.  Each parameter is identified by $1,
$2, $3 and so on.  The name of the command is $0.  A short hand for all the
parameters is $*.  To find out how many parameters there are, $#argv is used.

Here's an example of the beginning of a shell script which checkes to see if
the user entered enough parameters, because some scripts require a certain
number.  For example, grep needs at least one parameter, which is the string
to search for.

   +----------------------------------------------------------
   | #
   | if ($#argv < 2) then
   |     echo "Sorry, but you entered too few parameters"
   |     echo "usage:  slop file searchstring
   |     exit
   | endif
   +----------------------------------------------------------

This example gives you a flavor of the syntax of the if statement, use of the
echo command to act as output from a shell script, and the exit command which
terminates the shell script immediately.

The general syntax of if and if-then-else is:

    if ( expression ) then                    if ( expression ) then
         statements                                true statements
    endif                                     else
                                                   false statements
                                              endif

We will discuss what expressions can go inside the parentheses next.


Expressions
-----------

The C shell language was meant to be reminiscent of the C language, and it is
to some extent.   But there are differences.  For example, in the above patterns
for if statements, the two keywords "then" and "endif" do not appear in C.  The
curly braces of C are not used in the C shell for the same thing, but for some-
thing completely different, which may be quite confusing.  So it is wrong to 
imagine that knowledge of C confers on you the ability to write C shell scripts!

We start off with something that is used a lot in if statements, and is not in
C: file queries.  These are expressions that are used to determine characterist-
ics of files so that appropriate action may be taken.  For example, suppose 
that you want to see if a certain file exists:

     if (-e somefile) then
         grep $1 somefile
     else
         echo "Grievous error!  Database file does not exist".
     endif

The name of the file does not have to be "hard coded" into the if statement, but
may be a parameter:

     if (-e $2) then

Here is a full list of the Cshell file queries.

    -e file           file merely exists (may be protected from user)
    -r file           file exists and is readable by user
    -w file           file is writable by user
    -x file           file is executable by user
    -o file           file is owned by user
    -z file           file has size 0
    -f file           file is an ordinary file
    -d file           file is a directory
    
All of queries except -e automatically test for file existence.  That is, if 
the file does not exist, then it cannot be writable.  But -r will fail for one 
of two reasons:  1.) the file exists but is not readable by the owner of the
process that is running this script, or 2.) the file does not exist at all.

There are several boolean operators that are applied to C shell expressions, 
including the file queries above.  They are:

     !   -- negate                 
     &&  -- logical and
     ||  -- logical or

For example the way to test to see if a file does not exist would be:

     if (! -e somefile) then
          # does not exist

Make sure to put spaces before and after the -e because failure to do os will
confuse the C shell.  Here's a way to combine two queries:

     if (-f somefile && -w somefile) then
          # the file exists, is not a directory and I can write it

If there is a doubt as to precedence, use parentheses, but you may need to
use spaces before and after the parentheses.  The C shell's parser is not as
robust as the C compiler's, so it can get confused easily when things are run
together without intervening spaces.


Variables
---------

The C shell scripting language permits variables.  The variables can have
long, mnemonic names and can be either character or numeric, although floating
point variables are not allowed.  You can also create arrays, which will be
discussed in a later section.

When you refer to a variable's value in a C shell statement, you must prefix
the variable name with a dollar sign.  The only time you don't use a dollar
sign is in the "set" statement which assigns a value to a variable, or changes
the value of an existing variable.  The format of set is

     set name = expression

C shell variables are dynamic.  They are not declared but come into existence
when they are first set.  Consequently, you delete them in a shell by using
"unset".

     unset name

There is a special value, called the NULL value, and it is assigned to a
variable by doing

     set name =

with no expression.  Notice that such a variable is still defined, i.e. it
still exists, even though it has this special NULL value.  To actually get
rid of the variable, use unset.

To give a character value to a variable, you can use double quotes or you
can forego them.  If the character string contains special characters, such as
a blank, then you must use double quotes.  Here are some examples:

    set name = Mark
    echo $name
    if ($name == Mark) then
      ...

    set name = "Mark Meyer"
    echo $name
    set dirname = /usr/local/doc/HELP
    ls $dirname

You can find out if a variable is defined or not by using the special form 
$?var.  This could be used in an if statement.  For example:

    if ($?dirname) then
        ls $dirname
    else
        ...

To change a variable's value, just use set again, but do not use $.

    set dirname = /mnt1/dept/glorp

To add on to an existing character string variable, you can do something like
the following:

    set sentence = "Hi"
    set sentence = "$sentence there everybody"

Now $sentence, if echoed, would have "Hi there everybody" in it.  The following
also works:

    set sentence = Hi
    set sentence = "$sentence there everybody"

There is a special variable called $$ which has the process id number of the
process that is running this shell script.  Many programmers use this to create
unique file names, often in the /tmp directory.  Here's an example of copying
the first parameter (which is obviously a filename) into a temp file whose name
uses the pid number:

    cp $1 /tmp/tempfile.$$

This will create a file whose name is something like /tmp/tempfile.14506, if
the pid number is 14506.

Actually, the computer cycles through the pid numbers eventually, but usually
the same pid does not occur for several days, so there is seldom any need to
worry.


Use of variables in the shell
-----------------------------

One of the nice features about Cshell programming is that there is no clear
line between what you can do in a shell script and what you can type in from
the prompt.  Thus, you can set and unset variables, use for loops and do all
sorts of things at the command prompt.  Some things will not work, like using
the parameters $1, $2, etc because there are none.  But other features work,
and the use of setting variables is quite handy, especially when you want to
use a long, complex pathname repeatedly:

    % set X = /usr/local/doc/HELP
    % ls $X
    % ls $X/TUTORIALS

You can even embed the shell variables inside other strings, as shown above in
$X/TUTORIALS.  Obviously, you cannot follow the shell variable with a string
that begins with an alphabetic or numeric character because the C shell will 
not know which variable you are talking about, such as $XHITHERE.


Arithmetic variables
--------------------

Variables whose values are integer use a slightly different set command.
The commercial-at sign is used instead of "set" to indicate "assignment".
Otherwise, the Cshell would use a character string "123" instead of the
integer 123.  Here are a couple of examples:

    @ i = 2
    @ k = ($x - 2) * 4
    @ k = $k + 1

There is also a -- and a ++ operator to decrement and increment numeric
variables.  Be careful not to omit the blank that follows the at-sign!

    @ i--
    @ i++


Expressions and true and false
------------------------------

The Cshell works very much like C in that it treats 0 as false and anything
else as true.  Consequently, the expressions that are used in if and while
statements use the numeric values.  Here's a counting loop that uses a numeric
variable:

    @ n = 5
    while ($n) 
         # do something
         @ n--
    end

There are also numeric constants, such as 0, 1, etc.  An infinite loop is
often seen in Cshell scripts as

    while (1) 
        ...
    end

To get out of such a loop, use break or exit.  Of course, exit also causes the
entire shell script to end!  In the following while statement, the user is
asked to type in something.  If 0 is entered, then the while loop ends.  Note
the use of $< as the input device in the Cshell language, and an abbreviated
if statement that foregoes the use of then and endif:

    while (1) 
       echo -n "Gimme something: "
       set x = $<
       if (! $x) break
    end

If a variable contains the NULL value, then its use in an expression will be
the same as if it were 0.


Boolean conditions
------------------

To wrap up the discussion of operators and conditions, here are the Boolean
comparison operators.  Note that some of them are used only for strings while
some are used for only numbers.  A string does not necessarily have to be
surrounded by double quotes (unless it contains special characters like spaces
or other things.)

Expressions and operators

     ==        equal     (either strings or numbers)
     !=        not equal     (either strings or numbers)
     =~        string match
     !~        string mismatch
     <=        numerical less than or equal to
     >=        numerical greater than or equal to
     >         numerical greater than
     <         numerical less than

Here's a simple script to illustrate:

     #
     set x = mark
     set y = $<
     echo $x, $y
     if ($x == $y) then
        echo "They are the same"
     endif

If you type in "mark" without the double quotes, it will say they are the
same.  Strangely enough, if you omit the double quotes when you type in mark,
the Cshell no longer thinks the variables are equal!  Apparently, the double
quotes are stored as part of the string when you enter the value by means of
$<.

Strings have to match exactly, and 0005 and 5 are two completely different
strings.  However, they are the same numerical value.  The following shell
script would say that 0005 and 5 are the same:

     #
     @ x = 5
     @ y = $<
     echo $x, $y
     if ($x == $y) then
        echo "They are the same"
     endif

But if you were to replace the @'s with set's, they would no longer be the 
same.


Input and output
----------------

Output is fairly simple.  You can use echo to show literals and variable values.
If you do not want to cause a newline to be printed, use -n.  This is especial-
ly valuable in prompts, as in the while loop in the last section.

     echo "Hi there world"
     echo -n "Please type in your name: "
     echo "The current directory is " $cwd

$cwd is the current working directory, and is a built-in variable (discussed
next).

To get something from the user, use $<.  This causes the shell to pause until
the user types a carriage return.  What the user typed before the RETURN is
the value that $< returns.  This can be used in many different settings:  in
if conditions, while loops, or in set statements. 

     set x = $< 

Of course, if you expect to get something intelligent from the user, make sure
to prompt her for the type of information you are requesting!


Built-in variables
------------------

There are a few built-in variables, like $cwd and $HOME.  $Cwd is the current
working directory, what you see when you use "pwd".  $HOME is your home 
directory.  Here are others:

     $user      -- who am I?
     $hostess   -- name of the computer I am logged on to
     $path      -- my execution path (list of directories to be searched
                   for executables)
     $term      -- what kind of terminal I am using
     $status    -- a numeric variable, usually used to retun error codes
     $prompt    -- what I am currently using for a prompt
     $shell     -- which shell am I using  (usu. either /bin/csh or /bin/sh)

These variables can be found by typing:

     % set

from the prompt.


Array variables
---------------

Not all variables are single values.  Some consist of a list of values, which
are variously dubbed "arrays", "multi-word" variables or "lists" (3 names for
the same thing).  We will call them arrays herein, but they really are just 
lists of values.  The lists are dynamic in size, meaning that they can shrink 
or grow.

To create an array out of a single value, use the parentheses.  For example,
the following creates a list of four names:

    set name = (mark sally kathy tony)

You can still retrieve the value of this variable by doing $name, but in doing
so you get the whole list.

A new syntax is used to find out how long an array is:  $#name, such as:

   echo $#name

which will print out 4.  The value of $#name is always an integer, and can be
used in several settings.

To access elements in an array, square brackets surround a subscript expression
such as

   echo $name[1]
   echo $name[4]

If you give too high a subscript, Cshell prints "Subscript out of range".

There are many handy shortcuts that you can use in Cshell subscripts that are
not possible in C.  For instance, you can specify a range of subscripts.  The
range can even be one-ended so that you can specify, for example, all elements
from 5 to the end:

   echo $name[2-3]
   echo $name[2-]        # all elements from 2 to the end
   echo $name[1-3]

The subscript can itself be a variable, such as

   echo $name[$i]

You can add to an array in several ways, all involving reassignment to the
variable using parentheses.  For example to add something to the end, you
specify the current value of the variable followed by the new item, all sur-
rounded by parentheses:

   set name = ($name doran)

Likewise you can add to the beginning:

   set name = (doran $name)

The size of the array also changes, naturally.  To add to the middle of the
array, you need to specify two ranges.  For example, if your array is 5
elements long, say (mark kathy sally tony doran) and you wanted to add alfie
between kathy and sally, you could do

   set name = ($name[1-2] alfie $name[3-])

Likewise, you could remove a middle element by specifying two ranges inside
parentheses.

   @ k = 2
   @ j = 4
   set name = ($name[1-$k] $name[$j-])

Unfortunately, you cannot put arithmetic expressions inside the brackets, so
you must use extra variables.

The shift command gets rid of the first element of an array.  For example, if
name contains (mark kathy sally), then

   shift name

will get rid of the first element and move the remaining down by 1. If no 
argument is given, then it shifts the built-in array variable argv.

    shift
    shift names

In fact, shift is a holdover from Bourne shell programming which does not have
arrays.  When a shell script examines its arguments, it often makes note of
what options were requested, and then moves on to the next option.  Shift
makes this a whole lot easier.

Here's a typical example:

    while ($#argv > 0)
        grep $something $argv[1]
    end

In conclusion, the arguments to a shell script are put into the array variable
argv, so that the first argument is $argv[1], the second is $argv[2], etc.
As another holdover from the Bourne shell, $1 is a shorthand for $argv[1],
$2 for $argv[2], and so forth.  But the Bourne shell expression $* which stood
for all arguments will not work.  You must use either $argv[*] or just $argv.


Switch statements
-----------------

The switch statement provides a multi-way branch, much as in C.  However, 
several keywords differ from C.  Here's the general format:

     switch ( expression )
        case a:
               commands
               breaksw
        case b:
               commands
               breaksw
     endsw

Notice that breaksw is used instead of just break, unlike C.  Another major
difference is that the commands for a particular case MUST NOT be on the same
line.  Thus, the following would be wrong:

       case a: commands

The reason for this lies in the fact that the Cshell language is interpreted,
not compiled.

The values in the cases do not need to be integers or scalar values.  They 
can be "words" from an array.  The following might be inside a while loop:

      switch ($argv[$i])
         case quit:
                break        # leave the switch statement
         case list:
                ls
                breaksw
         case delete:
         case erase:
                @ k = $i + 1
                rm $argv[$k]
                breaksw
      endsw


Here document
--------------

We know how > and < work in I/O redirection.  There is a use for >>, namely to 
append data to the end of an existing file.  What about <<?  Logically, this 
should deal with some form of input, and it does.  If you want to create a file
inside a shell script and get the data from the script itself, rather than from
another separate file or from the user, you create a HERE document.

Following << is a symbol, usually a word, often in capital letters.  The cshell
takes the next line and all lines following until it finds the same word in
column 1 as the input to be sent into the command using the <<.  Here's a simple
example of a shellscript that looks up your friends and family in a small data-
base:

     #
     grep $i <<HERE
     John Doe   101 Surrey Lane    London, UK    5E7 J2K
     Angela Langsbury   99 Knightsbridge, Apt. K4     Liverpool
     John Major  10 Downing Street  London
     HERE

Here's an example of creating a temporary file:

     cat > tempdata <<ENDOFDATA
     53.3 94.3 67.1
     48.3 01.3 99.9
     42.1 48.6 92.8
     ENDOFDATA

You can use any symbol to mark the end of the HERE document.   The only require-
ment is that it must match << and be in column 1.

Be careful about symbols in your here document because alias, history, and
variable substitutions are performed on the lines of the here document.  This
can actually be quite useful.  Just put $variables into your here document if
you want to customize the here document.  

Remember to clean up files that you might create inside a shell script.  For
example the numerical data file above, tempdata, is still lingering in the
current directory, so you should probably delete it, unless you specifically
want it to remain.  However, the database of names given to the grep command
above does not create an extra file, so it is preferred.  But occasionally you
need the same file to be given to several commands, and it would be wasteful and
error-prone to duplicate it in the shellscript with several here documents.


Executing commands
------------------

Occasionally we need to execute a command inside another command in order to get
its output or its return code.  To get the output, use the backquotes.  For
example, the following could be put inside a shell script:

     echo "Hello there `whoami`.  How are you today?"
     echo "You are currently using `hostname` and the time is `date`"
     echo "Your directory is `pwd`"

Of course all of these commands have equivalents in Cshell variables except the
date command.  Following is a better example:

     echo "There are `wc -l $1` lines in file $1"

Another use of commands is to use their return codes inside conditional expres-
sions.  For example, the -s option of the grep command stands for silent mode.
It causes grep to do its job without producing any output, but the return code
is then used.  You cannot see the return code, but you can use it if you sur-
round the command in curly braces:

     if ({grep -s junk $1}) then
           echo "We found junk in file $1"
     endif

Notice that if (`grep junk $1`) would not work because this would cause 
grep's output to be substituted into the expression, but in silent mode, there
is no output.

The return code of a shell script is set by the exit statement, which can take
an integer argument:

     exit -1
     exit 0
     exit 12

Good script programmers follow the convention that 0 means "all ok" while a
non-zero value indicates some error code.  If you use "exit" with no argument,
0 is assumed.

The return code of a C program is set by the exit() system call, which also
takes an integer argument.  The same convention is followed that 0 is "all ok".

Now the odd thing is that 0 usually means "false" which would cause the if
statement to do the false statements.  To get around this weird mismatch of
conventions, the curly braces invert the return code.  That is, if grep finds
the string it normally returns 0.  But the curly braces turn this into 1 so
that the if statement will trigger properly.  You do not necessarily have to
be aware of this to program Cshell scripts properly.  Just follow the conven-
tions.


Recursion
---------

Cshell scripts (and also Bourne shell scripts) can be recursive.  This works 
because each UNIX command is started in its own shell, with its own process and
its own process id.  This is also the reason shell scripts run so much more 
slowly, because starting processes is slow.  So if the same shell script 
filename appears inside itself, UNIX just blindly starts up another process and
runs the Cshell in it, interpreting the commands in the file.

Recursive shell scripts are very common when the script is naturally recursive
with regard to the tree structure.  Many built-in UNIX commands allow the -R
option to specify that the command is done recursively to all components of
the directory:

    % ls -RC /

As an example of a recursive shellscript, here's one that prints the head of
each file in the current directory and in every subdirectory.  Let us suppose
that this shellscript is in a file called "headers":

    #
    foreach i (*)
        if (-f $i) then
            echo "============= $i ==================="
            head $i
        endif
        if (-d $i) then
            (cd $i; headers)
        endif
    end

Note the use of parentheses in (cd $i;headers).  The parentheses here mean to
do the commands in a new shell, for the cd command normally changes the current
directory, which would be disastrous for later functioning of the script, which
would have no way to return to the previous directory when it finished.  But
isolating the commands in their own shell makes this secure and modular.

To run headers, just do

    % cd <whatever dir you want>
    % headers


Debugging
---------

There is not much support for debugging in Cshell scripts.  You can always rely
on the good old standard way of debugging:  peppering your code with output
statements, echo in this case, to see what is going on.  To deactivate some of
them without getting rid of them, comment them out by putting a pound sign in 
column 1.

About the only other support for debugging is using some options to the Cshell.
-v is verbose and -x echoes the commands after ALL substitutions are made.  In
order to use these, however, you cannot run your shellscript by just typing in
the name followed by arguments.  Rather, you must give the name of the file as
an argument itself to the csh command, followed by the arguments to your own
script:

     % csh -vx somescript args

Both options are needed because the Cshell does a lot of substitutions (history,
alias, and variable) after it reads each line.  -vx causes both the original 
line from the script file to be printed, as well as the revised form after the
substitutions are made.

Another handy option is -n, which parses the script commands without execution
in order to check for Cshell syntax errors.

     % csh -n somescript


Performance considerations
--------------------------

Shell scripts are interpreted in UNIX.  That is, there does not exist a
compiler to translate the code into machine language, such as the C or Ada
compiler does.  As you might have heard, interpreted languages tend to be
very slow in execution speed, so do not write a numerical analysis program in
the C-shell script language!  Most shell scripts run very slowly.

The interpreter of shell scripts is the /bin/csh program itself.  The cshell
"knows" when it is executing commands from a file as opposed to reading them
from the user sitting at a terminal, but it is still the same interpreter
program.

Whenever you run a command in a shell, a new copy of the shell is started up
(or "forked off", to use proper UNIX lingo).  The new copy is actually another
process that is also running the csh interpreter.  When it starts, it reads
the .cshrc file from your home directory in order to learn about any aliases
and paths that you may have customized.  Thus, if your .cshrc file is long,
startup time for a command is long.

There is a way to avoid loading the .cshrc file for a shell script.  On the
first line of the file containing the script put

    #!/bin/csh

The comment symbol (#) is actually a special UNIX symbol that means "the name
of the program to interpret this file follows me".  Thus, /bin/csh appears be-
cause it is the interpreter for this file.  The bang symbol (!) means not to 
load the preamble file for this interpreter.

You can even put options to the interpreter on this line.  For instance if
you wanted the shell script lines echoed for purposes of debugging, you could
use instead:

    #!/bin/csh -vx

Generally shell scripts are either short or are used because it is too clumsy
to write a C program to make all the file decisions that need to be made.
Shell programming is a convenience, and it has a clearly defined niche, but
that niche is not general purpose problem solving such as you might use C or
Ada for.

Many programmers still use the Bourne shell for shell programming, partly be-
cause it is faster and partly because there are more books and examples out
there.  Since the Bourne shell is simpler and has fewer features, it is a
smaller interpreter so starting it up takes less time.

Automating backups with tar

  1. Create the backup script backup.cron file, touch /etc/cron.daily/backup.cron and add the following lines to this backup file:
    #!/bin/sh
    # full and incremental backup script
    
    #Change the 5 variables below to fit your computer/backup
    
    COMPUTER=deep                           	# name of this computer
    DIRECTORIES="/home"                     	# directoris to backup
    BACKUPDIR=/backups                      	# where to store the backups
    TIMEDIR=/backups/last-full              	# where to store time of full backup
    TAR=/bin/tar                            		# name and locaction of tar
    
    #You should not have to change anything below here
    
    PATH=/usr/local/bin:/usr/bin:/bin
    DOW=`date +%a`              		# Day of the week e.g. Mon
    DOM=`date +%d`              		# Date of the Month e.g. 27
    DM=`date +%d%b`             	# Date and Month e.g. 27Sep
    
    # On the 1st of the month a permanet full backup is made
    # Every Sunday a full backup is made - overwriting last Sundays backup
    # The rest of the time an incremental backup is made. Each incremental
    # backup overwrites last weeks incremental backup of the same name.
    #
    # if NEWER = "", then tar backs up all files in the directories
    # otherwise it backs up files newer than the NEWER date. NEWER
    # gets it date from the file written every Sunday.
    
    
    # Monthly full backup
    if [ $DOM = "01" ]; then
            NEWER=""
            $TAR $NEWER -cf $BACKUPDIR/$COMPUTER-$DM.tar $DIRECTORIES
    fi
    
    # Weekly full backup
    if [ $DOW = "Sun" ]; then
            NEWER=""
            NOW=`date +%d-%b`
    
            # Update full backup date
            echo $NOW > $TIMEDIR/$COMPUTER-full-date
            $TAR $NEWER -cf $BACKUPDIR/$COMPUTER-$DOW.tar $DIRECTORIES
    
    # Make incremental backup - overwrite last weeks
    else
    
            # Get date of last full backup
            NEWER="--newer `cat $TIMEDIR/$COMPUTER-full-date`"
            $TAR $NEWER -cf $BACKUPDIR/$COMPUTER-$DOW.tar $DIRECTORIES
    fi
    

    Here is an abbreviated look of the backup directory after one week:

    [root@deep] /# ls -l /backups/
    
    
    total 22217
    -rw-r--r--   	1 root     root     	 10731288 	Feb  7 11:24 deep-01Feb.tar
    -rw-r--r--   	1 root     root            	6879 	Feb  7 11:24 deep-Fri.tar
    -rw-r--r--   	1 root     root         	2831 	Feb  7 11:24 deep-Mon.tar
    -rw-r--r--   	1 root     root            	7924 	Feb  7 11:25 deep-Sat.tar
    -rw-r--r--   	1 root     root     	 11923013 	Feb  7 11:24 deep-Sun.tar
    -rw-r--r--   	1 root     root            	5643 	Feb  7 11:25 deep-Thu.tar
    -rw-r--r--   	1 root     root            	3152 	Feb  7 11:25 deep-Tue.tar
    -rw-r--r--   	1 root     root            	4567 	Feb  7 11:25 deep-Wed.tar
    drwxr-xr-x	2 root     root         	1024 	Feb  7 11:20 last-full
    

    Backup directory of a week

    The directory where to store the backups BACKUPDIR, and the directory where to store time of full backup TIMEDIR must exist or be created before the use of the backup-script, or you will receive an error message.

  2. If you are not running this backup script from the beginning of the month 01-month-year, the incremental backups will need the time of the Sunday backup to be able to work properly. If you start in the middle of the week, you will need to create the time file in the TIMEDIR. To create the time file in the TIMEDIR directory, use the following command:
    [root@deep] /# date +%d%b < /backups/last-full/myserver-full-date
    

    Where /backups/last-full is our variable TIMEDIR wherein we want to store the time of the full backup, and myserver-full-date is the name of our server e.g. deep, and our time file consists of a single line with the present date i.e. 15-Feb.

  3. Make this script executable and change its default permissions to be writable only by the super-user root 755.
    [root@deep] /# chmod 755 /etc/cron.daily/backup.cron
    

Because this script is in the /etc/cron.daily directory, it will be automatically run as a cron job at one o’clock in the morning every day.

How To Set Up a Firewall Using FirewallD on CentOS 7

Introduction

Firewalld is a complete firewall solution available by default on CentOS 7 servers. In this guide, we will cover how to set up a firewall for your server and show you the basics of managing the firewall with thefirewall-cmd administrative tool (if you’d rather use iptables with CentOS, follow this guide).

Basic Concepts in Firewalld

Before we begin talking about how to actually use the firewall-cmd utility to manage your firewall configuration, we should get familiar with a few basic concepts that the tool introduces.

Zones

The firewalld daemon manages groups of rules using entities called “zones”. Zones are basically sets of rules dictating what traffic should be allowed depending on the level of trust you have in the networks your computer is connected to. Network interfaces are assigned a zone to dictate the behavior that the firewall should allow.

For computers that might move between networks frequently (like laptops), this kind of flexibility provides a good method of changing your rules depending on your environment. You may have strict rules in place prohibiting most traffic when operating on a public WiFi network, while allowing more relaxed restrictions when connected to your home network. For a server, these zones are not as immediately important because the network environment rarely, if ever, changes.

Regardless of how dymaic your network environment may be, it is still useful to be familiar with the general idea behind each of the pre-defined zones for firewalld. In order from least trusted to most trusted, the pre-defined zones within firewalld are:

  • drop: The lowest level of trust. All incoming connections are dropped without reply and only outgoing connections are possible.
  • block: Similar to the above, but instead of simply dropping connections, incoming requests are rejected with an icmp-host-prohibited or icmp6-adm-prohibited message.
  • public: Represents public, untrusted networks. You don’t trust other computers but may allow selected incoming connections on a case-by-case basis.
  • external: External networks in the event that you are using the firewall as your gateway. It is configured for NAT masquerading so that your internal network remains private but reachable.
  • internal: The other side of the external zone, used for the internal portion of a gateway. The computers are fairly trustworthy and some additional services are available.
  • dmz: Used for computers located in a DMZ (isolated computers that will not have access to the rest of your network). Only certain incoming connections are allowed.
  • work: Used for work machines. Trust most of the computers in the network. A few more services might be allowed.
  • home: A home environment. It generally implies that you trust most of the other computers and that a few more services will be accepted.
  • trusted: Trust all of the machines in the network. The most open of the available options and should be used sparingly.

To use the firewall, we can create rules and alter the properties of our zones and then assign our network interfaces to whichever zones are most appropriate.

Rule Permanence

In firewalld, rules can be designated as either permanent or immediate. If a rule is added or modified, by default, the behavior of the currently running firewall is modified. At the next boot, the old rules will be reverted.

Most firewall-cmd operations can take the --permanent flag to indicate that the non-ephemeral firewall should be targeted. This will affect the rule set that is reloaded upon boot. This separation means that you can test rules in your active firewall instance and then reload if there are problems. You can also use the --permanent flag to build out an entire set of rules over time that will all be applied at once when the reload command is issued.

Turning on the Firewall

Before we can begin to create our firewall rules, we need to actually turn the daemon on. The systemdunit file is called firewalld.service. We can start the daemon for this session by typing:

  • sudo systemctl start firewalld.service

We can verify that the service is running and reachable by typing:

  • firewall-cmd –state
output
running

This indicates that our firewall is up and running with the default configuration.

At this point, we will not enable the service. Enabling the service would cause the firewall to start up at boot. We should wait until we have created our firewall rules and had an opportunity to test them before configuring this behavior. This can help us avoid being locked out of the machine if something goes wrong.

Getting Familiar with the Current Firewall Rules

Before we begin to make modifications, we should familiarize ourselves with the default environment and rules provided by the daemon.

Exploring the Defaults

We can see which zone is currently selected as the default by typing:

  • firewall-cmd –get-default-zone
output
public

Since we haven’t given firewalld any commands to deviate from the default zone, and none of our interfaces are configured to bind to another zone, that zone will also be the only “active” zone (the zone that is controlling the traffic for our interfaces). We can verify that by typing:

  • firewall-cmd –get-active-zones
output
public
  interfaces: eth0 eth1

Here, we can see that we have two network interfaces being controlled by the firewall (eth0 and eth1). They are both currently being managed according to the rules defined for the public zone.

How do we know what rules are associated with the public zone though? We can print out the default zone’s configuration by typing:

  • firewall-cmd –list-all
output
public (default, active)
  interfaces: eth0 eth1
  sources: 
  services: dhcpv6-client ssh
  ports: 
  masquerade: no
  forward-ports: 
  icmp-blocks: 
  rich rules:

We can tell from the output that this zone is both the default and active and that the eth0 and eth1interfaces are associated with this zone (we already knew all of this from our previous inquiries). However, we can also see that this zone allows for the normal operations associated with a DHCP client (for IP address assignment) and SSH (for remote administration).

Exploring Alternative Zones

Now we have a good idea about the configuration for the default and active zone. We can find out information about other zones as well.

To get a list of the available zones, type:

  • firewall-cmd –get-zones
output
block dmz drop external home internal public trusted work

We can see the specific configuration associated with a zone by including the --zone= parameter in our --list-all command:

  • firewall-cmd –zone=home –list-all
output
home
  interfaces: 
  sources: 
  services: dhcpv6-client ipp-client mdns samba-client ssh
  ports: 
  masquerade: no
  forward-ports: 
  icmp-blocks: 
  rich rules:

You can output all of the zone definitions by using the --list-all-zones option. You will probably want to pipe the output into a pager for easier viewing:

  • firewall-cmd –list-all-zones | less

Selecting Zones for your Interfaces

Unless you have configured your network interfaces otherwise, each interface will be put in the default zone when the firewall is booted.

Changing the Zone of an Interface for the Current Session

You can transition an interface between zones during a session by using the --zone= parameter in combination with the --change-interface= parameter. As with all commands that modify the firewall, you will need to use sudo.

For instance, we can transition our eth0 interface to the “home” zone by typing this:

  • sudo firewall-cmd –zone=home –change-interface=eth0
output
success
Note

Whenever you are transitioning an interface to a new zone, be aware that you are probably modifying the services that will be operational. For instance, here we are moving to the “home” zone, which has SSH available. This means that our connection shouldn’t drop. Some other zones do not have SSH enabled by default and if your connection is dropped while using one of these zones, you could find yourself unable to log back in.

We can verify that this was successful by asking for the active zones again:

  • firewall-cmd –get-active-zones
output
home
  interfaces: eth0
public
  interfaces: eth1

If the firewall is completely restarted, the interface will revert to the default zone:

  • sudo systemctl restart firewalld.service
  • firewall-cmd –get-active-zones
output
public
  interfaces: eth0 eth1

Changing the Zone of your Interface Permanently

Interfaces will always revert to the default zone if they do not have an alternative zone defined within their configuration. On CentOS, these configurations are defined within the /etc/sysconfig/network-scriptsdirectory with files of the format ifcfg-interface.

To define a zone for the interface, open up the file associated with the interface you’d like to modify. We’ll demonstrate making the change we showed above permanent:

  • sudo nano /etc/sysconfig/network-scripts/ifcfg-eth0

At the bottom of the file, set the ZONE= variable to the zone you wish to associate with the interface. In our case, this would be the “home” interface:

/etc/sysconfig/network-scripts/ifcfg-eth0
. . .

DNS1=2001:4860:4860::8844
DNS2=2001:4860:4860::8888
DNS3=8.8.8.8
ZONE=home

Save and close the file.

To implement your changes, you’ll have to restart the network service, followed by the firewall service:

  • sudo systemctl restart network.service
  • sudo systemctl restart firewalld.service

After your firewall restarts, you can see that your eth0 interface is automatically placed in the “home” zone:

  • firewall-cmd –get-active-zones
output
home
  interfaces: eth0
public
  interfaces: eth1

Make sure to revert these changes if this is not the actual zone you’d like to use for this interface.

Adjusting the Default Zone

If all of your interfaces can best be handled by a single zone, it’s probably easier to just select the best default zone and then use that for your configuration.

You can change the default zone with the --set-default-zone= parameter. This will immediately change any interface that had fallen back on the default to the new zone:

  • sudo firewall-cmd –set-default-zone=home
output
home
  interfaces: eth0 eth1

Setting Rules for your Applications

The basic way of defining firewall exceptions for the services you wish to make available is easy. We’ll run through the basic idea here.

Adding a Service to your Zones

The easiest method is to add the services or ports you need to the zones you are using. Again, you can get a list of the available services with the --get-services option:

  • firewall-cmd –get-services
output
RH-Satellite-6 amanda-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns ftp high-availability http https imaps ipp ipp-client ipsec kerberos kpasswd ldap ldaps libvirt libvirt-tls mdns mountd ms-wbt mysql nfs ntp openvpn pmcd pmproxy pmwebapi pmwebapis pop3s postgresql proxy-dhcp radius rpc-bind samba samba-client smtp ssh telnet tftp tftp-client transmission-client vnc-server wbem-https
Note

You can get more details about each of these services by looking at their associated .xml file within the /usr/lib/firewalld/services directory. For instance, the SSH service is defined like this:

/usr/lib/firewalld/services/ssh.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>SSH</short>
  <description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications. If you plan on accessing your machine remotely via SSH over a firewalled interface, enable this option. You need the openssh-server package installed for this option to be useful.</description>
  <port protocol="tcp" port="22"/>
</service>

You can enable a service for a zone using the --add-service= parameter. The operation will target the default zone or whatever zone is specified by the --zone= parameter. By default, this will only adjust the current firewall session. You can adjust the permanent firewall configuration by including the --permanentflag.

For instance, if we are running a web server serving conventional HTTP traffic, we can allow this traffic for interfaces in our “public” zone for this session by typing:

  • sudo firewall-cmd –zone=public –add-service=http

You can leave out the --zone= if you wish to modify the default zone. We can verify the operation was successful by using the --list-all or --list-services operations:

  • firewall-cmd –zone=public –list-services
output
dhcpv6-client http ssh

Once you have tested that everything is working as it should, you will probably want to modify the permanent firewall rules so that your service will still be available after a reboot. We can make our “public” zone change permanent by typing:

  • sudo firewall-cmd –zone=public –permanent –add-service=http

You can verify that this was successful by adding the --permanent flag to the --list-servicesoperation. You need to use sudo for any --permanent operations:

  • sudo firewall-cmd –zone=public –permanent –list-services
output
dhcpv6-client http ssh

Your “public” zone will now allow HTTP web traffic on port 80. If your web server is configured to use SSL/TLS, you’ll also want to add the https service. We can add that to the current session and the permanent rule-set by typing:

  • sudo firewall-cmd –zone=public –add-service=https
  • sudo firewall-cmd –zone=public –permanent –add-service=https

What If No Appropriate Service Is Available?

The firewall services that are included with the firewalld installation represent many of the most common requirements for applications that you may wish to allow access to. However, there will likely be scenarios where these services do not fit your requirements.

In this situation, you have two options.

Opening a Port for your Zones

The easiest way to add support for your specific application is to open up the ports that it uses in the appropriate zone(s). This is as easy as specifying the port or port range, and the associated protocol for the ports you need to open.

For instance, if our application runs on port 5000 and uses TCP, we could add this to the “public” zone for this session using the --add-port= parameter. Protocols can be either tcp or udp:

  • sudo firewall-cmd –zone=public –add-port=5000/tcp

We can verify that this was successful using the --list-ports operation:

  • firewall-cmd –list-ports
output
5000/tcp

It is also possible to specify a sequential range of ports by separating the beginning and ending port in the range with a dash. For instance, if our application uses UDP ports 4990 to 4999, we could open these up on “public” by typing:

  • sudo firewall-cmd –zone=public –add-port=4990-4999/udp

After testing, we would likely want to add these to the permanent firewall. You can do that by typing:

  • sudo firewall-cmd –zone=public –permanent –add-port=5000/tcp
  • sudo firewall-cmd –zone=public –permanent –add-port=4990-4999/udp
  • sudo firewall-cmd –zone=public –permanent –list-ports
output
success
success
4990-4999/udp 5000/tcp

Defining a Service

Opening ports for your zones is easy, but it can be difficult to keep track of what each one is for. If you ever decommission a service on your server, you may have a hard time remembering which ports that have been opened are still required. To avoid this situation, it is possible to define a service.

Services are simply collections of ports with an associated name and description. Using services is easier to administer than ports, but requires a bit of upfront work. The easiest way to start is to copy an existing script (found in /usr/lib/firewalld/services) to the /etc/firewalld/services directory where the firewall looks for non-standard definitions.

For instance, we could copy the SSH service definition to use for our “example” service definition like this. The filename minus the .xml suffix will dictate the name of the service within the firewall services list:

  • sudo cp /usr/lib/firewalld/services/service.xml /etc/firewalld/services/example.xml

Now, you can adjust the definition found in the file you copied:

sudo nano /etc/firewalld/services/example.xml

To start, the file will contain the SSH definition that you copied:

/etc/firewalld/services/example.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>SSH</short>
  <description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications. If you plan on accessing your machine remotely via SSH over a firewalled interface, enable this option. You need the openssh-server package installed for this option to be useful.</description>
  <port protocol="tcp" port="22"/>
</service>

The majority of this definition is actually metadata. You will want to change the short name for the service within the <short> tags. This is a human-readable name for your service. You should also add a description so that you have more information if you ever need to audit the service. The only configuration you need to make that actually affects the functionality of the service will likely be the port definition where you identify the port number and protocol you wish to open. This can be specified multiple times.

For our “example” service, imagine that we need to open up port 7777 for TCP and 8888 for UDP. We could modify the existing definition with something like this:

/etc/firewalld/services/example.xml

<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Example Service</short>
  <description>This is just an example service.  It probably shouldn't be used on a real system.</description>
  <port protocol="tcp" port="7777"/>
  <port protocol="udp" port="8888"/>
</service>

Save and close the file.

Reload your firewall to get access to your new service:

  • sudo firewall-cmd –reload

You can see that it is now among the list of available services:

  • firewall-cmd –get-services
output
RH-Satellite-6 amanda-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns example ftp high-availability http https imaps ipp ipp-client ipsec kerberos kpasswd ldap ldaps libvirt libvirt-tls mdns mountd ms-wbt mysql nfs ntp openvpn pmcd pmproxy pmwebapi pmwebapis pop3s postgresql proxy-dhcp radius rpc-bind samba samba-client smtp ssh telnet tftp tftp-client transmission-client vnc-server wbem-https

You can now use this service in your zones as you normally would.

Creating Your Own Zones

While the predefined zones will probably be more than enough for most users, it can be helpful to define your own zones that are more descriptive of their function.

For instance, you might want to create a zone for your web server, called “publicweb”. However, you might want to have another zone configured for the DNS service you provide on your private network. You might want a zone called “privateDNS” for that.

When adding a zone, you must add it to the permanent firewall configuration. You can then reload to bring the configuration into your running session. For instance, we could create the two zones we discussed above by typing:

  • sudo firewall-cmd –permanent –new-zone=publicweb
  • sudo firewall-cmd –permanent –new-zone=privateDNS

You can verify that these are present in your permanent configuration by typing:

  • sudo firewall-cmd –permanent –get-zones
output
block dmz drop external home internal privateDNS public publicweb trusted work

As stated before, these won’t be available in the current instance of the firewall yet:

  • firewall-cmd –get-zones
output
block dmz drop external home internal public trusted work

Reload the firewall to bring these new zones into the active configuration:

  • sudo firewall-cmd –reload
  • firewall-cmd –get-zones
output
block dmz drop external home internal privateDNS public publicweb trusted work

Now, you can begin assigning the appropriate services and ports to your zones. It’s usually a good idea to adjust the active instance and then transfer those changes to the permanent configuration after testing. For instance, for the “publicweb” zone, you might want to add the SSH, HTTP, and HTTPS services:

  • sudo firewall-cmd –zone=publicweb –add-service=ssh
  • sudo firewall-cmd –zone=publicweb –add-service=http
  • sudo firewall-cmd –zone=publicweb –add-service=https
  • firewall-cmd –zone=publicweb –list-all
output
publicweb
  interfaces: 
  sources: 
  services: http https ssh
  ports: 
  masquerade: no
  forward-ports: 
  icmp-blocks: 
  rich rules:

Likewise, we can add the DNS service to our “privateDNS” zone:

  • sudo firewall-cmd –zone=privateDNS –add-service=dns
  • firewall-cmd –zone=privateDNS –list-all
output
privateDNS
  interfaces: 
  sources: 
  services: dns
  ports: 
  masquerade: no
  forward-ports: 
  icmp-blocks: 
  rich rules:

We could then change our interfaces over to these new zones to test them out:

  • sudo firewall-cmd –zone=publicweb –change-interface=eth0
  • sudo firewall-cmd –zone=privateDNS –change-interface=eth1

At this point, you have the opportunity to test your configuration. If these values work for you, you will want to add the same rules to the permanent configuration. You can do that by re-applying the rules with the --permanent flag:

  • sudo firewall-cmd –zone=publicweb –permanent –add-service=ssh
  • sudo firewall-cmd –zone=publicweb –permanent –add-service=http
  • sudo firewall-cmd –zone=publicweb –permanent –add-service=https
  • sudo firewall-cmd –zone=privateDNS –permanent –add-service=dns

You can then modify your network interfaces to automatically select the correct zones.

We can associate the eth0 interface with the “publicweb” zone:

  • sudo nano /etc/sysconfig/network-scripts/ifcfg-eth0
[label /etc/sysconfig/network-scripts/ifcfg-eth0
. . .

IPV6_AUTOCONF=no
DNS1=2001:4860:4860::8844
DNS2=2001:4860:4860::8888
DNS3=8.8.8.8
ZONE=publicweb

And we can associate the eth1 interface with “privateDNS”:

  • sudo nano /etc/sysconfig/network-scripts/ifcfg-eth1
/etc/sysconfig/network-scripts/ifcfg-eth1
. . .

NETMASK=255.255.0.0
DEFROUTE='no'
NM_CONTROLLED='yes'
ZONE=privateDNS

Afterwards, you can restart your network and firewall services:

  • sudo systemctl restart network
  • sudo systemctl restart firewalld

Validate that the correct zones were assigned:

  • firewall-cmd –get-active-zones
output
privateDNS
  interfaces: eth1
publicweb
  interfaces: eth0

And validate that the appropriate services are available for both of the zones:

  • firewall-cmd –zone=publicweb –list-services
output
http htpps ssh
  • firewall-cmd –zone=privateDNS –list-services
output
dns

You have successfully set up your own zones. If you want to make one of these zones the default for other interfaces, remember to configure that behavior with the --set-default-zone= parameter:

sudo firewall-cmd --set-default-zone=publicweb

Enable Your Firewall to Start at Boot

At the beginning of the guide, we started our firewalld service, but we did not enable it. If you are happy with your current configuration and have tested that it is functional when you restart the service, you can safely enable the service.

To configure your firewall to start at boot, type:

  • sudo systemctl enable firewalld

When the server restarts, your firewall should be brought up, your network interfaces should be put into the zones you configured (or fall back to the configured default zone), and the rules associated with the zone(s) will be applied to the associated interfaces.

Conclusion

You should now have a fairly good understanding of how to administer the firewalld service on your CentOS system for day-to-day use.

The firewalld service allows you to configure maintainable rules and rule-sets that take into consideration your network environment. It allows you to seamlessly transition between different firewall policies through the use of zones and gives administrators the ability to abstract the port management into more friendly service definitions. Acquiring a working knowledge of this system will allow you to take advantage of the flexibility and power that this tool provides.