2016-02-07 19:36:13 +00:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Holds the everything networking.
|
|
|
|
* @package Sakura
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace Sakura;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Networking methods.
|
|
|
|
* @package Sakura
|
|
|
|
* @author Julian van de Groep <me@flash.moe>
|
|
|
|
*/
|
2016-02-13 13:36:21 +00:00
|
|
|
class Net
|
|
|
|
{
|
2016-02-07 19:36:13 +00:00
|
|
|
/**
|
|
|
|
* Returns the connecting IP.
|
2016-08-05 02:35:37 +00:00
|
|
|
* @return string
|
2016-02-07 19:36:13 +00:00
|
|
|
*/
|
2016-03-27 21:18:57 +00:00
|
|
|
public static function ip()
|
2016-02-07 19:36:13 +00:00
|
|
|
{
|
|
|
|
return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '::1';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Detect the version of an IP.
|
2016-08-05 02:35:37 +00:00
|
|
|
* @param string $ipAddr
|
|
|
|
* @return int
|
2016-02-07 19:36:13 +00:00
|
|
|
*/
|
|
|
|
public static function detectIPVersion($ipAddr)
|
|
|
|
{
|
|
|
|
// Check if var is IP
|
|
|
|
if (filter_var($ipAddr, FILTER_VALIDATE_IP)) {
|
|
|
|
// v4
|
|
|
|
if (filter_var($ipAddr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// v6
|
|
|
|
if (filter_var($ipAddr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
|
|
|
return 6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not an IP or unknown type
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts a printable IP address into an unpacked binary string.
|
2016-08-05 02:35:37 +00:00
|
|
|
* @param string $ip
|
|
|
|
* @throws Exception
|
|
|
|
* @return string
|
2016-02-07 19:36:13 +00:00
|
|
|
*/
|
|
|
|
public static function pton($ip)
|
|
|
|
{
|
|
|
|
// Detect the IP version
|
|
|
|
$ipv = self::detectIPVersion($ip);
|
|
|
|
|
|
|
|
// Check for IPv4 first since that's most common
|
|
|
|
if ($ipv === 4) {
|
|
|
|
return current(unpack("A4", inet_pton($ip)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then attempt IPv6
|
|
|
|
if ($ipv === 6) {
|
|
|
|
return current(unpack("A16", inet_pton($ip)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Throw an exception if an invalid IP was supplied
|
2016-04-25 02:01:14 +00:00
|
|
|
throw new Exception("Invalid IP address supplied.");
|
2016-02-07 19:36:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts a binary unpacked IP to a printable packed IP.
|
2016-08-05 02:35:37 +00:00
|
|
|
* @param string $bin
|
|
|
|
* @throws Exception
|
|
|
|
* @return string
|
2016-02-07 19:36:13 +00:00
|
|
|
*/
|
|
|
|
public static function ntop($bin)
|
|
|
|
{
|
|
|
|
// Get the length of the binary string
|
|
|
|
$len = strlen($bin);
|
|
|
|
|
|
|
|
// Throw an exception if it's not 4 or 16 bytes
|
|
|
|
if ($len !== 4 && $len !== 16) {
|
2016-04-25 02:01:14 +00:00
|
|
|
throw new Exception("Could not handle this IP type.");
|
2016-02-07 19:36:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Finally pack the IP
|
|
|
|
return inet_ntop(pack("A{$len}", $bin));
|
|
|
|
}
|
|
|
|
|
2016-08-05 02:35:37 +00:00
|
|
|
/**
|
|
|
|
* Matches an IP to a CIDR range.
|
|
|
|
* @param string $ip
|
|
|
|
* @param string $range
|
|
|
|
* @return bool
|
|
|
|
*/
|
2016-02-07 19:36:13 +00:00
|
|
|
public static function matchCIDR($ip, $range)
|
|
|
|
{
|
|
|
|
// Break the range up in parts
|
|
|
|
list($net, $mask) = explode('/', $range);
|
|
|
|
|
|
|
|
// Check IP version
|
|
|
|
$ipv = self::detectIPVersion($ip);
|
|
|
|
$rangev = self::detectIPVersion($net);
|
|
|
|
|
|
|
|
// Return false if it's not a valid IP
|
|
|
|
if ($ipv !== $rangev && !$ipv) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// v4
|
|
|
|
if ($ipv === 4) {
|
|
|
|
return self::matchCIDRv4($ip, $net, $mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
// v6
|
|
|
|
if ($ipv === 6) {
|
|
|
|
return self::matchCIDRv6($ip, $net, $mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return false by default
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-08-05 02:35:37 +00:00
|
|
|
* Match an IPv4 CIDR.
|
|
|
|
* @param string $ip
|
|
|
|
* @param string $net
|
|
|
|
* @param string $mask
|
|
|
|
* @return bool
|
2016-02-07 19:36:13 +00:00
|
|
|
*/
|
|
|
|
private static function matchCIDRv4($ip, $net, $mask)
|
|
|
|
{
|
|
|
|
// Convert IP and Net address to long
|
|
|
|
$ip = ip2long($ip);
|
|
|
|
$net = ip2long($net);
|
|
|
|
|
|
|
|
// Generate mask
|
|
|
|
$mask = -1 << (32 - $mask);
|
|
|
|
|
|
|
|
// Do the check
|
|
|
|
return ($ip & $mask) === $net;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-08-05 02:35:37 +00:00
|
|
|
* Converts an IPv6 mask to a byte array.
|
|
|
|
* @param int $mask
|
|
|
|
* @return string
|
2016-02-07 19:36:13 +00:00
|
|
|
*/
|
|
|
|
private static function maskToByteArray($mask)
|
|
|
|
{
|
|
|
|
// Generate an address from the mask
|
|
|
|
$addr = str_repeat("f", $mask / 4);
|
2016-03-27 21:18:57 +00:00
|
|
|
|
2016-02-07 19:36:13 +00:00
|
|
|
// Append uneven bit
|
|
|
|
switch ($mask % 4) {
|
|
|
|
case 1:
|
|
|
|
$addr .= '8';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
$addr .= 'c';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
$addr .= 'e';
|
|
|
|
break;
|
|
|
|
}
|
2016-03-27 21:18:57 +00:00
|
|
|
|
2016-02-07 19:36:13 +00:00
|
|
|
// Pad the address with zeroes
|
|
|
|
$addr = str_pad($addr, 32, '0');
|
2016-03-27 21:18:57 +00:00
|
|
|
|
2016-02-07 19:36:13 +00:00
|
|
|
// Pack the address
|
|
|
|
$addr = pack('H*', $addr);
|
|
|
|
|
|
|
|
// Return the packed address
|
|
|
|
return $addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-08-05 02:35:37 +00:00
|
|
|
* Match an IPv6 CIDR.
|
|
|
|
* @param string $ip
|
|
|
|
* @param string $net
|
|
|
|
* @param int $mask
|
|
|
|
* @return bool
|
2016-02-07 19:36:13 +00:00
|
|
|
*/
|
|
|
|
private static function matchCIDRv6($ip, $net, $mask)
|
|
|
|
{
|
|
|
|
// Pack the IP and Net addresses
|
|
|
|
$ip = inet_pton($ip);
|
|
|
|
$net = inet_pton($net);
|
|
|
|
|
|
|
|
// Convert the mask to a byte array
|
|
|
|
$mask = self::maskToByteArray($mask);
|
|
|
|
|
|
|
|
// Compare them
|
|
|
|
return ($ip & $mask) === $net;
|
|
|
|
}
|
2016-02-28 17:45:25 +00:00
|
|
|
|
|
|
|
/**
|
2016-08-05 02:35:37 +00:00
|
|
|
* Fetch a remote file.
|
|
|
|
* @param string $url
|
|
|
|
* @return mixed
|
2016-02-28 17:45:25 +00:00
|
|
|
*/
|
|
|
|
public static function fetch($url)
|
|
|
|
{
|
|
|
|
// Create a curl instance
|
|
|
|
$curl = curl_init();
|
|
|
|
|
|
|
|
// Set options
|
|
|
|
curl_setopt($curl, CURLOPT_URL, $url);
|
|
|
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
|
|
|
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 2);
|
|
|
|
curl_setopt($curl, CURLOPT_TIMEOUT, 4);
|
|
|
|
curl_setopt($curl, CURLOPT_USERAGENT, 'Sakura/' . SAKURA_VERSION);
|
|
|
|
|
|
|
|
// Execute
|
|
|
|
$curl = curl_exec($curl);
|
|
|
|
|
|
|
|
// Return the data
|
|
|
|
return $curl;
|
|
|
|
}
|
2016-02-07 19:36:13 +00:00
|
|
|
}
|