1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
30: $plugin_is_filter = 8 | CLASS_PLUGIN;
31: $plugin_description = gettext("Tools to block hacker access to your site.");
32: $plugin_author = "Stephen Billard (sbillard)";
33:
34: $option_interface = 'ipBlocker';
35:
36: zp_register_filter('load_theme_script', 'ipBlocker::load');
37: zp_register_filter('admin_allow_access', 'ipBlocker::adminGate');
38: zp_register_filter('admin_login_attempt', 'ipBlocker::login');
39: zp_register_filter('federated_login_attempt', 'ipBlocker::login');
40: zp_register_filter('guest_login_attempt', 'ipBlocker::login');
41:
42: 43: 44: 45:
46: class ipBlocker {
47:
48: 49: 50: 51: 52:
53: function __construct() {
54: setOptionDefault('ipBlocker_list', serialize(array()));
55: setOptionDefault('ipBlocker_type', 'block');
56: setOptionDefault('ipBlocker_threshold', 10);
57: setOptionDefault('ipBlocker_timeout', 60);
58: }
59:
60: 61: 62: 63: 64:
65: function getOptionsSupported() {
66: $buttons = array(gettext('Allow') => 'allow', gettext('Block') => 'block');
67: $text = array_flip($buttons);
68: $cwd = getcwd();
69: chdir(SERVERPATH . '/' . UPLOAD_FOLDER);
70: $list = safe_glob('*.txt');
71: chdir($cwd);
72: $files = array('' => '');
73: foreach ($list as $file) {
74: $files[$file] = $file;
75: }
76: $options = array(gettext('IP list') => array('key' => 'ipBlocker_IP', 'type' => OPTION_TYPE_CUSTOM,
77: 'order' => 4,
78: 'desc' => sprintf(gettext('List of IP ranges to %s.'), $text[getOption('ipBlocker_type')])),
79: gettext('Import list') => array('key' => 'ipBlocker_import', 'type' => OPTION_TYPE_SELECTOR,
80: 'order' => 5,
81: 'selections' => $files,
82: 'nullselection' => '',
83: 'disabled' => !extensionEnabled('ipBlocker'),
84: 'desc' => sprintf(gettext('Import an external IP list. <p class="notebox"><strong>NOTE:</strong> If this list is large it may exceed the capacity of Zenphoto and %s to process and store the results.'), DATABASE_SOFTWARE)),
85: gettext('Action') => array('key' => 'ipBlocker_type', 'type' => OPTION_TYPE_RADIO,
86: 'order' => 3,
87: 'buttons' => $buttons,
88: 'desc' => gettext('How the plugin will interpret the IP list.')),
89: gettext('Logon threshold') => array('key' => 'ipBlocker_threshold', 'type' => OPTION_TYPE_TEXTBOX,
90: 'order' => 1,
91: 'desc' => gettext('Admin page requests will be ignored after this many failed tries.')),
92: gettext('Logon cool off') => array('key' => 'ipBlocker_timeout', 'type' => OPTION_TYPE_TEXTBOX,
93: 'order' => 2,
94: 'desc' => gettext('The block will be removed after this many minutes.'))
95: );
96: if (!extensionEnabled('ipBlocker')) {
97: $options['note'] = array('key' => 'ipBlocker_note', 'type' => OPTION_TYPE_NOTE,
98: 'order' => 0,
99: 'desc' => '<p class="notebox">' . gettext('IP list ranges cannot be managed with the plugin disabled') . '</p>');
100: }
101: return $options;
102: }
103:
104: function handleOption($option, $currentValue) {
105: $list = getSerializedArray(getOption('ipBlocker_list'));
106: if (extensionEnabled('ipBlocker')) {
107: $disabled = '';
108: } else {
109: $disabled = ' disabled="disabled"';
110: }
111:
112: switch ($option) {
113: case 'ipBlocker_IP':
114: $key = 0;
115: foreach ($list as $key => $range) {
116: ?>
117: <input id="ipholder_<?php echo $key; ?>a" type="textbox" size="20" name="ipBlocker_ip_start_<?php echo $key; ?>"
118: value="<?php echo html_encode($range['start']); ?>" <?php echo $disabled; ?> />
119: -
120: <input id="ipholder_<?php echo $key; ?>b" type="textbox" size="20" name="ipBlocker_ip_end_<?php echo $key; ?>"
121: value="<?php echo html_encode($range['end']); ?>" <?php echo $disabled; ?> />
122: <br />
123: <?php
124: }
125: $i = $key;
126: while ($i < $key + 4) {
127: $i++;
128: ?>
129: <input id="ipholder_<?php echo $i; ?>a" type="textbox" size="20" name="ipBlocker_ip_start_<?php echo $i; ?>"
130: value="" <?php echo $disabled; ?> />
131: -
132: <input id="ipholder_<?php echo $i; ?>b" type="textbox" size="20" name="ipBlocker_ip_end_<?php echo $i; ?>"
133: value="" <?php echo $disabled; ?> />
134: <br />
135: <?php
136: }
137: ?>
138: <script type="text/javascript">
139: <!--
140: function clearips() {
141: <?php
142: for ($i = 0; $i <= $key + 4; $i++) {
143: ?>
144: $('#ipholder_<?php echo $i; ?>a').val('');
145: $('#ipholder_<?php echo $i; ?>b').val('');
146: <?php
147: }
148: ?>
149: }
150:
151: </script>
152: <p class="buttons">
153: <a href="javascript:clearips();"><?php echo gettext('clear list'); ?></a>
154: </p>
155: <?php
156: break;
157: }
158: }
159:
160: static function handleOptionSave($themename, $themealbum) {
161: $notify = '';
162: $list = array();
163: foreach ($_POST as $key => $param) {
164: if ($param) {
165: if (strpos($key, 'ipBlocker_ip_') !== false) {
166: if (preg_match("/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/", $param)) {
167: $p = explode('_', substr($key, 13));
168: $list[$p[1]][$p[0]] = $param;
169: }
170: }
171: }
172: }
173: foreach ($list as $key => $range) {
174: if (!array_key_exists('start', $range) || !array_key_exists('end', $range)) {
175: unset($list[$key]);
176: $notify .= gettext('IP address format error') . '<br />';
177: }
178: }
179: setOption('ipBlocker_list', serialize($list));
180: purgeOption('ipBlocker_import');
181: if (!empty($_POST['ipBlocker_import'])) {
182: $file = SERVERPATH . '/' . UPLOAD_FOLDER . '/' . sanitize_path($_POST['ipBlocker_import']);
183: if (file_exists($file)) {
184: $import_list = array();
185:
186: foreach ($list as $range) {
187: $ipa = explode('.', $range['end']);
188: $ipend = sprintf('%03u.%03u.%03u.%03u', @$ipa[0], @$ipa[1], @$ipa[2], @$ipa[3]);
189: $ipa = explode('.', $range['start']);
190: do {
191: $current = sprintf('%03u.%03u.%03u.%03u', @$ipa[0], @$ipa[1], @$ipa[2], @$ipa[3]);
192: $ipa[3] ++;
193: if ($ipa[3] > 255) {
194: $ipa[3] = 0;
195: $ipa[2] ++;
196: if ($ipa[2] > 255) {
197: $ipa[2] = 0;
198: $ipa[2] ++;
199: if ($ipa[1] > 255) {
200: $ipa[1] = 0;
201: $ipa[0] ++;
202: if ($ipa[0] > 255) {
203: break;
204: }
205: }
206: }
207: }
208: $import_list[] = $current;
209: } while ($current < $ipend);
210: }
211:
212:
213: $import = explode("\n", file_get_contents($file));
214: foreach ($import as $ip) {
215: $ip = trim($ip);
216: if ($ip) {
217: $ipa = explode('.', $ip);
218: $import_list[] = sprintf('%03u.%03u.%03u.%03u', @$ipa[0], @$ipa[1], @$ipa[2], @$ipa[3]);
219: }
220: }
221:
222:
223: $list = array();
224: if (!empty($import_list)) {
225: $import_list = array_unique($import_list);
226: sort($import_list);
227:
228: $current = $start = array_shift($import_list);
229: $end = $start;
230: $clean = false;
231: while (!empty($import_list)) {
232: $try = trim(array_shift($import_list));
233: if ($try) {
234: $ipa = explode('.', $current);
235: $ipa[3] ++;
236: if ($ipa[3] > 255) {
237: $ipa[3] = 0;
238: $ipa[2] ++;
239: if ($ipa[2] > 255) {
240: $ipa[2] = 0;
241: $ipa[2] ++;
242: if ($ipa[1] > 255) {
243: $ipa[1] = 0;
244: $ipa[0] ++;
245: if ($ipa[0] > 255) {
246: break;
247: }
248: }
249: }
250: }
251: $next = sprintf('%03u.%03u.%03u.%03u', @$ipa[0], @$ipa[1], @$ipa[2], @$ipa[3]);
252: $current = $try;
253: if ($clean = $current != $next) {
254: $list[] = array('start' => $start, 'end' => $end);
255: $start = $end = $current;
256: } else {
257: $end = $next;
258: }
259: }
260: }
261: if (!$clean) {
262: $list[] = array('start' => $start, 'end' => $end);
263: }
264: setOption('ipBlocker_list', serialize($list));
265: }
266: }
267: }
268: if ($notify)
269: return '&custom=' . $notify;
270: else
271: return false;
272: }
273:
274: 275: 276: 277: 278: 279:
280: static function login($loggedin, $user, $pass = NULL) {
281: if (!$loggedin) {
282: self::adminGate('', '');
283: }
284: return $loggedin;
285: }
286:
287: static function suspended() {
288: if ($block = getOption('ipBlocker_forbidden')) {
289: $block = getSerializedArray($block);
290: if (array_key_exists($ip = getUserIP(), $block)) {
291: if ($block[$ip] < (time() - getOption('ipBlocker_timeout') * 60)) {
292:
293: unset($block[$ip]);
294: if (count($block) > 0) {
295: setOption('ipBlocker_forbidden', serialize($block));
296: } else {
297: setOption('ipBlocker_forbidden', NULL);
298: }
299: } else {
300: return true;
301: }
302: }
303: }
304: return false;
305: }
306:
307: 308: 309: 310: 311:
312: static function adminGate($allow, $page) {
313:
314: $sql = 'DELETE FROM ' . prefix('plugin_storage') . ' WHERE `type`="ipBlocker" AND `aux` < "' . (time() - getOption('ipBlocker_timeout') * 60) . '"';
315: query($sql);
316:
317: $sql = 'INSERT INTO ' . prefix('plugin_storage') . ' (`type`, `aux`,`data`) VALUES ("ipBlocker", "' . time() . '","' . getUserIP() . '")';
318: query($sql);
319:
320: $count = db_count('plugin_storage', 'WHERE `type`="ipBlocker" AND `data`="' . getUserIP() . '"');
321: if ($count >= getOption('ipBlocker_threshold')) {
322: $block = getOption('ipBlocker_forbidden');
323: if ($block) {
324: $block = getSerializedArray($block);
325: } else {
326: $block = array();
327: }
328: $block[getUserIP()] = time();
329: setOption('ipBlocker_forbidden', serialize($block));
330: }
331: return $allow;
332: }
333:
334: 335: 336: 337: 338: 339:
340: static function load($path) {
341: $list = getSerializedArray(getOption('ipBlocker_list'));
342: $allow = getOption('ipBlocker_type') == 'allow';
343: $gate = $allow;
344: if (!empty($list)) {
345: $ipa = explode('.', getUserIP());
346: $ip = sprintf('%03u.%03u.%03u.%03u', @$ipa[0], @$ipa[1], @$ipa[2], @$ipa[3]);
347: foreach ($list as $range) {
348: if ($ip >= $range['start'] && $ip <= $range['end']) {
349: $gate = !$allow;
350: break;
351: }
352: }
353: }
354: if ($gate) {
355: header("HTTP/1.0 403 " . gettext("Forbidden"));
356: header("Status: 403 " . gettext("Forbidden"));
357: exitZP();
358: } else {
359: return $path;
360: }
361: }
362:
363: }
364:
365: if (extensionEnabled('ibBlocker') && ipBlocker::suspended()) {
366: header("HTTP/1.0 403 " . gettext("Forbidden"));
367: header("Status: 403 " . gettext("Forbidden"));
368: exitZP();
369: }
370: ?>
371: