Skip to content

Commit

Permalink
Implemented rate limiting
Browse files Browse the repository at this point in the history
fixes #2
  • Loading branch information
telephone committed Sep 26, 2012
1 parent 4416a4b commit 5c6ed42
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 102 deletions.
98 changes: 98 additions & 0 deletions LookingGlass/RateLimit.php
@@ -0,0 +1,98 @@
<?php
/**
* MIT License
* ===========
*
* Copyright (c) 2012 Nick Adams <nick89@zoho.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @package LookingGlass
* @author Nick Adams <nick89@zoho.com>
* @copyright 2012 Nick Adams.
* @link http://iamtelephone.com
* @version 1.1.0
*/
namespace Telephone;

class RateLimit
{
private $dbh;

public function rateLimit($limit = 120)
{
// check if rate limit is disabled
if ($limit === 0) {
return false;
}

/**
* check for DB file
* if nonexistent, no rate limit is applied
*/
if (!file_exists('LookingGlass/ratelimit.db')) {
return false;
}

// connect to DB
try {
$dbh = new \PDO('sqlite:LookingGlass/ratelimit.db');
} catch (PDOException $e) {
exit($e->getMessage());
}

// check for IP
$q = $dbh->prepare('SELECT * FROM RateLimit WHERE ip = ?');
$q->execute(array($_SERVER['REMOTE_ADDR']));
$row = $q->fetch(\PDO::FETCH_ASSOC);

// save time by declaring time()
$time = time();

// if IP does not exist
if (!isset($row['ip'])) {
// create new record
$q = $dbh->prepare('INSERT INTO RateLimit (ip, hits, accessed) VALUES (?, ?, ?)');
$q->execute(array($_SERVER['REMOTE_ADDR'], 1, $time));
return true;
}

// typecast SQLite results
$accessed = (int) $row['accessed'] + 3600;
$hits = (int) $row['hits'];

// apply rate limit
if ($accessed > $time) {
if ($hits >= $limit) {
exit('Rate limit exceeded. Try again in: ' . (int) (($accessed - $time) / 60) . ' minutes');
}
// update hits
$q = $dbh->prepare('UPDATE RateLimit SET hits = ? WHERE ip = ?');
$q->execute(array(($hits + 1), $_SERVER['REMOTE_ADDR']));
} else {
// reset hits + accessed time
$q = $dbh->prepare('UPDATE RateLimit SET hits = ?, accessed = ? WHERE ip = ?');
$q->execute(array(0, time(), $_SERVER['REMOTE_ADDR']));
}

$dbh = null;
return true;
}
}
227 changes: 129 additions & 98 deletions LookingGlass/configure.sh
Expand Up @@ -37,70 +37,6 @@
## ##
#######################

##
# Check and install script requirements
##
function requirements()
{
sleep 1
# Check for apt-get/yum
if [ -f /usr/bin/apt-get ]; then
# Check for root
if [ $(id -u) != "0" ]; then
INSTALL='sudo apt-get'
else
INSTALL='apt-get'
fi
elif [ -f /usr/bin/yum ]; then
INSTALL='yum'
else
echo 'Skipping script requirements.'
return
fi

# Array of required functions
REQUIRE=( host iputils-ping mtr traceroute )

# Loop through required & install
for i in "${REQUIRE[@]}"; do
# Fix host for CentOS
if [ $i = 'host' ]; then
echo 'Checking for host...'
if [ ! -f "/usr/bin/$i" ]; then
if [ $INSTALL = 'yum' ]; then
${INSTALL} -y install "bind-utils"
else
${INSTALL} -y install ${i}
fi
echo ''
fi
# Fix ping
elif [ $i = 'iputils-ping' ]; then
echo 'Checking for ping...'
if [ ! -f "/bin/ping" ]; then
${INSTALL} -y install ${i}
echo ''
fi
# Check both bin and sbin
elif [ $i = 'traceroute' ]; then
echo "Checking for $i..."
if [ ! -f "/usr/bin/$i" ]; then
if [ ! -f "/usr/sbin/$i" ]; then
${INSTALL} -y install ${i}
echo ''
fi
fi
else
echo "Checking for $i..."
if [ ! -f "/usr/bin/$i" ]; then
${INSTALL} -y install ${i}
echo ''
fi
fi
sleep 1
done
}

##
# Create Config.php
##
Expand Down Expand Up @@ -144,6 +80,8 @@ function createConfig()
\$ipv4 = '${IPV4}';
// IPv6 address (can be blank)
\$ipv6 = '${IPV6}';
// Rate limit
\$rateLimit = (int) '${RATELIMIT}';
// Site name (header)
\$siteName = '${SITE}';
// Server location
Expand Down Expand Up @@ -185,17 +123,117 @@ function config()
IPV4="$(echo $f2 | awk -F\' '{print $(NF-1)}')"
elif [ $f1 = '$ipv6' ]; then
IPV6="$(echo $f2 | awk -F\' '{print $(NF-1)}')"
elif [ $f1 = '$rateLimit' ]; then
RATELIMIT=("$(echo $f2 | awk -F\' '{print $(NF-1)}')")
elif [ $f1 = '$serverLocation' ]; then
LOCATION="$(echo $f2 | awk -F\' '{print $(NF-1)}')"
elif [ $f1 = '$testFiles[]' ]; then
TEST+=("$(echo $f2 | awk -F\' '{print $(NF-1)}')")
elif [ $f1 = '$siteName' ]; then
SITE=("$(echo $f2 | awk -F\' '{print $(NF-1)}')")
elif [ $f1 = '$testFiles[]' ]; then
TEST+=("$(echo $f2 | awk -F\' '{print $(NF-1)}')")
fi
fi
done < "$DIR/$CONFIG"
}

##
# Create SQLite database
##
function database()
{
if [ ! -f "${DIR}/ratelimit.db" ]; then
echo 'Creating SQLite database...'
sqlite3 ratelimit.db 'CREATE TABLE RateLimit (ip TEXT UNIQUE NOT NULL, hits INTEGER NOT NULL DEFAULT 0, accessed INTEGER NOT NULL);'
sqlite3 ratelimit.db 'CREATE UNIQUE INDEX "RateLimit_ip" ON "RateLimit" ("ip");'
fi
}

##
# Fix MTR on REHL based OS
##
function mtrFix()
{
# Check permissions for MTR & Symbolic link
if [ $(stat --format="%a" /usr/sbin/mtr) -ne 4755 ] || [ ! -f "/usr/bin/mtr" ]; then
if [ $(id -u) = "0" ]; then
echo 'Fixing MTR permissions...'
chmod 4755 /usr/sbin/mtr
ln -s /usr/sbin/mtr /usr/bin/mtr
else
echo '##### IMPORTANT #####'
echo 'You are not root. Please log into root and run:'
echo 'chmod 4755 /usr/sbin/mtr'
echo 'and'
echo 'ln -s /usr/sbin/mtr /usr/bin/mtr'
echo '#####################'
fi
fi
}

##
# Check and install script requirements
##
function requirements()
{
sleep 1
# Check for apt-get/yum
if [ -f /usr/bin/apt-get ]; then
# Check for root
if [ $(id -u) != "0" ]; then
INSTALL='sudo apt-get'
else
INSTALL='apt-get'
fi
elif [ -f /usr/bin/yum ]; then
INSTALL='yum'
else
echo 'Skipping script requirements.'
return
fi

# Array of required functions
local REQUIRE=(host mtr iputils-ping traceroute sqlite3)

# Loop through required & install
for i in "${REQUIRE[@]}"; do
# Fix host for CentOS
if [ $i = 'host' ]; then
echo 'Checking for host...'
if [ ! -f "/usr/bin/$i" ]; then
if [ $INSTALL = 'yum' ]; then
${INSTALL} -y install "bind-utils"
else
${INSTALL} -y install ${i}
fi
echo ''
fi
# Fix ping
elif [ $i = 'iputils-ping' ]; then
echo 'Checking for ping...'
if [ ! -f "/bin/ping" ]; then
${INSTALL} -y install ${i}
echo ''
fi
# Check both bin and sbin
elif [ $i = 'traceroute' ]; then
echo "Checking for $i..."
if [ ! -f "/usr/bin/$i" ]; then
if [ ! -f "/usr/sbin/$i" ]; then
${INSTALL} -y install ${i}
echo ''
fi
fi
else
echo "Checking for $i..."
if [ ! -f "/usr/bin/$i" ]; then
${INSTALL} -y install ${i}
echo ''
fi
fi
sleep 1
done
}

##
# Setup parameters for PHP file creation
##
Expand All @@ -216,6 +254,7 @@ function setup()
read -e -p "Enter the test IPv4 address [${IPV4}]: " IP4
read -e -p "Enter the test IPv6 address (Re-enter everytime this script is run) [${IPV6}]: " IP6
read -e -p "Enter the size of test files in MB (Example: 25MB 50MB 100MB) [${TEST[*]}]: " T
read -e -p "Do you wish to enable rate limiting of network commands? (y/n): " RATE

# Check local vars aren't empty; Set new values
if [[ -n $IP4 ]]; then
Expand All @@ -229,6 +268,18 @@ function setup()
if [[ -n $S ]]; then
SITE=$S
fi
# Rate limit
if [[ "$RATE" = 'y' ]] || [[ "$RATE" = 'yes' ]]; then
read -e -p "Enter the # of commands allowed per hour (per IP) [${RATELIMIT}]: " RATE
if [[ -n $RATE ]]; then
if [ "$RATE" != "$RATELIMIT" ]; then
RATELIMIT=$RATE
fi
fi
else
RATELIMIT=0
fi
# Create sparse files
if [[ -n $T ]]; then
echo ''
echo 'Removing old sparse files:'
Expand Down Expand Up @@ -275,28 +326,6 @@ function testFiles()
fi
}

##
# Fix MTR on REHL based OS
##
function mtrFix()
{
# Check permissions for MTR & Symbolic link
if [ $(stat --format="%a" /usr/sbin/mtr) -ne 4755 ] || [ ! -f "/usr/bin/mtr" ]; then
if [ $(id -u) = "0" ]; then
echo 'Fixing MTR permissions...'
chmod 4755 /usr/sbin/mtr
ln -s /usr/sbin/mtr /usr/bin/mtr
else
echo '##### IMPORTANT #####'
echo 'You are not root. Please log into root and run:'
echo 'chmod 4755 /usr/sbin/mtr'
echo 'and'
echo 'ln -s /usr/sbin/mtr /usr/bin/mtr'
echo '#####################'
fi
fi
}

###########################
## ##
## Configuration ##
Expand Down Expand Up @@ -344,8 +373,9 @@ DIR="$(cd "$(dirname "$0")" && pwd)"
IPV4=''
IPV6=''
LOCATION=''
TEST=()
RATELIMIT=''
SITE=''
TEST=()

# Install required scripts
echo 'Checking script requirements:'
Expand All @@ -371,18 +401,19 @@ echo 'Running setup:'
setup
echo ''
# Create Config.php file
echo 'Creating Config.php'
echo 'Creating Config.php...'
createConfig

echo ''
# Create DB
database
# Check for RHEL mtr
if [ "$INSTALL" = 'yum' ]; then
mtrFix
fi
# All done
cat <<EOF
Installation is complete...
Installation is complete
EOF

# Check for RHEL mtr
if [ "$INSTALL" = 'yum' ]; then
mtrFix
echo ''
fi
sleep 1

0 comments on commit 5c6ed42

Please sign in to comment.