BioTorrents.de’s version of Gazelle
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ipv4.class.php 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <?php
  2. declare(strict_types = 1);
  3. /**
  4. * Adapted from
  5. * https://github.com/OPSnet/Gazelle/blob/master/app/Manager/IPv4.php
  6. *
  7. * Not working as of 2020-12-12
  8. */
  9. class IPv4
  10. {
  11. const CACHE_KEY = 'ipv4_bans_';
  12. /**
  13. * Returns the unsigned 32bit form of an IPv4 address
  14. *
  15. * @param string $ipv4 The IP address x.x.x.x
  16. * @return string the long it represents.
  17. */
  18. public function ip2ulong(string $ipv4)
  19. {
  20. return sprintf('%u', ip2long($ipv4));
  21. }
  22. /**
  23. * Returns true if given IP is banned.
  24. * TODO: This looks really braindead. Why not compare the 32bit address
  25. * directly BETWEEN FromIP AND ToIP? Apart from dubious merits of
  26. * caching?
  27. *
  28. * @param string $IP
  29. * @return bool True if banned
  30. */
  31. public function isBanned(string $IP)
  32. {
  33. $A = substr($IP, 0, strcspn($IP, '.'));
  34. $key = self::CACHE_KEY . $A;
  35. $IPBans = G::$Cache->get_value($key);
  36. if (!is_array($IPBans)) {
  37. G::$DB->prepare_query("
  38. SELECT
  39. `FromIP`,
  40. `ToIP`,
  41. `ID`
  42. FROM
  43. `ip_bans`
  44. WHERE
  45. `FromIP` BETWEEN $A << 24 AND (($A+1) << 24) - 1
  46. ");
  47. G::$DB->exec_prepared_query();
  48. $IPBans = G::$DB->to_array(0, MYSQLI_NUM);
  49. G::$Cache->cache_value($key, $IPBans, 0);
  50. }
  51. $IPNum = IPv4::ip2ulong($IP);
  52. foreach ($IPBans as $IPBan) {
  53. list($FromIP, $ToIP) = $IPBan;
  54. if ($IPNum >= $FromIP && $IPNum <= $ToIP) {
  55. return true;
  56. }
  57. }
  58. return false;
  59. }
  60. /**
  61. * Create an ip address ban over a range of addresses. Will append
  62. * the given reason to an existing ban.
  63. *
  64. * @param int $userId The person doing the band (0 for system)
  65. * @param string $from The first address (dotted quad a.b.c.d)
  66. * @param string $to The last adddress in the range (may equal $from)
  67. * @param string $reason Why ban?
  68. */
  69. public function createBan(int $userId, $ipv4From, string $ipv4To, string $reason)
  70. {
  71. $from = $this->ip2ulong($ipv4From);
  72. $to = $this->ip2ulong($ipv4To);
  73. $current = G::$DB->scalar("
  74. SELECT
  75. `Reason`
  76. FROM
  77. `ip_bans`
  78. WHERE
  79. '$from' BETWEEN `FromIP` AND `ToIP`
  80. ");
  81. if ($current) {
  82. if ($current !== $reason) {
  83. G::$DB->prepare_query("
  84. UPDATE
  85. `ip_bans`
  86. SET
  87. `Reason` = CONCAT('$reason', ' AND ', `Reason`),
  88. `UserID` = '$userId',
  89. `Created` = NOW()
  90. WHERE
  91. `FromIP` = '$from' AND `ToIP` = '$to'
  92. ");
  93. G::$DB->exec_prepared_query();
  94. }
  95. } else { // Not yet banned
  96. G::$DB->prepare_query("
  97. INSERT INTO `ip_bans`(`Reason`, `FromIP`, `ToIP`, `UserID`)
  98. VALUES('$reason', '$from', '$to', '$userId')
  99. ");
  100. G::$DB->exec_prepared_query();
  101. G::$Cache->delete_value(
  102. self::CACHE_KEY . substr($ipv4From, 0, strcspn($ipv4From, '.'))
  103. );
  104. }
  105. }
  106. /**
  107. * Remove an ip ban
  108. *
  109. * param int $id Row to remove
  110. */
  111. public function removeBan(int $id)
  112. {
  113. $fromClassA = G::$DB->scalar("
  114. SELECT
  115. `FromIP` >> 24
  116. FROM
  117. `ip_bans`
  118. WHERE
  119. `ID` = '$id'
  120. ");
  121. if (is_null($fromClassA)) {
  122. return;
  123. }
  124. G::$DB->prepare_query("
  125. DELETE
  126. FROM
  127. `ip_bans`
  128. WHERE
  129. `ID` = '$id'
  130. ");
  131. if (G::$DB->affected_rows()) {
  132. G::$DB->exec_prepared_query();
  133. G::$Cache->delete_value(self::CACHE_KEY . $fromClassA);
  134. }
  135. }
  136. }