Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 317 lines (205 sloc) 5.7 KB
#!/usr/local/bin/perl -w
use strict;
=head1 PROGRAM
C<> - Blocks and unblocks IPs using C<iptables>.
=head2 Usage Examples
Using the Unix iptables can be confusing, blip is a simple interface
that un/blocks IPs and put them in a designated chain.
./ -block
./ -unblock
You can pass to it multiple IPs by separating them with commas.
List the blocked IPs:
./ -list
When you're tired of it all:
./ -wipe
=head2 Options
=head3 -verbose <level>
Turns on vebosity.
=head3 -bin <path-to-iptables>
Defaults to C</sbin/iptables> if it's not there, set it yourself.
=head3 -chain <chain>
Chain or target to add IPs to. Defaults to C<BLIP>.
use vars qw/$BLIP/;
use constant HELP => qq{ v1.1 - Block IP
./ -[un]block <ip-address> -verbose
./ -[wipe|list]
die HELP unless scalar @ARGV;
$BLIP = BlockIP->new(@ARGV);
exit (0);
package BlockIP;
use constant {
IPTABLES => '/sbin/iptables',
=head1 NAME
C<> - Simple interface for C<iptables>.
$BLIP = BlockIP->new(@ARGV);
Blocks and unblocks IPs to a special chain called C<BLIP>.
=head2 Public Methods
=head3 new
Creates the object, subsequently, creates the C<CHAIN> if doesn't exist.
sub new {
my $class = shift;
my $self = {};
for (my $i=0;$i<=$#_;$i++) {
if (substr($_[$i],0,1) eq '-') {
$self->{$_[$i]} = 1;
} else {
$self->{$_[$i-1]} = $_[$i];
bless $self, $class;
return $self;
=head3 commands (I<void>)
Accepts these command-line args:
-verbose = 2 levels of outputs
-list = shows current table
-wipe = remove chain
-block = block this IP
-unblock = unblock this IP
sub commands {
my $self = shift;
$self->{-data} or die "ABORT: Cannot find chain BLIP in iptables\n";
if ($self->{-list}) {
printf "Blocked IPs:\n%s\n", join "\n", $self->_get_ips;
} elsif ($self->{-unblock}) {
my @ips = split ',', $self->{-unblock};
map { $self->unblock($_) } @ips;
} elsif ($self->{-block}) {
my @ips = split ',', $self->{-block};
map { $self->block($_) } @ips;
} elsif ($self->{-wipe}) {
my $cmd = sprintf "%s -D INPUT -j %s",
$self->{-bin}, $self->{-chain};
$self->_execute($cmd) and
die "ERROR: unchain $cmd\n";
$cmd = sprintf "%s -X %s",
$self->{-bin}, $self->{-chain};
$self->_printf(1,"Removing chain %s\n", $self->{-chain});
map { $self->unblock($_) } $self->_get_ips;
$self->_execute($cmd) and
die "ERROR: Cannot wipe $cmd\n";
=head3 block (I<ip>)
Blocks an IP if not already blacklisted.
sub block {
my ($self,$ip) = (@_);
if ($self->{-data} =~ /$self->{-block}/) {
return print "ERROR: $ip already blocked\n";
my $cmd = sprintf "%s -I %s -s %s -j DROP",
$self->{-bin}, $self->{-chain}, $ip;
$self->_printf(1,"Blocking %s\n", $ip);
$self->_execute($cmd) and
die "ERROR: Cannot block $ip\n";
=head3 unblock (I<ip>)
Unblocks an IP in the C<chain>.
sub unblock {
my ($self,$ip) = (@_);
my $cmd = sprintf "%s -D %s -s %s -j DROP",
$self->{-bin}, $self->{-chain}, $ip;
$self->_printf(1,"Unblocking %s\n", $ip);
$self->_execute($cmd) and
die "ERROR: Cannot unblock $ip\n";
=head2 Private Methods
=head3 _init (I<void>)
Prepares C<iptables> to accept un/block of IPs.
sub _init {
my $self = shift;
$self->{-bin} ||= IPTABLES;
$self->{-chain} ||= CHAIN;
$self->{-verbose} ||= 0;
my $cmd = sprintf "%s -L %s -n", $self->{-bin}, $self->{-chain};
select STDOUT; $| = 1;
local $/ = undef;
my $info = $self->_execute($cmd);
$info =~ /denied/i
and die "ABORT: Need to be root to do this\n";
if ($info =~ /no chain/i) {
$info = $self->_execute($cmd);
if ($info =~ /^target/m) {
$self->{-data} = $info;
sub _get_ips {
my $self = shift;
return () unless $self->{-data};
my @list = ();
while ($self->{-data} =~ m/--\s+(\d+\.\d+\.\d+\.\d+)/g) {
push @list, $1;
return @list;
=head3 _create_chain (I<void>)
Creates a new C<chain> and chain this to C<INPUT>.
sub _create_chain {
my $self = shift;
my $cmd = sprintf "%s -N %s", $self->{-bin}, $self->{-chain};
$self->_printf(1, "$cmd\n");
my $info = $self->_execute($cmd);
$info and die "ABORT: $cmd failed ($info)\n";
$cmd = sprintf "%s -A INPUT -j %s",
$self->{-bin}, $self->{-chain};
$info = $self->_execute($cmd);
$info and die "ABORT: $cmd failed ($info)\n";
=head3 _execute (I<command>,[I<reg-pattern>])
Execute command, if passed a regexp, it'll try to match it with the output
returns true/false otherwise, return entire output for parsing.
sub _execute {
my ($self,$cmd,$re) = (@_);
$self->_printf(2, "CMD: $cmd\n");
open CMD, "$cmd 2>&1 |" or die "ABORT: Cannot execute $cmd\n";
my $info = <CMD>;
close CMD;
$self->_printf(2, "%sOUTPUT%s\n%s\n%s\n\n",
$re and return $info =~ $re;
return $info;
=head3 _printf (I<level>,I<format>,I<@array>)
Works just like C<printf> except has a built-in check for C<-verbose>.
sub _printf {
my $self = shift;
my $level = shift;
return 0 if $self->{-verbose} < $level;
return printf @_;
=head1 HISTORY
20120314 - v1.0 - Created.
v1.0.1 - Remove C<README>.
Link C<README.pod> to C<>.
Change C<blip> to C<>.
Adds C<-chain> option so user chan specify which C<chain/target> to use.
v1.1 - Add chaining to C<INPUT> for this thing to actually do the blocking. Oops.
=head1 AUTHOR
This module by Paul Pham.
Copyright 2012 by Paul Pham
This program and library is free software;
you can redistribute it and/or modify it under the same terms as Perl itself.
Something went wrong with that request. Please try again.