Dynamic firewall met CLI parser

Gepost door Peter Davidse op 23-04-2009 13:42.

Command Line script voor het dynamisch verwijderen en toevoegen van host in een iptables firewall.

De CLI parameter parser is zo opgebouwd dat het script eenvoudig is aan te passen voor andere toepassingen.

Het script maakt gebruik van "exec", dus shell commando's om te functioneren, controleer zelf of deze voldoen aan jouw systeem eisen.

Zonder parameters of bij fouten krijg je een uitgebreide help.

Het gebruik als Dynamische Firewall is "proof of concept" voor de CLI parser.

Doel van het script is om snel een host toe te voegen die bv je ssh bashed.
Het is geen firewall builder script en is ook nooit zo bedoeld!

Knownbug :
Het verwijderen gaat niet altijd goed wanneer ipv het ipaddress de hostname is vermeld en vice versa.

Bestanden van dit script

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/usr/bin/php -q
<?php

/** Description : Dynamic Firewall.
 *  Function    : Configure iptables dynamically from CLI
 *  Author      : Peter Davidse (phpscripts at esdivad dot com)
 *  Version     : 1.0
 *  Date        : 30.3.2009
 *  notes       - Linux with iptables only
 *              - loosely based on dynfw
 *              - you can use the parameter parser for other CLI scripts
 */

// Parse the parameter and put them in an array for evaluation
function parseOptions($array) {
  $isoption = FALSE;
  
  $parameters['filename'] = str_replace("./","",$array[0]);
  
  array_shift($array); //we do not need the program name
  
  foreach ($array as $val) {
    
    if ($isoption) {
      
      // check if we have an option
      if (strpos($val,"-")===0) {
        
        $parameters[$option] = '';
        
        $option = $val;
        $isoption = TRUE;
        
      } else {
        $option = str_replace("-","", $option);
        $parameters[$option] = $val;
        $isoption = FALSE;
        
      }
      
    } else {
      
      if (strpos($val,"-")===0) {
        
        $option = str_replace("-","", $val);
        $isoption = TRUE;
      
      } else {
 
        $isoption = FALSE;

      }
    }
    
    // if there is an last option
    if (current($array) && (strpos($val,"-")===0)) {
        
      $option = str_replace("-","", $val);
      $parameters[$option] = '';
    
    }
  }
 
  return $parameters;

}

// see if the ipaddress is correctly formed
function checkIPAddress($address) {
    if (preg_match( "/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/", $address))  { 
    return TRUE;
  } else {
    echo FALSE;
  } 
}

function checkParameters($parameters) {
  // sanitize the parameters given on the command line
  
  if (array_key_exists('h',$parameters) || count($parameters)==0) {
    help();
  }
  
  $error = '';
  
  //convert all parameters in array to variables
  foreach ($parameters as $key => $value) { 
    global $$key;
    $$key = $value;
  }

  if (isset($b) && isset($d)) {
    $error .= "\nconfused! do not set -b and -d together";
  }
  
  if (isset($i) && isset($n)) {
    $error .= "\nconfused! do not use -i and -n together";
  }
 
  // check action parameter, needs to be on or off
  if (!isset($a)) {
    $error .= "\nparameter -a not set";
  } else {
     if(!in_array($a,array("on","off"))) {
      $error .= "\nparameter -a needs to be valid";
    }
  }
  
  // see if we have a valid hostname or ipaddress (ip v4 only)
  if (!isset($i) && !isset($n)) {
    $error .= "\nparameter -i or -n not set";
  } else {
    if(isset($i)) {
      if(!checkIPAddress($i)) {
        $error .= "\nparameter -i not a valid IP Address";
      }
    } else {
      if(!checkIPAddress(gethostbyname($n))) {
        $error .= "\nparameter -n does not return a valid IP Address";
      }
    }
  }

  if(!empty($error)) {
    echo "\nErrors found in parameters:\n";
    echo $error."\n";
    help();
  }
}

// displays help
function help() {
  //show help and quit

  $help = "\nusage:\n";
  $help .= "\n";
  $help .= "block : -b -i [ipaddress] / -n [hostname] -a {on/off} {-f} \n";
  $help .= "drop  : -d -i [ipaddress] /- n [hostname] -a {on/off} {-f} \n";
  $help .= "-f forces an addition even if the host is already listed\n";
  $help .= "Use drop if the host is really intrusive, otherwise use block!";
  $help .= "\n";
  echo $help;
  exit;
}

// BEGIN OF THE SCRIPT

checkParameters(parseOptions($argv)); // if parameter are wrong script exits in help()

if ($a=="on") {
  $action = "-I";
} else {
  $action = "-D";
}

// use hostname as option
if (isset($n)) {
  $i = $n;
}

// is the address already in iptables
$ipexists = exec("iptables -L | grep $i | wc -l");

if ($ipexists!=0 && $a == "on") {
  echo "IP address already exists in iptables! You can use -f to force addition!\n";
  if (!isset($f)) { // force the rule even if the ip address exists
    exit;
  }
}

if ($ipexists==0 && $a == "off") {
  echo "IP address does not exist in iptables!\n";
  exit;
} 

// do the drop action
if (isset($d)) {  
  exec("iptables $action INPUT -s $i -j DROP");
  exec("iptables $action OUTPUT -s $i -j DROP");
  exec("iptables $action FORWARD -s $i -j DROP");
  echo "IP address $i drop $a\n";
}

// do the block action
if (isset($b)) {
  exec("iptables $action INPUT   -s $i -j DROP");
  exec("iptables $action INPUT   -p tcp -s $i -j REJECT --reject-with tcp-reset");
  exec("iptables $action OUTPUT  -d $i -j DROP");
  exec("iptables $action OUTPUT  -p tcp -d $i -j REJECT --reject-with tcp-reset");
  exec("iptables $action FORWARD -d $i -j DROP");
  exec("iptables $action FORWARD -p tcp -d $i -j REJECT --reject-with tcp-reset");
  echo "IP address $i block $a\n";
}

Commentaar

22-04-2009 20:42

1 . Heel leuk en aardig, maar gebruik nooit vars in teksten.

2. En escapeshellarg zou ik wel verstandig zijn.

Maar voor de rest wel ok hoor ;)

1
2
3
4
5
6
7
8
9
10
11
12
<?php
// fout:
$a = "bla";
$text = "bla $a";

// goed:
$text = 'bla '.$a;
?>

<?php
exec('/path/to/bin '.escapeshellarg('arg 1').' '.escapeshellarg('arg 2'));
?>
22-04-2009 21:49

"Het verwijderen gaat niet altijd goed wanneer ipv het ipaddress de hostname is vermeld en vice versa."

Goed dat je het even zegt, want mijn iptables installatie doet die conversie namelijk altijd.

Afgezien van het feit dat ik dit script nooit zou gebruiken omdat het veel te beperkt is en mijn huidige iptables inrichting hopeloos overhoop zou halen (zelfs portsentry doet meer en nog automagisch ook) ga ik verder met Leon mee.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
23-04-2009 00:04

Ik gebruik zelf Shorewall. Shorewall werkt gewoon met config bestanden. Je zet alles in de configs, je restart shorewall, en je veranderingen zijn door gevoerd (je hoeft niets te doen met iptables etc.). De configs hebben een gewoon logishe in deling. Heel makkelijk allemaal.

(Ik gebruik hem op mijn Debian server).

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
23-04-2009 13:26

Een firewall is iets te complex alleen via command line te doen.

http://howtoforge.org/getting-started-with-firewall-builder

Dit script zal je moeten draaien onder root om het überhaupt laten werken.

1
N.V.T.
23-04-2009 13:49

Dit script is geschreven om een goed werkende CLI parser te verkrijgen en dat is m.i. gelukt!
Het gebruik van het script om firewall regels toe te voegen en te verwijderen was bijzaak.
Voor het zelfde geld was het een CLI parser met interface naar "convert" om grafische bestanden aan te passen.

Firewalls zijn lastige dingen maar met een soortgelijk script is het toevoegen van IP zondaars een peuleschil.
Gelukkig kan het script alleen maar gebruikt worden root, gebruikers zouden "leuke" dingen kunnen doen.
Overigens kan je met kleine aanpassingen gewone gebruikers het script laten gebruiken.

1
NVT
23-04-2009 15:21

"Dit script zal je moeten draaien onder root om het überhaupt laten werken."

Daar heb ik opzich geen probleem mee, omdat root de enige is die überhaupt aan de firewall hoort te komen. Ik bouw overigens wel altijd zelf mijn firewall configs op met iptables, ja, helemaal met de hand. Waarom? De vrijheid die ik krijg als ik dat doe. Daar kan geen script of schil als bvb shorewall of bastille bij helpen. Ze maken je leven makkelijker maar beperken je mogelijkheden tegelijkertijd enorm.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
Inloggen wachtwoord vergeten? Aanmelden