> IIRC, the connections-per-ip code isn't in a plugin right now -- it's
> part of the main binary -- because it requires some sort of shared
> state which we don't have for plugins.

The checks do exist in the binaries but they don't have to, you can use
$arg{child_addrs} and $arg{remote_ip} in hook_pre_connection to get at it,
at least in prefork, we've been doing it forever.  Our code is heavily
modified for our db-based prefs but it's a lot like this:

my %per_ip_limits = ( # fake magic per-ip config hashref
    1.2.3.4 => 10,
);

my %class_c_limits = (
    1.2.3.4 => 20,
);

sub ip_to_int {
    my ( $ip ) = @_;
    $ip = inet_aton($ip) if length($ip) > 4;
    return unpack 'N', $ip;
}

sub hook_pre_connection {
    my ( $self, $txn, %arg ) = @_;
    return NEXT unless @{ $arg{child_addrs };
    my $ip_limit = $per_ip_limits{ $arg{remote_ip} } || 5;
    return DENYSOFT_DISCONNECT, 'Too many connections from your IP'
        if ( grep { $_ eq $arg{remote_ip} }
             @{$arg{child_addrs}} )
            > $ip_limit;
    my $c_limit = $class_c_limits{ $arg{remote_ip} } || 10;
    my $ip = ip_to_int( $arg{remote_ip} );
    my $mask = $ip & 0xffffff00;
    return DENYSOFT_DISCONNECT, 'Too many connections from your class C'
        if ( grep {(ip_to_int($_)&0xffffff00) == $mask}
             @{$arg->{child_addrs}} )
            > $c_limit;
    return NEXT;
}

another interesting thing we support is allowing people to set a custom
max concurrency override for an arbitrary cidr; when an IP matches the
CIDR, we check how many other child_addr's match the same CIDR instead of
checking the other limits.  We use Net::CIDR::Lite::Span for this business
though so it's probably less efficient than the above.  We also use
hook_pre_connection to implement global connection limits, which allows us
to defer and write an entry to our DB logs when the limit is exceeded,
rather than just not responding.  This is way less efficient though, and
we've had to contend with it snowballing when the system becomes so busy
that the db is slow.  Oh well, someday we'll switch to async :)

-Jared

Reply via email to