diff --git a/bitflu.config.example b/bitflu.config.example index 0fe39c1f4..55a5fd399 100644 --- a/bitflu.config.example +++ b/bitflu.config.example @@ -139,6 +139,10 @@ webgui_port = 4081 # Bitflus 'root directory' workdir = ./workdir +# Support for ipfilter.dat files - needs Net::IPAddress::Filter::IPFilterDat +# Filepath of filter list file. +# ipfilter_dat_file = ./ipfilter.dat +ipfilter_dat_file = # Change uid/gid after startup (if started as root, needed for chroot) # runas_uid = diff --git a/bitflu.pl b/bitflu.pl index c4cda37e7..129187cee 100755 --- a/bitflu.pl +++ b/bitflu.pl @@ -1791,7 +1791,7 @@ package Bitflu::Network; use constant MAGIC_DSNUM => 1024*0.75; # Don't ask me why, but 0.75 makes our downspeed guess much better use constant KILL_IPV4 => 0; # 'simulate' non-working ipv4 stack -use fields qw( super NOWTIME avfds bpx_dn bpx_up _HANDLES _SOCKETS stagger up_q stats resolver_fail have_ipv6); +use fields qw( super NOWTIME avfds bpx_dn bpx_up _HANDLES _SOCKETS stagger up_q stats resolver_fail have_ipv6 ip_filter); ########################################################################## # Creates a new Networking Object @@ -1835,6 +1835,20 @@ package Bitflu::Network; } } + # Check whether to use an ipfilter.dat IP address filter. + if($self->{super}->Configuration->GetValue('ipfilter_dat_file')) { + my $ipfilter_dat_file = $self->{super}->Configuration->GetValue('ipfilter_dat_file'); + eval { + require Net::IPAddress::Filter::IPFilterDat; + }; + if ($@) { + $self->stop("Net::IPAddress::Filter::IPFilterDat is required for ipfilter.dat support."); + } + if ( ! -f $ipfilter_dat_file ) { + $self->stop("Unable to find ipfilter.dat file at '$ipfilter_dat_file'"); + } + } + if(KILL_IPV4) { $self->warn("IPv4 support is *DISABLED*"); } @@ -1843,7 +1857,7 @@ package Bitflu::Network; } ########################################################################## - # Register Admin commands + # Register Admin commands. Load any IP filter file. sub init { my($self) = @_; $self->info("IPv6 support is ".($self->HaveIPv6 ? 'enabled' : 'not active')); @@ -1853,6 +1867,16 @@ package Bitflu::Network; $self->{super}->Admin->RegisterCommand('netstat', $self, '_Command_Netstat', 'Display networking statistics'); $self->{super}->Admin->RegisterCommand('dig', $self, '_Command_Dig', 'Resolve a hostname'); $self->{super}->CreateSxTask(Superclass=>$self,Callback=>'_UpdateNetstats', Interval=>NETSTATS, Args=>[]); + + # Check whether to use an ipfilter.dat IP address filter. + if($self->{super}->Configuration->GetValue('ipfilter_dat_file')) { + my $ipfilter_dat_file = $self->{super}->Configuration->GetValue('ipfilter_dat_file'); + $self->info("Loading ipfilter.dat file '$ipfilter_dat_file'"); + $self->{ip_filter} = Net::IPAddress::Filter::IPFilterDat->new(); + $self->{ip_filter}->load_file($ipfilter_dat_file); + $self->info("IP address filter initialized"); + } + return 1; } @@ -2421,6 +2445,10 @@ package Bitflu::Network; $self->debug("Won't connect to blacklisted IP $remote_ip"); return undef; } + elsif($self->IpIsFiltered($remote_ip)) { + $self->debug("Won't connect to filtered IP $remote_ip"); + return undef; + } if(KILL_IPV4 && $self->IsNativeIPv4($remote_ip)) { $self->debug("Will not connect to IPv4 addr $remote_ip"); return undef; @@ -2482,6 +2510,10 @@ package Bitflu::Network; $self->debug("Refusing incoming connection from blacklisted ip $new_ip"); $new_sock->close; } + elsif($self->IpIsFiltered($new_ip)) { + $self->debug("Refusing incoming connection from filtered ip $new_ip"); + $new_sock->close; + } elsif(KILL_IPV4 && $self->IsNativeIPv4($new_ip)) { $self->debug("Dropping new IPv4 connection from $new_ip"); $new_sock->close; @@ -2657,6 +2689,24 @@ package Bitflu::Network; } } + sub IpIsFiltered { + my($self, $this_ip) = @_; + + return 0 unless $self->{ip_filter}; + + # Filter only supports IPv4 + return 0 if $self->IsNativeIPv6($this_ip); + + if ( !$self->IsNativeIPv4($this_ip) ) { + $this_ip = $self->SixToFour($this_ip); + } + my $is_filtered = $self->{ip_filter}->in_filter($this_ip); + + $self->debug("Filtering $this_ip") if $is_filtered; + + return $is_filtered; + } + sub debug { my($self, $msg) = @_; $self->{super}->debug("Network : ".$msg); } sub info { my($self, $msg) = @_; $self->{super}->info("Network : ".$msg); }