Changeset 3357194
- Timestamp:
- 09/06/2025 06:05:09 PM (6 months ago)
- Location:
- edh-bad-bots/trunk
- Files:
-
- 7 edited
-
admin/views/admin-display.php (modified) (10 diffs)
-
assets/js/admin-script.js (modified) (1 diff)
-
edh-bad-bots.php (modified) (7 diffs)
-
includes/class-edhbb-admin.php (modified) (3 diffs)
-
includes/class-edhbb-blocker.php (modified) (3 diffs)
-
includes/class-edhbb-database.php (modified) (9 diffs)
-
readme.txt (modified) (14 diffs)
Legend:
- Unmodified
- Added
- Removed
-
edh-bad-bots/trunk/admin/views/admin-display.php
r3355590 r3357194 6 6 * It displays blocked bots, allows whitelisting IPs, and manages unblocking. 7 7 */ 8 declare(strict_types=1); 8 9 9 10 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly … … 112 113 <div class="card edhbb-card"> 113 114 <h2 class="title"><?php esc_html_e( 'Currently Blocked Bots', 'edh-bad-bots' ); ?></h2> 115 116 <!-- Manual hostname update buttons --> 117 <div style="margin-bottom: 20px;"> 118 <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display: inline;"> 119 <input type="hidden" name="action" value="edhbb_update_hostnames"> 120 <?php wp_nonce_field( 'edhbb_update_hostnames_nonce' ); ?> 121 <?php submit_button( __( 'Update Missing Hostnames', 'edh-bad-bots' ), 'secondary', 'submit_update_hostnames', false ); ?> 122 </form> 123 124 <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display: inline; margin-left: 10px;"> 125 <input type="hidden" name="action" value="edhbb_force_refresh_all_hostnames"> 126 <?php wp_nonce_field( 'edhbb_force_refresh_all_hostnames_nonce' ); ?> 127 <?php submit_button( __( 'Force Refresh All Hostnames', 'edh-bad-bots' ), 'secondary', 'submit_force_refresh_all', false ); ?> 128 </form> 129 130 <p class="description" style="margin-top: 5px;"> 131 <?php esc_html_e( 'Update Missing: Resolves hostnames for IPs that show empty or "[No PTR Record]". Force Refresh: Clears cache and re-resolves ALL hostnames.', 'edh-bad-bots' ); ?> 132 </p> 133 </div> 134 135 <?php 136 // Display debug information if available and WP_DEBUG is enabled 137 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 138 $debug_info = get_transient( 'edhbb_debug_info' ); 139 if ( $debug_info ) : 140 delete_transient( 'edhbb_debug_info' ); // Delete after displaying 141 ?> 142 <div class="notice notice-info inline"> 143 <h3><?php esc_html_e( 'Hostname Resolution Debug Info', 'edh-bad-bots' ); ?></h3> 144 <p><?php esc_html_e( 'The following information was gathered to help debug hostname resolution issues.', 'edh-bad-bots' ); ?></p> 145 <table class="widefat"> 146 <thead> 147 <tr> 148 <th><?php esc_html_e( 'Function', 'edh-bad-bots' ); ?></th> 149 <th><?php esc_html_e( 'Exists?', 'edh-bad-bots' ); ?></th> 150 <th><?php esc_html_e( 'Callable?', 'edh-bad-bots' ); ?></th> 151 <th><?php esc_html_e( 'Result for 8.8.8.8', 'edh-bad-bots' ); ?></th> 152 </tr> 153 </thead> 154 <tbody> 155 <tr> 156 <td><code>gethostbyaddr()</code></td> 157 <td><?php echo esc_html( $debug_info['gethostbyaddr']['exists'] ); ?></td> 158 <td><?php echo esc_html( $debug_info['gethostbyaddr']['callable'] ); ?></td> 159 <td><pre><?php echo esc_html( print_r( $debug_info['gethostbyaddr']['result'], true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- Debug output only shown when WP_DEBUG is enabled ?></pre></td> 160 </tr> 161 <tr> 162 <td><code>dns_get_record()</code></td> 163 <td><?php echo esc_html( $debug_info['dns_get_record']['exists'] ); ?></td> 164 <td><?php echo esc_html( $debug_info['dns_get_record']['callable'] ); ?></td> 165 <td><pre><?php echo esc_html( print_r( $debug_info['dns_get_record']['result'], true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- Debug output only shown when WP_DEBUG is enabled ?></pre></td> 166 </tr> 167 </tbody> 168 </table> 169 </div> 170 <?php endif; 171 } ?> 172 114 173 <?php if ( ! empty( $blocked_bots ) ) : ?> 115 174 <table class="wp-list-table widefat fixed striped"> … … 117 176 <tr> 118 177 <th scope="col"><?php esc_html_e( 'IP Address', 'edh-bad-bots' ); ?></th> 178 <th scope="col"><?php esc_html_e( 'Hostname', 'edh-bad-bots' ); ?></th> 119 179 <th scope="col"><?php esc_html_e( 'Blocked At', 'edh-bad-bots' ); ?></th> 120 180 <th scope="col"><?php esc_html_e( 'Expires At', 'edh-bad-bots' ); ?></th> … … 126 186 <tr> 127 187 <td><?php echo esc_html( $bot['ip_address'] ); ?></td> 188 <td> 189 <?php 190 $hostname = esc_html( $bot['hostname'] ); 191 if ( $hostname === '[No PTR Record]' || empty( $hostname ) ) { 192 echo '<em style="color: #666;">[No PTR Record]</em>'; 193 } else { 194 echo esc_html( $hostname ); 195 } 196 ?> 197 </td> 128 198 <td><?php echo esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $bot['blocked_at'] ) ) ); ?></td> 129 199 <td><?php echo esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $bot['expires_at'] ) ) ); ?></td> … … 190 260 $path = !empty($site_url_parts['path']) ? $site_url_parts['path'] : ''; 191 261 $trap_url = home_url( $path . '/' . $hash . '/' ); 262 263 // Get current block duration setting 264 $current_block_duration = get_option( 'edhbb_block_duration_days', 30 ); 192 265 ?> 193 266 <!-- Section for Help Text --> … … 195 268 <h2 class="title"><?php esc_html_e( 'How EDH Bad Bots Works', 'edh-bad-bots' ); ?></h2> 196 269 <p> 197 <?php esc_html_e( 'This plugin helps protect your site from bots that do not respect the `robots.txt` file .', 'edh-bad-bots' ); ?>270 <?php esc_html_e( 'This plugin helps protect your site from bots that do not respect the `robots.txt` file using an advanced honeypot system with intelligent hostname identification.', 'edh-bad-bots' ); ?> 198 271 </p> 199 272 <h3><?php esc_html_e( 'The Blocking Process:', 'edh-bad-bots' ); ?></h3> … … 212 285 </li> 213 286 <li> 214 <?php esc_html_e( 'When a bot hits the trap URL, its IP address is recorded and added to a **blocklist** for 30 days.', 'edh-bad-bots' ); ?> 287 <?php 288 echo sprintf( 289 /* translators: %d: number of days bots are blocked */ 290 esc_html__( 'When a bot hits the trap URL, its IP address is recorded and added to a blocklist for %d days (configurable in Options).', 'edh-bad-bots' ), 291 $current_block_duration 292 ); 293 ?> 294 </li> 295 <li> 296 <?php esc_html_e( 'The plugin performs reverse DNS lookups (PTR records) to identify the hostname/organization behind the blocked IP for better analysis.', 'edh-bad-bots' ); ?> 215 297 </li> 216 298 <li> … … 218 300 </li> 219 301 </ol> 302 303 <h3><?php esc_html_e( 'Hostname Resolution System:', 'edh-bad-bots' ); ?></h3> 304 <p> 305 <?php esc_html_e( 'The plugin includes an advanced DNS lookup system to identify blocked bots:', 'edh-bad-bots' ); ?> 306 </p> 307 <ul> 308 <li> 309 <strong><?php esc_html_e( 'DNS over HTTPS (DoH):', 'edh-bad-bots' ); ?></strong> 310 <?php esc_html_e( 'Uses secure, encrypted DNS queries via Cloudflare and Google DNS for enhanced privacy and reliability.', 'edh-bad-bots' ); ?> 311 </li> 312 <li> 313 <strong><?php esc_html_e( 'PTR Record Lookups:', 'edh-bad-bots' ); ?></strong> 314 <?php esc_html_e( 'Converts IP addresses to hostnames (e.g., "crawl-66-249-66-1.googlebot.com") for better identification of what\'s being blocked.', 'edh-bad-bots' ); ?> 315 </li> 316 <li> 317 <strong><?php esc_html_e( 'Background Processing:', 'edh-bad-bots' ); ?></strong> 318 <?php esc_html_e( 'Hostname resolution runs automatically in the background via WordPress cron to avoid delays.', 'edh-bad-bots' ); ?> 319 </li> 320 <li> 321 <strong><?php esc_html_e( 'Manual Updates:', 'edh-bad-bots' ); ?></strong> 322 <?php esc_html_e( 'Use the "Update Missing Hostnames" and "Force Refresh All Hostnames" buttons in the Blocked Bots tab for manual control.', 'edh-bad-bots' ); ?> 323 </li> 324 </ul> 220 325 221 326 <h3><?php esc_html_e( 'Managing IPs:', 'edh-bad-bots' ); ?></h3> … … 223 328 <li> 224 329 <strong><?php esc_html_e( 'Whitelisted IPs', 'edh-bad-bots' ); ?></strong> 225 <?php esc_html_e( 'IP addresses added to the whitelist will **never**be blocked, even if they hit the bot trap. Use this for your own IP address, trusted services, or known legitimate bots.', 'edh-bad-bots' ); ?>330 <?php esc_html_e( 'IP addresses added to the whitelist will never be blocked, even if they hit the bot trap. Use this for your own IP address, trusted services, or known legitimate bots.', 'edh-bad-bots' ); ?> 226 331 </li> 227 332 <li> 228 333 <strong><?php esc_html_e( 'Blocked Bots', 'edh-bad-bots' ); ?></strong> 229 <?php esc_html_e( 'This tab shows all IP addresses currently on the blocklist. IPs are automatically removed after 30 days, but you can manually unblock them here at any time.', 'edh-bad-bots' ); ?> 230 </li> 231 <li> 232 <strong><?php esc_html_e( '.htaccess Blocking Option:', 'edh-bad-bots' ); ?></strong> 233 <?php esc_html_e( 'On the "Options" tab, you can choose to enable or disable server-level IP blocking via the .htaccess file. If disabled, blocking will rely solely on PHP, which might be less effective with caching plugins.', 'edh-bad-bots' ); ?> 334 <?php 335 echo sprintf( 336 /* translators: %d: number of days bots are blocked */ 337 esc_html__( 'This tab shows all IP addresses currently on the blocklist with their resolved hostnames. IPs are automatically removed after %d days, but you can manually unblock them here at any time.', 'edh-bad-bots' ), 338 $current_block_duration 339 ); 340 ?> 341 </li> 342 <li> 343 <strong><?php esc_html_e( 'Options Tab Features:', 'edh-bad-bots' ); ?></strong> 344 <ul> 345 <li><?php esc_html_e( '.htaccess Blocking: Enable or disable server-level IP blocking via the .htaccess file. If disabled, blocking will rely solely on PHP, which might be less effective with caching plugins.', 'edh-bad-bots' ); ?></li> 346 <li><?php esc_html_e( 'Block Duration: Configure how many days to block detected bot IPs (default: 30 days).', 'edh-bad-bots' ); ?></li> 347 </ul> 234 348 </li> 235 349 </ul> 236 350 351 <h3><?php esc_html_e( 'Admin Tools:', 'edh-bad-bots' ); ?></h3> 352 <ul> 353 <li> 354 <strong><?php esc_html_e( 'Update Missing Hostnames:', 'edh-bad-bots' ); ?></strong> 355 <?php esc_html_e( 'Resolves hostnames for blocked IPs that show empty or "[No PTR Record]" to help identify what type of bots are being blocked.', 'edh-bad-bots' ); ?> 356 </li> 357 <li> 358 <strong><?php esc_html_e( 'Force Refresh All Hostnames:', 'edh-bad-bots' ); ?></strong> 359 <?php esc_html_e( 'Clears the DNS cache and re-resolves hostnames for all blocked IPs. Useful for troubleshooting or getting updated information.', 'edh-bad-bots' ); ?> 360 </li> 361 <li> 362 <strong><?php esc_html_e( 'Debug Information:', 'edh-bad-bots' ); ?></strong> 363 <?php esc_html_e( 'When WP_DEBUG is enabled, diagnostic information about hostname resolution functions is displayed to help troubleshoot issues.', 'edh-bad-bots' ); ?> 364 </li> 365 </ul> 366 237 367 <h3><?php esc_html_e( 'Caching Plugin Exclusion:', 'edh-bad-bots' ); ?></h3> 238 368 <p> 239 <?php esc_html_e( 'To ensure that the bot trap works correctly, you **must**exclude the following unique URL from your caching plugin. This prevents the trap page from being cached and served to human visitors.', 'edh-bad-bots' ); ?>369 <?php esc_html_e( 'To ensure that the bot trap works correctly, you must exclude the following unique URL from your caching plugin. This prevents the trap page from being cached and served to human visitors.', 'edh-bad-bots' ); ?> 240 370 </p> 241 371 <p> … … 249 379 </p> 250 380 381 <h3><?php esc_html_e( 'Technical Notes:', 'edh-bad-bots' ); ?></h3> 382 <ul> 383 <li> 384 <strong><?php esc_html_e( 'IPv4 and IPv6 Support:', 'edh-bad-bots' ); ?></strong> 385 <?php esc_html_e( 'The hostname resolution system supports both IPv4 and IPv6 addresses for comprehensive coverage.', 'edh-bad-bots' ); ?> 386 </li> 387 <li> 388 <strong><?php esc_html_e( 'DNS Caching:', 'edh-bad-bots' ); ?></strong> 389 <?php esc_html_e( 'Hostname lookups are cached for 1 hour to improve performance and reduce DNS server load.', 'edh-bad-bots' ); ?> 390 </li> 391 <li> 392 <strong><?php esc_html_e( 'Fallback Methods:', 'edh-bad-bots' ); ?></strong> 393 <?php esc_html_e( 'If DNS over HTTPS fails, the system automatically falls back to traditional DNS methods for maximum compatibility.', 'edh-bad-bots' ); ?> 394 </li> 395 </ul> 251 396 </div> 252 397 <?php endif; ?> -
edh-bad-bots/trunk/assets/js/admin-script.js
r3355590 r3357194 1 // TODO: Add JavaScript for the admin page to add client side validation for the whitelist IP address field 2 // TODO: Add JavaScript for the admin page to add client side validation for the block duration days field 3 // TODO: Add JavaScript for the admin page to add client side validation for the .htaccess blocking field 4 // TODO: Add JavaScript for the admin page to add client side validation for the enable server-level IP blocking field 5 // TODO: Add JavaScript for the admin page to add client side validation for the enable server-level IP blocking field -
edh-bad-bots/trunk/edh-bad-bots.php
r3355590 r3357194 4 4 * Plugin URI: https://github.com/EncodeDotHost/edh-bad-bots 5 5 * Description: This plugin is used to block bots that don't honor the robots.txt file from the site. 6 * Version: 1.4. 26 * Version: 1.4.3 7 7 * Requires at least: 6.2 8 8 * Requires PHP: 7.4 … … 17 17 * @author EncodeDotHost 18 18 * @contributor nbwpuk 19 * @version 1.4. 219 * @version 1.4.3 20 20 * @link https://github.com/EncodeDotHost/edh-bad-bots 21 21 * @license GPL v3 or later 22 22 */ 23 24 if(!defined('ABSPATH')) exit; 23 declare(strict_types=1); 24 25 if(!defined('ABSPATH')) exit; 25 26 26 27 /** … … 30 31 define( 'EDHBB_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 31 32 define( 'EDHBB_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); 32 define( 'EDHBB_VERSION', '1.4. 2' );33 define( 'EDHBB_VERSION', '1.4.3' ); 33 34 34 35 /** … … 38 39 */ 39 40 require_once EDHBB_PLUGIN_DIR . 'includes/class-edhbb-database.php'; 41 require_once EDHBB_PLUGIN_DIR . 'includes/class-edhbb-dnslookup.php'; 40 42 require_once EDHBB_PLUGIN_DIR . 'includes/class-edhbb-blocker.php'; 41 43 require_once EDHBB_PLUGIN_DIR . 'includes/class-edhbb-admin.php'; … … 47 49 register_activation_hook( __FILE__, 'edhbb_activate_plugin' ); 48 50 register_deactivation_hook( __FILE__, 'edhbb_deactivate_plugin' ); 51 52 /** 53 * Schedule hostname update cron job on activation. 54 */ 55 add_action( 'edhbb_update_hostnames_cron', 'edhbb_update_missing_hostnames' ); 56 57 /** 58 * Schedule the cron event if it's not already scheduled. 59 */ 60 if ( ! wp_next_scheduled( 'edhbb_update_hostnames_cron' ) ) { 61 wp_schedule_event( time(), 'hourly', 'edhbb_update_hostnames_cron' ); 62 } 49 63 50 64 /** … … 65 79 */ 66 80 function edhbb_deactivate_plugin() { 81 // Clear the scheduled cron job 82 wp_clear_scheduled_hook( 'edhbb_update_hostnames_cron' ); 83 67 84 // Optionally, you can drop tables here. Be cautious with this as users might want to reactivate. 68 85 // For now, we'll leave it empty to preserve data on deactivation. … … 84 101 add_action( 'plugins_loaded', 'edhbb_init_plugin' ); 85 102 103 /** 104 * Background cron function to update missing hostnames. 105 * This runs periodically to resolve hostnames for blocked IPs that don't have them. 106 */ 107 function edhbb_update_missing_hostnames() { 108 $edh_database = new EDHBB_Database(); 109 $edh_blocker = new EDHBB_Blocker( $edh_database ); 110 111 // Get IPs without hostnames (limit to 5 per run to avoid timeouts) 112 $ips_without_hostnames = $edh_database->get_blocked_ips_without_hostnames( 5 ); 113 114 if ( empty( $ips_without_hostnames ) ) { 115 return; // Nothing to do 116 } 117 118 // Use reflection to access the private method (since we need the improved hostname resolution) 119 $reflection = new ReflectionClass( $edh_blocker ); 120 $hostname_method = $reflection->getMethod( 'get_hostname_for_ip' ); 121 $hostname_method->setAccessible( true ); 122 123 foreach ( $ips_without_hostnames as $ip_address ) { 124 // Get hostname using the improved method 125 $hostname = $hostname_method->invoke( $edh_blocker, $ip_address ); 126 127 // Update the database with the resolved hostname (even if empty) 128 $edh_database->update_blocked_bot_hostname( $ip_address, $hostname ); 129 130 // Log successful resolution if debug logging is enabled 131 if ( ! empty( $hostname ) && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) { 132 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs when WP_DEBUG_LOG is enabled 133 error_log( '[EDH Bad Bots] Background hostname resolution: ' . $ip_address . ' -> ' . $hostname ); 134 } 135 136 // Small delay to prevent overwhelming DNS servers 137 usleep( 100000 ); // 100ms delay 138 } 139 } 86 140 87 141 /** -
edh-bad-bots/trunk/includes/class-edhbb-admin.php
r3355590 r3357194 6 6 * and displaying blocked bots and whitelisted IPs. 7 7 */ 8 declare(strict_types=1); 8 9 9 10 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly … … 35 36 // Handle form submission for plugin options. 36 37 add_action( 'admin_post_edhbb_save_options', array( $this, 'handle_save_options' ) ); 38 39 // Handle manual hostname update trigger. 40 add_action( 'admin_post_edhbb_update_hostnames', array( $this, 'handle_update_hostnames' ) ); 41 42 // Handle force refresh all hostnames trigger. 43 add_action( 'admin_post_edhbb_force_refresh_all_hostnames', array( $this, 'handle_force_refresh_all_hostnames' ) ); 37 44 } 38 45 … … 318 325 exit; // Important: Always exit after a redirect to prevent further script execution. 319 326 } 327 328 /** 329 * Handles the manual hostname update trigger from the admin interface. 330 */ 331 public function handle_update_hostnames() { 332 // Verify nonce for security. 333 if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), 'edhbb_update_hostnames_nonce' ) ) { 334 wp_die( esc_html__( 'Security check failed.', 'edh-bad-bots' ) ); 335 } 336 337 // Check user capabilities. 338 if ( ! current_user_can( 'manage_options' ) ) { 339 wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'edh-bad-bots' ) ); 340 } 341 342 // Run the debug function if WP_DEBUG is enabled 343 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 344 $this->debug_hostname_resolution(); 345 } 346 347 // Trigger the hostname update function 348 $updated_count = $this->manual_hostname_update(); 349 350 // Add a success message to be displayed on the admin page. 351 add_settings_error( 352 'edhbb_messages', 353 'edhbb_hostnames_updated', 354 sprintf( 355 /* translators: %d: number of updated hostnames */ 356 _n( 357 'Updated %d hostname.', 358 'Updated %d hostnames.', 359 $updated_count, 360 'edh-bad-bots' 361 ), 362 $updated_count 363 ), 364 'success' 365 ); 366 367 // Redirect back to the admin page, specifically the 'blocked' tab. 368 $redirect_url = admin_url( 'tools.php?page=' . $this->admin_page_slug . '&tab=blocked' ); 369 wp_redirect( esc_url_raw( $redirect_url ) ); 370 exit; 371 } 372 373 /** 374 * Manually updates hostnames for blocked IPs that don't have them. 375 * 376 * @return int Number of hostnames updated. 377 */ 378 private function manual_hostname_update() { 379 // Get IPs without hostnames (limit to 10 for manual processing) 380 $ips_without_hostnames = $this->db->get_blocked_ips_without_hostnames( 10 ); 381 382 if ( empty( $ips_without_hostnames ) ) { 383 return 0; // Nothing to do 384 } 385 386 // Create a blocker instance to access the hostname resolution method 387 $blocker = new EDHBB_Blocker( $this->db ); 388 389 // Use reflection to access the private method 390 $reflection = new ReflectionClass( $blocker ); 391 $hostname_method = $reflection->getMethod( 'get_hostname_for_ip' ); 392 $hostname_method->setAccessible( true ); 393 394 $updated_count = 0; 395 396 foreach ( $ips_without_hostnames as $ip_address ) { 397 // Use the DNS lookup if available, otherwise fall back to blocker method 398 if ( class_exists( 'EDHBB_DNSLookup' ) ) { 399 $hostname = EDHBB_DNSLookup::get_hostname_for_blocked_ip( $ip_address ); 400 } else { 401 // Fallback to the original blocker method 402 $hostname = $hostname_method->invoke( $blocker, $ip_address ); 403 } 404 405 // Update the database with the resolved hostname (even if empty) 406 if ( $this->db->update_blocked_bot_hostname( $ip_address, $hostname ) ) { 407 $updated_count++; 408 } 409 } 410 411 return $updated_count; 412 } 413 414 /** 415 * Debugs hostname resolution for a sample IP address. 416 */ 417 public function debug_hostname_resolution() { 418 $debug_info = array(); 419 $ip_to_test = '8.8.8.8'; // A reliable IP for testing 420 421 // Test gethostbyaddr() 422 $debug_info['gethostbyaddr']['exists'] = function_exists( 'gethostbyaddr' ) ? 'Yes' : 'No'; 423 $debug_info['gethostbyaddr']['callable'] = is_callable( 'gethostbyaddr' ) ? 'Yes' : 'No'; 424 if ( function_exists( 'gethostbyaddr' ) ) { 425 $debug_info['gethostbyaddr']['result'] = gethostbyaddr( $ip_to_test ); 426 } 427 428 // Test dns_get_record() 429 $debug_info['dns_get_record']['exists'] = function_exists( 'dns_get_record' ) ? 'Yes' : 'No'; 430 $debug_info['dns_get_record']['callable'] = is_callable( 'dns_get_record' ) ? 'Yes' : 'No'; 431 if ( function_exists( 'dns_get_record' ) ) { 432 $debug_info['dns_get_record']['result'] = dns_get_record( $ip_to_test, DNS_PTR ); 433 } 434 435 set_transient( 'edhbb_debug_info', $debug_info, 60 ); 436 } 437 438 /** 439 * Handles the force refresh all hostnames action. 440 */ 441 public function handle_force_refresh_all_hostnames() { 442 // Verify nonce for security. 443 if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), 'edhbb_force_refresh_all_hostnames_nonce' ) ) { 444 wp_die( esc_html__( 'Security check failed.', 'edh-bad-bots' ) ); 445 } 446 447 // Check user capabilities. 448 if ( ! current_user_can( 'manage_options' ) ) { 449 wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'edh-bad-bots' ) ); 450 } 451 452 // Clear all DNS caches 453 if ( class_exists( 'EDHBB_DNSLookup' ) ) { 454 // Clear hostname cache 455 global $wpdb; 456 // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Intentionally clearing transient cache for this plugin, caching not applicable for cache clearing operations 457 $wpdb->query( 458 $wpdb->prepare( 459 "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", 460 $wpdb->esc_like( '_transient_edhbb_hostname_' ) . '%' 461 ) 462 ); 463 $wpdb->query( 464 $wpdb->prepare( 465 "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", 466 $wpdb->esc_like( '_transient_timeout_edhbb_hostname_' ) . '%' 467 ) 468 ); 469 // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching 470 } 471 472 // Get ALL blocked IPs (not just ones without hostnames) 473 $all_blocked_ips = $this->db->get_blocked_bots( 0 ); // 0 = no limit 474 $updated_count = 0; 475 476 foreach ( $all_blocked_ips as $bot ) { 477 $ip_address = $bot['ip_address']; 478 479 // Force new hostname lookup 480 if ( class_exists( 'EDHBB_DNSLookup' ) ) { 481 $hostname = EDHBB_DNSLookup::get_hostname_for_blocked_ip( $ip_address ); 482 } else { 483 // Fallback method 484 $blocker = new EDHBB_Blocker( $this->db ); 485 $reflection = new ReflectionClass( $blocker ); 486 $hostname_method = $reflection->getMethod( 'get_hostname_for_ip' ); 487 $hostname_method->setAccessible( true ); 488 $hostname = $hostname_method->invoke( $blocker, $ip_address ); 489 // Ensure we set a clear indicator for empty results in fallback 490 if ( empty( $hostname ) ) { 491 $hostname = '[No PTR Record]'; 492 } 493 } 494 495 // Update the database 496 if ( $this->db->update_blocked_bot_hostname( $ip_address, $hostname ) ) { 497 $updated_count++; 498 } 499 } 500 501 // Add success message 502 add_settings_error( 503 'edhbb_messages', 504 'edhbb_force_refresh_completed', 505 sprintf( 506 /* translators: %d: number of updated hostnames */ 507 _n( 508 'Force refreshed %d hostname (cleared cache and re-resolved all).', 509 'Force refreshed %d hostnames (cleared cache and re-resolved all).', 510 $updated_count, 511 'edh-bad-bots' 512 ), 513 $updated_count 514 ), 515 'success' 516 ); 517 518 // Redirect back to the admin page 519 $redirect_url = admin_url( 'tools.php?page=' . $this->admin_page_slug . '&tab=blocked' ); 520 wp_redirect( esc_url_raw( $redirect_url ) ); 521 exit; 522 } 320 523 } -
edh-bad-bots/trunk/includes/class-edhbb-blocker.php
r3355590 r3357194 5 5 * Handles detecting and blocking bad bots that hit the trap URL. 6 6 */ 7 declare(strict_types=1); 7 8 8 9 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly … … 108 109 $current_url = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ); 109 110 $site_path = wp_parse_url( site_url(), PHP_URL_PATH ); 111 112 // Handle cases where site_path might be null (when URL has no path component) 113 $site_path = $site_path ?? ''; 110 114 $expected_trap_path = rtrim( $site_path, '/' ) . '/' . $this->trap_url_hash . '/'; 111 115 … … 127 131 128 132 // Add the bot to the blocked list. 129 $this->db->add_blocked_bot( $client_ip ); 133 $hostname = $this->get_hostname_for_ip($client_ip); 134 $this->db->add_blocked_bot( $client_ip, $hostname ); 130 135 131 136 // Immediately block the request after adding to the blocklist. 132 137 $this->block_request_action( $client_ip, true ); // Pass true to indicate it's a trap hit block 133 138 } 139 } 140 141 /** 142 * Attempts to resolve hostname for an IP address using enhanced DNS lookup. 143 * Uses the new EDHBB_DNSLookup class with DoH support and fallback methods. 144 * 145 * @param string $ip_address The IP address to resolve. 146 * @return string The hostname if resolved, empty string if failed. 147 */ 148 private function get_hostname_for_ip( $ip_address ) { 149 // Validate IP address first 150 if ( ! filter_var( $ip_address, FILTER_VALIDATE_IP ) ) { 151 return ''; 152 } 153 154 // Check if the DNSLookup class is available 155 if ( ! class_exists( 'EDHBB_DNSLookup' ) ) { 156 // Fallback to traditional method if class not loaded 157 return $this->traditional_hostname_lookup( $ip_address ); 158 } 159 160 // Use the DNS lookup method for blocked IPs 161 return EDHBB_DNSLookup::get_hostname_for_blocked_ip( $ip_address ); 162 } 163 164 /** 165 * Traditional hostname lookup method as fallback. 166 * 167 * @param string $ip_address The IP address to resolve. 168 * @return string The hostname if resolved, empty string if failed. 169 */ 170 private function traditional_hostname_lookup( $ip_address ) { 171 // Check if dns_get_record is disabled 172 if ( ! function_exists( 'dns_get_record' ) || ! is_callable( 'dns_get_record' ) ) { 173 if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) { 174 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 175 error_log( '[EDH Bad Bots] Hostname lookup failed: dns_get_record() is disabled.' ); 176 } 177 return ''; 178 } 179 180 $hostname = ''; 181 182 try { 183 // Perform a reverse DNS lookup (PTR record) 184 $ptr_records = @dns_get_record( $ip_address, DNS_PTR ); 185 186 if ( $ptr_records && ! empty( $ptr_records[0]['target'] ) ) { 187 $resolved = $ptr_records[0]['target']; 188 189 // Validate the resolved hostname 190 if ( filter_var( $resolved, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME ) || 191 preg_match( '/^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/', $resolved ) ) { 192 $hostname = $resolved; 193 } 194 } 195 } catch ( Exception $e ) { 196 // Log the error if debug logging is enabled 197 if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) { 198 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs when WP_DEBUG_LOG is enabled 199 error_log( '[EDH Bad Bots] Hostname lookup failed for IP ' . $ip_address . ': ' . $e->getMessage() ); 200 } 201 } 202 203 return $hostname; 134 204 } 135 205 -
edh-bad-bots/trunk/includes/class-edhbb-database.php
r3355590 r3357194 5 5 * Handles all database interactions for storing blocked bots and whitelisted IPs. 6 6 */ 7 declare(strict_types=1); 7 8 8 9 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly … … 67 68 * - id: Primary key. 68 69 * - ip_address: The IP address of the blocked bot. 70 * - hostname: The hostname of the blocked bot. 69 71 * - blocked_at: Timestamp when the bot was blocked. 70 72 * - expires_at: Timestamp when the block will expire (30 days after blocked_at). … … 72 74 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- %i placeholder is valid since WordPress 6.2 73 75 $sql_blocked_bots = $this->wpdb->prepare( 74 "CREATE TABLE IF NOT EXISTS%i (76 "CREATE TABLE %i ( 75 77 id bigint(20) NOT NULL AUTO_INCREMENT, 76 78 ip_address varchar(45) NOT NULL, 79 hostname varchar(255) DEFAULT NULL, 77 80 blocked_at datetime NOT NULL, 78 81 expires_at datetime NOT NULL, … … 93 96 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- %i placeholder is valid since WordPress 6.2 94 97 $sql_whitelisted_ips = $this->wpdb->prepare( 95 "CREATE TABLE IF NOT EXISTS%i (98 "CREATE TABLE %i ( 96 99 id bigint(20) NOT NULL AUTO_INCREMENT, 97 100 ip_address varchar(45) NOT NULL, … … 108 111 dbDelta( $sql_whitelisted_ips ); 109 112 113 // Run database migrations for existing installations 114 $this->migrate_database(); 115 110 116 // Ensure .htaccess rules are up-to-date on activation, respecting the option flag 111 117 $this->update_htaccess_block_rules(); 118 } 119 120 /** 121 * Handles database migrations for existing installations. 122 * Adds missing columns to existing tables. 123 */ 124 private function migrate_database() { 125 // Check if hostname column exists in blocked_bots table 126 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- INFORMATION_SCHEMA queries require literal DB_NAME constant and table names 127 $column_exists = $this->wpdb->get_results( 128 $this->wpdb->prepare( 129 "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS 130 WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s AND COLUMN_NAME = 'hostname'", 131 DB_NAME, 132 $this->blocked_bots_table_name 133 ) 134 ); 135 // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared 136 137 // If hostname column doesn't exist, add it 138 if ( empty( $column_exists ) ) { 139 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- %i placeholder is valid since WordPress 6.2 140 $result = $this->wpdb->query( 141 $this->wpdb->prepare( 142 "ALTER TABLE %i ADD COLUMN hostname varchar(255) DEFAULT NULL AFTER ip_address", 143 $this->blocked_bots_table_name 144 ) 145 ); 146 // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared 147 148 // Log any errors if WP_DEBUG_LOG is enabled 149 if ( $result === false && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) { 150 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs when WP_DEBUG_LOG is enabled 151 error_log( '[EDH Bad Bots] Failed to add hostname column to blocked_bots table. Error: ' . $this->wpdb->last_error ); 152 } 153 } 154 } 155 156 /** 157 * Public method to trigger database migrations manually. 158 * This can be called from admin interfaces or other parts of the plugin. 159 * 160 * @return bool True if migration was successful or not needed, false on failure. 161 */ 162 public function run_migrations() { 163 $this->migrate_database(); 164 return true; 165 } 166 167 /** 168 * Checks if a column exists in a given table. 169 * 170 * @param string $table_name The name of the table to check. 171 * @param string $column_name The name of the column to check. 172 * @return bool True if the column exists, false otherwise. 173 */ 174 private function column_exists( $table_name, $column_name ) { 175 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- INFORMATION_SCHEMA queries require literal DB_NAME constant and table names 176 $column_exists = $this->wpdb->get_results( 177 $this->wpdb->prepare( 178 "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS 179 WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s AND COLUMN_NAME = %s", 180 DB_NAME, 181 $table_name, 182 $column_name 183 ) 184 ); 185 // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared 186 187 return ! empty( $column_exists ); 112 188 } 113 189 … … 131 207 * 132 208 * @param string $ip_address The IP address to block. 209 * @param string $hostname The hostname of the blocked bot. 133 210 * @return bool True on success, false on failure. 134 211 */ 135 public function add_blocked_bot( $ip_address ) {212 public function add_blocked_bot( $ip_address, $hostname = '' ) { 136 213 // Clean up old entries before adding a new one to keep the table lean. 137 214 $this->clean_old_blocked_bots(); … … 142 219 $expires_at = gmdate( 'Y-m-d H:i:s', $expires_timestamp ); 143 220 221 // Check if hostname column exists to determine the query format 222 $hostname_exists = $this->column_exists( $this->blocked_bots_table_name, 'hostname' ); 223 144 224 // Insert the IP address into the blocked bots table. 145 225 // Using `INSERT IGNORE` to prevent errors if the IP is already present due to the UNIQUE KEY constraint. 146 226 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- %i placeholder is valid since WordPress 6.2 147 $result = $this->wpdb->query( 148 $this->wpdb->prepare( 149 "INSERT IGNORE INTO %i (ip_address, blocked_at, expires_at) VALUES (%s, %s, %s)", 150 $this->blocked_bots_table_name, 151 $ip_address, 152 $current_time, 153 $expires_at 154 ) 155 ); 227 if ( $hostname_exists ) { 228 $result = $this->wpdb->query( 229 $this->wpdb->prepare( 230 "INSERT IGNORE INTO %i (ip_address, hostname, blocked_at, expires_at) VALUES (%s, %s, %s, %s)", 231 $this->blocked_bots_table_name, 232 $ip_address, 233 $hostname, 234 $current_time, 235 $expires_at 236 ) 237 ); 238 } else { 239 // Fallback for tables without hostname column 240 $result = $this->wpdb->query( 241 $this->wpdb->prepare( 242 "INSERT IGNORE INTO %i (ip_address, blocked_at, expires_at) VALUES (%s, %s, %s)", 243 $this->blocked_bots_table_name, 244 $ip_address, 245 $current_time, 246 $expires_at 247 ) 248 ); 249 } 156 250 // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared 157 251 … … 194 288 $this->clean_old_blocked_bots(); // Ensure only current blocks are considered. 195 289 196 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- %i placeholder is valid since WordPress 6.2 197 $sql = "SELECT id, ip_address, blocked_at, expires_at FROM %i WHERE expires_at > %s ORDER BY blocked_at DESC"; 290 // Check if hostname column exists to avoid SQL errors 291 $hostname_exists = $this->column_exists( $this->blocked_bots_table_name, 'hostname' ); 292 $select_fields = $hostname_exists ? 293 "id, ip_address, hostname, blocked_at, expires_at" : 294 "id, ip_address, '' as hostname, blocked_at, expires_at"; 295 296 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- %i placeholder is valid since WordPress 6.2 297 $sql = "SELECT {$select_fields} FROM %i WHERE expires_at > %s ORDER BY blocked_at DESC"; 198 298 $sql_params = array( $this->blocked_bots_table_name, current_time( 'mysql' ) ); 199 299 … … 320 420 321 421 return ( $result > 0 ); 422 } 423 424 /** 425 * Updates hostname for a specific blocked IP address. 426 * 427 * @param string $ip_address The IP address to update. 428 * @param string $hostname The hostname to set. 429 * @return bool True on success, false on failure. 430 */ 431 public function update_blocked_bot_hostname( $ip_address, $hostname ) { 432 // Check if hostname column exists 433 if ( ! $this->column_exists( $this->blocked_bots_table_name, 'hostname' ) ) { 434 return false; // Cannot update if column doesn't exist 435 } 436 437 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- %i placeholder is valid since WordPress 6.2 438 $result = $this->wpdb->update( 439 $this->blocked_bots_table_name, 440 array( 'hostname' => $hostname ), 441 array( 'ip_address' => $ip_address ), 442 array( '%s' ), 443 array( '%s' ) 444 ); 445 // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared 446 447 return $result !== false; 448 } 449 450 /** 451 * Gets blocked IPs that have empty or null hostnames for background processing. 452 * 453 * @param int $limit Maximum number of IPs to return. 454 * @return array Array of IP addresses that need hostname resolution. 455 */ 456 public function get_blocked_ips_without_hostnames( $limit = 10 ) { 457 // Check if hostname column exists 458 if ( ! $this->column_exists( $this->blocked_bots_table_name, 'hostname' ) ) { 459 return array(); // Return empty array if column doesn't exist 460 } 461 462 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- %i placeholder is valid since WordPress 6.2 463 $results = $this->wpdb->get_results( 464 $this->wpdb->prepare( 465 "SELECT ip_address FROM %i WHERE (hostname IS NULL OR hostname = '' OR hostname = '[No PTR Record]') AND expires_at > %s LIMIT %d", 466 $this->blocked_bots_table_name, 467 current_time( 'mysql' ), 468 $limit 469 ), 470 ARRAY_A 471 ); 472 // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared 473 474 return wp_list_pluck( $results, 'ip_address' ); 322 475 } 323 476 -
edh-bad-bots/trunk/readme.txt
r3355590 r3357194 1 1 === EDH Bad Bots === 2 2 Contributors: EncodeDotHost, nbwpuk 3 Tags: Security, Bots 3 Tags: Security, Bots, DNS, PTR, Hostname 4 4 Requires at least: 6.2 5 5 Tested up to: 6.8 6 Stable tag: 1.4. 26 Stable tag: 1.4.3 7 7 Requires PHP: 7.4 8 8 License: GPLv2 or later … … 18 18 19 19 - **Automatic Bot Detection**: Identifies bad bots using a hidden trap URL technique 20 - **Smart Blocking System**: Blocks misbehaving bots for 30 days automatically 20 - **Smart Blocking System**: Blocks misbehaving bots with configurable duration (default 30 days) 21 - **Advanced DNS Resolution**: PTR record lookups with DNS over HTTPS (DoH) support for hostname identification 21 22 - **Dual-Level Blocking**: Server-level `.htaccess` blocking AND PHP-level blocking for maximum effectiveness 22 23 - **Configurable Blocking Methods**: Choose between `.htaccess` blocking (Apache) or PHP-only blocking (Nginx compatible) 23 24 - **IP Whitelist Management**: Protect trusted IPs from ever being blocked 24 - **Clean Admin Interface**: Easy-to-use dashboard with tabbed navigation 25 - **Enhanced Admin Interface**: Clean dashboard with hostname display, manual hostname updates, and debug tools 26 - **Background Processing**: Automated hostname resolution via WordPress cron jobs 25 27 - **Zero False Positives**: Legitimate search engine bots that follow robots.txt rules are never affected 26 28 - **Database Optimization**: Automatic cleanup of expired blocks to maintain performance … … 35 37 3. **Hidden Link Placement**: Places an invisible link to the trap URL in your site's footer 36 38 4. **Bot Detection**: When bad bots ignore robots.txt and follow the hidden link, they're identified 37 5. **Automatic Blocking**: Detected bot IPs are blocked for 30 days with immediate effect 38 6. **Legitimate Bot Protection**: Good bots (like Googlebot) respect robots.txt and never trigger the trap 39 5. **Automatic Blocking**: Detected bot IPs are blocked with configurable duration and immediate effect 40 6. **Hostname Resolution**: PTR record lookups identify the hostname/organization behind blocked IPs 41 7. **Legitimate Bot Protection**: Good bots (like Googlebot) respect robots.txt and never trigger the trap 39 42 40 43 ## Installation … … 57 60 58 61 #### Blocked Bots Tab 59 - View all currently blocked IP addresses 62 - View all currently blocked IP addresses with hostnames 60 63 - See when each IP was blocked and when the block expires 64 - Manually update missing hostnames for better identification 65 - Force refresh all hostnames to clear cache and re-resolve 66 - Debug hostname resolution issues (when WP_DEBUG is enabled) 61 67 - Manually unblock IPs if needed 62 68 63 69 #### Options Tab 64 70 - **`.htaccess Blocking`**: Enable/disable server-level IP blocking via `.htaccess` file 71 - **Block Duration**: Configure how many days to block detected bots 65 72 - Configure blocking method based on your server setup (Apache vs Nginx) 66 73 - Server-level blocking bypasses caching for immediate effect … … 70 77 - Best practices for managing IPs 71 78 - Information about `.htaccess` blocking options 79 - Unique trap URL for caching plugin exclusion 72 80 73 81 ### Requirements 74 82 75 - WordPress 5.0or higher83 - WordPress 6.2 or higher 76 84 - PHP 7.4 or higher 77 85 - MySQL 5.6 or higher … … 85 93 The plugin creates two custom database tables: 86 94 87 - `wp_edhbb_blocked_bots`: Stores blocked IP addresses with expiration dates 95 - `wp_edhbb_blocked_bots`: Stores blocked IP addresses with expiration dates and hostnames 88 96 - `wp_edhbb_whitelisted_ips`: Stores permanently whitelisted IP addresses 97 98 ### DNS Resolution System 99 100 The plugin includes an advanced DNS lookup system: 101 102 #### DNS over HTTPS (DoH) Support 103 - **Primary providers**: Cloudflare DNS, Google DNS 104 - **Secure queries**: HTTPS-encrypted DNS requests for enhanced privacy 105 - **Fallback system**: Automatic fallback to traditional DNS methods 106 107 #### PTR Record Lookups 108 - **Reverse DNS**: Converts IP addresses to hostnames for better identification 109 - **IPv4 and IPv6 support**: Full support for both IP versions 110 - **Caching**: Results cached for 1 hour to improve performance 111 - **Background processing**: Automated hostname resolution via WordPress cron 89 112 90 113 ### Blocking Methods … … 122 145 - **Server-Level Blocking**: `.htaccess` blocking prevents blocked requests from reaching PHP 123 146 - **Whitelist Filtering**: Whitelisted IPs are excluded from `.htaccess` rules automatically 147 - **DNS Caching**: Hostname lookups cached to reduce DNS query overhead 148 - **Background Processing**: Hostname resolution runs in background to avoid delays 124 149 125 150 ## API Hooks … … 131 156 - `wp_footer`: Hidden link injection 132 157 - `admin_menu`: Admin page registration 158 - `edhbb_update_hostnames_cron`: Background hostname resolution 133 159 134 160 ### Filters … … 148 174 │ └── admin-script.js # Admin page JavaScript 149 175 ├── includes/ 150 │ ├── class-edh -admin.php# Admin functionality151 │ ├── class-edh -blocker.php# Bot detection and blocking152 │ └── class-edh-database.php# Database operations153 ├── changelog.txt 176 │ ├── class-edhbb-admin.php # Admin functionality 177 │ ├── class-edhbb-blocker.php # Bot detection and blocking 178 │ ├── class-edhbb-database.php # Database operations 179 │ └── class-edhbb-dnslookup.php # DNS/PTR lookup system 154 180 ├── edh-bad-bots.php # Main plugin file 155 181 ├── LICENSE 156 └── README.md182 └── readme.txt 157 183 ``` 158 184 159 185 ## Screenshots 160 186 1. Allow list management 161 2. Block list management 162 3. Options Page 187 2. Block list management with hostname display 188 3. Options Page with configurable settings 163 189 164 190 ## Contributing … … 174 200 ## Changelog 175 201 202 ### Version 1.4.3 203 - **New**: Advanced DNS lookup system with DNS over HTTPS (DoH) support 204 - **New**: PTR record resolution for hostname identification of blocked IPs 205 - **New**: Background hostname resolution via WordPress cron jobs 206 - **New**: Manual hostname update buttons in admin interface 207 - **New**: Force refresh all hostnames feature with cache clearing 208 - **New**: Configurable block duration (days) in Options tab 209 - **New**: Enhanced admin interface with hostname display in blocked bots table 210 - **New**: Debug information panel for hostname resolution troubleshooting 211 - **New**: Support for both IPv4 and IPv6 PTR lookups 212 - **Enhancement**: Improved blocked bots table with hostname column 213 - **Enhancement**: Better identification of blocked bots through hostname resolution 214 - **Enhancement**: Automatic database migration system for hostname column 215 - **Enhancement**: Fallback DNS resolution methods for better compatibility 216 - **Enhancement**: DNS query caching for improved performance 217 - **Fix**: Updated queries to gracefully handle missing columns during migration 218 - **Fix**: Added backward compatibility for existing installations 219 - **Fix**: Improved error handling and logging for database migrations 220 176 221 ### Version 1.4.2 177 - Fixed Internal.LineEndings.Mixed in class-edhbb-blocker.php222 - Fixed Internal.LineEndings.Mixed in class-edhbb-blocker.php 178 223 179 224 ### Version 1.4.1 180 - Fixed blank admin page225 - Fixed blank admin page 181 226 182 227 ### Version 1.4.0 … … 186 231 187 232 ### Version 1.3.0 188 - Bringing up to WordPress coding standards233 - Bringing up to WordPress coding standards 189 234 190 235 ### Version 1.2.3 191 - Added instructions to the "Help" tab for excluding the unique trap URL from caching plugins. 192 236 - Added instructions to the "Help" tab for excluding the unique trap URL from caching plugins. 193 237 194 238 ### Version 1.2.2 … … 261 305 262 306 ### How long are bots blocked for? 263 Bots are automatically blocked for 30 days. You can manually unblock them earlier if needed.307 Bots are blocked for a configurable duration (default 30 days) that you can adjust in the Options tab. You can manually unblock them earlier if needed. 264 308 265 309 ### Can I protect my own IP address? … … 269 313 `.htaccess` blocking (default) blocks bots at the server level before WordPress loads, making it faster and more effective. PHP blocking works during WordPress initialization and is compatible with Nginx servers. 270 314 315 ### What is hostname resolution and why is it useful? 316 The plugin performs PTR record lookups to identify the hostname/organization behind blocked IP addresses. This helps you understand what types of bots are being blocked (e.g., "crawl-66-249-66-1.googlebot.com" vs unknown IPs) for better analysis and decision-making. 317 318 ### How does the DNS over HTTPS feature work? 319 The plugin uses secure HTTPS-encrypted DNS queries via providers like Cloudflare and Google DNS for enhanced privacy and reliability when resolving hostnames. It automatically falls back to traditional DNS methods if DoH is unavailable. 320 271 321 ### Does this affect site performance? 272 The plugin is designed for minimal performance impact. Server-level `.htaccess` blocking actually improves performance by stopping blocked requests before they reach PHP. D atabase operations are optimized with automatic cleanup.322 The plugin is designed for minimal performance impact. Server-level `.htaccess` blocking actually improves performance by stopping blocked requests before they reach PHP. DNS lookups are cached and processed in the background to avoid delays. 273 323 274 324 ### Will this work with caching plugins? … … 280 330 ### Is it safe for my .htaccess file? 281 331 Yes! The plugin uses unique markers (`# BEGIN EDH Bad Bots Block` / `# END EDH Bad Bots Block`) to safely manage its rules without affecting other configurations. Rules are automatically removed on deactivation. 332 333 ### Can I manually update hostnames for blocked IPs? 334 Yes! In the "Blocked Bots" tab, you can use the "Update Missing Hostnames" button to resolve hostnames for IPs that don't have them, or "Force Refresh All Hostnames" to clear the cache and re-resolve all hostnames.
Note: See TracChangeset
for help on using the changeset viewer.