<?php
$ip_version 
'0.5.1';

/*
    ip - tells you your ip address, aka. "What's my IP?"

    Simply tells the HTTP client your current ip address. handy.
    Simply being the operative word - it's plain text, nothing else, so
    you can use a regular web browser, or incorporate something like..

        curl https://corz.org/ip

    into your scripts/DUC/FTP client/etc.. /ip just happens to be where
    I keep it, for ease of use (and easy to remember). I have a mod_rewrite
    redirect that points you to the real script, currently..

        rewriterule ^ip$ /public/machine/source/php/ip.php [nc]

    or something along those lines. Feel free to link to mine, it's a
    permanent feature.

    You can get back your host "name", if you have one, by sending ?name=true


        rewriterule ^host$ /public/machine/source/php/ip.php?name=true [nc]


    NOTE: if you are running this somewhere relativelty quiet, the entire
    script can be reduced to a couple of lines..

        <?php
        header('Content-Type: text/plain');
        header('Connection: Close');
        echo $_SERVER['REMOTE_ADDR'];
        ?>

    Everything else is for dealing with potential abuse.

    Enjoy!

    ;o)

    (c) 2004->tomorrow! cor + corz.org ;o)

*/


// prefs..
//

// Minimum check interval, in minutes..
// Note: you can use fractions, e.g. for 30 seconds, use: 0.5
//
$ip['min_interval'] = 10//  minutes

// location of ip sessions directory..
$ip['sessions_folder'] = '/home/cor/tmp/ip';

// An email address that banned users can mail once they have fixed their setup.
// this is sent in plain text - you may want to use some kind of obfuscation..
$ip['display_email'] = 'abuses at this domain';

/*
    Garbage Collection Limit

    [default: $ip['GC_limit'] = 10000;]

    To prevent your server's hard drive filling up with stale client sessions,
    we run a periodic garbage collection routine to sweep up the old files.

    How periodically, is up to you. By default, we will check for garbage every
    10,000 hits. I'm thinking this would be around a 2-daily hit rate for a
    small site (@ 5000 hits per day).

    Obviously, you can chage this number to anything you like, depending on how
    busy your site is, and how much space you have on the disks.

    If you don't want ip to clean up its garbage, set this to 0. And ensure you
    have some other mechanism to handle it.

    NOTE: this does not clean up your banned ip addresses, you will need to deal
    with those manually. Or better yet, just leave them!
                                                                            */
$ip['GC_limit'] = 10000;

/*
    GarbAge!

    [default: $ip['GC_age'] = 168;]    // a week

    How old, in hours, is considered "stale"?
    Any ID files older than this will be swept away (deleted).
                                                                */
$ip['GC_age'] = 168;





//
// end prefs



// let's go..

// grab their ip..
$ip['remote_ip'] = $_SERVER['REMOTE_ADDR'];

// and their host name
$ip['remote_name'] = gethostbyaddr($ip['remote_ip']);


// If IP is BANNED - die right now..
//
if (file_exists($ip['sessions_folder'].'/banned/'.$ip['remote_ip'])) {
    
send_banned_header();
}

$banned_host false;
// Plug bad hosts into this file. Partial match is fine.
$ip['banned_hosts'] = file($_SERVER['DOCUMENT_ROOT'].'/inc/data/ip_banned_hosts');

// Please don't plug my ip URL into your API - that's how to get your entire platform banned!
// This service is for corz.org visitors, thanks!
if (stristr(@$_SERVER['HTTP_USER_AGENT'], 'Linux; U; Android')) {
    
$banned_host true;
}
if (
is_array($ip['banned_hosts'])) {
    foreach(
$ip['banned_hosts'] as $somehost) {
         if (
strstr($ip['remote_name'], $somehost)) {
            
$banned_host true;
         }
    }
}
if (
$banned_host) {
    
header('Warning: This service is for corz.org visitors - If you want to plug it into your API/Appliance, please contact me to discuss license terms. Better yet, use the STUN protocol, which was designed specifically for that sort of thing!');
    
send_banned_header();
}


// Let us begin..
ip_collect_garbage($ip['sessions_folder'].'/Counter'$ip['GC_limit'], $ip['GC_age']);


// Some basic throttling - max hits one per X minutes

$ip['session'] = array();
$ip['sess_file'] = $ip['sessions_folder'].'/'.$ip['remote_ip'];

if (
file_exists($ip['sess_file'])) {
    
$ip['session'] = read_ip_session($ip['sess_file']);
}

$last_hit 0;
if (isset(
$ip['session']['last_hit'])) {
    
$last_hit $ip['session']['last_hit']; // UNIX timestamp
}

$now time();
$lp chr(9).'OK!  ';
$banned false;

$log_str gmdate('Y-m-d H:i:s').':';
$hits_log $_SERVER['DOCUMENT_ROOT'].'/inc/log/.ip_hits';


// the "page"..
header('Content-Type: text/plain; charset=utf-8');
header('Connection: Close');


// format the check interval for display...
$pl '';
$cint 'minute';
if (
$ip['min_interval'] !== 1) {
    
$pl 's';
    if (
$ip['min_interval'] < 1) {
        
$cint 'second';
        
$ip['min_interval'] = 60*$ip['min_interval'];
    }
}
$intv_msg $ip['min_interval'].' '.$cint.$pl;


if ((
$now $last_hit) > ($ip['min_interval']*60)) {
    if (isset(
$_GET['name']) and $_GET['name']) {
        echo 
$ip['remote_name'];
    } else {
        echo 
$ip['remote_ip'];
    }
    unset(
$ip['session']['throttle_msg_sent']);
    
// reset hammer count - they backed-off.
    
$ip['session']['hammer_count'] = 0;

} else {

    
// HAMMER!

    
$lp chr(9).'DENY!  ';
    if (!isset(
$ip['session']['throttle_msg_sent'])) {
        echo 
'Minimum check interval is ',$intv_msg,"\n\n",'NOTE: 10 infractions = banned!';
        
$ip['session']['throttle_msg_sent'] = true;
        
$lp chr(9).'NOTIFIED!';
    }

    
// increasse the hammer count..
    
$ip['session']['hammer_count'] += 1;

    if (
$ip['session']['hammer_count'] == 10) {
        echo 
"This is your final warning!\n\nPlease set your check interval to less than $intv_msg.";
    }

    if (
$ip['session']['hammer_count'] > 10) {
        
$lp chr(9).'BANNED! ';
        
$banned true;
        echo 
"This IP address is now banned!\n\nTo lift the ban, please set your check interval to less than $intv_msg\nand then email: ",$ip['display_email'],".";
    }
}

// store the time of THIS hit..
$ip['session']['last_hit'] = time();


// write out updated session to session file..
write_ip_session($ip['sess_file'], $ip['session']);


// some basic logging..


// IP Address / Host..
$log_str .= ' ['.$ip['remote_ip'].'] ';
$log_str .= @str_repeat (' '15-strlen($ip['remote_ip']));
//$ip['remote_name'] = gethostbyaddr($ip['remote_ip']);
$log_str .= '['.$ip['remote_name'].']' ;
$log_str .= @str_repeat (' '32-strlen($ip['remote_name']));
$log_str .= $lp;

$ua substr(@$_SERVER['HTTP_USER_AGENT'], 0100);
$ua str_replace('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome''Chrome'$ua);
if (
$ua) {
    
$log_str .= chr(9).'User Agent: '.$ua;
}

write_log($hits_log$log_str);

// they are gone!
if ($banned) { ban_ip_user(); }



function 
write_log($log_file$logstring) {
    if (
$logstring and $log_file) {
        
// Write the log..
        
if (!file_exists($log_file)) { file_put_contents($log_file''); }
        if (
$fp fopen($log_file'a')) {
            
fwrite($fp$logstring."\n");
            
fclose($fp);
        }
    }
}


// We are using an Anti-Hammer-like "fake" session, as 9 out of 10
// devices will not support php sessions at all (no cookies).


// read serialized array data from a file, and return as an array..
function read_ip_session($no_cookie_file) {
    if (
file_exists($no_cookie_file)) {

        
$file_handle fopen($no_cookie_file'rb');
        if (
$file_handle) {
            
$lock flock($file_handleLOCK_EX);
            if (
$lock) {
                
$file_contents = @fread($file_handlefilesize($no_cookie_file));
                
flock ($file_handleLOCK_UN);
            }
        }
        
fclose($file_handle);
        
$file_contents unserialize($file_contents);
        if (
is_array($file_contents)) {
            return 
$file_contents;
        }
    }
    return 
false;
}

// serialize an array and write the string data to a file..
function write_ip_session($no_cookie_file$array) {
    
$data serialize($array);
    if (empty(
$data)) { return; }
    
$fp = @fopen($no_cookie_file'wb');
    if (
$fp) {
        
$lock flock($fpLOCK_EX);
        if (
$lock) {
            
fwrite($fp$data);
            
flock ($fpLOCK_UN);
        }
        
fclose($fp);
        
clearstatcache();
        return (
true);
    }
}


// Ban someone who is hammering..
//
// This is elegant - we simply move the session file to a "banned" directory.
// Then we can check for its existence before we begin. If it exists, we die().
//
function ban_ip_user() {
  global 
$ip;

    if (!
file_exists($ip['sessions_folder'].'/banned')) {
         
mkdir($ip['sessions_folder'].'/banned'0777);
    }

    
// move the session file to the banned directory..
    
rename($ip['sessions_folder'].'/'.$ip['remote_ip'], $ip['sessions_folder'].'/banned/'.$ip['remote_ip']);
}


function 
send_banned_header() {
  global 
$ip$hits_log;
    
write_log($hits_log'['.$ip['remote_ip'].']['.$ip['remote_name'].'] BANNED!');
    
header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
    
header('Status: 403 Forbidden');
    
header('Connection: Close');
    die(
1);
}




/*

    collect garbage

    You could transplant this into another web app fairly easily.
    Useful stuf..
                                                                                */
function ip_collect_garbage($count_file$limit$GC_age=168) {
    if (
$limit === 0) { return; }
    if (
ip_increment_hit_counter($count_file) >= $limit) {
        
$file_list = array();
        if (
$the_dir = @opendir(dirname($count_file))) {
            while (
false != ($file readdir($the_dir))) {
                if ((
ord($file) != 46)) {
                    
$file_path dirname($count_file).'/'.$file;
                    if (
file_exists($file_path)) {
                        if (
filemtime($file_path)  < (time() - $GC_age*60*60)) {
                            @
unlink($file_path);
                        }
                    }
                }
            }
        }
        
ip_increment_hit_counter($count_file01); // reset the counter
    
}
}


/*
    increment a counter
    from my "file-tools.php", available elsewhere.
                                                    */
function ip_increment_hit_counter($count_file$report_only=false$reset=false) {

    
$count false;

    if (!
file_exists($count_file) or $reset) {
        
$file_pointer fopen($count_file'wb');
        
fwrite ($file_pointer'0');
        
fclose ($file_pointer);
    }

    
// now the counter..
    
if (file_exists($count_file)) {

        
// read in the old score..
        
$count trim(file_get_contents($count_file));
        if (
$report_only) { return $count; }
        if (!
$count) { $count 0; }
        
$count++;

        
// write out new score..
        
if (is_writable($count_file)) {
            
$file_pointer fopen($count_file'wb+');
            
$lock flock($file_pointerLOCK_EX);
                if (
$lock) {
                    
fwrite($file_pointer$count);
                    
flock ($file_pointerLOCK_UN);
                }
                
fclose($file_pointer);
                
clearstatcache();
        }
    }
    return 
$count;
}




/*
changes:

  0.2:

    Added basic hit logging.

    Once enabled, I realize that corz.org/ip is getting over two thousand hits a
    MINUTE! Holy Shit!

    I noticed that a lot of these hits came from the same ISP, picked an IP at
    random and popped it into my web browser. Auth login! Tried admin/admin and
    got straight in! Tried another, the same story. And another.. YES! WTF!

    Seriously? It looks like VNPT (using Yes Telecom hardware) have put my ip
    check URL into their router firmware, for some reason - checks every 13s!
    Thanks guys!

    I wonder if their users realize how insecure their gateways are? I mean you
    can get to everything - user/pass wifi setup, everything. pfff...

    BTW, I tried a further six IPs at random and EVERY SINGLE ONE had its admin
    open to the public with the default (Zyxel) admin/admin user/pass. SHODDY!


  0.3:

    Added throttle using Anti-Hammer-like fake session. Works great.

    The minimum interval is configurable. If they attempt to update in this
    time, they get a notification (one time) informing them of the minimum
    interval, and thereafter nothing, until they back-off and wait a few
    minutes. The default minimum interval is 1 minute.


  0.4:

    Added banning facility. After 10 strikes, they are out!


  0.5:

    Added garbage collection - old session files will be automatically cleaned-
    up after a certain time. You can set how long is considered "stale"; by
    default it is set to one week.


*/
?>
back to the source menu
downloadtest

Welcome to corz.org!

I'm always messing around with the back-end.. See a bug? Wait a minute and try again. Still see a bug? Mail Me!