|
| 1 | +<?php |
| 2 | +/* |
| 3 | +Plugin Name: IPBan WordPress Integration |
| 4 | +Plugin URI: https://ipban.com/ |
| 5 | +Description: Sends WordPress login success and failure events to IPBan using the IPBan custom log format. |
| 6 | +Version: 1.0.0 |
| 7 | +Author: DigitalRuby (IPBan) |
| 8 | +License: MIT |
| 9 | +
|
| 10 | +INSTRUCTIONS: |
| 11 | +- Drop this file into wp-content/plugins/IPBan/IPBanWordpress.php (create the IPBan folder if it does not exist) and activate the plugin in wp-admin. |
| 12 | +- IPBan will detect these lines automatically on Windows (C:/IPBanCustomLogs) and Linux (/var/log) using existing ipban.config entries. |
| 13 | +- On Linux, if the web server cannot write to /var/log, the plugin falls back to wp-content/plugins/IPBan/ipbancustom_wordpress.log. |
| 14 | + In that case add that fallback path to <PathAndMask> in ipban.config (e.g. /var/www/html/wp-content/plugins/IPBan/ipbancustom_wordpress.log). |
| 15 | +- Log line format examples generated: |
| 16 | + 2024-10-10 12:00:00, ipban failed login, ip address: 1.2.3.4, source: WordPress, user: admin |
| 17 | + 2024-10-10 12:00:10, ipban success login, ip address: 1.2.3.4, source: WordPress, user: admin |
| 18 | +*/ |
| 19 | + |
| 20 | +if (!defined('ABSPATH')) { |
| 21 | + exit; // Prevent direct access |
| 22 | +} |
| 23 | + |
| 24 | +/** |
| 25 | + * Get remote IP address, considering possible proxy headers. |
| 26 | + */ |
| 27 | +function ipban_wp_get_remote_ip(): string { |
| 28 | + $keys = ['HTTP_CF_CONNECTING_IP', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR']; |
| 29 | + foreach ($keys as $k) { |
| 30 | + if (!empty($_SERVER[$k])) { |
| 31 | + // X_FORWARDED_FOR may contain a list, take first |
| 32 | + $parts = explode(',', $_SERVER[$k]); |
| 33 | + $ip = trim($parts[0]); |
| 34 | + if ($ip !== '') { |
| 35 | + return $ip; |
| 36 | + } |
| 37 | + } |
| 38 | + } |
| 39 | + return '0.0.0.0'; |
| 40 | +} |
| 41 | + |
| 42 | +/** |
| 43 | + * Write a line to IPBan custom log. |
| 44 | + * @param string $type 'failed' or 'success' |
| 45 | + * @param string $username Username (may be empty for failed attempts) |
| 46 | + */ |
| 47 | +function ipban_wp_write_line(string $type, string $username): void { |
| 48 | + $ip = ipban_wp_get_remote_ip(); |
| 49 | + $source = 'WordPress'; |
| 50 | + $timestamp = gmdate('Y-m-d H:i:s'); // UTC |
| 51 | + $user = ($username === '' ? '-' : $username); |
| 52 | + $line = $timestamp . ', ipban ' . $type . ' login, ip address: ' . $ip . ', source: ' . $source . ', user: ' . $user . "\n"; |
| 53 | + |
| 54 | + if (strtoupper(PHP_OS_FAMILY) === 'WINDOWS') { |
| 55 | + $dir = 'C:/IPBanCustomLogs'; |
| 56 | + if (!is_dir($dir)) { @mkdir($dir, 0777, true); } |
| 57 | + $file = $dir . '/ipban_wordpress.log'; |
| 58 | + } else { |
| 59 | + // Preferred path (already monitored by ipban.config) |
| 60 | + $preferred = '/var/log/ipbancustom_wordpress.log'; |
| 61 | + $preferredDir = dirname($preferred); |
| 62 | + if (@is_dir($preferredDir) && @is_writable($preferredDir)) { |
| 63 | + $file = $preferred; |
| 64 | + } else { |
| 65 | + // Fallback path inside plugin directory - requires ipban.config update |
| 66 | + $fallbackDir = WP_CONTENT_DIR . '/plugins/IPBan'; |
| 67 | + if (!is_dir($fallbackDir)) { @mkdir($fallbackDir, 0777, true); } |
| 68 | + $file = $fallbackDir . '/ipbancustom_wordpress.log'; |
| 69 | + } |
| 70 | + } |
| 71 | + |
| 72 | + @file_put_contents($file, $line, FILE_APPEND | LOCK_EX); |
| 73 | +} |
| 74 | + |
| 75 | +/** |
| 76 | + * Failed login hook. |
| 77 | + * @param string $username The attempted username. |
| 78 | + */ |
| 79 | +function ipban_wp_login_failed(string $username): void { |
| 80 | + ipban_wp_write_line('failed', $username); |
| 81 | +} |
| 82 | +add_action('wp_login_failed', 'ipban_wp_login_failed'); |
| 83 | + |
| 84 | +/** |
| 85 | + * Successful login hook. |
| 86 | + * @param string $user_login Username. |
| 87 | + * @param WP_User $user User object. |
| 88 | + */ |
| 89 | +function ipban_wp_login_success(string $user_login, $user): void { |
| 90 | + ipban_wp_write_line('success', $user_login); |
| 91 | +} |
| 92 | +add_action('wp_login', 'ipban_wp_login_success', 10, 2); |
| 93 | + |
| 94 | +/** |
| 95 | + * Optional: Detect XML-RPC authentication failures (common brute force vector). |
| 96 | + * This simplistic approach hooks into the authentication filter; if auth returns a WP_Error we log failed. |
| 97 | + */ |
| 98 | +function ipban_wp_authenticate($user, $username) { |
| 99 | + if (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST) { |
| 100 | + if (is_wp_error($user)) { |
| 101 | + ipban_wp_write_line('failed', (string)$username); |
| 102 | + } elseif ($user instanceof WP_User) { |
| 103 | + ipban_wp_write_line('success', (string)$username); |
| 104 | + } |
| 105 | + } |
| 106 | + return $user; |
| 107 | +} |
| 108 | +add_filter('authenticate', 'ipban_wp_authenticate', 99, 2); |
| 109 | + |
| 110 | +/** |
| 111 | + * Optional: REST API login attempts (e.g. via /wp-json/jwt-auth/v1/token). You can extend by adding specific action hooks here. |
| 112 | + */ |
| 113 | +// add_action('jwt_auth_failed', function($error){ ipban_wp_write_line('failed', '-'); }); |
| 114 | +// add_action('jwt_auth_valid_token_response', function($response){ if(isset($response['user'])) ipban_wp_write_line('success', $response['user']->user_login); }); |
| 115 | + |
| 116 | +/* End of IPBan WordPress Integration */ |
0 commit comments