File: odonovan.html

package info (click to toggle)
lg-issue108 1-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 1,784 kB
  • ctags: 186
  • sloc: perl: 534; python: 288; xml: 67; sh: 39; makefile: 34; sed: 27
file content (487 lines) | stat: -rw-r--r-- 21,065 bytes parent folder | download
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487

<html>
<head>
<link href="../lg.css" rel="stylesheet" type="text/css" media="screen, projection"  />
<link rel="shortcut icon" href="../favicon.ico" />
<title>Advanced Features of netfilter/iptables LG #108</title>

<style type="text/css" media="screen, projection">
<!--

-->
</style>


</head>

<body>


<img src="../gx/2003/newlogo-blank-200-gold2.jpg" id="logo" alt="Linux Gazette"/>
<p id="fun">...making Linux just a little more fun!</p>


<div class="content articlecontent">

<div id="previousnexttop">
<A HREF="nielsen.html" >&lt;-- prev</A> | <A HREF="okopnik.html" >next --&gt;</A>
</div>



<h1>Advanced Features of netfilter/iptables</h1>
<p id="by"><b>By <A HREF="../authors/odonovan.html">Barry O'Donovan</A></b></p>

<p>
<h3>Introduction</h3>
It is commonly known that netfilter/iptables is the firewall of the
Linux operating system. What is not commonly known is that iptables
has many hidden gems that can allow you do things with your
firewall that you might never have even imagined. In this article I
am going to introduce many of these features with some practical
uses. If you are not <em>au fait</em> with the basics of iptables
then you should read my previous article in the Gazette, "<a href=
"../103/odonovan.html">Firewalling with netfilter/iptables</a>".
<p>The following features are discussed:</p>
<ol>
<li>Specifying multiple ports in one rule</li>
<li>Load balancing</li>
<li>Restricting the number of connections</li>
<li>Maintaining a list of recent connections to match against</li>
<li>Matching against a string in a packet's data payload</li>
<li>Time-based rules</li>
<li>Setting transfer quotas</li>
<li>Packet matching based on TTL values</li>
</ol>
<p>All of the features discussed in this article are extensions to
the packet matching modules of iptables. I used only two of these
extensions in the previous article: the <code>--state</code> module
which allowed us to filter packets based on whether they were
<code>NEW</code>, <code>ESTABLISHED</code>, <code>RELATED</code> or
<code>INVALID</code> connections; and the <code>multiport</code>
extension, of which I will go into more detail on in this
article.</p>
<p>Some of the modules introduced in this article (marked with an
asterisk) have not made their way into the default Linux kernel yet
but a netfilter utility called "patch-o-matic" can be used to add
them to your own kernel and this will be discussed at the end of
the article.</p>
<h3>1. Specifying Multiple Ports with <code>multiport</code></h3>
The <code>multiport</code> module allows one to specify a number of
different ports in one rule. This allows for fewer rules and easier
maintenance of iptables configuration files. For example, if we
wanted to allow global access to the SMTP, HTTP, HTTPS and SSH
ports on our server we would normally use something like the
following:
<pre class="code">
-A INPUT -i eth0 -p tcp -m state --state NEW --dport ssh   -j ACCEPT
-A INPUT -i eth0 -p tcp -m state --state NEW --dport smtp  -j ACCEPT
-A INPUT -i eth0 -p tcp -m state --state NEW --dport http  -j ACCEPT
-A INPUT -i eth0 -p tcp -m state --state NEW --dport https -j ACCEPT
</pre>
Using the <code>multiport</code> matching module, we can now write:
<pre class="code">
-A INPUT -i eth0 -p tcp -m state --state NEW -m multiport --dports ssh,smtp,http,https -j ACCEPT
</pre>
It must be used in conjunction with either <code>-p tcp</code> or
<code>-p udp</code> and only up to 15 ports may be specified. The
supported options are:
<blockquote>
<dl>
<dt><code>--sports port[,port,port...]</code></dt>
<dd>matches source port(s)</dd>
<dt><code>--dports port[,port,port...]</code></dt>
<dd>matches destination port(s)</dd>
<dt><code>--ports port[,port,port...]</code></dt>
<dd>matches both source and destination port(s)</dd>
</dl>
</blockquote>
<p><code>mport</code><sup>*</sup> is another similar extension that
also allows you to specify port ranges, e.g. <code>--dport
22,80,6000:6100</code>.</p>
<h3>2. Load Balancing with <code>random</code><sup>*</sup> or
<code>nth</code><sup>*</sup></h3>
Both the <code>random</code> and <code>nth</code> extensions can be
used for load balancing. If, for example, you wished to balance
incoming web traffic between four mirrored web servers then you
could add either of the following rule sets to your
<code>nat</code> table:
<pre class="code">
-A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 0 --every 4 --packet 0 \
    -j DNAT --to-destination 192.168.0.5:80
-A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 0 --every 4 --packet 1 \
    -j DNAT --to-destination 192.168.0.6:80
-A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 0 --every 4 --packet 2 \
    -j DNAT --to-destination 192.168.0.7:80
-A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 0 --every 4 --packet 3 \
    -j DNAT --to-destination 192.168.0.8:80
</pre>
or:
<pre class="code">
-A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m random --average 25 \
    -j DNAT --to-destination 192.168.0.5:80
-A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m random --average 25 \
    -j DNAT --to-destination 192.168.0.6:80
-A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m random --average 25 \
    -j DNAT --to-destination 192.168.0.7:80
-A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW \
    -j DNAT --to-destination 192.168.0.8:80
</pre>
The <code>nth</code> matching extension allows you to match the nth
packet received by the rule. There are up to 16 (0...15) counters
for matching the nth packets. The above four (<code>nth</code>)
rules use counter 0 to count every 4th packet. Once the 4th packet
is received, the counter is reset to zero. The first rule matches
the 1st packet (<code>--packet 0</code>) of every four counted, the
second rule matches the 2nd packet (<code>--packet 0</code>), and
so on.
<p>The <code>random</code> matching extension allows you to match
packets based on a given probability. The first rule from the set
of <code>random</code> rules above matches 25% (<code>--average
25</code>) of the TCP connections to port 80 and redirects these to
the first mirrored web server. Of the 75% of connections not
matching on the first rule, 25% will match the second and a further
25% will match the third. The remaining 25% will be caught by the
fourth rule.</p>
<p>Another use of the <code>random</code> extension would be to
simulate a faulty network connection to evaluate the performance of
networking hardware/software, etc.</p>
<h3>3. Restricting the Number of Connections with
<code>limit</code> and <code>iplimit</code><sup>*</sup></h3>
The <code>limit</code> matching extension can be used to limit the
number of times a rule matches in a given time period while the
<code>iplimit</code> extension can restrict the number of parallel
TCP connections from a particular host or network. These extensions
can be used for a variety of purposes:
<ul>
<li>to protect against DOS (denial of service) attacks such as
preventing a flood of HTTP requests to your web server while
ensuring all your customers have unlimited access;</li>
<li>to prevent a brute-force attack to guess passwords;</li>
<li>to limit Internet usage by staff during working hours;</li>
<li>and many many more.</li>
</ul>
Let's take the case where we want to limit the Internet usage of
our employees during working hours. We could use a rule like:
<pre class="code">
-A FORWARD -m state --state NEW -p tcp -m multiport --dport http,https -o eth0 -i eth1 \
    -m limit --limit 50/hour --limit-burst 5 -j ACCEPT
</pre>
This rule assumes that we are acting as a proxy server where the
external connection is via <code>eth0</code> and <code>eth1</code>
connects to our office network. The rule limits all of our internal
computers to only 50 new HTTP or HTTPS connections per hour and the
use of <code>--limit-burst</code> prevents any one employee from
using up all 50 in one go. Packets can be matched
<code>/day</code>, <code>/hour</code>, <code>/minute</code> or
<code>/sec</code>.
<p>The <code>--limit-burst</code> parameter can be quite confusing
at first. In the above example, it will ensure that if all
employees are trying to access the Internet throughout the hour
then only 5 connections are made every 5 minutes. If 30 minutes
pass with no connections and then there is a sudden rush for the
remaining 30 minutes, only 5 connections will be permitted every
2.5 minutes. I once heard it explained as follows:</p>
<blockquote><em>For every</em> <code>limit</code> <em>rule, there's
a "bucket" containing "tokens". Whenever the rule matches, a token
is removed and when the token count reaches zero, the rule doesn't
match anymore.</em>
<p><code>--limit</code> <em>is the bucket refill rate.</em><br>
<code>--limit-burst</code> <em>is the bucket size (number of tokens
that it can hold).</em></p>
</blockquote>
<p>The <code>iplimit</code> extension allows us to restrict the
number of parallel TCP connections from a particular host or
network. If, for example, we wanted to limit the number of HTTP
connections made by any single IP address to 5 we could use:</p>
<pre class="code">
-A INPUT -p tcp -m state --state NEW --dport http -m iplimit --iplimit-above 5 -j DROP
</pre>
<h3>4. Maintaining a List of <code>recent</code> Connections to
Match Against</h3>
By using the <code>recent</code> extension one can dynamically
create a list of IP addresses that match a rule and then match
against these IPs in different ways later. One possible use would
be to create a "temporary" bad-guy list by detecting possible port
scans and to then <code>DROP</code> all other connections from the
same source for a given period of time
<p>Port 139 is one of the most dangerous ports for Microsoft
Windows&reg; users as it is through this port that the Windows file
and print sharing service runs. This also makes this port one of
the first scanned by many port scanners or potential hackers and a
target for many of the worms around today. We can use the
<code>recent</code> matching extension to temporarily block any IP
from connecting with our machine that scans this port as
follows:</p>
<pre class="code">
-A FORWARD -m recent --name portscan --rcheck --seconds 300 -j DROP
-A FORWARD -p tcp -i eth0 --dport 139 -m recent --name portscan --set -j DROP
</pre>
Now anyone trying to connect to port 139 on our firewall will have
all of their packets dropped until 300 seconds has passed. The
supported options include:
<blockquote>
<dl>
<dt><code>--name name</code></dt>
<dd>The name of the list to store the IP in or check it against. If
no name is given then <code>DEFAULT</code> will be used</dd>
<dt><code>--set</code></dt>
<dd>This will add the source address of the packet to the list. If
the source address is already in the list, this will update the
existing entry.</dd>
<dt><code>--rcheck</code></dt>
<dd>This will check if the source address of the packet is
currently in the list.</dd>
<dt><code>--update</code></dt>
<dd>This will check if the source address of the packet is
currently in the list. If it is then that entry will be updated and
the rule will return true.</dd>
<dt><code>--remove</code></dt>
<dd>This will check if the source address of the packet is
currently in the list and if so that address will be removed from
the list and the rule will return true.</dd>
<dt><code>--seconds seconds</code></dt>
<dd>This option must be used in conjunction with one of
<code>--rcheck</code> or <code>--update</code>. When used, this
will narrow the match to only happen when the address is in the
list and was seen within the last given number of seconds.</dd>
<dt><code>--hitcount hits</code></dt>
<dd>This option must be used in conjunction with one of
<code>--rcheck</code> or <code>--update</code>. When used, this
will narrow the match to only happen when the address is in the
list and packets had been received greater than or equal to the
given value. This option may be used along with `seconds' to create
an even narrower match requiring a certain number of hits within a
specific time frame.</dd>
</dl>
</blockquote>
<h3>5. Matching Against a <code>string</code><sup>*</sup> in a
Packet's Data Payload</h3>
The <code>string</code> extension allows one to match a string
anywhere in a packet's data payload. Although this extension does
have many valid uses, I would strongly advise caution. Let's say,
for example, that our Linux firewall is protecting an internal
network with some computers running Microsoft Windows&reg; and we
would like to block all executable files. We might try something
like:
<pre class="code">
-A FORWARD -m string --string '.com' -j DROP
-A FORWARD -m string --string '.exe' -j DROP
</pre>
This has a number of problems:
<ul>
<li>if the '<code>.com</code>' or '<code>.exe</code>' is split
across two packets it will not be matched</li>
<li>if any packet being transmitted contains either of the stings
it will be dropped; this includes any packets from a web page
containing those strings, from an e-mail transmission, etc</li>
</ul>
<h3>6. Time-based Rules with <code>time</code><sup>*</sup></h3>
We can match rules based on the time of day and the day of the week
using the <code>time</code> module. This could be used to limit
staff web usage to lunch-times, to take each of a set of mirrored
web servers out of action for automated backups or system
maintenance, etc. The following example allows web access during
lunch hour:
<pre class="code">
-A FORWARD -p tcp -m multiport --dport http,https -o eth0 -i eth1 \
    -m time --timestart 12:30 --timestop 13:30 --days Mon,Tue,Wed,Thu,Fri -j ACCEPT
</pre>
Clearly the start and stop times are 24-hour with the format
<code>HH:MM</code>. The day is a comma-separated list that is case
sensitive and made up of <code>Mon</code>, <code>Tue</code>,
<code>Wed</code>, <code>Thu</code>, <code>Fri</code>,
<code>Sat</code> and/or <code>Sun</code>.
<h3>7. Setting transfer quotas with
<code>quota</code><sup>*</sup></h3>
Setting transfer quotas can be very useful in many situations. As
an example, a lot of broadband users will have download quotas set
for them by their ISP and many may charge extra for every megabyte
transferred in excess of this quota. You can use iptables to
monitor your usage and cut you off when you reach your quota (say
2GB) with a rule similar to the following:
<pre class="code">
-A INPUT -p tcp -m quota --quota 2147483648 -j ACCEPT
-A INPUT -j DROP
</pre>
You can then view your usage with the following command:<br>
<code>$ iptables -v -L</code>
<p>You would also need to reset the quota every month manually (by
restarting iptables) or with a cron job. Clearly your computer
would need to be 'always-on' for this example to be of any use, but
there are also any other situations where the <code>quota</code>
extension would be useful.</p>
<h3>8. Packet Matching Based on TTL Values</h3>
The TTL (Time-To-Live) value of a packet is an 8-bit number that is
decremented by one each time the packet is processed by an
intermediate host between its source and destination. The default
value is operating system dependant and usually ranges from 32 to
128. Its purpose includes ensuring that no packet stays in the
network for an unreasonable length of time, gets stuck in an
endless loop because of bad routing tables, etc. Once the TTL value
of a packet reaches 0 it is discarded and a message is sent to its
source which can decide whether or not to resend it.
<p>As an interesting aside: this is actually how the
<code>traceroute</code> command works. It sends a packet to the
destination with a TTL of 1 first and gets a reply from the first
intermediate host. It then sends a packet with a TTL of 2 and
receives a reply from the second intermediate host and so on until
it reaches its destination.</p>
<p>The usefulness of packet matching based on TTL value depends on
your imagination. One possible use is to identify
"man-in-the-middle" attacks. If you regularly connect from home to
work you could monitor your TTL values and establish a reasonable
maximum value at the receiving end. You can the use this to deny
any packets that arrive with a higher TTL value as it may indicate
a possible "man-in-the-middle" attack; someone intercepting your
packets, reading/storing them and resending them onto the
destination. There are of course "man-in-the-middle" methods that
wouldn't alter the TTL value but, as always, security is never
absolute, only incremental. TTL matching could also be used for
network debugging or to find hosts with bad default TTL values.</p>
<p>As a simple example, let's reject all packets from a specific IP
with a TTL of less than 40:</p>
<pre class="code">
-A INPUT -s 1.2.3.4 -m ttl --ttl-lt 40 -j REJECT
</pre>
You can also check for TTL values that are less than
(<code>--ttl-gt</code>) or equal to (<code>--ttl-eq</code>) a
particular value.
<h3>Patching Your Kernel with Patch-O-Matic (POM)</h3>
Some of the newer features introduced in this article are not
considered stable enough by the netfilter development team for
inclusion in the current Linux kernel. To use these you will need
to patch your kernel using a utility called patch-o-matic. This is
not for the faint of heart and I am not going to provide
step-by-step instructions here. I will simply cover patch-o-matic
and provide references to more information.
<p>Patch-o-matic can be downloaded from the netfilter homepage,
<a href="http://www.netfilter.org/">http://www.netfilter.org/</a>.
You will also need the source code for your kernel (if you are
using a kernel supplied with your distribution, install the
<code>kernel-source</code> package or install a new kernel by
downloading the latest kernel source code from <a href=
"http://www.kernel.org/">http://www.kernel.org/</a>) and the source
code for iptables which you can also download from the netfilter
homepage. Once you have these, unpack them and execute the
<code>runme</code> script from patch-o-matic as follows:<br>
<code>$ KERNEL_DIR=&lt;path to the kernel source code&gt;
IPTABLES_DIR=&lt;path to the iptables source code&gt; ./runme
extra</code></p>
<p>The script describes each new extension and asks whether or not
to patch the kernel for it. Once that is finished you will need to
recompile the kernel, the netfilter kernel modules and the iptables
binaries. This is outside the scope of this article but you will
find useful information on the following sites:</p>
<ul>
<li><a href=
"http://www.netfilter.org/documentation/HOWTO/netfilter-extensions-HOWTO.html">
Netfilter Extensions HOWTO</a></li>
<li><a href=
"http://www.digitalhermit.com/linux/Kernel-Build-HOWTO.html">Kernel
Rebuild Guide</a><br>
(<em>this was part of the <a href="http://www.tldp.org/">The Linux
Documentation Project</a> but was removed for review - this is the
latest version from that review process but it is still in
development</em>)</li>
</ul>



</p>


<!-- *** BEGIN author bio *** -->
<P>&nbsp;
<P>
<!-- *** BEGIN bio *** -->
<hr>
<p>
<! -- REPLACE THE FOLLOWING WITH AUTHOR'S ~200x200 PIC. -->
<img align="left" alt="[BIO]" src="../gx/authors/odonovan.jpg" class="bio">
<em>

<! -- BIO GOES HERE -->

Barry O'Donovan graduated from the National University of Ireland, Galway
with a B.Sc. (Hons) in computer science and mathematics. He is currently
completing a Ph.D. in computer science with the <a
href="http://www.ihl.ucd.ie/">Information Hiding Laboratory</a>, University
College Dublin, Ireland in the area of audio watermarking.

<p> Barry has been using Linux since 1997 and his current flavor of choice
is Fedora Core. He is a member of the <a href="http://www.linux.ie/">Irish
Linux Users Group</a>. Whenever he's not doing his Ph.D. he can usually be
found supporting his finances by doing some work for <a 
href="http://www.openhosting.ie/" title="An Irish based web hosting and web 
design company">Open Hosting</a>, in the pub with friends or running in the local 
park.
</em>
<br clear="all">
<!-- *** END bio *** -->


<!-- *** END author bio *** -->

<div id="articlefooter">

<p>
Copyright &copy; 2004, Barry O'Donovan. Released under the
<a href="http://linuxgazette.net/copying.html">Open Publication license</a>
</p>

<p>
Published in Issue 108 of Linux Gazette, November 2004
</p>

</div>


<div id="previousnextbottom">
<A HREF="nielsen.html" >&lt;-- prev</A> | <A HREF="okopnik.html" >next --&gt;</A>
</div>


</div>






<div id="navigation">

<a href="../index.html">Home</a>
<a href="../faq/index.html">FAQ</a>
<a href="../lg_index.html">Site Map</a>
<a href="../mirrors.html">Mirrors</a>
<a href="../mirrors.html">Translations</a>
<a href="../search.html">Search</a>
<a href="../archives.html">Archives</a>
<a href="../authors/index.html">Authors</a>
<a href="../contact.html">Contact Us</a>

</div>



<div id="breadcrumbs">

<a href="../index.html">Home</a> &gt; 
<a href="index.html">November 2004 (#108)</a> &gt; 
Article

</div>





<img src="../gx/2003/sit3-shine.7-2.gif" id="tux" alt="Tux"/>




</body>
</html>