Ridding of IPAddress and IPAddressRange, the latter was broken and the former was obsoleted by INET funcs.

This commit is contained in:
flash 2018-09-27 10:32:43 +02:00
parent b0f6db2450
commit 012171635e
11 changed files with 67 additions and 409 deletions

View file

@ -30,6 +30,7 @@ require_once __DIR__ . '/src/colour.php';
require_once __DIR__ . '/src/comments.php';
require_once __DIR__ . '/src/general.php';
require_once __DIR__ . '/src/git.php';
require_once __DIR__ . '/src/ip.php';
require_once __DIR__ . '/src/manage.php';
require_once __DIR__ . '/src/news.php';
require_once __DIR__ . '/src/perms.php';

View file

@ -2,7 +2,6 @@
use Carbon\Carbon;
use Misuzu\Application;
use Misuzu\Database;
use Misuzu\Net\IPAddress;
require_once __DIR__ . '/../misuzu.php';
@ -169,7 +168,7 @@ switch ($authMode) {
break;
}
$ipAddress = remote_address();
$ipAddress = ip_remote_address();
$emailSent = Database::prepare('
SELECT COUNT(`verification_code`) > 0
FROM `msz_users_password_resets`
@ -235,7 +234,7 @@ MSG;
$authLoginError = '';
while ($isSubmission) {
$ipAddress = remote_address();
$ipAddress = ip_remote_address();
if (!isset($authUsername, $authPassword)) {
$authLoginError = "You didn't fill all the forms!";
@ -343,7 +342,7 @@ MSG;
$authUsername,
$authPassword,
$authEmail,
remote_address()
ip_remote_address()
);
if ($createUser < 1) {

View file

@ -123,7 +123,7 @@ if ($postRequest) {
$topicId,
$forum['forum_id'],
$app->getUserId(),
remote_address(),
ip_remote_address(),
$postText,
MSZ_PARSER_BBCODE
);

View file

@ -1,221 +0,0 @@
<?php
namespace Misuzu\Net;
use InvalidArgumentException;
/**
* IP Address object.
* @package Misuzu\Net
* @author flashwave <me@flash.moe>
*/
final class IPAddress
{
/**
* Default IP Address if $_SERVER['REMOTE_ADDR'] is not set.
*/
private const FALLBACK_ADDRESS = '::1';
/**
* Fallback version number.
*/
public const UNKNOWN_VERSION = 0;
/**
* IPv4.
*/
public const V4 = 4;
/**
* IPv6.
*/
public const V6 = 6;
/**
* String lengths of expanded IP addresses.
*/
public const BYTE_COUNT = [
self::V4 => 4,
self::V6 => 16,
];
/**
* IP address version.
* @var int
*/
private $ipVersion = self::UNKNOWN_VERSION;
/**
* Raw IP address.
* @var null|string
*/
private $ipRaw = null;
/**
* @return int
*/
public function getVersion(): int
{
return $this->ipVersion;
}
/**
* @return string
*/
public function getRaw(): string
{
return $this->ipRaw;
}
/**
* @return string
*/
public function getString(): string
{
return inet_ntop($this->ipRaw);
}
/**
* Gets GeoIP country for this IP address.
* @return string
*/
public function getCountryCode(): string
{
return get_country_code($this->getString());
}
/**
* IPAddress constructor.
* @param int $version
* @param string $rawIp
*/
public function __construct(int $version, string $rawIp)
{
if (!array_key_exists($version, self::BYTE_COUNT)) {
throw new InvalidArgumentException('Invalid IP version provided.');
}
if (strlen($rawIp) !== self::BYTE_COUNT[$version]) {
throw new InvalidArgumentException('Binary IP was of invalid length.');
}
$this->ipVersion = $version;
$this->ipRaw = $rawIp;
}
/**
* Compares one IP to another.
* @param IPAddress $other
* @return int
* @throws InvalidArgumentException If the versions of the IP mismatch.
*/
public function compareTo(IPAddress $other): int
{
if ($other->getVersion() !== $this->getVersion()) {
throw new InvalidArgumentException('Both addresses must be of the same version.');
}
$parts_this = array_values(unpack('N*', $this->getRaw()));
$parts_other = array_values(unpack('N*', $other->getRaw()));
$size = count($parts_this);
if ($size !== count($parts_other)) {
throw new InvalidArgumentException('Addresses varied in length. (if you touched $ipRaw, i will fight you)');
}
for ($i = 0; $i < $size; $i++) {
$result = $parts_other[$i] <=> $parts_this[$i];
if ($result !== 0) {
return $result;
}
}
return 0;
}
/**
* Gets the remote address.
* @param string $fallbackAddress
* @return IPAddress
*/
public static function remote(string $fallbackAddress = self::FALLBACK_ADDRESS): IPAddress
{
try {
return self::fromString(remote_address($fallbackAddress));
} catch (InvalidArgumentException $ex) {
return self::fromString($fallbackAddress);
}
}
/**
* Creates an IPAddress instance from just a raw IP string.
* @param string $rawIp
* @return IPAddress
*/
public static function fromRaw(string $rawIp): IPAddress
{
$version = self::detectVersionFromRaw($rawIp);
if ($version === self::UNKNOWN_VERSION) {
throw new InvalidArgumentException('Invalid raw IP address supplied.');
}
return new static($version, $rawIp);
}
/**
* Creates an IPAddress instance from a human readable address string.
* @param string $ipAddress
* @return IPAddress
*/
public static function fromString(string $ipAddress): IPAddress
{
$version = self::detectVersionFromString($ipAddress);
if (!array_key_exists($version, self::BYTE_COUNT)) {
throw new InvalidArgumentException('Invalid IP address supplied.');
}
return new static($version, inet_pton($ipAddress));
}
/**
* Detects the version of a raw address string.
* @param string $rawIp
* @return int
*/
public static function detectVersionFromRaw(string $rawIp): int
{
$rawLength = strlen($rawIp);
foreach (self::BYTE_COUNT as $version => $length) {
if ($rawLength === $length) {
return $version;
}
}
return self::UNKNOWN_VERSION;
}
/**
* Detects the version of a human readable address string.
* @param string $ipAddress
* @return int
*/
public static function detectVersionFromString(string $ipAddress): int
{
if (filter_var($ipAddress, FILTER_VALIDATE_IP) === false) {
return self::UNKNOWN_VERSION;
}
if (filter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
return self::V6;
}
if (filter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
return self::V4;
}
return self::UNKNOWN_VERSION;
}
}

View file

@ -1,160 +0,0 @@
<?php
namespace Misuzu\Net;
use InvalidArgumentException;
final class IPAddressRange
{
/**
* @var IPAddress
*/
private $maskAddress;
/**
* @var int
*/
private $cidrLength;
/**
* @return IPAddress
*/
public function getMaskAddress(): IPAddress
{
return $this->maskAddress;
}
/**
* @return int
*/
public function getCidrLength(): int
{
return $this->cidrLength;
}
/**
* IPAddressRange constructor.
* @param IPAddress $maskAddress
* @param int $cidrLength
*/
public function __construct(IPAddress $maskAddress, int $cidrLength)
{
if ($cidrLength > IPAddress::BYTE_COUNT[$maskAddress->getVersion()] * 8) {
throw new InvalidArgumentException('CIDR length is out of range.');
}
$this->maskAddress = $maskAddress;
$this->cidrLength = $cidrLength;
}
/**
* Gets a conventional <MASKED ADDRESS>/<CIDR LENGTH> format string.
* @return string
*/
public function getMaskedString(): string
{
return $this->getMaskAddress()->getString() . '/' . $this->getCidrLength();
}
/**
* Matches an IPAddress to this range.
* @param IPAddress $ipAddress
* @param bool $explicitExceptions
* @return bool
*/
public function match(IPAddress $ipAddress, bool $explicitExceptions = false): bool
{
if ($ipAddress->getVersion() !== $this->getMaskAddress()->getVersion()) {
if ($explicitExceptions) {
throw new InvalidArgumentException('Both addresses must be of the same version.');
}
return false;
}
$ipParts = array_values(unpack('N*', $ipAddress->getRaw()));
$maskParts = array_values(unpack('N*', $this->getMaskAddress()->getRaw()));
$parts = count($ipParts);
if ($parts !== count($maskParts)) {
if ($explicitExceptions) {
throw new InvalidArgumentException('Both addresses must be of the same version (failed 1).');
}
return false;
}
for ($i = 0; $i < $parts; $i++) {
$ipParts[$i] = $ipParts[$i] & $maskParts[$i];
}
return $this->getMaskAddress()->getRaw() === pack('N*', ...$ipParts);
}
/**
* Creates an IPAddressRange instance using the conventional notation format.
* @param string $maskedString
* @return IPAddressRange
*/
public static function fromMaskedString(string $maskedString): IPAddressRange
{
if (mb_strpos($maskedString, '/') === false) {
throw new InvalidArgumentException('Invalid masked string.');
}
[$maskedAddress, $cidrLength] = explode('/', $maskedString, 2);
$maskedAddress = IPAddress::fromString($maskedAddress);
$cidrLength = (int)$cidrLength;
return new static($maskedAddress, $cidrLength);
}
/**
* Creates an IPAddresRange instance from a dash separated range.
* I'm very uncertain about the logic here when it comes to addresses larger than 32 bits.
* If you do know what you're doing, please review this and call me an idiot.
*
* @param string $rangeString
* @return IPAddressRange
*/
public static function fromRangeString(string $rangeString): IPAddressRange
{
if (mb_strpos($rangeString, '-') === false) {
throw new InvalidArgumentException('Invalid range string.');
}
[$rangeStart, $rangeEnd] = explode('-', $rangeString, 2);
$rangeStart = IPAddress::fromString($rangeStart);
$rangeEnd = IPAddress::fromString($rangeEnd);
// implicitly performs a version compare as well, throws an exception if different
if ($rangeStart->compareTo($rangeEnd) < 1) {
throw new InvalidArgumentException('Range start was larger (or equal) to the range end.');
}
$partsStart = array_values(unpack('N*', $rangeStart->getRaw()));
$partsEnd = array_values(unpack('N*', $rangeEnd->getRaw()));
$parts = count($partsStart);
if ($parts !== count($partsEnd)) {
throw new InvalidArgumentException('Range start was larger (or equal) to the range end (failed 1).');
}
$bits = $parts * 32;
$mask = array_fill(0, $parts, 0);
for ($i = 0; $i < $parts; $i++) {
$diffs = $partsStart[$i] ^ $partsEnd[$i];
while ($diffs != 0) {
$diffs >>= 1;
$bits -= 1;
$mask[$i] = ($mask[$i] << 1) | 1;
}
$mask[$i] = $partsStart[$i] & ~$mask[$i];
}
$mask = pack('N*', ...$mask);
return new static(new IPAddress($rangeStart->getVersion(), $mask), $bits);
}
}

View file

@ -12,7 +12,7 @@ function user_login_attempt_record(bool $success, ?int $userId, string $ipAddres
$storeAttempt->bindValue('was_successful', $success ? 1 : 0);
$storeAttempt->bindValue('attempt_ip', $ipAddress);
$storeAttempt->bindValue('attempt_country', get_country_code($ipAddress));
$storeAttempt->bindValue('attempt_country', ip_country_code($ipAddress));
$storeAttempt->bindValue('user_agent', $userAgent);
$storeAttempt->bindValue('user_id', $userId, $userId === null ? PDO::PARAM_NULL : PDO::PARAM_INT);
$storeAttempt->execute();

View file

@ -24,7 +24,7 @@ function user_session_create(
');
$createSession->bindValue('user_id', $userId);
$createSession->bindValue('session_ip', $ipAddress);
$createSession->bindValue('session_country', get_country_code($ipAddress));
$createSession->bindValue('session_country', ip_country_code($ipAddress));
$createSession->bindValue('user_agent', $userAgent);
$createSession->bindValue('session_key', $sessionKey);

View file

@ -40,7 +40,7 @@ function user_create(
$createUser->bindValue('email', $email);
$createUser->bindValue('register_ip', $ipAddress);
$createUser->bindValue('last_ip', $ipAddress);
$createUser->bindValue('user_country', get_country_code($ipAddress));
$createUser->bindValue('user_country', ip_country_code($ipAddress));
return $createUser->execute() ? (int)Database::lastInsertId() : 0;
}
@ -77,7 +77,7 @@ function user_bump_last_active(int $userId, string $ipAddress = null): void
`last_ip` = INET6_ATON(:last_ip)
WHERE `user_id` = :user_id
');
$bumpUserLast->bindValue('last_ip', $ipAddress ?? remote_address());
$bumpUserLast->bindValue('last_ip', $ipAddress ?? ip_remote_address());
$bumpUserLast->bindValue('user_id', $userId);
$bumpUserLast->execute();
}

View file

@ -1,6 +1,5 @@
<?php
use Misuzu\Database;
use Misuzu\Net\IPAddress;
function audit_log(
string $action,
@ -8,7 +7,7 @@ function audit_log(
array $params = [],
?string $ipAddress = null
): void {
$ipAddress = $ipAddress ?? remote_address();
$ipAddress = $ipAddress ?? ip_remote_address();
for ($i = 0; $i < count($params); $i++) {
if (preg_match('#^(-?[0-9]+)$#', $params[$i])) {
@ -26,7 +25,7 @@ function audit_log(
$addLog->bindValue('user', $userId < 1 ? null : $userId);
$addLog->bindValue('params', json_encode($params));
$addLog->bindValue('ip', $ipAddress);
$addLog->bindValue('country', get_country_code($ipAddress));
$addLog->bindValue('country', ip_country_code($ipAddress));
$addLog->execute();
}

56
src/ip.php Normal file
View file

@ -0,0 +1,56 @@
<?php
use Misuzu\Application;
define('MSZ_IP_UNKNOWN', 0);
define('MSZ_IP_V4', 4);
define('MSZ_IP_V6', 6);
define('MSZ_IP_SIZES', [
MSZ_IP_V4 => 4,
MSZ_IP_V6 => 16,
]);
function ip_remote_address(string $fallback = '::1'): string
{
return $_SERVER['REMOTE_ADDR'] ?? $fallback;
}
function ip_country_code(string $ipAddr, string $fallback = 'XX'): string
{
try {
return Application::geoip()->country($ipAddr)->country->isoCode ?? $fallback;
} catch (Exception $e) {
}
return $fallback;
}
function ip_detect_string_version(string $address): int
{
if (filter_var($address, FILTER_VALIDATE_IP) === false) {
return MSZ_IP_UNKNOWN;
}
if (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
return MSZ_IP_V6;
}
if (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
return MSZ_IP_V4;
}
return MSZ_IP_UNKNOWN;
}
function ip_detect_raw_version(string $raw): int
{
$rawLength = strlen($raw);
foreach (MSZ_IP_SIZES as $version => $length) {
if ($rawLength === $length) {
return $version;
}
}
return MSZ_IP_UNKNOWN;
}

View file

@ -29,11 +29,6 @@ function array_apply(array $array, callable $func): array
return $array;
}
function remote_address(string $fallback = '::1'): string
{
return $_SERVER['REMOTE_ADDR'] ?? $fallback;
}
function set_cookie_m(string $name, string $value, int $expires): void
{
setcookie(
@ -151,17 +146,6 @@ function byte_symbol($bytes, $decimal = false)
return sprintf("%.2f %s%sB", $bytes, $symbol, $symbol !== '' && !$decimal ? 'i' : '');
}
function get_country_code(string $ipAddr, string $fallback = 'XX'): string
{
try {
return \Misuzu\Application::geoip()->country($ipAddr)->country->isoCode ?? $fallback;
} catch (\Exception $e) {
// report error?
}
return $fallback;
}
function get_country_name(string $code): string
{
switch (strtolower($code)) {