Implementing a firewall Your program reads from standard input and prints to standard output.

The first thing you'll be receiving on stdinput will be the ruleset for your firewall (until you encounter a double newline).

We'll start explaining the ruleset itself with some sample input:


/* header abbreviations added for demonstration purposes only */

 /> Allow (A) or Block (B)
|
|  /> Source (incl. mask)
| |
| |               /> Destination (incl. mask)
| |              |
| |              |          /> Source port(s)
| |              |         |
| |              |         |           /> Destination port(s)
| |              |         |          |

A 192.168.1.0/24 0.0.0.0/0 1024:65536 80
A 0.0.0.0/0 192.168.1.0/24 80 1024:65536
A 192.168.1.1/32 0.0.0.0/0 80 1024:65536
A 0.0.0.0/0 192.168.1.1/32 1024:65536 80
B 0.0.0.0/0 0.0.0.0/0 * *



Rules are processed in cascading order. Once you find a matching rule, determine the outcome and stop processing.
If a packet does not match any given rule, block it (sane defaults).
Elements of a rule are single-space delimited.
Source and destination adresses will provide a netmask. Be sure to filter accordingly.
The specification of the source and destinations ports must support the following syntax:

Single ports: e.g. "80"
Inclusive port ranges: e.g. "1024:65536"
All ports: e.g. "*"

You may assume input to be well-formed.


After the double newline, you'll receive (one or more) newline seperated input packets to test according to the ruleset you've now acquired.

Some sample input for the packets to clarify:


/* header abbreviations added for demonstration purposes only */

 /> Source
|
|             /> Source port
|            |
|            |     /> Destination
|            |    |
|            |    |              /> Destination port
|            |    |             |

192.168.1.18 1036 157.136.122.5 22
157.136.108.8 2400 192.168.1.1 80


You'll examine these input packets and determine the outcome of filtering according to the rules.

The above sample input (ruleset + packets) should thus yield the following output:


BLOCK 192.168.1.18 1036 157.136.122.5 22
ALLOW 157.136.108.8 2400 192.168.1.1 80


The output is basically no more than 'BLOCK' or 'ALLOW' followed by a space and the verbatim input line.

Some varia:


This is code golf, the shortest (source code, by byte count) solution wins. Have fun!
You are not allowed to use specific IP address handling features of your language.
Specialized languages for routing or firewalling will be excluded from contending for first place (if they exist).
If any part of the question is ambiguous or in need of further clarification, feel free to comment.
Haskell, 356 characters

main=interact$f.break null.lines;f(r,_:p)=unlines$map(foldr(g.w)(j"B"++)r)p
g[r,s,d,a,b]n x|and$zipWith3($)(cycle[k.('/'#),q.(':'#)])[s,a,d,b]$w x=j r++x|t=n x
k[y,z]x=y%z==x%z;y%z=foldl((.r).(+).(*256))0('.'#y)`div`2^(32-r z)
q["*"]x=t;q[y]x=x==y;q[a,b]x=r x&gt;=r a&amp;&amp;r x&lt;=r b
d#x=w$map(d?)x;d?x|d==x=' '|t=x;j"A"="ALLOW ";j"B"="BLOCK ";t=1&lt;3;r=read;w=words