Compare commits

..
241 Commits
Author SHA1 Message Date
Mr Chen 9b83a2ef79 Merge pull request #216 from midoks/dev
0.9.14
2022-10-23 01:12:02 +08:00
midoks 6aefa3b7dc Update config_api.py 2022-10-23 01:11:20 +08:00
midoks 566fabbf24 Update README.md 2022-10-23 01:08:41 +08:00
midoks ea8aa5102b Update common.lua 2022-10-23 00:41:39 +08:00
midoks b8421d36ae up 2022-10-23 00:37:42 +08:00
midoks 24bd8daca0 Update install.sh 2022-10-22 22:57:04 +08:00
midoks d8047b43fa Update install.sh 2022-10-22 22:49:32 +08:00
midoks 016dde04e7 Update my8.0.cnf 2022-10-22 22:36:33 +08:00
midoks df5d86a883 Update README.md 2022-10-22 22:26:55 +08:00
midoks 84077de5d1 Update common.lua 2022-10-22 22:22:53 +08:00
midoks 04ed4b180a up 2022-10-22 21:58:35 +08:00
midoks f980dba7ed up 2022-10-22 21:36:12 +08:00
midoks f702f70f89 up 2022-10-22 20:25:46 +08:00
midoks a8e6ee052c init 2022-10-22 18:32:11 +08:00
midoks b3d0a36dcd up 2022-10-22 16:29:11 +08:00
midoks 96275303c6 Update index.py 2022-10-22 13:30:08 +08:00
midoks 0337a1bded up 2022-10-22 13:19:35 +08:00
midoks 8bd985fca9 up 2022-10-21 19:53:36 +08:00
midoks b6ef8d1625 up 2022-10-21 19:16:07 +08:00
midoks 3dc695508f up 2022-10-21 19:09:34 +08:00
midoks 0c769b02e5 Update op_waf.js 2022-10-21 17:45:30 +08:00
midoks e289037598 up 2022-10-21 17:34:38 +08:00
midoks 63e6a95553 up 2022-10-21 12:08:43 +08:00
midoks 8e1d95bf82 up 2022-10-21 01:33:35 +08:00
midoks 24fe8b6f5f up 2022-10-21 01:25:57 +08:00
midoks 3d366ee774 up 2022-10-20 23:40:28 +08:00
midoks 0428956141 up 2022-10-20 20:59:15 +08:00
midoks 37747427be up 2022-10-20 17:59:16 +08:00
midoks fb94fb8304 up 2022-10-20 16:31:30 +08:00
midoks 65d07d3934 0.2.2 2022-10-20 14:52:51 +08:00
midoks 5e6ffafeb5 Update install.sh 2022-10-20 14:10:20 +08:00
midoks 572f231fae up 2022-10-20 14:03:17 +08:00
midoks 0328dd21e7 Update webstats_common.lua 2022-10-20 13:20:54 +08:00
midoks 597d171733 Update webstats_common.lua 2022-10-20 13:10:40 +08:00
midoks 745ab9dcd0 Update webstats_common.lua 2022-10-20 12:59:26 +08:00
midoks 30323b031c Update webstats_common.lua 2022-10-20 12:58:41 +08:00
midoks f47e6a47df Update webstats_common.lua 2022-10-20 12:57:20 +08:00
midoks 0eccebd9da Update webstats_common.lua 2022-10-20 12:45:24 +08:00
midoks 0ad5e74fae Update webstats_common.lua 2022-10-20 12:38:54 +08:00
midoks 2640ba97c5 Update webstats_common.lua 2022-10-18 18:03:35 +08:00
midoks e5f440ff02 up 2022-10-18 17:41:29 +08:00
midoks 7bc9c44ec1 Update webstats_log.lua 2022-10-18 16:38:18 +08:00
midoks 9cd74db011 Update webstats_common.lua 2022-10-18 03:14:00 +08:00
midoks 5da8e5a7f6 Update webstats_common.lua 2022-10-18 03:07:12 +08:00
midoks 4da895b8df Update webstats_common.lua 2022-10-18 02:54:31 +08:00
midoks 42eca14168 Update webstats_common.lua 2022-10-18 02:13:07 +08:00
midoks 43a3dfd9bd Update webstats_common.lua 2022-10-18 01:48:18 +08:00
midoks 794eba4186 Update webstats_common.lua 2022-10-18 01:41:26 +08:00
midoks a4f533acba Update webstats_common.lua 2022-10-18 01:20:08 +08:00
midoks adb3c5250c Update webstats_common.lua 2022-10-18 01:08:05 +08:00
midoks e4226fcdd4 Update webstats_log.lua 2022-10-18 00:58:08 +08:00
midoks d3e9353589 up 2022-10-18 00:56:31 +08:00
midoks 757284cdf1 up 2022-10-17 23:48:20 +08:00
midoks 58232e10ab Update index.py 2022-10-17 23:40:44 +08:00
midoks fde211e026 Update webstats_log.lua 2022-10-17 23:30:34 +08:00
midoks c9a527e487 up 2022-10-17 23:29:57 +08:00
midoks c501efdfac up 2022-10-17 21:12:42 +08:00
midoks 80c0bbed71 Update webstats_log.lua 2022-10-17 14:54:53 +08:00
midoks 1fb3c30775 Update webstats_log.lua 2022-10-17 14:29:52 +08:00
midoks 24ab203770 Update webstats_log.lua 2022-10-17 14:08:00 +08:00
midoks bd0242db2f Update webstats_common.lua 2022-10-17 14:03:35 +08:00
midoks 42bf5edd1f Update webstats_common.lua 2022-10-17 13:45:21 +08:00
midoks 7b2a011b6a Update webstats_common.lua 2022-10-17 13:44:35 +08:00
midoks 76e01201a2 Update webstats_common.lua 2022-10-17 13:31:36 +08:00
midoks 16e45cabfc Update webstats_common.lua 2022-10-17 13:30:30 +08:00
midoks c08542ff54 Update webstats_common.lua 2022-10-17 13:23:48 +08:00
midoks 5beb76d0b7 Update webstats_common.lua 2022-10-17 13:07:22 +08:00
midoks f16a7e016e up 2022-10-17 13:06:34 +08:00
midoks eb86ac3ee6 Update webstats_common.lua 2022-10-17 12:17:37 +08:00
midoks 14c2606532 Update webstats_common.lua 2022-10-17 12:12:17 +08:00
midoks 86b8939cb8 Update webstats_common.lua 2022-10-17 12:10:15 +08:00
midoks dd28c1ef56 Update webstats_common.lua 2022-10-17 11:43:37 +08:00
midoks 6b24dfc21e Update webstats_common.lua 2022-10-17 11:36:29 +08:00
midoks dc06573125 Update webstats_common.lua 2022-10-17 03:03:32 +08:00
midoks df35e5a780 Update webstats_common.lua 2022-10-17 02:56:28 +08:00
midoks a678d851a0 Update webstats_common.lua 2022-10-17 02:49:16 +08:00
midoks 6a706651e4 Update webstats_common.lua 2022-10-17 02:45:18 +08:00
midoks 1acdfe4368 Update webstats_common.lua 2022-10-17 02:30:36 +08:00
midoks cae245efca up 2022-10-17 02:04:01 +08:00
midoks 238f1e76d8 Update webstats.conf 2022-10-17 01:09:57 +08:00
midoks f3a754d1ae Update webstats_common.lua 2022-10-17 01:06:50 +08:00
midoks 21aab0573a Update webstats_common.lua 2022-10-17 00:58:20 +08:00
midoks 011949ba85 up 2022-10-17 00:44:04 +08:00
midoks f3e7dd1cc0 Update init_worker.lua 2022-10-15 23:44:53 +08:00
midoks b49d2025eb Update install.sh 2022-10-15 23:38:12 +08:00
midoks 556b0869f2 Update config.json 2022-10-15 23:34:20 +08:00
midoks aad6deeb78 Update init_worker.lua 2022-10-15 23:28:36 +08:00
midoks 64601e42c1 up 2022-10-15 23:16:25 +08:00
midoks 6555d927ea Update common.lua 2022-10-15 21:20:40 +08:00
midoks 444ff40570 up 2022-10-15 19:13:01 +08:00
midoks 7bdcd0ac2b up 2022-10-15 17:38:42 +08:00
midoks 6e6a41e6df Update ngx_demo.sh 2022-10-15 10:03:22 +08:00
midoks feca2a6d33 aa 2022-10-15 03:23:08 +08:00
midoks 5e382e7347 Update init.lua 2022-10-15 03:16:02 +08:00
midoks abc778fb52 up 2022-10-15 02:05:29 +08:00
midoks 6b42d35cd4 up 2022-10-15 00:34:14 +08:00
midoks c74a2c9655 Update common.lua 2022-10-14 23:46:10 +08:00
midoks 01543f951a Update init.lua 2022-10-14 23:45:57 +08:00
midoks d78a5d8f27 Update init.lua 2022-10-14 23:45:43 +08:00
midoks 2a1d759cd2 Update config.json 2022-10-14 23:23:08 +08:00
midoks 43889f83f7 up 2022-10-14 21:41:25 +08:00
midoks 79a0a93959 up 2022-10-14 17:50:26 +08:00
midoks 735cf9b872 up 2022-10-14 12:41:32 +08:00
midoks e7c318e560 Update info.json 2022-10-14 12:18:09 +08:00
midoks 78d03754f6 Update install.sh 2022-10-14 12:09:19 +08:00
midoks 67cc1cac86 Update install.sh 2022-10-14 12:08:14 +08:00
midoks 77ec90980a Update install.sh 2022-10-14 12:06:57 +08:00
midoks d07b2babfd up 2022-10-14 12:05:54 +08:00
midoks 4d9ee94038 up 2022-10-14 11:36:54 +08:00
midoks 61479d5db6 Update init.lua 2022-10-13 22:23:46 +08:00
midoks 897c28034d up 2022-10-13 22:18:57 +08:00
midoks b3fef4c104 up 2022-10-13 21:29:28 +08:00
midoks 48cec8ee47 up 2022-10-13 21:05:06 +08:00
midoks 7c369ef19f up 2022-10-13 21:03:26 +08:00
midoks 1411bb1639 up 2022-10-13 20:43:46 +08:00
midoks be875d9d8c Update soft.js 2022-10-13 17:39:41 +08:00
midoks 746dc7ee4d Update soft.js 2022-10-13 17:34:44 +08:00
midoks ea7ba7d461 软件界面优化 2022-10-13 17:29:41 +08:00
midoks 48ed4156b5 Update common.lua 2022-10-13 17:06:42 +08:00
midoks ca73d0e280 Update common.lua 2022-10-13 17:01:57 +08:00
midoks 8cef43d9a7 Update info.json 2022-10-13 16:51:13 +08:00
midoks 75445774a1 test & op 2022-10-13 16:46:44 +08:00
midoks 9b29f19b96 up 2022-10-13 14:59:49 +08:00
midoks 1e6655e7f9 Update readme.md 2022-10-13 14:46:48 +08:00
midoks 363656e06c up 2022-10-13 14:46:29 +08:00
midoks a1860bc4fc up 2022-10-13 14:21:39 +08:00
midoks f8ce39bc74 up 2022-10-13 11:46:03 +08:00
midoks 969d02ef93 Update ngx_debug.sh 2022-10-13 04:35:23 +08:00
midoks a54410df6e up 2022-10-13 04:18:47 +08:00
midoks 01e388ea45 up 2022-10-13 03:12:44 +08:00
midoks ef75f22a86 Update index.py 2022-10-13 01:38:20 +08:00
midoks 97f6b232fd Update ngx_debug.sh 2022-10-13 01:36:53 +08:00
midoks 2506f5e940 Update install.sh 2022-10-13 01:10:03 +08:00
midoks dcb23ada41 Update ngx_debug.sh 2022-10-13 01:06:32 +08:00
midoks 35e1bf048c Update ngx_debug.sh 2022-10-13 00:58:47 +08:00
midoks a9e24f8eaf Update ngx_debug.sh 2022-10-13 00:58:05 +08:00
midoks 2f4ac74f52 Create ngx_debug.sh 2022-10-13 00:42:51 +08:00
midoks 522122feb6 Update common.lua 2022-10-12 20:37:56 +08:00
midoks a3c677a926 Update common.lua 2022-10-12 19:41:35 +08:00
midoks fd1c52530e Update common.lua 2022-10-12 19:35:59 +08:00
midoks 071c690583 Update linux.conf 2022-10-12 18:04:20 +08:00
midoks 67c9cd0277 up 2022-10-12 17:51:50 +08:00
midoks 61292868ad 统计变为ngx.timer.every执行 2022-10-12 17:18:51 +08:00
midoks 54b2a00b23 Update safe_js.html 2022-10-12 16:56:36 +08:00
midoks af6d377664 Update safe_js.html 2022-10-12 16:47:29 +08:00
midoks 6d55e345b0 Update common.lua 2022-10-12 16:39:55 +08:00
midoks fab4e68d8d Update common.lua 2022-10-12 15:42:48 +08:00
midoks 8864e91f21 Update install.sh 2022-10-12 15:31:42 +08:00
midoks f14ce1b66c Update info.json 2022-10-12 15:29:03 +08:00
midoks 48098efd56 Update safe_js.html 2022-10-12 15:28:09 +08:00
midoks 04eba8e33f Update init.lua 2022-10-12 15:26:38 +08:00
midoks 89cf7ffafc Update init.lua 2022-10-12 15:19:08 +08:00
midoks 47544520e8 Update init.lua 2022-10-12 15:03:51 +08:00
midoks bc1fd9a8af Update init.lua 2022-10-12 14:51:46 +08:00
midoks 27efc7ef6e Update config_api.py 2022-10-12 14:38:45 +08:00
midoks 47ead816c0 Update init.lua 2022-10-12 14:37:43 +08:00
midoks 31d36182c3 Update init.lua 2022-10-12 14:37:11 +08:00
midoks c9a58c7ea5 Update init.lua 2022-10-12 14:36:57 +08:00
midoks a6e59ae37c Update init.lua 2022-10-12 14:36:42 +08:00
midoks 328e1b0ff1 up 2022-10-12 14:30:37 +08:00
midoks f76cc5ceb8 Update init.lua 2022-10-12 13:59:30 +08:00
midoks d6c74c3f7d waf demo 3 2022-10-12 13:49:57 +08:00
midoks 4f932c36e7 up 2022-10-12 10:11:55 +08:00
midoks 0d02d0ebea Update init.lua 2022-10-12 00:53:00 +08:00
midoks 9e207ad4d3 添加 强制安全验证 功能 2022-10-12 00:38:23 +08:00
midoks f6cfe29956 Update debian.sh 2022-10-11 18:03:36 +08:00
midoks e439111761 Update mw.py 2022-10-11 17:47:48 +08:00
midoks e576d0b443 listen.backlog = 4096 设置默认 2022-10-11 17:28:07 +08:00
midoks 02e2c42225 up 2022-10-11 17:10:13 +08:00
midoks 45dec0a3d6 ip 2022-10-11 16:35:44 +08:00
midoks 28e2abc829 demo 2022-10-11 16:26:15 +08:00
midoks d59c82b7c8 Update common.lua 2022-10-11 15:46:04 +08:00
midoks 32b2158795 Update common.lua 2022-10-11 15:45:49 +08:00
midoks 5a37305c73 Update common.lua 2022-10-11 15:45:08 +08:00
midoks c043963e8e Update common.lua 2022-10-11 15:43:10 +08:00
midoks 40d755b44e up 2022-10-11 15:39:13 +08:00
midoks 00aa791205 waf debug3 2022-10-11 15:34:02 +08:00
midoks 431b3646af waf debug2 2022-10-11 15:27:08 +08:00
midoks 910aaa81de waf debug1 2022-10-11 15:22:28 +08:00
Mr Chen c4a844cadb Merge pull request #209 from midoks/dev
0.9.13
2022-10-11 12:47:26 +08:00
midoks a88a281175 0.9.13
0.9.13
2022-10-11 12:46:35 +08:00
midoks f3f3b1c6bd Update init.lua 2022-10-11 12:35:59 +08:00
midoks 4259ac51cb up 2022-10-11 11:41:32 +08:00
midoks 4db1357d3d 更新mysql版本 2022-10-11 09:03:53 +08:00
midoks 15873e0824 Update op_waf.js 2022-10-11 00:40:21 +08:00
midoks dcdb07f76d up 2022-10-11 00:35:13 +08:00
midoks 8b70637479 Update index.py 2022-10-10 23:28:36 +08:00
midoks c77085fea4 Update index.py 2022-10-10 23:27:20 +08:00
midoks a265f3d0d5 Update index.py 2022-10-10 23:24:54 +08:00
midoks 7ea486cd1d Update index.py 2022-10-10 23:22:43 +08:00
midoks 0e31e87e28 Update index.py 2022-10-10 23:22:04 +08:00
midoks 8c621c892e Update index.py 2022-10-10 23:16:59 +08:00
midoks 32bcae603c Update index.py 2022-10-10 23:16:48 +08:00
midoks 98ec21446d Update index.py 2022-10-10 22:41:36 +08:00
midoks 0ee3682502 Update redis.service.tpl 2022-10-10 22:11:51 +08:00
midoks c609d1a012 Update redis.service.tpl 2022-10-10 22:05:55 +08:00
midoks 27b1a78879 up 2022-10-10 22:03:21 +08:00
midoks 773de840a5 Update redis.js 2022-10-10 21:55:00 +08:00
midoks 91d6ff3c54 Update index.py 2022-10-10 21:52:11 +08:00
midoks 03376bd42d Update redis.conf 2022-10-10 21:50:04 +08:00
midoks 036c5114c2 Update index.py 2022-10-10 21:35:51 +08:00
midoks a772e70fde Update index.py 2022-10-10 21:33:20 +08:00
midoks 53055bbdef Update index.py 2022-10-10 21:31:43 +08:00
midoks f81d598fcf Update index.py 2022-10-10 21:13:44 +08:00
midoks 3530e83bb9 up 2022-10-10 21:09:35 +08:00
midoks 1271b2f637 Update index.py 2022-10-10 21:00:30 +08:00
midoks 2dc6bc7753 Update index.py 2022-10-10 20:58:45 +08:00
midoks e52d9e3ea3 Update index.py 2022-10-10 20:55:45 +08:00
midoks d8a570e55e Update index.html 2022-10-10 20:46:07 +08:00
midoks f4ceaf667b php-yum更新 2022-10-10 20:43:48 +08:00
midoks 958ba16b85 Update index.html 2022-10-10 20:28:44 +08:00
midoks 73039777bb Update index.py 2022-10-10 20:06:00 +08:00
midoks 864e4c910c PHP添加会话管理功能 2022-10-10 19:54:23 +08:00
midoks 4da57405af Update init.lua 2022-10-10 13:01:27 +08:00
midoks dff638571a Update init.lua 2022-10-10 12:45:31 +08:00
midoks c7d9ec51cc up 2022-10-10 12:36:42 +08:00
midoks 501c575f73 up 2022-10-10 12:13:45 +08:00
midoks 0fd966ca65 up 2022-10-10 02:14:31 +08:00
midoks 172dde2794 Update mariadb.js 2022-10-09 23:26:50 +08:00
midoks 78fdc80652 优化mysql进入phpmyadmin 2022-10-09 23:24:47 +08:00
midoks 01b8c9b8ff Update init.lua 2022-10-09 22:47:28 +08:00
midoks b840086d4d op防火墙更新1 2022-10-09 21:29:40 +08:00
midoks 4c73f13f2d up 2022-10-09 11:36:57 +08:00
midoks f31c1aae96 up 2022-10-09 10:39:46 +08:00
midoks 5c24a831db Update index.py 2022-10-09 02:04:17 +08:00
midoks 91d07eebad Update install.sh 2022-10-09 01:59:17 +08:00
midoks 3b51ef2434 up 2022-10-09 01:49:17 +08:00
midoks 31c5e42b09 Update index.html 2022-10-09 01:38:15 +08:00
midoks b8b3a237ef up 2022-10-09 01:37:14 +08:00
midoks 5cb2aefbbc up 2022-10-09 01:25:53 +08:00
midoks 19173af3e2 Update logs_backup.py 2022-10-09 00:31:15 +08:00
midoks 3dc493108b Update mw.tpl 2022-10-09 00:30:03 +08:00
midoks 55af62000b Update logs_backup.py 2022-10-09 00:26:28 +08:00
midoks a1c8c48761 Update index.js 2022-10-08 22:45:44 +08:00
midoks 8c3ec0a103 Update index.js 2022-10-08 22:40:23 +08:00
midoks 5cbde31105 Update tool_task.py 2022-10-08 18:15:57 +08:00
midoks 04dd94032e Update tool_task.py 2022-10-08 18:12:45 +08:00
midoks 8a11195b0d Update tool_task.py 2022-10-08 18:08:38 +08:00
midoks 1eb76baae7 改变弹框方式 2022-10-08 16:05:24 +08:00
midoks 2669d6f021 Update init.lua 2022-10-08 15:21:17 +08:00
midoks 6f13a03a2c Update config_api.py 2022-10-08 14:24:58 +08:00
105 changed files with 5768 additions and 1822 deletions
+5
View File
@@ -0,0 +1,5 @@
# These are supported funding model platforms
github: midoks
custom: https://afdian.net/a/mdserver-web
+7 -10
View File
@@ -65,6 +65,8 @@ phpMyAdmin[5.2.0]支持MySQL[8.0]
PHP[53-72]支持phpMyAdmin[4.4.15]
PHP[72-81]支持phpMyAdmin[5.2.0]
```
# 特别赞助
@@ -78,7 +80,7 @@ PHP[72-81]支持phpMyAdmin[5.2.0]
| 服务商 | LOGO | 推广地址 | 优惠码 |
| ------------- |----------|-----------|-------|
| digitalvirt |[![digitalvirt](https://digitalvirt.com/templates/BlueWhite/img/logo-dark.svg)](https://digitalvirt.com/aff.php?aff=154) | https://digitalvirt.com/aff.php?aff=154 | 9SYDY7UH0U |
| 搬瓦工 |[![搬瓦工](https://bwh81.net/templates/organicbandwagon/images/logo.png)](https://bandwagonhost.com/aff.php?aff=54161) | https://bandwagonhost.com/aff.php?aff=54161 | BWH3HYATVBJW |
| 搬瓦工 |[![搬瓦工](https://bwh81.net/templates/organicbandwagon/images/logo.png)](https://bwh81.net/aff.php?aff=54161) | https://bwh81.net/aff.php?aff=54161 | BWH3HYATVBJW |
# Docker
@@ -90,16 +92,11 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:
```
### 版本更新 0.9.12
* 日志清理插件优化。
* 计划任务显示完整。
* 加入gitea插件。
* 融合mw-cli命令。
* 加快php编译速度。
* swap加上调整功能。
* 其他细节优化。
### 版本更新 0.9.14
* 优化网站统计插件,提搞速度和并发数。
* mysql8安装地址更新。
* OP防火墙优化。
### JSDelivr安装地址
+1 -1
View File
@@ -15,7 +15,7 @@ from flask import request
class config_api:
__version = '0.9.12'
__version = '0.9.14'
def __init__(self):
pass
+11 -4
View File
@@ -161,19 +161,24 @@ def isInstalledWeb():
def restartWeb():
return opWeb("reload")
def opWeb(method):
if not isInstalledWeb():
return False
# systemd
systemd = '/lib/systemd/system/openresty.service'
if os.path.exists(systemd):
execShell('systemctl reload openresty')
execShell('systemctl ' + method + ' openresty')
return True
# initd
initd = getServerDir() + '/openresty/init.d/openresty'
if os.path.exists(initd):
execShell(initd + ' ' + 'reload')
execShell(initd + ' ' + method)
return True
return False
@@ -595,12 +600,14 @@ def getLastLine(path, num, p=1):
count = start_line + num
fp = open(path, 'rb')
buf = ""
fp.seek(-1, 2)
fp.seek(0, 2)
if fp.read(1) == "\n":
fp.seek(-1, 2)
fp.seek(0, 2)
data = []
b = True
n = 0
for i in range(count):
while True:
newline_pos = str.rfind(str(buf), "\n")
+1
View File
@@ -98,6 +98,7 @@ def initConf():
"/var/log/secure",
"/var/log/lastlog",
"/var/log/cron",
"/www/server/cron"
]
for i in clogcom:
if os.path.exists(i):
-2
View File
@@ -23,8 +23,6 @@ Install_app()
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/clean
echo "" > $serverPath/clean/clean.conf
cd ${rootPath} && python3 ${rootPath}/plugins/clean/index.py start
echo "${VERSION}" > $serverPath/clean/version.pl
echo '安装完成' > $install_tmp
+4 -2
View File
@@ -88,16 +88,18 @@ def createBgTaskByName(name, args):
_where1 = args['minute-n']
_minute = ''
mw_dir = mw.getRunDir()
cmd = '''
mw_dir=%s
rname=%s
plugin_path=%s
script_path=%s
logs_file=$plugin_path/${rname}.log
''' % (name, getServerDir(), getPluginDir())
''' % (mw_dir, name, getServerDir(), getPluginDir())
cmd += 'echo "★【`date +"%Y-%m-%d %H:%M:%S"`】 STSRT★" >> $logs_file' + "\n"
cmd += 'echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" >> $logs_file' + "\n"
cmd += 'echo "python3 $script_path/index.py clean >> $logs_file 2>&1"' + "\n"
cmd += 'python3 $script_path/index.py clean >> $logs_file 2>&1' + "\n"
cmd += 'cd $mw_dir && python3 $script_path/index.py clean >> $logs_file 2>&1' + "\n"
cmd += 'echo "【`date +"%Y-%m-%d %H:%M:%S"`】 END★" >> $logs_file' + "\n"
cmd += 'echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" >> $logs_file' + "\n"
+5 -1
View File
@@ -817,6 +817,7 @@ function openPhpmyadmin(name,username,password){
layer.msg('当前为['+rdata.choose+']模式,若要使用请切换模式.',{icon:2,shade: [0.3, '#000']});
return;
}
var phpmyadmin_cfg = rdata;
data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'get_home_page'});
var rdata = $.parseJSON(data.data);
@@ -824,7 +825,10 @@ function openPhpmyadmin(name,username,password){
layer.msg(rdata.msg,{icon:2,shade: [0.3, '#000']});
return;
}
$("#toPHPMyAdmin").attr('action',rdata.data);
var home_page = rdata.data;
home_page = home_page.replace("http://","http://"+phpmyadmin_cfg['username']+":"+phpmyadmin_cfg['password']+"@");
$("#toPHPMyAdmin").attr('action',home_page);
if($("#toPHPMyAdmin").attr('action').indexOf('phpmyadmin') == -1){
layer.msg('请先安装phpMyAdmin',{icon:2,shade: [0.3, '#000']});
+2 -1
View File
@@ -80,7 +80,8 @@ innodb_data_home_dir = {$SERVER_APP_PATH}/data
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = {$SERVER_APP_PATH}/data
innodb_buffer_pool_size = 16M
innodb_log_file_size = 5M
#innodb_log_file_size = 5M
innodb_redo_log_capacity=10485760
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 2
innodb_lock_wait_timeout = 120
+1 -1
View File
@@ -11,7 +11,7 @@
"path": "server/mysql/VERSION",
"todo_versions":["5.6","5.7","8.0"],
"versions":["5.5", "5.6", "5.7","8.0"],
"updates":["5.5.62","5.6.50", "5.7.32","8.0.22"],
"updates":["5.5.62","5.6.50", "5.7.32","8.0.30"],
"shell":"install.sh",
"checks":"server/mysql",
"path":"server/mysql",
+27 -4
View File
@@ -68,6 +68,26 @@ function myAsyncPost(method,args){
return syncPost('/plugins/run', {name:'mysql', func:method, args:_args});
}
function vaildPhpmyadmin(url,username,password){
console.log("Authorization: Basic " + btoa(username + ":" + password));
$.ajax({
type: "GET",
url: url,
dataType: 'json',
async: false,
username:username,
password:password,
headers: {
"Authorization": "Basic " + btoa(username + ":" + password)
},
data: 'vaild',
success: function (){
alert('Thanks for your comment!');
}
});
}
function runInfo(){
myPost('run_info','',function(data){
@@ -818,16 +838,19 @@ function openPhpmyadmin(name,username,password){
layer.msg('当前为[mariadb]模式,若要使用请切换模式.',{icon:2,shade: [0.3, '#000']});
return;
}
// console.log(data);
var phpmyadmin_cfg = rdata;
data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'get_home_page'});
var rdata = $.parseJSON(data.data);
if (!rdata.status){
layer.msg(rdata.msg,{icon:2,shade: [0.3, '#000']});
return;
}
$("#toPHPMyAdmin").attr('action',rdata.data);
var home_page = rdata.data;
home_page = home_page.replace("http://","http://"+phpmyadmin_cfg['username']+":"+phpmyadmin_cfg['password']+"@")
$("#toPHPMyAdmin").attr('action',home_page);
if($("#toPHPMyAdmin").attr('action').indexOf('phpmyadmin') == -1){
layer.msg('请先安装phpMyAdmin',{icon:2,shade: [0.3, '#000']});
setTimeout(function(){ window.location.href = '/soft'; },3000);
@@ -836,7 +859,7 @@ function openPhpmyadmin(name,username,password){
//检查版本
data = syncPost('/plugins/run',{'name':'phpmyadmin','func':'version'});
bigVer = data.data.split('.')[0]
bigVer = data.data.split('.')[0];
if (bigVer>=4.5){
setTimeout(function(){
+4 -4
View File
@@ -17,7 +17,7 @@ sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
mysqlDir=${serverPath}/source/mysql
VERSION="5.7.37"
VERSION=5.7.39
Install_mysql()
@@ -64,11 +64,11 @@ Install_mysql()
cd ${rootPath}/plugins/mysql/lib && /bin/bash rpcgen.sh
if [ ! -f ${mysqlDir}/mysql-boost-${VERSION}.tar.gz ];then
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/Downloads/MySQL-5.7/mysql-boost-${VERSION}.tar.gz
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/archives/mysql-5.7/mysql-boost-${VERSION}.tar.gz
fi
#检测文件是否损坏.
md5_mysql_ok=d0489fc3880248a58759c50bfb286dbb
md5_mysql_ok=d949b0ef81c3f52f7ef0874066244221
if [ -f ${mysqlDir}/mysql-boost-${VERSION}.tar.gz ];then
md5_mysql=`md5sum ${mysqlDir}/mysql-boost-${VERSION}.tar.gz | awk '{print $1}'`
if [ "${md5_mysql_ok}" == "${md5_mysql}" ]; then
@@ -76,7 +76,7 @@ Install_mysql()
else
# 重新下载
rm -rf ${mysqlDir}/mysql-${VERSION}
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/Downloads/MySQL-5.7/mysql-boost-${VERSION}.tar.gz
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/archives/mysql-5.7/mysql-boost-${VERSION}.tar.gz
fi
fi
+4 -4
View File
@@ -57,7 +57,7 @@ fi
VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
VERSION=8.0.28
VERSION=8.0.30
Install_mysql()
{
mkdir -p ${mysqlDir}
@@ -107,11 +107,11 @@ Install_mysql()
fi
if [ ! -f ${mysqlDir}/mysql-boost-${VERSION}.tar.gz ];then
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/Downloads/MySQL-8.0/mysql-boost-${VERSION}.tar.gz
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/archives/mysql-8.0/mysql-boost-${VERSION}.tar.gz
fi
#检测文件是否损坏.
md5_mysql_ok=362b8141ecaf425b803fe55292e2df98
md5_mysql_ok=313d625fcaa932bd87b48f0cf9b40f1c
if [ -f ${mysqlDir}/mysql-boost-${VERSION}.tar.gz ];then
md5_mysql=`md5sum ${mysqlDir}/mysql-boost-${VERSION}.tar.gz | awk '{print $1}'`
if [ "${md5_mysql_ok}" == "${md5_mysql}" ]; then
@@ -119,7 +119,7 @@ Install_mysql()
else
# 重新下载
rm -rf ${mysqlDir}/mysql-${VERSION}
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/Downloads/MySQL-8.0/mysql-boost-${VERSION}.tar.gz
wget -O ${mysqlDir}/mysql-boost-${VERSION}.tar.gz --tries=3 https://cdn.mysql.com/archives/mysql-8.0/mysql-boost-${VERSION}.tar.gz
fi
fi
+61
View File
@@ -0,0 +1,61 @@
import sys
import os
class luamaker:
"""
lua 处理器
"""
@staticmethod
def makeLuaTable(table):
"""
table 转换为 lua table 字符串
"""
_tableMask = {}
_keyMask = {}
def analysisTable(_table, _indent, _parent):
if isinstance(_table, tuple):
_table = list(_table)
if isinstance(_table, list):
_table = dict(zip(range(1, len(_table) + 1), _table))
if isinstance(_table, dict):
_tableMask[id(_table)] = _parent
cell = []
thisIndent = _indent + " "
for k in _table:
if sys.version_info[0] == 2:
if type(k) not in [int, float, bool, list, dict, tuple]:
k = k.encode()
if not (isinstance(k, str) or isinstance(k, int) or isinstance(k, float)):
return
key = isinstance(
k, int) and "[" + str(k) + "]" or "[\"" + str(k) + "\"]"
if _parent + key in _keyMask.keys():
return
_keyMask[_parent + key] = True
var = None
v = _table[k]
if sys.version_info[0] == 2:
if type(v) not in [int, float, bool, list, dict, tuple]:
v = v.encode()
if isinstance(v, str):
# print("lua", var)
v = v.replace("\\", "\\\\")
v = v.replace("\"", "\\\"")
var = "\"" + v + "\""
elif isinstance(v, bool):
var = v and "true" or "false"
elif isinstance(v, int) or isinstance(v, float):
var = str(v)
else:
var = analysisTable(v, thisIndent, _parent + key)
cell.append(thisIndent + key + " = " + str(var))
lineJoin = ",\n"
return "{\n" + lineJoin.join(cell) + "\n" + _indent + "}"
else:
pass
return analysisTable(table, "", "root")
+17
View File
@@ -0,0 +1,17 @@
PRAGMA synchronous = 0;
PRAGMA page_size = 4096;
PRAGMA journal_mode = wal;
PRAGMA journal_size_limit = 1073741824;
CREATE TABLE IF NOT EXISTS `logs` (
`time` INTEGER,
`ip` TEXT,
`domain` TEXT,
`server_name` TEXT,
`method` TEXT,
`status_code` INTEGER,
`user_agent` TEXT,
`uri` TEXT,
`rule_name` TEXT,
`reason` TEXT
);
+8 -6
View File
@@ -1,8 +1,10 @@
lua_shared_dict limit 30m;
lua_shared_dict drop_ip 30m;
lua_shared_dict drop_sum 30m;
lua_package_path "{$WAF_PATH}/lua/?.lua;{$ROOT_PATH}/openresty/lualib/?.lua;;";
lua_shared_dict waf_limit 30m;
lua_shared_dict waf_drop_ip 10m;
lua_shared_dict waf_drop_sum 10m;
lua_package_path "{$WAF_PATH}/html/?.lua;{$WAF_PATH}/conf/?.lua;{$WAF_PATH}/lua/?.lua;{$ROOT_PATH}/openresty/lualib/?.lua;;";
lua_package_cpath "{$WAF_PATH}/conf/?.so;{$ROOT_PATH}/openresty/lualib/?.so;;";
init_worker_by_lua_file {$WAF_PATH}/lua/init_worker.lua;
access_by_lua_file {$WAF_PATH}/lua/init.lua;
#init_by_lua_file {$WAF_PATH}/lua/init.lua;
#access_by_lua_file {$WAF_PATH}/lua/waf.lua;
# init_by_lua_file {$WAF_PATH}/lua/init.lua;
+16 -2
View File
@@ -1,4 +1,18 @@
<style>
.overflow_hide {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
vertical-align: middle;
}
.cur {
background-color: #20a53a;
color: #fff;
}
/*waf*/
.lib-con-title {
height: 26px;
@@ -231,8 +245,8 @@
<p onclick="wafScreen();">首页</p>
<p onclick="wafGloabl();">全局配置</p>
<p onclick="wafSite();">站点配置</p>
<p onclick="wafHistory();">封锁历史</p>
<!-- <p onclick="wafLogs();">操作日志</p> -->
<p onclick="wafLogs();">封锁历史</p>
<!-- <p onclick="wafOpLogs();">操作日志</p> -->
</div>
<!-- lib-con -->
<div class="bt-w-con pd15">
+295 -27
View File
@@ -52,11 +52,50 @@ def checkArgs(data, ck=[]):
return (True, mw.returnJson(True, 'ok'))
sys.path.append(getPluginDir() + "/class")
from luamaker import luamaker
def listToLuaFile(path, lists):
content = luamaker.makeLuaTable(lists)
content = "return " + content
mw.writeFile(path, content)
def htmlToLuaFile(path, content):
content = "return [[" + content + "]]"
mw.writeFile(path, content)
def getConf():
path = mw.getServerDir() + "/openresty/nginx/conf/nginx.conf"
return path
def pSqliteDb(dbname='logs'):
name = "waf"
db_dir = getServerDir() + '/logs/'
if not os.path.exists(db_dir):
mw.execShell('mkdir -p ' + db_dir)
file = db_dir + name + '.db'
if not os.path.exists(file):
conn = mw.M(dbname).dbPos(db_dir, name)
sql = mw.readFile(getPluginDir() + '/conf/init.sql')
sql_list = sql.split(';')
for index in range(len(sql_list)):
conn.execute(sql_list[index])
else:
conn = mw.M(dbname).dbPos(db_dir, name)
conn.execute("PRAGMA synchronous = 0")
conn.execute("PRAGMA page_size = 4096")
conn.execute("PRAGMA journal_mode = wal")
conn.execute("PRAGMA journal_size_limit = 1073741824")
return conn
def initDomainInfo():
data = []
path_domains = getJsonPath('domains')
@@ -111,7 +150,7 @@ def initSiteInfo():
tmp['log'] = True
tmp['get'] = True
tmp['post'] = True
tmp['open'] = False
tmp['open'] = True
tmp['cc'] = config_contents['cc']
tmp['retry'] = config_contents['retry']
@@ -120,9 +159,24 @@ def initSiteInfo():
tmp['user-agent'] = config_contents['user-agent']
tmp['cookie'] = config_contents['cookie']
tmp['scan'] = config_contents['scan']
tmp['safe_verify'] = config_contents['safe_verify']
cdn_header = ['x-forwarded-for',
'x-real-ip', 'HTTP_CF_CONNECTING_IP']
'x-real-ip',
'x-forwarded',
'forwarded-for',
'forwarded',
'true-client-ip',
'client-ip',
'ali-cdn-real-ip',
'cdn-src-ip',
'cdn-real-ip',
'cf-connecting-ip',
'x-cluster-client-ip',
'wl-proxy-client-ip',
'proxy-client-ip',
'true-client-ip',
'HTTP_CF_CONNECTING_IP']
tmp['cdn_header'] = cdn_header
disable_upload_ext = ["php", "jsp"]
@@ -163,6 +217,9 @@ def initTotalInfo():
tmp['get'] = 0
tmp['post'] = 0
tmp['total'] = 0
tmp['path'] = 0
tmp['php_path'] = 0
tmp['upload_ext'] = 0
_name = {}
_name[name] = tmp
total_contents['sites'] = _name
@@ -186,21 +243,109 @@ def status():
def contentReplace(content):
service_path = mw.getServerDir()
waf_path = getServerDir() + "/waf"
waf_root = getServerDir()
waf_path = waf_root + "/waf"
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$WAF_PATH}', waf_path)
content = content.replace('{$WAF_ROOT}', waf_root)
return content
def autoMakeLuaConfSingle(file):
path = getServerDir() + "/waf/rule/" + file + ".json"
to_path = getServerDir() + "/waf/conf/rule_" + file + ".lua"
content = mw.readFile(path)
# print(content)
content = json.loads(content)
listToLuaFile(to_path, content)
def autoMakeLuaImportSingle(file):
path = getServerDir() + "/waf/" + file + ".json"
to_path = getServerDir() + "/waf/conf/waf_" + file + ".lua"
content = mw.readFile(path)
# print(content)
content = json.loads(content)
listToLuaFile(to_path, content)
def autoMakeLuaHtmlSingle(file):
path = getServerDir() + "/waf/html/" + file + ".html"
to_path = getServerDir() + "/waf/html/html_" + file + ".lua"
content = mw.readFile(path)
htmlToLuaFile(to_path, content)
def autoMakeLuaConf():
conf_list = ['args', 'cookie', 'ip_black', 'ip_white',
'ipv6_black', 'post', 'scan_black', 'url',
'user_agent']
for x in conf_list:
autoMakeLuaConfSingle(x)
import_list = ['config', 'site', 'domains']
for x in import_list:
autoMakeLuaImportSingle(x)
html_list = ['get', 'post', 'safe_js', 'user_agent', 'cookie', 'other']
for x in html_list:
autoMakeLuaHtmlSingle(x)
def initDefaultInfo():
path = getServerDir()
djson = path + "/waf/domains.json"
default_json = path + "/waf/default.json"
if os.path.exists(djson):
content = mw.readFile(djson)
content = json.loads(content)
ddata = {}
dlist = []
for i in content:
dlist.append(i["name"])
dlist.append('unset')
ddata["list"] = dlist
if len(ddata["list"]) < 1:
ddata["default"] = "unset"
else:
ddata["default"] = dlist[0]
mw.writeFile(default_json, json.dumps(ddata))
def autoMakeConfig():
path = getServerDir()
initDomainInfo()
initSiteInfo()
initTotalInfo()
autoMakeLuaConf()
def restartWeb():
autoMakeConfig()
mw.restartWeb()
def initDreplace():
path = getServerDir()
if not os.path.exists(path + '/waf'):
if not os.path.exists(path + '/waf/lua'):
sdir = getPluginDir() + '/waf'
cmd = 'cp -rf ' + sdir + ' ' + path
mw.execShell(cmd)
logs_path = path + '/logs'
if not os.path.exists(logs_path):
mw.execShell('mkdir -p ' + logs_path)
debug_log = path + '/debug.log'
if not os.path.exists(debug_log):
mw.execShell('echo "" > ' + debug_log)
config = path + '/waf/config.json'
content = mw.readFile(config)
content = json.loads(content)
@@ -214,6 +359,16 @@ def initDreplace():
content = contentReplace(content)
mw.writeFile(config, content)
config_common = path + "/waf/lua/common.lua"
content = mw.readFile(config_common)
content = contentReplace(content)
mw.writeFile(config_common, content)
init_worker = path + "/waf/lua/init_worker.lua"
content = mw.readFile(init_worker)
content = contentReplace(content)
mw.writeFile(init_worker, content)
waf_conf = mw.getServerDir() + "/openresty/nginx/conf/luawaf.conf"
waf_tpl = getPluginDir() + "/conf/luawaf.conf"
content = mw.readFile(waf_tpl)
@@ -223,6 +378,13 @@ def initDreplace():
initDomainInfo()
initSiteInfo()
initTotalInfo()
autoMakeLuaConf()
initDefaultInfo()
pSqliteDb()
if not mw.isAppleSystem():
mw.execShell("chown -R www:www " + path)
def start():
@@ -233,6 +395,9 @@ def start():
conf = conf.replace('#include luawaf.conf;', "include luawaf.conf;")
mw.writeFile(path, conf)
import tool_task
tool_task.createBgTask()
mw.restartWeb()
return 'ok'
@@ -243,6 +408,10 @@ def stop():
conf = conf.replace('include luawaf.conf;', "#include luawaf.conf;")
mw.writeFile(path, conf)
import tool_task
tool_task.removeBgTask()
mw.restartWeb()
return 'ok'
@@ -254,8 +423,10 @@ def restart():
def reload():
stop()
mw.execShell('rm -rf ' + mw.getServerDir() +
"/openresty/nginx/logs/error.log")
errlog = mw.getServerDir() + "/openresty/nginx/logs/error.log"
mw.execShell('rm -rf ' + errlog)
start()
return 'ok'
@@ -306,7 +477,7 @@ def addRule():
cjson = mw.getJson(content)
mw.writeFile(fpath, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!', content)
@@ -328,7 +499,7 @@ def removeRule():
cjson = mw.getJson(content)
mw.writeFile(fpath, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!', content)
@@ -353,7 +524,7 @@ def setRuleState():
cjson = mw.getJson(content)
mw.writeFile(fpath, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!', content)
@@ -384,7 +555,7 @@ def modifyRule():
cjson = mw.getJson(content)
mw.writeFile(fpath, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!', content)
@@ -425,6 +596,7 @@ def addSiteRule():
cjson = mw.getJson(content)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -460,6 +632,7 @@ def addIpWhite():
cjson = mw.getJson(content)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -480,6 +653,8 @@ def removeIpWhite():
cjson = mw.getJson(content)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -515,6 +690,8 @@ def addIpBlack():
cjson = mw.getJson(content)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -535,6 +712,8 @@ def removeIpBlack():
cjson = mw.getJson(content)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -553,6 +732,7 @@ def setIpv6Black():
cjson = mw.getJson(content)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -569,9 +749,10 @@ def delIpv6Black():
content = json.loads(content)
content.remove(addr)
cjson = mw.getJson(content)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -594,6 +775,8 @@ def removeSiteRule():
cjson = mw.getJson(content)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -608,11 +791,13 @@ def setObjStatus():
cobj = json.loads(content)
o = args['obj']
status = args['statusCode']
status = int(args['statusCode'])
cobj[o]['status'] = status
cjson = mw.getJson(cobj)
mw.writeFile(conf, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -632,6 +817,32 @@ def setRetry():
cjson = mw.getJson(cobj)
mw.writeFile(conf, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!', [])
def setSafeVerify():
args = getArgs()
data = checkArgs(args, ['auto', 'time', 'cpu'])
if not data[0]:
return data[1]
conf = getJsonPath('config')
content = mw.readFile(conf)
cobj = json.loads(content)
cobj['safe_verify']['time'] = args['time']
cobj['safe_verify']['cpu'] = args['cpu']
if args['auto'] == '0':
cobj['safe_verify']['auto'] = False
else:
cobj['safe_verify']['auto'] = True
cjson = mw.getJson(cobj)
mw.writeFile(conf, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!', [])
@@ -642,7 +853,7 @@ def setSiteRetry():
def setCcConf():
args = getArgs()
data = checkArgs(args, ['siteName', 'cycle', 'limit',
'endtime', 'is_open_global', 'increase'])
'endtime', 'is_open_global'])
if not data[0]:
return data[1]
@@ -661,6 +872,8 @@ def setCcConf():
cjson = mw.getJson(cobj)
mw.writeFile(conf, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!', [])
@@ -677,6 +890,8 @@ def saveScanRule():
path = getRuleJsonPath('scan_black')
cjson = mw.getJson(args)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!', [])
@@ -716,6 +931,26 @@ def getSiteConfig():
return mw.returnJson(True, 'ok!', content)
def getSiteListData():
path = getServerDir() + "/waf/default.json"
data = mw.readFile(path)
return json.loads(data)
def setDefaultSite(name):
path = getServerDir() + "/waf/default.json"
data = mw.readFile(path)
data = json.loads(data)
data['default'] = name
mw.writeFile(path, json.dumps(data))
return mw.returnJson(True, 'OK')
def getDefaultSite():
data = getSiteListData()
return mw.returnJson(True, 'OK', data)
def getSiteConfigByName():
args = getArgs()
data = checkArgs(args, ['siteName'])
@@ -749,6 +984,8 @@ def addSiteCdnHeader():
cjson = mw.getJson(content)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '添加成功!')
@@ -768,6 +1005,8 @@ def removeSiteCdnHeader():
cjson = mw.getJson(content)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '删除成功!')
@@ -790,29 +1029,44 @@ def importData():
path = getRuleJsonPath(args['s_Name'])
mw.writeFile(path, args['pdata'])
restartWeb()
return mw.returnJson(True, '设置成功!')
def getLogsList():
args = getArgs()
data = checkArgs(args, ['siteName'])
data = checkArgs(args, ['site', 'page', 'page_size', 'tojs'])
if not data[0]:
return data[1]
data = []
path = mw.getLogsDir() + '/waf'
page = int(args['page'])
page_size = int(args['page_size'])
domain = args['site']
tojs = args['tojs']
if not os.path.exists(path):
return mw.returnJson(False, '还未生成!', [])
conn = pSqliteDb('logs')
files = os.listdir(path)
for f in files:
if f == '.DS_Store':
continue
f = f.split('_')
if f[0] == args['siteName']:
fl = f[1].split('.')
data.append(fl[0])
field = 'time,ip,domain,server_name,method,uri,user_agent,rule_name,reason'
limit = str(page_size) + ' offset ' + str(page_size * (page - 1))
condition = ''
conn = conn.field(field)
conn = conn.where("1=1", ()).where("domain=?", (domain,))
clist = conn.limit(limit).order('time desc').inquiry()
count_key = "count(*) as num"
count = conn.field(count_key).limit('').order('').inquiry()
# print(count)
count = count[0][count_key]
data = {}
_page = {}
_page['count'] = count
_page['p'] = page
_page['row'] = page_size
_page['tojs'] = tojs
data['page'] = mw.getPage(_page)
data['data'] = clist
return mw.returnJson(True, 'ok!', data)
@@ -823,7 +1077,7 @@ def getSafeLogs():
if not data[0]:
return data[1]
path = mw.getLogsDir() + '/waf'
path = getServerDir() + '/logs'
file = path + '/' + args['siteName'] + '_' + args['toDate'] + '.log'
if not os.path.exists(file):
return mw.returnJson(False, "文件不存在!")
@@ -859,6 +1113,7 @@ def setObjOpen():
cjson = mw.getJson(cobj)
mw.writeFile(conf, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -888,6 +1143,7 @@ def setSiteObjOpen():
cjson = mw.getJson(content)
mw.writeFile(path, cjson)
restartWeb()
return mw.returnJson(True, '设置成功!')
@@ -908,6 +1164,12 @@ def installPreInspection():
return 'ok'
def cleanDropIp():
url = "http://127.0.0.1/clean_waf_drop_ip"
data = mw.httpGet(url)
return mw.returnJson(True, 'ok!', data)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
@@ -964,12 +1226,16 @@ if __name__ == "__main__":
print(setSiteCcConf())
elif func == 'set_retry':
print(setRetry())
elif func == 'set_safe_verify':
print(setSafeVerify())
elif func == 'set_site_retry':
print(setSiteRetry())
elif func == 'save_scan_rule':
print(saveScanRule())
elif func == 'get_site_config':
print(getSiteConfig())
elif func == 'get_default_site':
print(getDefaultSite())
elif func == 'get_site_config_byname':
print(getSiteConfigByName())
elif func == 'add_site_cdn_header':
@@ -990,5 +1256,7 @@ if __name__ == "__main__":
print(getWafConf())
elif func == 'waf_site':
print(getWafSite())
elif func == 'clean_drop_ip':
print(cleanDropIp())
else:
print('error')
+1 -1
View File
@@ -11,5 +11,5 @@
"home":"https://github.com/loveshell/ngx_lua_waf",
"date":"2019-04-21",
"pid": "1",
"versions": ["0.1"]
"versions": ["0.2.2"]
}
+76 -8
View File
@@ -7,31 +7,99 @@ rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
action=$1
version=$2
sys_os=`uname`
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
if [ "$sys_os" == "Darwin" ];then
BAK='_bak'
else
BAK=''
fi
Install_of(){
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/source/op_waf
mkdir -p $serverPath/op_waf
echo '0.1' > $serverPath/op_waf/version.pl
# luarocks
if [ ! -f $serverPath/source/op_waf/luarocks-3.5.0.tar.gz ];then
wget --no-check-certificate -O $serverPath/source/op_waf/luarocks-3.5.0.tar.gz http://luarocks.org/releases/luarocks-3.5.0.tar.gz
fi
# which luarocks
# if [ "$?" != "0" ];then
if [ ! -d $serverPath/op_waf/luarocks ];then
cd $serverPath/source/op_waf && tar xvf luarocks-3.5.0.tar.gz
# cd luarocks-3.9.1 && ./configure && make bootstrap
cd luarocks-3.5.0 && ./configure --prefix=$serverPath/op_waf/luarocks --with-lua-include=$serverPath/openresty/luajit/include/luajit-2.1 --with-lua-bin=$serverPath/openresty/luajit/bin
make -I${serverPath}/openresty/luajit/bin
make install
fi
if [ ! -f $serverPath/source/op_waf/lsqlite3_fsl09y.zip ];then
wget --no-check-certificate -O $serverPath/source/op_waf/lsqlite3_fsl09y.zip http://lua.sqlite.org/index.cgi/zip/lsqlite3_fsl09y.zip?uuid=fsl_9y
cd $serverPath/source/op_waf && unzip lsqlite3_fsl09y.zip
fi
if [ ! -d $serverPath/source/op_waf/lsqlite3_fsl09y ];then
cd $serverPath/source/op_waf && unzip lsqlite3_fsl09y.zip
fi
PATH=${serverPath}/openresty/luajit:${serverPath}/openresty/luajit/include/luajit-2.1:$PATH
export PATH=$PATH:$serverPath/op_waf/luarocks/bin
if [ ! -f $serverPath/op_waf/waf/conf/lsqlite3.so ];then
if [ "${sys_os}" == "Darwin" ];then
cd $serverPath/source/op_waf/lsqlite3_fsl09y
find_cfg=`cat Makefile | grep 'SQLITE_DIR'`
if [ "$find_cfg" == "" ];then
LIB_SQLITE_DIR=`brew info sqlite | grep /usr/local/Cellar/sqlite | cut -d \ -f 1 | awk 'END {print}'`
echo $LIB_SQLITE_DIR
sed -i $BAK "s#\$(ROCKSPEC)#\$(ROCKSPEC) SQLITE_DIR=${LIB_SQLITE_DIR}#g" Makefile
fi
make
else
cd $serverPath/source/op_waf/lsqlite3_fsl09y && make
fi
fi
# copy to code path
DEFAULT_DIR=$serverPath/op_waf/luarocks/lib/lua/5.1
if [ -f ${DEFAULT_DIR}/lsqlite3.so ];then
mkdir -p $serverPath/op_waf/waf/conf
cp -rf ${DEFAULT_DIR}/lsqlite3.so $serverPath/op_waf/waf/conf/lsqlite3.so
fi
echo "${version}" > $serverPath/op_waf/version.pl
echo 'install ok' > $install_tmp
cd ${rootPath} && python3 plugins/op_waf/index.py start
cd ${rootPath} && python3 ${rootPath}/plugins/op_waf/index.py start
# cd ${rootPath} && python3 ${rootPath}/plugins/op_waf/index.py restart
}
Uninstall_of(){
cd ${rootPath} && python3 plugins/op_waf/index.py stop
rm -rf $serverPath/op_waf
cd ${rootPath} && python3 ${rootPath}/plugins/op_waf/index.py stop
if [ "$?" == "0" ];then
rm -rf $serverPath/op_waf
fi
}
action=$1
type=$2
action=$1
if [ "${1}" == 'install' ];then
Install_of
+311 -211
View File
@@ -28,7 +28,7 @@ function setRequestCode(ruleName, statusCode){
title: "设置响应代码【" + ruleName + "】",
area: '300px',
shift: 5,
closeBtn: 2,
closeBtn: 1,
shadeClose: true,
content: '<div class="bt-form pd20 pb70">\
<div class="line">\
@@ -69,8 +69,10 @@ function setObjOpen(ruleName){
owPost('set_obj_open', {obj:ruleName},function(data){
var rdata = $.parseJSON(data.data);
if (rdata.status){
layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
wafGloabl();
showMsg(rdata.msg, function(){
wafGloabl();
},{icon:1,time:2000,shade: [0.3, '#000']},2000);
} else {
layer.msg('设置失败!',{icon:0,time:2000,shade: [0.3, '#000']});
}
@@ -84,7 +86,7 @@ function saveCcRule(siteName,is_open_global, type) {
if(type == 2){
// set_aicc_open('start');
increase = "0";
}else{
} else {
// set_aicc_open('stop');
increase = type;
}
@@ -144,7 +146,7 @@ function setCcRule(cycle, limit, endtime, siteName, increase){
type: 1,
title: "设置CC规则",
area: '540px',
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<form class="bt-form pd20 pb70">\
<div class="line">\
@@ -164,7 +166,10 @@ function setCcRule(cycle, limit, endtime, siteName, increase){
<li>请不要设置过于严格的CC规则,以免影响正常用户体验</li>\
<li><font style="color:red;display:'+ (siteName == 'undefined'?'display: inline-block;':'none') +';">全局应用:全局设置当前CC规则,且覆盖当前全部站点的CC规则</font></li>\
</ul>\
<div class="bt-form-submit-btn"><button type="button" class="btn btn-danger btn-sm btn_cc_all" style="margin-right:10px;display:'+ (siteName == 'undefined'?'display: inline-block;':'none') +';">全局应用</button><button type="button" class="btn btn-success btn-sm btn_cc_present">应用</button></div>\
<div class="bt-form-submit-btn">\
<button type="button" class="btn btn-danger btn-sm btn_cc_all" style="margin-right:10px;display:'+ (siteName == 'undefined'?'display: inline-block;':'none') +';">全局应用</button>\
<button type="button" class="btn btn-success btn-sm btn_cc_present">应用</button>\
</div>\
</form>',
success:function(layero,index){
$('.btn_cc_all').click(function(){
@@ -184,7 +189,7 @@ function setRetry(retry_cycle, retry, retry_time, siteName) {
type: 1,
title: "设置恶意容忍规则",
area: '500px',
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<form class="bt-form pd20 pb70">\
<div class="line">\
@@ -201,9 +206,12 @@ function setRetry(retry_cycle, retry, retry_time, siteName) {
</div>\
<ul class="help-info-text c7 ptb10">\
<li><font style="color:red;">'+ retry_cycle + '</font> 秒内累计恶意请求超过 <font style="color:red;">' + retry + '</font> 次,封锁 <font style="color:red;">' + retry_time + '</font> 秒</li>\
<li><font style="color:red;">全局应用:全局设置当前恶意容忍规则,且覆盖当前全部站点的恶意容忍规则</li>\
<li><font style="color:red;">全局应用:全局设置当前恶意容忍规则,且覆盖当前全部站点的恶意容忍规则</font></li>\
</ul>\
<div class="bt-form-submit-btn"><button type="button" class="btn btn-danger btn-sm btn_retry_all" style="margin-right:10px;display:'+ (siteName == undefined?'inline-block;':'none') +';">全局应用</button><button type="button" class="btn btn-success btn-sm btn_retry_present">应用</button></div>\
<div class="bt-form-submit-btn">\
<button type="button" class="btn btn-danger btn-sm btn_retry_all" style="margin-right:10px;display:'+ (siteName == undefined?'inline-block;':'none') +';">全局应用</button>\
<button type="button" class="btn btn-success btn-sm btn_retry_present">应用</button>\
</div>\
</form>',
success:function(){
$('.btn_retry_all').click(function(){
@@ -217,6 +225,65 @@ function setRetry(retry_cycle, retry, retry_time, siteName) {
}
//设置safe_verify规则
function setSafeVerify(auto, cpu, time, siteName) {
var svlayer = layer.open({
type: 1,
title: "设置强制安全验证",
area: '500px',
closeBtn: 1,
shadeClose: false,
content: '<form class="bt-form pd20 pb70">\
<div class="line">\
<span class="tname">CPU</span>\
<div class="info-r"><input class="bt-input-text" name="cpu" type="number" max-number="100" value="'+ cpu + '" /> %</div>\
</div>\
<div class="line">\
<span class="tname">通行时间</span>\
<div class="info-r"><input class="bt-input-text" name="time" type="number" value="'+ time + '" /> 秒</div>\
</div>\
<div class="line">\
<span class="tname">开启自动</span>\
<div class="info-r">\
<select class="bt-input-text mr5" style="width:80px" name="auto">\
<option value="0" '+(auto==false?"selected=selected":"")+'>关闭</option>\
<option value="1" '+(auto==true?"selected=selected":"")+'>开启</option>\
</select>\
</div>\
</div>\
<ul class="help-info-text c7 ptb10">\
<li><font style="color:red;">全局设置强制安全验证</font></li>\
<li>开启自动后:cpu超过['+cpu+'%]后,强制验证。</li>\
</ul>\
<div class="bt-form-submit-btn">\
<button type="button" class="btn btn-success btn-sm btn_sv_present">应用</button>\
</div>\
</form>',
success:function(index){
$('.btn_sv_present').click(function(){
var pdata = {
siteName: siteName,
cpu: $("input[name='cpu']").val(),
auto: $("select[name='auto']").val(),
time: $("input[name='time']").val(),
}
var act = 'set_safe_verify';
owPost(act, pdata, function(data){
var rdata = $.parseJSON(data.data);
showMsg(rdata.msg, function() {
layer.close(svlayer);
wafGloabl();
},{ icon: rdata.status ? 1 : 2 },1000);
});
});
},
});
}
//保存retry规则
function saveRetry(siteName,type) {
var pdata = {
@@ -253,15 +320,6 @@ function addRule(ruleName) {
},1000);
}
});
// var loadT = layer.msg('正在添加,请稍候..', { icon: 16, time: 0 });
// $.post('/plugin?action=a&name=btwaf&s=add_rule', pdata, function (rdata) {
// layer.close(loadT);
// layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
// if (rdata.status) {
// set_obj_conf(ruleName, 1);
// }
// });
}
function modifyRule(index, ruleName) {
@@ -339,7 +397,7 @@ function setObjConf(ruleName, type) {
type: 1,
title: "编辑规则【" + ruleName + "】",
area: ['700px', '530px'],
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div class="pd15">\
<div style="border-bottom:#ccc 1px solid;margin-bottom:10px;padding-bottom:10px">\
@@ -405,7 +463,7 @@ function scanRule() {
type: 1,
title: "常用扫描器过滤规则",
area: '650px',
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<form class="bt-form pd20 pb70">\
<div class="line">\
@@ -571,7 +629,7 @@ function ipWhite(type) {
type: 1,
title: "管理IP白名单",
area: ['500px', '500px'],
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div class="pd15 ipv4_list">\
<div style="border-bottom:#ccc 1px solid;margin-bottom:10px;padding-bottom:10px">\
@@ -695,6 +753,23 @@ function addIpBlack() {
});
}
function addIpBlackArgs(ip) {
var pdata = {
start_ip: ip,
end_ip: ip,
}
if (pdata['start_ip'].split('.').length < 4 || pdata['end_ip'].split('.').length < 4) {
layer.msg('起始IP或结束IP格式不正确!');
return;
}
owPost('add_ip_black', pdata, function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
//从IP黑名单删除IP段
function removeIpBlack(index) {
@@ -714,7 +789,7 @@ function ipBlack(type) {
type: 1,
title: "管理IP黑名单",
area: ['500px', '500px'],
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div class="tab_list"><div class="tab_block active">IPv4黑名单</div><div class="tab_block">IPv6黑名单</div></div>\
<div class="pd15 ipv4_block">\
@@ -820,17 +895,17 @@ function wafScreen(){
con += '<div class="screen">\
<div class="line"><span class="name">POST渗透</span><span class="val">'+rdata.rules.post+'</span></div>\
<div class="line"><span class="name">GET渗透</span><span class="val">0</span></div>\
<div class="line"><span class="name">GET渗透</span><span class="val">'+rdata.rules.args+'</span></div>\
<div class="line"><span class="name">CC攻击</span><span class="val">'+rdata.rules.cc+'</span></div>\
<div class="line"><span class="name">恶意User-Agent</span><span class="val">'+rdata.rules.user_agent+'</span></div>\
<div class="line"><span class="name">Cookie渗透</span><span class="val">'+rdata.rules.cookie+'</span></div>\
<div class="line"><span class="name">恶意扫描</span><span class="val">0</span></div>\
<div class="line"><span class="name">恶意扫描</span><span class="val">'+rdata.rules.scan+'</span></div>\
<div class="line"><span class="name">恶意HEAD请求</span><span class="val">0</span></div>\
<div class="line"><span class="name">URI自定义拦截</span><span class="val">0</span></div>\
<div class="line"><span class="name">URI保护</span><span class="val">0</span></div>\
<div class="line"><span class="name">恶意文件上传</span><span class="val">0</span></div>\
<div class="line"><span class="name">禁止的扩展名</span><span class="val">0</span></div>\
<div class="line"><span class="name">禁止PHP脚本</span><span class="val">0</span></div>\
<div class="line"><span class="name">URI自定义拦截</span><span class="val">'+rdata.rules.url+'</span></div>\
<div class="line"><span class="name">URI保护</span><span class="val">'+rdata.rules.args+'</span></div>\
<div class="line"><span class="name">恶意文件上传</span><span class="val">'+rdata.rules.upload_ext+'</span></div>\
<div class="line"><span class="name">禁止的扩展名</span><span class="val">'+rdata.rules.path+'</span></div>\
<div class="line"><span class="name">禁止PHP脚本</span><span class="val">'+rdata.rules.php_path+'</span></div>\
</div>';
con += '<div style="width:660px;"><ul class="help-info-text c7">\
@@ -878,6 +953,16 @@ function wafGloabl(){
<td style="text-align: center;">--</td>\
<td class="text-right"><a class="btlink" onclick="setRetry('+ rdata.retry.retry_cycle + ',' + rdata.retry.retry + ',' + rdata.retry.retry_time + ')">初始规则</a></td>\
</tr>\
<tr>\
<td>强制安全验证</td>\
<td>'+rdata.safe_verify.ps+'</td>\
<td>--</td>\
<td style="text-align: center;"><div class="ssh-item">\
<input class="btswitch btswitch-ios" id="close_safe_verify" type="checkbox" '+(rdata.safe_verify.open ? 'checked' : '')+'>\
<label class="btswitch-btn" for="close_safe_verify" onclick="setObjOpen(\'safe_verify\')"></label></div>\
</td>\
<td class="text-right"><a class="btlink" onclick="setSafeVerify('+ rdata.safe_verify.auto + ',' + rdata.safe_verify.cpu + ',' + rdata.safe_verify.time + ')">设置</a> | <a class="btlink" href="javascript:;" onclick="onlineEditFile(0,\''+rdata['reqfile_path']+'/safe_js.html\')">响应内容</a></td>\
</tr>\
<tr>\
<td>GET-URI过滤</td>\
<td>'+ rdata.get.ps + '</td>\
@@ -956,146 +1041,6 @@ function back_css(v) {
}
}
//查看网站日志
function siteWafLog(siteName) {
var loadT = layer.msg('正在处理,请稍候..', { icon: 16, time: 0 });
owPost('get_logs_list', { siteName: siteName } , function (data) {
var tmp = $.parseJSON(data.data);
var rdata = tmp.data;
var selectLogDay = "";
var day = rdata[0];
for (var i = 0; i < rdata.length; i++) {
selectLogDay += '<option value="' + rdata[i] + '">' + rdata[i] + '</option>';
}
if (rdata == "") {
layer.msg("暂无日志记录", { icon: 6, shade: 0.3, time: 1000 });
return
}
layer.open({
type: 1,
title: "日志【" + siteName + "】",
area: ['880px', '500px'],
closeBtn: 2,
shadeClose: false,
content: '<div class="lib-box pd15 lib-box-log">\
<div class="lib-con-title" style="height:40px"><select id="selectLogDay" class="bt-input-text" onchange="siteLogCon(\''+ siteName + '\',this.options[this.options.selectedIndex].value,1)">' + selectLogDay + '</select></div>\
<div class="lib-con">\
<div class="divtable">\
<div id="site_waf_log" style="max-height:400px;overflow:auto;border:#ddd 1px solid">\
<table class="table table-hover" style="border:none;">\
<thead><tr><th width="150">时间</th><th width="120">用户IP</th><th width="70">类型</th><th>URI地址</th><th class="tdhide">User-Agent</th><th width="60">状态</th><th width="100">过滤器</th><th class="tdhide">过滤规则</th><th width="100" class="text-right">操作</th></tr></thead>\
<tbody id="LogDayCon"></tbody>\
</table>\
</div>\
</div>\
<div class="page pull-right" id="size_log_page" style="margin-top:10px"></div>\
</div>\
</div>'
});
siteLogCon(siteName, day, 1);
tableFixed("site_waf_log");
});
}
//日志内容
function siteLogCon(siteName, day, page) {
if (!page) page = 1;
var last = page - 1;
var next = page + 1;
var pagehtml = '';
$("#site_waf_log").scrollTop(0);
owPost('get_safe_logs', { siteName: siteName, toDate: day, p: page }, function(data){
var tmp = $.parseJSON(data.data);
if (!tmp.status){
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
return;
}
var rdata = tmp.data;
var con = '';
for (var i = 0; i < rdata.length; i++) {
con += '<tr>\
<td class="td0">'+ escapeHTML(rdata[i][0]) + '</td>\
<td class="td1"><a class="btlink" href="javascript:add_log_ip_black(\''+ escapeHTML(rdata[i][1]) + '\');" title="加入黑名单">' + escapeHTML(rdata[i][1]) + '</a></td>\
<td class="td2">'+ escapeHTML(rdata[i][2]) + '</td>\
<td class="td3"><span class="td3txt">'+ escapeHTML(rdata[i][3]) + '</span></td>\
<td class="tdhide td4">'+ escapeHTML(rdata[i][4]) + '</td><td>已拦截</td>\
<td class="td5"><span class="filtertext">'+ escapeHTML(rdata[i][5]) + '</span></td>\
<td class="tdhide td6">'+ escapeHTML(rdata[i][6]) + '</td>\
<td class="text-right"><a href="javascript:;" class="btlink submit_msg" data-index="'+ i +'">误报</a> | <a href="javascript:;" class="btlink btwaf_details" data-index="'+ i +'">详细</a></td>\
</tr>'
}
$("#LogDayCon").html(con);
pagehtml = '<a class="Pstart" onclick="site_log_con(\'' + siteName + '\',\'' + day + '\',1)">首页</a><a class="prevPage" onclick="site_log_con(\'' + siteName + '\',\'' + day + '\',' + last + ')">上一页</a><a class="nextPage" onclick="site_log_con(\'' + siteName + '\',\'' + day + '\',' + next + ')">下一页</a><a class="Pcount">第 ' + page + ' 页</a>';
$("#size_log_page").html(pagehtml);
if (rdata.length < 1) $(".nextPage").hide();
if (last < 1) $(".prevPage").hide();
// 发送误报请求
$(".submit_msg").click(function () {
var _this = $(this);
var res = rdata[$(this).attr('data-index')];
layer.confirm('是否确定提交误报反馈?', { title: '误报反馈',closeBtn:2,icon:3}, function () {
var url_address = res[3];
var rule_arry = res[6].split(" &gt;&gt; ");
var pdata = { url_rule: url_address };
var loadT = layer.msg('正在添加URL白名单..', { icon: 16, time: 0 });
$.post('/plugin?action=a&name=btwaf&s=add_url_white', pdata, function (rdata) {
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
layer.close(loadT);
if (rule_arry[1] != undefined){ $.get('https://www.bt.cn/Api/add_waf_logs?data=' + rule_arry[1],function(rdata){},'jsonp')}
});
});
})
// 详情
$(".btwaf_details").click(function () {
var res = rdata[$(this).attr('data-index')];
var time = res[0]; //时间
var ip_address = res[1]; //IP地址
var req_type = res[2]; // 请求类型
var url_address = res[3]; // 请求类型
var user_agent = res[4]; // 请求类型
var filters = res[5]; //过滤器
var filter_rule = ''; //过滤规则
var rule_arry = res[6].split(" &gt;&gt; ");
var incoming_value = '',risk_value = ''; //传入值,风险值
if(rule_arry.length == 0) filter_rule = rule_arry[0]
incoming_value = rule_arry[1] == undefined?'空':rule_arry[1];
risk_value = incoming_value.match(new RegExp(rule_arry[0].replace(/\//g,'\\/'),'i'));
risk_value = risk_value?risk_value[0]:'空';
layer.open({
type: 1,
title: time + "详情",
area: '600px',
closeBtn: 2,
shadeClose: false,
content: '<div class="pd15 lib-box">\
<table class="table" style="border:#ddd 1px solid; margin-bottom:10px">\
<tbody><tr><th>时间</th><td>'+ escapeHTML(time) + '</td><th>用户IP</th><td><a class="btlink" href="javascript:add_log_ip_black(\'' + escapeHTML(ip_address) + '\')" title="加入黑名单">' + escapeHTML(ip_address) + '</a></td></tr><tr><th>类型</th><td>' + escapeHTML(req_type) + '</td><th>过滤器</th><td>' + escapeHTML(filters) + '</td></tr></tbody></table>\
<div><b style="margin-left:10px">URI地址</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(url_address) + '</div></div>\
<div><b style="margin-left:10px">User-Agent</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(user_agent) + '</div></div>\
<div><b style="margin-left:10px">过滤规则</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(rule_arry[0]) + '</div></div>\
<div><b style="margin-left:10px">传入值</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(incoming_value) + '</div></div>\
<div><b style="margin-left:10px">风险值</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(risk_value) + '</div></div>\
</div>'
})
})
$("#LogDayCon td").click(function () {
$(this).parents("tr").addClass("active").siblings().removeClass("active");
});
});
}
function html_encode(value) {
return $('<div></div>').html(value).text();
}
@@ -1190,7 +1135,7 @@ function siteRuleAdmin(siteName, ruleName, type) {
type: 1,
title: "管理网站过滤规则【" + title + "】",
area: ['500px', '500px'],
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div class="pd15">\
<div style="border-bottom:#ccc 1px solid;margin-bottom:10px;padding-bottom:10px">\
@@ -1237,7 +1182,7 @@ function cdnHeader(siteName, type) {
type: 1,
title: "管理网站【" + siteName + "】CDN-Headers",
area: ['500px', '500px'],
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div class="pd15">\
<div style="border-bottom:#ccc 1px solid;margin-bottom:10px;padding-bottom:10px">\
@@ -1342,7 +1287,7 @@ function setSiteObjConf(siteName, ruleName, type) {
type: 1,
title: "编辑网站【" + siteName + "】规则【" + ruleName + "】",
area: ['700px', '530px'],
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div class="pd15">\
<div class="divtable">\
@@ -1394,7 +1339,7 @@ function siteWafConfig(siteName, type) {
type: 1,
title: "网站配置【" + siteName + "】",
area: ['700px', '500px'],
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div id="s_w_c"></div>'
});
@@ -1543,7 +1488,6 @@ function siteWafConfig(siteName, type) {
function wafSite(){
owPost('get_site_config', {}, function(data){
var tmp = $.parseJSON(data.data);
var rdata = $.parseJSON(tmp.data);
@@ -1553,32 +1497,20 @@ function wafSite(){
i += 1;
tbody += '<tr>\
<td><a onclick="siteWafConfig(\''+ k + '\')" class="sitename btlink" title="' + k + '">' + k + '</a></td>\
<td>\
<input onclick="setSiteObjState(\''+ k + '\',\'get\')" type="checkbox" ' + (v.get ? 'checked' : '') + '><span class="' + back_css(v.total[1].value) + '" title="拦截GET渗透次数:' + v.total[1].value + '">' + v.total[1].value + '</span>\
</td>\
<td>\
<input onclick="setSiteObjState(\''+ k + '\',\'post\')" type="checkbox" ' + (v.post ? 'checked' : '') + '><span class="' + back_css(v.total[0].value) + '" title="拦截POST渗透次数:' + v.total[0].value + '">' + v.total[0].value + '</span>\
</td>\
<td>\
<input onclick="setSiteObjState(\''+ k + '\',\'user-agent\')" type="checkbox" ' + (v['user-agent'] ? 'checked' : '') + '><span class="' + back_css(v.total[3].value) + '" title="拦截恶意User-Agent次数:' + v.total[3].value + '">' + v.total[3].value + '</span>\
</td>\
<td>\
<input onclick="setSiteObjState(\''+ k + '\',\'cookie\')" type="checkbox" ' + (v.cookie ? 'checked' : '') + '><span class="' + back_css(v.total[4].value) + '" title="拦截Cookie渗透次数:' + v.total[4].value + '">' + v.total[4].value + '</span>\
</td>\
<td>\
<input onclick="setSiteObjState(\''+ k + '\',\'cdn\')" type="checkbox" ' + (v.cdn ? 'checked' : '') + '>\
</td>\
<td>\
<input onclick="setSiteObjState(\''+ k + '\',\'cc\')" type="checkbox" ' + (v.cc.open ? 'checked' : '') + '><span class="' + back_css(v.total[2].value) + '" title="拦截CC攻击次数:' + v.total[2].value + '">' + v.total[2].value + '</span>\
</td>\
<td><input onclick="setSiteObjState(\''+ k + '\',\'get\')" type="checkbox" ' + (v.get ? 'checked' : '') + '><span class="' + back_css(v.total[1].value) + '" title="拦截GET渗透次数:' + v.total[1].value + '">' + v.total[1].value + '</span></td>\
<td><input onclick="setSiteObjState(\''+ k + '\',\'post\')" type="checkbox" ' + (v.post ? 'checked' : '') + '><span class="' + back_css(v.total[0].value) + '" title="拦截POST渗透次数:' + v.total[0].value + '">' + v.total[0].value + '</span></td>\
<td><input onclick="setSiteObjState(\''+ k + '\',\'user-agent\')" type="checkbox" ' + (v['user-agent'] ? 'checked' : '') + '><span class="' + back_css(v.total[3].value) + '" title="拦截恶意User-Agent次数:' + v.total[3].value + '">' + v.total[3].value + '</span></td>\
<td><input onclick="setSiteObjState(\''+ k + '\',\'cookie\')" type="checkbox" ' + (v.cookie ? 'checked' : '') + '><span class="' + back_css(v.total[4].value) + '" title="拦截Cookie渗透次数:' + v.total[4].value + '">' + v.total[4].value + '</span></td>\
<td><input onclick="setSiteObjState(\''+ k + '\',\'cdn\')" type="checkbox" ' + (v.cdn ? 'checked' : '') + '></td>\
<td><input onclick="setSiteObjState(\''+ k + '\',\'cc\')" type="checkbox" ' + (v.cc.open ? 'checked' : '') + '><span class="' + back_css(v.total[2].value) + '" title="拦截CC攻击次数:' + v.total[2].value + '">' + v.total[2].value + '</span></td>\
<td>\
<div class="ssh-item" style="margin-left:0">\
<input class="btswitch btswitch-ios" id="closeget_'+ i + '" type="checkbox" ' + (v.open ? 'checked' : '') + '>\
<label class="btswitch-btn" for="closeget_'+ i + '" onclick="setSiteObjState(\'' + k + '\',\'open\')"></label>\
</div>\
</td>\
<td class="text-right"><a onclick="siteWafLog(\''+ k + '\')" class="btlink ' + (v.log_size > 0 ? 'dot' : '') + '">日志</a> | <a onclick="siteWafConfig(\'' + k + '\')" class="btlink">设置</a></td>\
</tr>'
<td class="text-right"><a onclick="wafLogs(\''+ k + '\')" class="btlink ' + (v.log_size > 0 ? 'dot' : '') + '">日志</a> | <a onclick="siteWafConfig(\'' + k + '\')" class="btlink">设置</a></td>\
</tr>';
});
var con = '<div class="lib-box">\
@@ -1612,27 +1544,195 @@ function wafSite(){
function wafHistory(){
function wafLogRequest(page){
var args = {};
args['page'] = page;
args['page_size'] = 10;
args['site'] = $('select[name="site"]').val();
var query_date = 'today';
if ($('#time_choose').attr("data-name") != ''){
query_date = $('#time_choose').attr("data-name");
} else {
query_date = $('#search_time button.cur').attr("data-name");
}
args['query_date'] = query_date;
args['tojs'] = 'wafLogRequest';
owPost('get_logs_list', args, function(rdata){
var rdata = $.parseJSON(rdata.data);
var list = '';
var data = rdata.data.data;
if (data.length > 0){
for(i in data){
list += '<tr>';
list += '<td><span class="overflow_hide" style="width:112px;">' + getLocalTime(data[i]['time'])+'</span></td>';
list += '<td><span class="overflow_hide" style="width:50px;">' + data[i]['domain'] +'</span></td>';
list += '<td><span class="overflow_hide" style="width:60px;">' + data[i]['ip'] +'</span></td>';
list += '<td><span class="overflow_hide" style="width:50px;">' + data[i]['uri'] +'</span></td>';
list += '<td><span class="overflow_hide" style="width:50px;">' + data[i]['rule_name'] +'</span></td>';
list += '<td><span class="overflow_hide" style="width:200px;">' + data[i]['reason'] +'</span></td>';
list += '<td><a data-id="'+i+'" href="javascript:;" class="btlink details" title="详情">详情</a></td>';
list += '</tr>';
}
} else{
list += '<tr><td colspan="8" style="text-align:center;">封锁日志为空</td></tr>';
}
var table = '<div class="tablescroll">\
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
<thead><tr>\
<th>时间</th>\
<th>域名</th>\
<th>IP</th>\
<th>URI</th>\
<th>规则名</th>\
<th>原因</th>\
<th style="text-align:right;">操作</th></tr></thead>\
<tbody>\
'+ list +'\
</tbody></table>\
</div>\
<div id="wsPage" class="dataTables_paginate paging_bootstrap page"></div>';
$('#ws_table').html(table);
$('#wsPage').html(rdata.data.page);
$(".tablescroll .details").click(function(){
var index = $(this).attr('data-id');
var res = data[index];
var ip = res.ip;
var time = getLocalTime(res.time);
layer.open({
type: 1,
title: "【"+res.domain + "】详情",
area: '600px',
closeBtn: 1,
shadeClose: false,
content: '<div class="pd15 lib-box">\
<table class="table" style="border:#ddd 1px solid; margin-bottom:10px">\
<tbody><tr><th>时间</th><td>'+ time + '</td><th>用户IP</th><td><a class="btlink" href="javascript:addIpBlackArgs(\'' + escapeHTML(ip) + '\')" title="加入黑名单">' + escapeHTML(ip) + '</a></td></tr><tr><th>类型</th><td>' + escapeHTML(res.method) + '</td><th>过滤器</th><td>' + escapeHTML(res.rule_name) + '</td></tr></tbody></table>\
<div><b style="margin-left:10px">URI地址</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.uri) + '</div></div>\
<div><b style="margin-left:10px">User-Agent</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.user_agent) + '</div></div>\
<div><b style="margin-left:10px">过滤规则</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.rule_name) + '</div></div>\
<div><b style="margin-left:10px">Reason</b></div>\
<div class="lib-con pull-left mt10"><div class="divpre">'+ escapeHTML(res.reason) + '</div></div>\
</div>'
})
});
});
}
function wafLogs(){
var randstr = getRandomString(10);
var html = '<div>\
<div style="padding-bottom:10px;">\
<span>网站: </span>\
<select class="bt-input-text" name="site" style="margin-left:4px;width:100px;">\
<option value="unset">未设置</option>\
</select>\
<span style="margin-left:10px">时间: </span>\
<div class="input-group" style="margin-left:10px;width:350px;display: inline-table;vertical-align: top;">\
<div id="search_time" class="input-group-btn btn-group-sm">\
<button data-name="today" type="button" class="btn btn-default">今日</button>\
<button data-name="yesterday" type="button" class="btn btn-default">昨日</button>\
<button data-name="l7" type="button" class="btn btn-default">近7天</button>\
<button data-name="l30" type="button" class="btn btn-default">近30天</button>\
</div>\
<span class="last-span"><input data-name="" type="text" id="time_choose" lay-key="1000001_'+randstr+'" class="form-control btn-group-sm" autocomplete="off" placeholder="自定义时间" style="display: inline-block;font-size: 12px;padding: 0 10px;height:30px;width: 200px;"></span>\
</div>\
<div style="float:right;"><button id="UncoverAll" class="btn btn-success btn-sm">解封所有</button></div>\
</div>\
<div class="divtable mtb10" id="ws_table"></div>\
</div>';
$(".soft-man-con").html(html);
// wafLogRequest(1);
$("#UncoverAll").click(function(){
owPost('clean_drop_ip',{},function(data){
var rdata = $.parseJSON(data.data);
var ndata = $.parseJSON(rdata.data);
if (ndata.status == 0){
layer.msg("解封所有成功",{icon:1,time:2000,shade: [0.3, '#000']});
} else{
layer.msg("解封所有异常:"+ndata.msg,{icon:5,time:2000,shade: [0.3, '#000']});
}
});
});
//日期范围
laydate.render({
elem: '#time_choose',
value:'',
range:true,
done:function(value, startDate, endDate){
if(!value){
return false;
}
$('#search_time button').each(function(){
$(this).removeClass('cur');
});
var timeA = value.split('-');
var start = $.trim(timeA[0]+'-'+timeA[1]+'-'+timeA[2])
var end = $.trim(timeA[3]+'-'+timeA[4]+'-'+timeA[5])
query_txt = toUnixTime(start + " 00:00:00") + "-"+ toUnixTime(end + " 00:00:00")
$('#time_choose').attr("data-name",query_txt);
$('#time_choose').addClass("cur");
wafLogRequest(1);
},
});
$('#search_time button:eq(0)').addClass('cur');
$('#search_time button').click(function(){
$('#search_time button').each(function(){
if ($(this).hasClass('cur')){
$(this).removeClass('cur');
}
});
$('#time_choose').attr("data-name",'');
$('#time_choose').removeClass("cur");
$(this).addClass('cur');
wafLogRequest(1);
});
owPost('get_default_site',{},function(rdata){
$('select[name="site"]').html('');
var rdata = $.parseJSON(rdata.data);
var rdata = rdata.data;
var default_site = rdata["default"];
var select = '';
for (var i = 0; i < rdata["list"].length; i++) {
if (default_site == rdata["list"][i]){
select += '<option value="'+rdata["list"][i]+'" selected>'+rdata["list"][i]+'</option>';
} else{
select += '<option value="'+rdata["list"][i]+'">'+rdata["list"][i]+'</option>';
}
}
$('select[name="site"]').html(select);
wafLogRequest(1);
$('select[name="site"]').change(function(){
wafLogRequest(1);
});
});
var con = '<button class="btn btn-success btn-sm" onclick="UncoverAll()">解封所有</button>';
con += '<div class="divtable mt10">\
<table class="table table-hover waftable" style="color:#fff;">\
<thead><tr><th width="18%">开始时间</th>\
<th width="44%">IP</th>\
<th width="10%">站点</th>\
<th width="10%">封锁原因</th>\
<th width="10%">封锁时长</th>\
<th style="text-align: center;" width="10%">状态</th>\
</thead>\
</table>\
</div>';
$(".soft-man-con").html(con);
}
function wafLogs(){
function wafOpLogs(){
var con = '<div class="divtable">\
<table class="table table-hover waftable" style="color:#fff;">\
<thead><tr><th width="18%">名称</th>\
+29
View File
@@ -0,0 +1,29 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
# echo $rootPath
resty=$rootPath/openresty/bin/resty
RUN_CMD=$resty
if [ ! -f $resty ];then
RUN_CMD=/www/server/openresty/bin/resty
fi
# test
# $RUN_CMD simple.lua
# $RUN_CMD test_gsub.lua
# $RUN_CMD --shdict 'limit 10m' test_find_server_name.lua
# $RUN_CMD --stap --shdict 'limit 10m' test_find_server_name.lua
# $RUN_CMD test_rand.lua
$RUN_CMD test_ffi_time.lua
+18
View File
@@ -0,0 +1,18 @@
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end
for i = 1, 100 do
target()
end
collectgarbage()
ngx.update_time()
local begin = ngx.now()
local N = 1e7
for i = 1, N do
target()
end
ngx.update_time()
ngx.say("elapsed: ", (ngx.now() - begin) / N)
+62
View File
@@ -0,0 +1,62 @@
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end
for i = 1, 100 do
target()
end
-- 以上为预热操作
collectgarbage()
local ffi = require("ffi")
ffi.cdef[[
struct timeval {
long int tv_sec;
long int tv_usec;
};
int gettimeofday(struct timeval *tv, void *tz);
]];
local tm = ffi.new("struct timeval");
-- 返回微秒级时间戳
local function current_time_millis()
ffi.C.gettimeofday(tm,nil);
local sec = tonumber(tm.tv_sec);
local usec = tonumber(tm.tv_usec);
return sec + usec * 10^-6;
end
ngx.update_time()
local begin = ngx.now()
local N = 1e7
for i = 1, N do
target()
end
ngx.update_time()
ngx.say("elapsed: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = ngx.now()
local N = 1e7
for i = 1, N do
target()
end
ngx.update_time()
ngx.say("elapsed[1]: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = current_time_millis()
local N = 1e7
for i = 1, N do
target()
end
ngx.update_time()
ngx.say("ffi elapsed: ", (current_time_millis() - begin) / N)
@@ -0,0 +1,75 @@
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end
for i = 1, 100 do
target()
end
-- 以上为预热操作
collectgarbage()
local config_domains = {
[1] = {
["name"] = "t1.cn",
["path"] = "/www/wwwroot/t1.cn",
["domains"] = {
[1] = "t1.cn",
[2] = "t3.cn"
}
}
}
local function get_server_name(request_name)
for _,v in ipairs(config_domains)
do
for _,cd_name in ipairs(v['domains'])
do
if request_name == cd_name then
return v['name']
end
end
end
return request_name
end
local function get_server_name_cache(request_name)
local cache_name = ngx.shared.limit:get(request_name)
if cache_name then return cache_name end
for _,v in ipairs(config_domains)
do
for _,cd_name in ipairs(v['domains'])
do
if request_name == cd_name then
ngx.shared.limit:set(cd_name,v['name'],3600)
return v['name']
end
end
end
return request_name
end
ngx.update_time()
local begin = ngx.now()
local N = 1e7
for i = 1, N do
get_server_name("t3.cn")
end
ngx.update_time()
ngx.say("test get_server_name elapsed: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = ngx.now()
local N = 1e7
for i = 1, N do
get_server_name_cache("t3.cn")
end
ngx.update_time()
ngx.say("test get_server_name_cache elapsed: ", (ngx.now() - begin) / N)
+47
View File
@@ -0,0 +1,47 @@
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end
for i = 1, 100 do
target()
end
-- 以上为预热操作
collectgarbage()
local function test_string_gsub(str,reps)
local resultStrList = {}
string.gsub(str,'[^'..reps..']+', function(w)
table.insert(resultStrList,w)
return w
end)
end
local function test_ngx_string_gsub(str,reps)
local resultStrList = {}
ngx.re.gsub(str,'[^'..reps..']+', function(w)
table.insert(resultStrList,w[0])
return w
end, "ijo")
end
ngx.update_time()
local begin = ngx.now()
local N = 1e6
for i = 1, N do
test_string_gsub("2409:8a62:e20:95f0:45b7:233e:f003:c0ab",",")
end
ngx.update_time()
ngx.say("test_string_gsub elapsed: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = ngx.now()
local N = 1e6
for i = 1, N do
test_ngx_string_gsub("2409:8a62:e20:95f0:45b7:233e:f003:c0ab",",")
end
ngx.update_time()
ngx.say("test_ngx_string_gsub elapsed: ", (ngx.now() - begin) / N)
+72
View File
@@ -0,0 +1,72 @@
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end
for i = 1, 100 do
target()
end
-- 以上为预热操作
collectgarbage()
local function get_random_t1(n)
math.randomseed(ngx.time())
local t = {
"0","1","2","3","4","5","6","7","8","9",
"a","b","c","d","e","f","g","h","i","j",
"k","l","m","n","o","p","q","r","s","t",
"u","v","w","x","y","z",
"A","B","C","D","E","F","G","H","I","J",
"K","L","M","N","O","P","Q","R","S","T",
"U","V","W","X","Y","Z",
}
local s = ""
for i = 1, n do
s = s .. t[math.random(#t)]
end
return s
end
local function get_random_t2(n)
local t = {
"0","1","2","3","4","5","6","7","8","9",
"a","b","c","d","e","f","g","h","i","j",
"k","l","m","n","o","p","q","r","s","t",
"u","v","w","x","y","z",
"A","B","C","D","E","F","G","H","I","J",
"K","L","M","N","O","P","Q","R","S","T",
"U","V","W","X","Y","Z",
}
local s = ""
for i = 1, n do
s = s .. t[math.random(#t)]
end
return s
end
ngx.update_time()
local begin = ngx.now()
local N = 1e5
for i = 1, N do
get_random_t1(16)
end
ngx.update_time()
ngx.say("test get_random_t1 elapsed: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = ngx.now()
local N = 1e5
math.randomseed(ngx.time())
for i = 1, N do
get_random_t2(16)
end
ngx.update_time()
ngx.say("test get_random_t2 elapsed: ", (ngx.now() - begin) / N)
-7
View File
@@ -1,7 +0,0 @@
# coding:utf-8
import sys
import io
import os
import time
import json
+315 -7
View File
@@ -6,14 +6,322 @@ import os
import time
import json
TEST_URL = "t1.cn"
import os
import sys
import time
import string
import json
import hashlib
import shlex
import datetime
import subprocess
import re
from random import Random
def run():
print('op lua run ok')
TEST_URL = "http://t1.cn/"
# TEST_URL = "https://www.zzzvps.com/"
def writeFile(filename, str):
# 写文件内容
try:
fp = open(filename, 'w+')
fp.write(str)
fp.close()
return True
except Exception as e:
return False
def httpGet(url, timeout=10):
import urllib.request
try:
req = urllib.request.urlopen(url, timeout=timeout)
result = req.read().decode('utf-8')
return result
except Exception as e:
return str(e)
def httpGet__Header(url, headers, timeout=10):
import urllib.request
try:
req = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(req)
result = response.read().decode('utf-8')
return result
except Exception as e:
return str(e)
def httpUpload(url, timeout=10):
try:
import requests
files = {
'file': open('/Users/midoks/Desktop/mwdev/server/op_waf/version.pl', 'rb')
}
res = requests.post(url=url, files=files)
return res
except Exception as e:
return "http.upload:" + str(e)
def httpUploadPhp(url, timeout=10):
try:
import requests
writeFile("/tmp/tmp.php", "")
files = {
'file': open('/tmp/tmp.php', 'rb')
}
res = requests.post(url=url, files=files)
return res
except Exception as e:
return "http.upload:" + str(e)
def httpUploadPhpData(url, timeout=10):
try:
import requests
writeFile("/tmp/tmp.py", "<?php echo '123123';?>")
files = {
'file': open('/tmp/tmp.py', 'rb')
}
res = requests.post(url=url, files=files)
return res
except Exception as e:
return "http.upload:" + str(e)
def httpGet__UA(url, ua, timeout=10):
import urllib.request
headers = {'user-agent': ua}
try:
req = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(req)
result = response.read().decode('utf-8')
return result
except Exception as e:
return str(e)
def httpGet__cdn(url, ip, timeout=10):
import urllib.request
headers = {'x-forwarded-for': ip}
try:
req = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(req)
result = response.read().decode('utf-8')
return result
except Exception as e:
return str(e)
def httpPost(url, data, timeout=10):
"""
发送POST请求
@url 被请求的URL地址(必需)
@data POST参数,可以是字符串或字典(必需)
@timeout 超时时间默认60秒
return string
"""
if sys.version_info[0] == 2:
try:
import urllib
import urllib2
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
data = urllib.urlencode(data)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req, timeout=timeout)
return response.read()
except Exception as ex:
return str(ex)
else:
try:
import urllib.request
import ssl
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:
pass
data = urllib.parse.urlencode(data).encode('utf-8')
req = urllib.request.Request(url, data)
response = urllib.request.urlopen(req, timeout=timeout)
result = response.read()
if type(result) == bytes:
result = result.decode('utf-8')
return result
except Exception as ex:
return str(ex)
def test_Dir():
'''
目录保存
'''
url = TEST_URL + '?t=../etc/passwd'
print("args test start")
url_val = httpGet(url, 10)
print(url_val)
print("args test end")
def test_UA():
'''
user-agent 过滤
'''
url = TEST_URL
print("user-agent test start")
url_val = httpGet__UA(url, 'ApacheBench')
print(url_val)
print("user-agent test end")
def test_Header():
'''
user-agent 过滤
'''
url = TEST_URL
print("user-agent test start")
url_val = httpGet__Header(url, {'X-forwarded-For': '../etc/passwd'})
print(url_val)
print("user-agent test end")
def test_UA_for(num):
'''
user-agent 过滤
'''
url = TEST_URL
print("user-agent test start")
for x in range(num):
url_val = httpGet__UA(url, 'ApacheBench')
print(url_val)
print("user-agent test end")
def test_cdn():
'''
user-agent 过滤
'''
url = TEST_URL
print("cdn test start")
url_val = httpGet__cdn(url, '2409:8a62:e20:95f0:45b7:233e:f003:c0ab')
print(url_val)
url_val2 = httpGet__cdn(url, '91.245.227.173')
print(url_val2)
print("cdn test end")
def test_POST():
'''
user-agent 过滤
'''
url = TEST_URL
print("POST test start")
url_val = httpPost(url, {'data': "substr($mmsss,0,1)"})
# url_val = httpPost(url, {'data': "123123"})
print(url_val)
print("POST test end")
def test_scan():
'''
目录保存
'''
url = TEST_URL + 'acunetix_wvs_security_test?t=1'
print("scan test start")
url_val = httpGet(url, 10)
print(url_val)
print("scan test end")
def test_CC():
'''
目录保存
'''
url = TEST_URL + 'ok.txt'
print("CC test start")
for x in range(122):
url_val = httpGet(url, 10)
print(url_val)
print("CC test end")
def test_url_ext():
'''
目录保存
'''
url = TEST_URL + 't.sql'
print("url_ext start")
url_val = httpGet(url, 10)
print(url_val)
print("url_ext end")
def test_OK():
'''
目录保存
'''
url = TEST_URL
print("ok test start")
url_val = httpGet(url, 10)
print(url_val)
print("ok test end")
def test_Upload():
'''
上传文件
'''
url = TEST_URL
print("upload test start")
url_val = httpUpload(url, 10)
print(url_val)
print("upload test end")
print("upload php test start")
url_val = httpUploadPhp(url, 10)
print(url_val)
print("upload php test start")
print("upload php data test start")
url_val = httpUploadPhpData(url, 10)
print(url_val)
print("upload php data test start")
def test_start():
# test_OK()
# test_Dir()
# test_UA()
test_Header()
# test_UA_for(1000)
test_POST()
test_scan()
# test_CC()
# test_url_ext()
# test_cdn()
# test_Upload()
if __name__ == "__main__":
if len(sys.argv) > 1:
if action == "run":
run()
os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/op_waf && sh install.sh uninstall 0.2.2 && sh install.sh install 0.2.2')
os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/ && python3 plugins/openresty/index.py stop && python3 plugins/openresty/index.py start')
test_start()
+82
View File
@@ -0,0 +1,82 @@
#!/bin/sh
export PATH=$PATH:/opt/stap/bin:/opt/stapxx
# https://moonbingbing.gitbooks.io/openresty-best-practices/content/flame_graph/install.html
# apt install elfutils
# sudo apt-get install -y systemtap gcc
# sudo apt-get install linux-headers-generic gcc libcap-dev
# apt-get install -y libdw-dev
# apt-get install -y fakeroot build-essential crash kexec-tools makedumpfile kernel-wedge kernel-package
# apt-get install -y git-core libncurses5 libncurses5-dev libelf-dev asciidoc binutils-dev
# apt-get build-dep linux
# cat > /etc/apt/sources.list.d/ddebs.list << EOF
# deb http://ddebs.ubuntu.com/ precise main restricted universe multiverse
# EOF
#
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ECDCAD72428D7C01
# apt-get update
if [ $# -ne 2 ]
then
echo "Usage: ./`basename $0` lua/c NAME"
exit
fi
pid=`ps -ef|grep openresty | grep -v grep | awk '{print $2}'`
name=$2
# /opt/openresty-systemtap-toolkit/ngx-active-reqs -p 496435
# /opt/openresty-systemtap-toolkit/sample-bt -p 496435 -t 5 -k > a.bt
# kernel-debuginfo-common kernel-debuginfo
# apt install -y kernel-debuginfo-common kernel-debuginfo
# apt install -y kernel-*
# /opt/stapxx/samples/lj-lua-stacks.sxx --arg time=5 --skip-badvars -x 45266 > tmp.bt
if [ ! -d /opt/openresty-systemtap-toolkit ];then
cd /opt && git clone https://github.com/openresty/openresty-systemtap-toolkit
fi
if [ ! -d /opt/stapxx ];then
cd /opt && git clone https://github.com/openresty/stapxx
fi
# stap++ -I ./tapset -x 45266 --arg limit=10 samples/ngx-upstream-post-conn.sxx
# dpkg -i --force-overwrite /var/cache/apt/archives/linux-tools-common_5.4.0-128.144_all.deb
# /opt/openresty-systemtap-toolkit/ngx-active-reqs -p 45266
# git clone git://sourceware.org/git/systemtap.git
# ./configure --prefix=/opt/stap --disable-docs --disable-publican --disable-refdocs CFLAGS="-g -O2"
if [ ! -d /opt/FlameGraph ];then
cd /opt && git clone https://github.com/brendangregg/FlameGraph
fi
if [ $1 == "lua" ]; then
# /opt/openresty-systemtap-toolkit/ngx-sample-lua-bt -p 377452 --luajit20 -t 30 >temp.bt
/opt/openresty-systemtap-toolkit/ngx-sample-lua-bt -p $pid --luajit20 -t 30 >temp.bt
# /opt/openresty-systemtap-toolkit/fix-lua-bt temp.bt >t1.bt
/opt/openresty-systemtap-toolkit/fix-lua-bt temp.bt >${name}.bt
elif [ $1 == "c" ]; then
# /opt/openresty-systemtap-toolkit/sample-bt -p 496435 -t 10 -u > t2.bt
/opt/openresty-systemtap-toolkit/sample-bt -p $pid -t 10 -u > ${name}.bt
else
echo "type is only lua/c"
exit
fi
# /opt/FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
# /opt/FlameGraph/flamegraph.pl perf.folded > perf.svg
/opt/FlameGraph/stackcollapse-stap.pl ${name}.bt >${name}.cbt
/opt/FlameGraph/flamegraph.pl ${name}.cbt >${name}.svg
rm -f temp.bt ${name}.bt ${name}.cbt
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
# cd /www/server/mdserver-web/plugins/op_waf/t && sh ngx_demo.sh
# cd /www/wwwroot/dev156.cachecha.com && sh ngx_demo.sh
# only openresty
# pid=`ps -ef|grep openresty | grep -v grep | awk '{print $2}'`
# perf record -F 99 -p $pid -g -- sleep 60
#全部
perf record -F 99 -g -a -- sleep 60
perf script -i perf.data &> perf.unfold
/opt/FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
/opt/FlameGraph/flamegraph.pl perf.folded > perf.svg
+29
View File
@@ -0,0 +1,29 @@
# 火焰图安装 [ubuntu 20.04]
```
sudo apt-get install -y linux-tools-common linux-tools-generic linux-tools-`uname -r`
apt-get update -y
sudo apt -y install elfutils
apt-get install -y systemtap gcc
sudo apt-get install -y linux-headers-generic gcc libcap-dev
apt install -y kernel-debuginfo-common kernel-debuginfo
```
# 测试有效性
```
stap -ve 'probe begin { log("hello systemtap!") exit() }'
stap -e 'probe kernel.function("sys_open") {log("hello world") exit()}'
stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}'
```
# openresty 测试
```
cd /www/server/mdserver-web/plugins/op_waf/t && sh ngx_debug.sh lua t1
cd /www/server/mdserver-web/plugins/op_waf/t && sh ngx_debug.sh c t2
```
+17 -2
View File
@@ -2,6 +2,21 @@
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# apt -y install apache2-utils
# yum -y install httpd-tools
# ab -c 3000 -n 10000000 http://www.zzzvps.com/
# /cc https://www.zzzvps.com/ 120
# ab -c 10 -n 1000 http://t1.cn/wp-admin/index.php
# ab -c 1000 -n 1000000 http://dev156.cachecha.com/
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
python3 index.py
+16 -7
View File
@@ -52,7 +52,7 @@ def createBgTask():
removeBgTask()
args = {
"period": "minute-n",
"minute-n": "3",
"minute-n": "1",
}
createBgTaskByName(getPluginName(), args)
@@ -71,7 +71,7 @@ def createBgTaskByName(name, args):
print("计划任务已经存在!")
return True
import crontab_api
api = crontab_api.crontab_api()
cron_api = crontab_api.crontab_api()
period = args['period']
_hour = ''
@@ -87,16 +87,18 @@ def createBgTaskByName(name, args):
_where1 = args['minute-n']
_minute = ''
mw_dir = mw.getRunDir()
cmd = '''
mw_dir=%s
rname=%s
plugin_path=%s
script_path=%s
logs_file=$plugin_path/${rname}.log
''' % (name, getServerDir(), getPluginDir())
''' % (mw_dir, name, getServerDir(), getPluginDir())
cmd += 'echo "★【`date +"%Y-%m-%d %H:%M:%S"`】 STSRT★" >> $logs_file' + "\n"
cmd += 'echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" >> $logs_file' + "\n"
cmd += 'echo "python3 $script_path/tool_task.py run >> $logs_file 2>&1"' + "\n"
cmd += 'python3 $script_path/tool_task.py run >> $logs_file 2>&1' + "\n"
cmd += 'echo "cd $mw_dir && source bin/activate && python3 $script_path/tool_task.py run >> $logs_file 2>&1"' + "\n"
cmd += 'cd $mw_dir && source bin/activate && python3 $script_path/tool_task.py run >> $logs_file 2>&1' + "\n"
cmd += 'echo "【`date +"%Y-%m-%d %H:%M:%S"`】 END★" >> $logs_file' + "\n"
cmd += 'echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" >> $logs_file' + "\n"
@@ -115,7 +117,7 @@ logs_file=$plugin_path/${rname}.log
'urladdress': '',
}
task_id = api.add(params)
task_id = cron_api.add(params)
if task_id > 0:
cfg["task_id"] = task_id
cfg["name"] = name
@@ -144,8 +146,15 @@ def removeBgTask():
return False
def getCpuUsed():
import psutil
used = psutil.cpu_percent(interval=1)
path = getServerDir() + "/cpu.info"
mw.writeFile(path, str(int(used)))
def run():
print('op lua run ok')
getCpuUsed()
if __name__ == "__main__":
if len(sys.argv) > 1:
+1
View File
@@ -0,0 +1 @@
自动生成配置文件
+1 -1
View File
@@ -1 +1 @@
{"reqfile_path": "{$WAF_PATH}/html", "retry": {"retry_time": 180, "is_open_global": 0, "retry": 6, "retry_cycle": 60}, "log": true, "scan": {"status": 444, "ps": "\u8fc7\u6ee4\u5e38\u89c1\u626b\u63cf\u6d4b\u8bd5\u5de5\u5177\u7684\u6e17\u900f\u6d4b\u8bd5", "open": true, "reqfile": ""}, "cc": {"status": 444, "ps": "\u8fc7\u8651CC\u653b\u51fb", "limit": 120, "endtime": 300, "open": true, "reqfile": "", "cycle": 60}, "get": {"status": 403, "ps": "\u8fc7\u6ee4uri\u3001uri\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "get.html"}, "log_save": 30, "user-agent": {"status": 403, "ps": "\u901a\u5e38\u7528\u4e8e\u8fc7\u6ee4\u6d4f\u89c8\u5668\u3001\u8718\u86db\u53ca\u4e00\u4e9b\u81ea\u52a8\u626b\u63cf\u5668", "open": true, "reqfile": "user_agent.html"}, "other": {"status": 403, "ps": "\u5176\u5b83\u975e\u901a\u7528\u8fc7\u6ee4", "reqfile": "other.html"}, "cookie": {"status": 403, "ps": "\u8fc7\u6ee4\u5229\u7528Cookie\u53d1\u8d77\u7684\u6e17\u900f\u653b\u51fb", "open": true, "reqfile": "cookie.html"}, "logs_path": "/www/wwwlogs/btwaf", "post": {"status": 403, "ps": "\u8fc7\u6ee4POST\u53c2\u6570\u4e2d\u5e38\u89c1sql\u6ce8\u5165\u3001xss\u7b49\u653b\u51fb", "open": true, "reqfile": "post.html"}, "open": true}
{"reqfile_path": "{$WAF_PATH}/html", "retry": {"retry_time": 180, "is_open_global": 0, "retry": 6, "retry_cycle": 60}, "log": true, "scan": {"status": 444, "ps": "过滤常见扫描测试工具的渗透测试", "open": true, "reqfile": ""}, "cc": {"status": 444, "ps": "过虑CC攻击", "limit": 120, "endtime": 300, "open": true,"cycle": 60}, "safe_verify":{"status": 200,"ps": "强制安全校验", "reqfile": "safe_js.html","open": false,"cpu":50,"auto":true,"time":86400 },"get": {"status": 200, "ps": "过滤uri、uri参数中常见sql注入、xss等攻击", "open": true, "reqfile": "get.html"}, "log_save": 30, "user-agent": {"status": 200, "ps": "通常用于过滤浏览器、蜘蛛及一些自动扫描器", "open": true, "reqfile": "user_agent.html"}, "other": {"status": 200, "ps": "其它非通用过滤", "reqfile": "other.html"}, "cookie": {"status": 200, "ps": "过滤利用Cookie发起的渗透攻击", "open": true, "reqfile": "cookie.html"}, "logs_path": "/www/wwwlogs/waf", "post": {"status": 200, "ps": "过滤POST参数中常见sql注入、xss等攻击", "open": true, "reqfile": "post.html"}, "open": true}
+1 -1
View File
@@ -7,7 +7,7 @@
*{margin:0;padding:0;color:#444}
body{font-size:14px;font-family:"宋体"}
.main{width:600px;margin:10% auto;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
.t2{margin-bottom:8px; font-weight:bold}
+1 -1
View File
@@ -7,7 +7,7 @@
*{margin:0;padding:0;color:#444}
body{font-size:14px;font-family:"宋体"}
.main{width:600px;margin:10% auto;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
.t2{margin-bottom:8px; font-weight:bold}
+1 -1
View File
@@ -7,7 +7,7 @@
*{margin:0;padding:0;color:#444}
body{font-size:14px;font-family:"宋体"}
.main{width:600px;margin:10% auto;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
.t2{margin-bottom:8px; font-weight:bold}
+1 -1
View File
@@ -7,7 +7,7 @@
*{margin:0;padding:0;color:#444}
body{font-size:14px;font-family:"宋体"}
.main{width:600px;margin:10% auto;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
.t2{margin-bottom:8px; font-weight:bold}
+151
View File
@@ -0,0 +1,151 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>OP网站防火墙|安全校验</title>
<style>
*{margin:0;padding:0;color:#444}
.main{width:600px;margin:10% auto;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
#change{
font-size: 200px;
text-align: center;
}
</style>
</head>
<body>
<div class="main">
<div class="title">OP网站防火墙|安全校验</div>
<div class="content">
<p id="change">5</p>
</div>
<div id="status" style="display: none;">false</div>
</div>
</body>
<script type="text/javascript">
function ajax(type,bool){
var xhr = {};
if(typeof(type)=='undefined'){
xhr.type='HTML';
}else{
xhr.type=type.toUpperCase();
}
if(typeof(bool)=='undefined'){
xhr.async=true;
}else{
xhr.async=bool;
}
xhr.url = '';
xhr.send = '';
xhr.result=null;
xhr.createXHR = function(){
try{
request = new XMLHttpRequest();
if(request.overrideMimeType){
request.overrideMimeType('text/html');
}
}catch(e){
var v = ['Microsoft.XMLHTTP', 'MSXML.XMLHTTP', 'Microsoft.XMLHTTP',
'Msxml2.XMLHTTP.7.0', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0',
'Msxml2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP'];
for(var i=0;i<v.length;i++){
try{
request = new ActiveXObject(v[i]);
if(request){return request;}
}catch(e){continue;
}
}
}
return request;
}
xhr.XHR = xhr.createXHR();
xhr.processHandle = function(){
if( xhr.XHR.readyState ==4 && xhr.XHR.status==200){
if(xhr.type=='HTML'){
xhr.result(xhr.XHR.responseText);
return xhr.XHR.responseText;
}else if(xhr.type=='JSON'){
xhr.result(eval('('+xhr.XHR.responseText+')'));
return eval('('+xhr.XHR.responseText+')');
}else{
xhr.result(xhr.XHR.responseXML);
return xhr.XHR.responseXML;
}
}
};
xhr.get = function(url,result){
//添加回调函数
var name ='PHPjs';
var r = name + '_' + Math.random().toString().substr(2);//随机
xhr.url = url+'&'+name+'='+r;
if(result!=null){
xhr.XHR.onreadystatechange = xhr.processHandle;
xhr.result = result;
}
if(window.XMLHttpRequest){
xhr.XHR.open('GET',xhr.url,xhr.async);
xhr.XHR.send(null);
}else{
xhr.XHR.open('GET',xhr.url,xhr.async);
xhr.XHR.send();
}
};
xhr.post = function(url,send,result){
xhr.url = url;
if(typeof(send) == 'object'){
var str = '';
for(var pro in send){
str +=pro +'='+send[pro]+'&';
}
xhr.send = str.substr(0,str.length-1);
}else{
xhr.send = send;
}
if(result!=null){
xhr.XHR.onreadystatechange = xhr.processHandle;
xhr.result = result;
}
xhr.XHR.open('POST',url,xhr.async);
xhr.XHR.setRequestHeader('request-type','ajax');
xhr.XHR.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xhr.XHR.send(xhr.send);
}
return xhr;
}
ajax('JSON',true).post('{uri}',{'pass':"ok"}, function(data){
if (data['status'] == 0){
document.getElementById('status').innerHTML = 'ok';
location.reload();
}
});
var ok = setInterval(function(){
var id = document.getElementById('change').innerHTML;
id = id - 1;
if (id == 0){
document.getElementById('change').innerHTML = '稍等';
clearInterval(ok);
if (document.getElementById('status').innerHTML == 'ok'){
location.reload();
}
} else {
document.getElementById('change').innerHTML = id;
}
},1000);
</script>
</html>
+1 -1
View File
@@ -7,7 +7,7 @@
*{margin:0;padding:0;color:#444}
body{font-size:14px;font-family:"宋体"}
.main{width:600px;margin:10% auto;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;text-align: center;}
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
.t2{margin-bottom:8px; font-weight:bold}
+494 -182
View File
@@ -1,26 +1,255 @@
local setmetatable = setmetatable
local _M = { _VERSION = '0.01' }
local _M = { _VERSION = '0.02' }
local mt = { __index = _M }
local json = require "cjson"
local sqlite3 = require "lsqlite3"
local ngx_match = ngx.re.find
local debug_mode = false
local waf_root = "{$WAF_ROOT}"
local cpath = waf_root.."/waf/"
local log_dir = waf_root.."/logs/"
local rpath = cpath.."/rule/"
function _M.new(self, cpath, rpath, logdir)
-- ngx.log(ngx.ERR,"read:"..cpath..",rpath:"..rpath)
local opt = {
cpath = cpath,
rpath = rpath,
logdir = logdir,
config = '',
site_config = '',
params = nil
function _M.new(self)
local self = {
waf_root = waf_root,
cpath = cpath,
rpath = rpath,
logdir = log_dir,
config = '',
site_config = '',
server_name = '',
global_tatal = nil,
params = nil,
}
local p = setmetatable(opt, mt)
return p
return setmetatable(self, mt)
end
function _M.getInstance(self)
if rawget(self, "instance") == nil then
rawset(self, "instance", self:new())
if 0 == ngx.worker.id() then
self:cron()
end
end
assert(self.instance ~= nil)
return self.instance
end
function _M.initDB(self)
local path = log_dir .. "/waf.db"
db, err = sqlite3.open(path)
if err then
self:D("initDB err:"..tostring(err))
return nil
end
db:exec([[PRAGMA synchronous = 0]])
db:exec([[PRAGMA cache_size = 8000]])
db:exec([[PRAGMA page_size = 32768]])
db:exec([[PRAGMA journal_mode = wal]])
db:exec([[PRAGMA journal_size_limit = 1073741824]])
return db
end
-- 后台任务
function _M.cron(self)
local timer_every_get_data = function (premature)
self.clean_log()
end
ngx.timer.every(10, timer_every_get_data)
local timer_every_import_data = function (premature)
local llen, _ = ngx.shared.waf_limit:llen('waf_limit_logs')
if llen == 0 then
return true
end
local db = self:initDB()
local stmt2 = db:prepare[[INSERT INTO logs(time, ip, domain, server_name, method, status_code, uri, user_agent, rule_name, reason)
VALUES(:time, :ip, :domain, :server_name, :method, :status_code, :uri, :user_agent, :rule_name, :reason)]]
db:exec([[BEGIN TRANSACTION]])
for i=1,llen do
local data, _ = ngx.shared.waf_limit:lpop('waf_limit_logs')
-- self:D("waf_limit_logs:"..data)
if not data then
break
end
local info = json.decode(data)
stmt2:bind_names{
time=info["time"],
ip=info["ip"],
domain=info["server_name"],
server_name=info["server_name"],
method=info["method"],
status_code=info["status_code"],
user_agent=info["user_agent"],
uri=info["request_uri"],
rule_name=info['rule_name'],
reason=info['reason']
}
local res, err = stmt2:step()
if tostring(res) == "5" then
self.D("waf the step database connection is busy, so it will be stored later.")
return false
end
stmt2:reset()
end
local res, err = db:execute([[COMMIT]])
if db and db:isopen() then
db:close()
end
end
ngx.timer.every(0.5, timer_every_import_data)
end
function _M.clean_log(self)
local db = self:initDB()
local now_date = os.date("*t")
local save_day = 90
local save_date_timestamp = os.time{year=now_date.year,
month=now_date.month, day=now_date.day-save_day, hour=0}
-- delete expire data
db:exec("DELETE FROM web_logs WHERE time<"..tostring(save_date_timestamp))
end
function _M.log(self, args, rule_name, reason)
args["rule_name"] = rule_name
args["reason"] = reason
local push_data = json.encode(args)
ngx.shared.waf_limit:rpush("waf_limit_logs", push_data)
-- self:D("push_data:"..push_data)
-- local db = self:initDB()
-- local stmt2 = db:prepare[[INSERT INTO logs(time, ip, domain, server_name, method, status_code, uri, user_agent, rule_name, reason)
-- VALUES(:time, :ip, :domain, :server_name, :method, :status_code, :uri, :user_agent, :rule_name, :reason)]]
-- db:exec([[BEGIN TRANSACTION]])
-- stmt2:bind_names{
-- time=args["time"],
-- ip=args["ip"],
-- domain=args["server_name"],
-- server_name=args["server_name"],
-- method=args["method"],
-- status_code=args["status_code"],
-- user_agent=args["user_agent"],
-- uri=args["request_uri"],
-- rule_name=rule_name,
-- reason=reason
-- }
-- local res, err = stmt2:step()
-- -- self:D("LOG[1]:"..tostring(res)..":"..tostring(err))
-- if tostring(res) == "5" then
-- self.D("waf the step database connection is busy, so it will be stored later.")
-- return false
-- end
-- stmt2:reset()
-- local res, err = db:execute([[COMMIT]])
-- -- self:D("LOG[2]:"..tostring(res)..":"..tostring(err))
-- if db and db:isopen() then
-- db:close()
-- end
-- return true
end
function _M.setDebug(self, mode)
debug_mode = mode
end
-- 调试方式
function _M.D(self, msg)
if not debug_mode then return true end
local _msg = ''
if type(msg) == 'table' then
for key, val in pairs(msg) do
_msg = tostring( key)..':'.."\n"
end
elseif type(msg) == 'string' then
_msg = msg
elseif type(msg) == 'nil' then
_msg = 'nil'
else
_msg = msg
end
local fp = io.open(waf_root.."/debug.log", "ab")
if fp == nil then
return nil
end
-- local localtime = os.date("%Y-%m-%d %H:%M:%S")
local localtime = ngx.localtime()
if server_name then
fp:write(tostring(_msg) .. "\n")
else
fp:write(localtime..":"..tostring(_msg) .. "\n")
end
fp:flush()
fp:close()
return true
end
function _M.is_working(self,sign)
local work_status = ngx.shared.waf_limit:get(sign.."_working")
if work_status ~= nil and work_status == true then
return true
end
return false
end
function _M.lock_working(self, sign)
local working_key = sign.."_working"
ngx.shared.waf_limit:set(working_key, true, 60)
end
function _M.unlock_working(self, sign)
local working_key = sign.."_working"
ngx.shared.waf_limit:set(working_key, false)
end
local function write_file_clear(filename, body)
fp = io.open(filename,'w')
if fp == nil then
return nil
end
fp:write(body)
fp:flush()
fp:close()
return true
end
function _M.setConfData( self, config, site_config )
self.config = config
self.site_config = site_config
@@ -64,11 +293,11 @@ function _M.is_max(self,ip1,ip2)
end
function _M.split(self, str,reps )
local resultStrList = {}
local rsList = {}
string.gsub(str,'[^'..reps..']+',function(w)
table.insert(resultStrList,w)
table.insert(rsList,w)
end)
return resultStrList
return rsList
end
function _M.arrip(self, ipstr)
@@ -94,28 +323,41 @@ function _M.compare_ip(self,ips)
end
function _M.return_message(self, status, msg)
ngx.header.content_type = "application/json;"
ngx.status = status
ngx.say(json.encode(msg))
ngx.exit(status)
function _M.to_json(self, msg)
return json.encode(msg)
end
function _M.return_state(status,msg)
result = {}
result['status'] = status
result['msg'] = msg
return result
end
function _M.return_html(self,status,html)
function _M.return_message(self, status, msg)
ngx.header.content_type = "application/json"
local data = self:return_state(status, msg)
ngx.say(json.encode(data))
ngx.exit(200)
end
function _M.return_html(self, status, html)
ngx.header.content_type = "text/html"
ngx.status = status
ngx.say(html)
status = tonumber(status)
-- self:D("return_html:"..tostring(status))
if status == 200 then
ngx.say(html)
end
ngx.exit(status)
end
function _M.read_file_body(self, filename)
-- ngx.log(ngx.ERR,"read_file_body:"..filename)
fp = io.open(filename, 'r')
if fp == nil then
return nil
end
fbody = fp:read("*a")
local fbody = fp:read("*a")
fp:close()
if fbody == '' then
return nil
@@ -123,7 +365,38 @@ function _M.read_file_body(self, filename)
return fbody
end
function _M.read_file(self, name)
f = self.rpath .. name .. '.json'
local fbody = self:read_file_body(f)
if fbody == nil then
return {}
end
local data = json.decode(fbody)
return data
end
function _M.select_rule(self, rules)
if not rules then return {} end
new_rules = {}
for i,v in ipairs(rules)
do
if v[1] == 1 then
table.insert(new_rules,v[2])
end
end
return new_rules
end
function _M.read_file_table( self, name )
return self:select_rule(self:read_file(name))
end
function _M.read_file_body_decode(self, name)
return json.decode(self:read_file_body(name))
end
function _M.write_file(self, filename, body)
fp = io.open(filename,'ab')
@@ -137,34 +410,9 @@ function _M.write_file(self, filename, body)
end
function _M.write_file_clear(self, filename, body)
fp = io.open(filename,'w')
if fp == nil then
return nil
end
fp:write(body)
fp:flush()
fp:close()
return true
return write_file_clear(filename, body)
end
function _M.write_drop_ip(self, is_drop, drop_time)
local filename = self.cpath .. 'drop_ip.log'
local fp = io.open(filename,'ab')
local server_name = self.params["server_name"]
local ip = self.params["server_name"]
local request_uri = self.params["request_uri"]
if fp == nil then return false end
local logtmp = {os.time(),ip,server_name,request_uri,drop_time,is_drop}
local logstr = json.encode(logtmp) .. "\n"
fp:write(logstr)
fp:flush()
fp:close()
return true
end
function _M.write_to_file(self, logstr)
local server_name = self.params['server_name']
local filename = self.logdir .. '/' .. server_name .. '_' .. ngx.today() .. '.log'
@@ -172,10 +420,19 @@ function _M.write_to_file(self, logstr)
return true
end
-- 是否文件迁入数据库中
function _M.is_migrating(self)
local migrating = self.waf_root +"/migrating"
local file = io.open(migrating, "rb")
if file then return true end
return false
end
function _M.continue_key(self,key)
key = tostring(key)
if string.len(key) > 64 then return false end;
local keys = {"content","contents","body","msg","file","files","img","newcontent"}
local keys = { "content", "contents", "body", "msg", "file", "files", "img", "newcontent" }
for _,k in ipairs(keys)
do
if k == key then return false end;
@@ -195,7 +452,7 @@ function _M.array_len(self, arr)
end
function _M.is_ipaddr(self, client_ip)
local cipn = split(client_ip,'.')
local cipn = self:split(client_ip,'.')
if self:array_len(cipn) < 4 then return false end
for _,v in ipairs({1,2,3,4})
do
@@ -206,47 +463,31 @@ function _M.is_ipaddr(self, client_ip)
return true
end
function _M.read_file_body_decode(self, filename)
return json.decode(self:read_file_body(filename))
end
function _M.select_rule(self, rules)
if not rules then return {} end
new_rules = {}
for i,v in ipairs(rules)
do
if v[1] == 1 then
table.insert(new_rules,v[2])
end
end
return new_rules
end
function _M.read_file(self, name)
f = self.rpath .. name .. '.json'
fbody = self:read_file_body(f)
if fbody == nil then
return {}
end
return json.decode(fbody)
end
function _M.read_file_table( self, name )
return self:select_rule(self:read_file('args'))
end
function _M.inc_log(self, name, rule)
local server_name = self.params['server_name']
-- 定时异步同步统计信息
function _M.timer_stats_total(self)
local total_path = self.cpath .. 'total.json'
local tbody = ngx.shared.limit:get(total_path)
if not tbody then
tbody = self:read_file_body(total_path)
if not tbody then return false end
local total = ngx.shared.waf_limit:get(total_path)
if not total then
return false
end
local total = json.decode(tbody)
return self:write_file_clear(total_path,total)
end
function _M.stats_total(self, name, rule)
local server_name = self.params['server_name']
local total_path = cpath .. 'total.json'
local total = ngx.shared.waf_limit:get(total_path)
if not total then
local tbody = self:read_file_body(total_path)
total = json.decode(tbody)
else
total = json.decode(total)
end
if not total then return false end
-- 开始计算
if not total['sites'] then total['sites'] = {} end
if not total['sites'][server_name] then total['sites'][server_name] = {} end
if not total['sites'][server_name][name] then total['sites'][server_name][name] = 0 end
@@ -256,84 +497,124 @@ function _M.inc_log(self, name, rule)
total['total'] = total['total'] + 1
total['sites'][server_name][name] = total['sites'][server_name][name] + 1
total['rules'][name] = total['rules'][name] + 1
local total_log = json.encode(total)
if not total_log then return false end
ngx.shared.limit:set(total_path,total_log)
if not ngx.shared.limit:get('mw_waf_timeout') then
self:write_file_clear(total_path,total_log)
ngx.shared.limit:set('mw_waf_timeout',1,5)
end
ngx.shared.waf_limit:set(total_path,json.encode(total))
-- 异步执行
-- 现在改再init_workder.lua 定时执行
-- ngx.timer.every(3, timer_stats_total_log)
end
---------------------------------------------------
-- 获取配置域名
function _M.get_sn(self, config_domains)
local request_name = ngx.var.server_name
local cache_name = ngx.shared.waf_limit:get(request_name)
if cache_name then return cache_name end
function _M.get_server_name(self)
local c_name = ngx.var.server_name
local my_name = ngx.shared.limit:get(c_name)
if my_name then return my_name end
local tmp = self:read_file_body(self.cpath .. 'domains.json')
if not tmp then return c_name end
local domains = json.decode(tmp)
for _,v in ipairs(domains)
for _,v in ipairs(config_domains)
do
for _,d_name in ipairs(v['domains'])
for _,cd_name in ipairs(v['domains'])
do
if c_name == d_name then
ngx.shared.limit:set(c_name,v['name'],3600)
if request_name == cd_name then
ngx.shared.waf_limit:set(request_name,v['name'],86400)
return v['name']
end
end
end
return c_name
return request_name
end
function _M.get_random(self,n)
math.randomseed(ngx.time())
local t = {
"0","1","2","3","4","5","6","7","8","9",
"a","b","c","d","e","f","g","h","i","j",
"k","l","m","n","o","p","q","r","s","t",
"u","v","w","x","y","z",
"A","B","C","D","E","F","G","H","I","J",
"K","L","M","N","O","P","Q","R","S","T",
"U","V","W","X","Y","Z",
}
local s = ""
for i =1, n do
s = s .. t[math.random(#t)]
end
return s
end
-- function _M.get_sn(self)
-- retun string.gsub(self:get_server_name(),'_','.')
-- end
function _M.is_ngx_match(self, rules, sbody, rule_name)
if rules == nil or sbody == nil then return false end
if type(sbody) == "string" then
sbody = {sbody}
end
if type(rules) == "string" then
rules = {rules}
function _M.is_ngx_match_orgin(self,rule, match, sign)
if ngx_match(ngx.unescape_uri(match), rule, "isjo") then
error_rule = rule .. ' >> ' .. sign .. ':' .. match
return true
end
return false
end
for k,body in pairs(sbody)
function _M.ngx_match_string(self, rule, content,sign)
local t = self:is_ngx_match_orgin(rule, content, sign)
if t then
return true
end
return false
end
function _M.ngx_match_list(self, rules, content)
local args_type = type(content)
for i,rule in ipairs(rules)
do
if self:continue_key(k) then
for i,rule in ipairs(rules)
do
if self.site_config[server_name] and rule_name then
local n = i - 1
for _,j in ipairs(self.site_config[server_name]['disable_rule'][rule_name])
do
if n == j then
rule = ""
end
end
end
if body and rule ~="" then
if type(body) == "string" then
if ngx_match(ngx.unescape_uri(body),rule,"isjo") then
error_rule = rule .. ' >> ' .. k .. ':' .. body
return true
end
end
if type(k) == "string" then
if ngx_match(ngx.unescape_uri(k),rule,"isjo") then
error_rule = rule .. ' >> ' .. k
return true
end
if rule[1] == 1 then
if args_type == 'string' then
-- self:D("string: "..tostring(rule[2])..":".. tostring(content)..":"..tostring(rule[3]))
local t = self:is_ngx_match_orgin(rule[2], content, rule[3])
if t then
return true
end
end
if args_type == 'table' then
for _,arg_v in pairs(content) do
-- self:D("table : "..tostring(rule[2])..":".. tostring(arg_v)..":"..tostring(rule[3]))
local t = self:is_ngx_match_orgin(rule[2], arg_v, rule[3])
if t then
return true
end
end
end
end
end
return false
end
function _M.is_ngx_match_ua(self, rules, content)
-- ngx.header.content_type = "text/html"
for i,rule in ipairs(rules)
do
-- 开启的规则,才匹配。
if rule[1] == 1 then
local t = self:is_ngx_match_orgin(rule[2], content, rule[3])
if t then
return true
end
end
end
return false
end
function _M.is_ngx_match_post(self, rules, content)
for i,rule in ipairs(rules)
do
-- 开启的规则,才匹配。
if rule[1] == 1 then
local t = self:is_ngx_match_orgin(rule[2],content, rule[3])
if t then
return true
end
end
end
return false
@@ -341,63 +622,84 @@ end
function _M.write_log(self, name, rule)
local ip = self.params['ip']
local retry = self.config['retry']['retry']
local retry_time = self.config['retry']['retry_time']
local retry_cycle = self.config['retry']['retry_cycle']
local config = self.config
local params = self.params
local ip = params['ip']
local ngx_time = ngx.time()
local count, _ = ngx.shared.drop_ip:get(ip)
local retry = config['retry']['retry']
local retry_time = config['retry']['retry_time']
local retry_cycle = config['retry']['retry_cycle']
local count = ngx.shared.waf_drop_ip:get(ip)
if count then
ngx.shared.drop_ip:incr(ip,1)
ngx.shared.waf_drop_ip:incr(ip, 1)
else
ngx.shared.drop_ip:set(ip,1,retry_cycle)
ngx.shared.waf_drop_ip:set(ip, 1, retry_cycle)
end
if self.config['log'] ~= true or self:is_site_config('log') ~= true then return false end
local method = ngx.req.get_method()
if config['log'] ~= true or self:is_site_config('log') ~= true then return false end
local method = params['method']
if error_rule then
rule = error_rule
error_rule = nil
end
local logtmp = {ngx.localtime(), ip, method, ngx.var.request_uri, ngx.var.http_user_agent, name, rule}
local logstr = json.encode(logtmp) .. "\n"
local count,_ = ngx.shared.drop_ip:get(ip)
if count > retry and name ~= 'cc' then
local safe_count,_ = ngx.shared.drop_sum:get(ip)
local count = ngx.shared.waf_drop_ip:get(ip)
-- self:D("write_log; count:" ..tostring(count).. ",retry:" .. tostring(retry) )
if (count > retry and name ~= 'cc') then
local safe_count,_ = ngx.shared.waf_drop_sum:get(ip)
if not safe_count then
ngx.shared.drop_sum:set(ip,1,86400)
ngx.shared.waf_drop_sum:set(ip, 1, 86400)
safe_count = 1
else
ngx.shared.drop_sum:incr(ip,1)
ngx.shared.waf_drop_sum:incr(ip, 1)
end
local lock_time = retry_time * safe_count
if lock_time > 86400 then lock_time = 86400 end
logtmp = {ngx.localtime(),ip,method,ngx.var.request_uri, ngx.var.http_user_agent,name,retry_cycle .. '秒以内累计超过'..retry..'次以上非法请求,封锁'.. lock_time ..'秒'}
logstr = logstr .. json.encode(logtmp) .. "\n"
ngx.shared.drop_ip:set(ip,retry+1,lock_time)
self:write_drop_ip('inc',lock_time)
retry_times = retry + 1
ngx.shared.waf_drop_ip:set(ip, retry_times, lock_time)
local reason = retry_cycle .. '秒以内累计超过'..retry..'次以上非法请求,封锁'.. lock_time ..'秒'
self:log(params, name, reason)
elseif name ~= 'cc' then
self:log(params, name, rule)
end
self:write_to_file(logstr)
self:inc_log(name,rule)
self:stats_total(name, rule)
end
function _M.get_client_ip(self)
function _M.get_real_ip(self, server_name)
local client_ip = "unknown"
if self.site_config[server_name] then
if self.site_config[server_name]['cdn'] then
for _,v in ipairs(self.site_config[server_name]['cdn_header'])
local site_config = self.site_config
if site_config[server_name] then
if site_config[server_name]['cdn'] then
local request_header = ngx.req.get_headers()
for _,v in ipairs(site_config[server_name]['cdn_header'])
do
if request_header[v] ~= nil and request_header[v] ~= "" then
local header_tmp = request_header[v]
if type(header_tmp) == "table" then header_tmp = header_tmp[1] end
client_ip = split(header_tmp,',')[1]
client_ip = self:split(header_tmp,',')[1]
-- return client_ip
break;
end
end
end
end
if string.match(client_ip,"%d+%.%d+%.%d+%.%d+") == nil or not self:is_ipaddr(client_ip) then
-- ipv6
if type(client_ip) == 'table' then client_ip = "" end
if client_ip ~= "unknown" and ngx.re.match(client_ip,"^([a-fA-F0-9]*):") then
return client_ip
end
-- ipv4
if not ngx.re.match(client_ip,"\\d+\\.\\d+\\.\\d+\\.\\d+") == nil or not self:is_ipaddr(client_ip) then
client_ip = ngx.var.remote_addr
if client_ip == nil then
client_ip = "unknown"
@@ -408,12 +710,12 @@ end
function _M.is_site_config(self,cname)
local server_name = self.params["server_name"]
if self.site_config[server_name] ~= nil then
local site_config = self.site_config
if site_config[server_name] ~= nil then
if cname == 'cc' then
return self.site_config[server_name][cname]['open']
return site_config[server_name][cname]['open']
else
return self.site_config[server_name][cname]
return site_config[server_name][cname]
end
end
return true
@@ -434,6 +736,16 @@ function _M.get_boundary(self)
end
function _M.is_key(self, arr, key)
for _,v in ipairs(arr) do
if v == key then
return true
end
end
return false
end
function _M.return_post_data(self)
if method ~= "POST" then return false end
content_length = tonumber(self.params["request_header"]['content-length'])
+322 -387
View File
@@ -1,171 +1,167 @@
local cpath = "{$WAF_PATH}/"
local rpath = "{$WAF_PATH}/rule/"
local logdir = "{$ROOT_PATH}/wwwlogs/waf/"
local json = require "cjson"
local ngx_match = ngx.re.find
local _C = require "common"
local C = _C:new(cpath, rpath, logdir)
local __WAF = require "common"
-- print(json.encode(__C))
local C = __WAF:getInstance()
local config = require "waf_config"
local site_config = require "waf_site"
local config_domains = require "waf_domains"
-- C:D("config:"..C:to_json(config))
config = C:read_file_body_decode(cpath .. 'config.json')
local site_config = C:read_file_body_decode(cpath .. 'site.json')
C:setConfData(config, site_config)
C:setDebug(true)
-- D func
local function D(msg)
local _msg = ''
if type(msg) == 'table' then
for key, val in pairs(msg) do
_msg = key..':'..val.."\n"
end
elseif type(msg) == 'string' then
_msg = msg
elseif type(msg) == 'nil' then
_msg = 'nil'
else
_msg = msg
end
if not debug_mode then return true end
local fp = io.open(cpath..'debug.log', 'ab')
if fp == nil then
return nil
end
local localtime = os.date("%Y-%m-%d %H:%M:%S")
if server_name then
fp:write(tostring(_msg) .. "\n")
else
fp:write(localtime..":"..tostring(_msg) .. "\n")
end
fp:flush()
fp:close()
return true
end
local get_html = require "html_get"
local post_html = require "html_post"
local other_html = require "html_other"
local user_agent_html = require "html_user_agent"
local cc_safe_js_html = require "html_safe_js"
function initParams()
local args_rules = require "rule_args"
local ip_white_rules = require "rule_ip_white"
local ip_black_rules = require "rule_ip_black"
local ipv6_black_rules = require "rule_ipv6_black"
local scan_black_rules = require "rule_scan_black"
local user_agent_rules = require "rule_user_agent"
local post_rules = require "rule_post"
local cookie_rules = require "rule_cookie"
local url_rules = require "rule_url"
local server_name = string.gsub(C:get_sn(config_domains),'_','.')
local function initParams()
local data = {}
data['ip'] = C:get_client_ip()
data['server_name'] = server_name
data['ip'] = C:get_real_ip(server_name)
data['ipn'] = C:arrip(data['ip'])
data['request_header'] = ngx.req.get_headers()
data['uri'] = ngx.unescape_uri(ngx.var.uri)
data['server_name'] = string.gsub(C:get_server_name(),'_','.')
data['uri_request_args'] = ngx.req.get_uri_args()
data['method'] = ngx.req.get_method()
data['request_uri'] = ngx.var.request_uri
data['status_code'] = ngx.status
data['user_agent'] = data['request_header']['user-agent']
data['cookie'] = ngx.var.http_cookie
data['time'] = ngx.time()
return data
end
local params = initParams()
C:setParams(params)
local cpu_percent = ngx.shared.waf_limit:get("cpu_usage")
if not cpu_percent then
cpu_percent = 0
end
function get_return_state(rstate,rmsg)
local function get_return_state(rstate,rmsg)
result = {}
result['status'] = rstate
result['msg'] = rmsg
return result
end
function get_waf_drop_ip()
local data = ngx.shared.drop_ip:get_keys(0)
local function get_waf_drop_ip()
local data = ngx.shared.waf_drop_ip:get_keys(0)
return data
end
local function return_json(status,msg)
ngx.header.content_type = "application/json"
result = {}
result['status'] = status
result['msg'] = msg
ngx.say(json.encode(data))
ngx.exit(200)
end
function is_chekc_table(data,strings)
local function is_chekc_table(data,strings)
if type(data) ~= 'table' then return 1 end
if not data then return 1 end
data=chekc_ip_timeout(data)
data = chekc_ip_timeout(data)
for k,v in pairs(data)
do
if strings ==v['ip'] then
if strings == v['ip'] then
return 3
end
end
return 2
end
function save_ip_on(data)
locak_file=read_file_body(cpath2 .. 'stop_ip.lock')
if not locak_file then
C:write_file(cpath2 .. 'stop_ip.lock','1')
local function remove_waf_drop_ip()
ngx.header.content_type = "application/json"
local ip = params['uri_request_args']['ip']
if not ip or not C:is_ipaddr(ip) then
local data = get_return_state(-1, "格式错误")
ngx.say(json.encode(data))
ngx.exit(200)
return true
end
name='stop_ip'
local extime=18000
data=json.encode(data)
ngx.shared.btwaf:set(cpath2 .. name,data,extime)
if not ngx.shared.btwaf:get(cpath2 .. name .. '_lock') then
ngx.shared.btwaf:set(cpath2 .. name .. '_lock',1,0.5)
C:write_file(cpath2 .. name .. '.json',data)
local sign = "remove_waf_drop_ip"
if C:is_working(sign) then
local data = get_return_state(-1, "fail")
ngx.say(json.encode(data))
ngx.exit(200)
return true
end
C:lock_working(sign)
ngx.shared.waf_drop_ip:delete(ip)
C:unlock_working(sign)
local data = get_return_state(0, "ok")
ngx.say(json.encode(data))
ngx.exit(200)
end
function remove_btwaf_drop_ip()
if not uri_request_args['ip'] or not C:is_ipaddr(uri_request_args['ip']) then return get_return_state(true,'格式错误') end
if ngx.shared.btwaf:get(cpath2 .. 'stop_ip') then
ret=ngx.shared.btwaf:get(cpath2 .. 'stop_ip')
ip_data=json.decode(ret)
result=is_chekc_table(ip_data,uri_request_args['ip'])
os.execute("sleep " .. 0.6)
ret2=ngx.shared.btwaf:get(cpath2 .. 'stop_ip')
ip_data2=json.decode(ret2)
if result == 3 then
for k,v in pairs(ip_data2)
do
if uri_request_args['ip'] == v['ip'] then
v['time']=0
end
end
end
save_ip_on(ip_data2)
local function clean_waf_drop_ip()
ngx.header.content_type = "application/json"
local sign = "clean_waf_drop_ip"
if C:is_working(sign) then
local data = get_return_state(-1, "fail")
ngx.say(json.encode(data))
ngx.exit(200)
return true
end
ngx.shared.drop_ip:delete(uri_request_args['ip'])
return get_return_state(true,uri_request_args['ip'] .. '已解封')
C:lock_working(sign)
ngx.shared.waf_drop_ip:flush_all()
C:unlock_working(sign)
local data = get_return_state(0, "ok")
ngx.say(json.encode(data))
ngx.exit(200)
end
function clean_btwaf_drop_ip()
if ngx.shared.btwaf:get(cpath2 .. 'stop_ip') then
ret2=ngx.shared.btwaf:get(cpath2 .. 'stop_ip')
ip_data2=json.decode(ret2)
for k,v in pairs(ip_data2)
do
v['time']=0
end
save_ip_on(ip_data2)
os.execute("sleep " .. 2)
end
local data = get_btwaf_drop_ip()
for _,value in ipairs(data)
do
ngx.shared.drop_ip:delete(value)
end
return get_return_state(true,'已解封所有封锁IP')
end
function min_route()
local function min_route()
if ngx.var.remote_addr ~= '127.0.0.1' then return false end
local uri = params['uri']
if uri == '/get_waf_drop_ip' then
return_message(200,get_waf_drop_ip())
ngx.header.content_type = "application/json"
local data = get_return_state(0, get_waf_drop_ip())
ngx.say(json.encode(data))
ngx.exit(200)
elseif uri == '/remove_waf_drop_ip' then
return_message(200,remove_waf_drop_ip())
remove_waf_drop_ip()
elseif uri == '/clean_waf_drop_ip' then
return_message(200,clean_waf_drop_ip())
clean_waf_drop_ip()
end
end
local get_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["get"]["reqfile"])
local post_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["post"]["reqfile"])
local user_agent_html = C:read_file_body(config["reqfile_path"] .. '/' .. config["user-agent"]["reqfile"])
local args_rules = C:read_file_table('args')
local ip_white_rules = C:read_file('ip_white')
local ip_black_rules = C:read_file('ip_black')
local scan_black_rules = C:read_file('scan_black')
function waf_args()
local function waf_get_args()
if not config['get']['open'] or not C:is_site_config('get') then return false end
if C:is_ngx_match(args_rules, params['uri_request_args'],'args') then
-- C:D("waf_get_args:"..C:to_json(args_rules)..":"..json.encode(params['uri_request_args']))
if C:ngx_match_list(args_rules, params['uri_request_args']) then
C:write_log('args','regular')
C:return_html(config['get']['status'], get_html)
return true
@@ -174,7 +170,7 @@ function waf_args()
end
function waf_ip_white()
local function waf_ip_white()
for _,rule in ipairs(ip_white_rules)
do
if C:compare_ip(rule) then
@@ -184,7 +180,8 @@ function waf_ip_white()
return false
end
function waf_ip_black()
local function waf_ip_black()
-- ipv4 ip black
for _,rule in ipairs(ip_black_rules)
do
if C:compare_ip(rule) then
@@ -192,115 +189,198 @@ function waf_ip_black()
return true
end
end
-- ipv6 ip black
for _,rule in ipairs(ipv6_black_rules)
do
if rule == params['ip'] then
ngx.exit(config['cc']['status'])
return true
end
end
return false
end
function waf_drop()
local count,_ = ngx.shared.drop_ip:get(ip)
local function waf_user_agent()
-- user_agent 过滤
-- if not config['user-agent']['open'] or not C:is_site_config('user-agent') then return false end
-- C:D("waf_user_agent;user_agent_rules:"..json.encode(user_agent_rules)..",ua:"..tostring(params['request_header']['user-agent']))
if C:is_ngx_match_ua(user_agent_rules, params['request_header']['user-agent']) then
-- C:D("waf_user_agent........... true")
C:write_log('user_agent','regular')
C:return_html(config['user-agent']['status'], user_agent_html)
return true
end
-- C:D("waf_user_agent........... false")
return false
end
local function waf_drop_ip()
local ip = params['ip']
local count = ngx.shared.waf_drop_ip:get(ip)
if not count then return false end
if count > config['retry'] then
local retry = config['retry']['retry']
-- C:D("waf_drop;count:"..tostring(count)..",retry:"..tostring(retry))
-- C:D("waf_drop;count > retry:"..tostring(count > retry))
if count > retry then
-- C:D("waf_drop_ip........... true")
ngx.exit(config['cc']['status'])
return true
end
-- C:D("waf_drop_ip........... false")
return false
end
local function waf_cc()
if not config['cc']['open'] or not C:is_site_config('cc') then return false end
function waf_user_agent()
if not config['user-agent']['open'] or not C:is_site_config('user-agent') then return false end
if C:is_ngx_match(user_agent_rules,params['request_header']['user-agent'],'user_agent') then
C:write_log('user_agent','regular')
C:return_html(config['user-agent']['status'],user_agent_html)
return true
end
return false
end
function cc()
local ip = params['ip']
local request_uri = params['request_uri']
local endtime = config['cc']['endtime']
if not config['cc']['open'] or not site_cc then return false end
-- 多次cc,才封禁。
-- local ip_lock = ngx.shared.waf_drop_ip:get(ip)
-- if ip_lock then
-- if ip_lock > 0 then
-- ngx.exit(config['cc']['status'])
-- return true
-- end
-- end
local request_uri = params['request_uri']
local token = ngx.md5(ip .. '_' .. request_uri)
local count,_ = ngx.shared.limit:get(token)
local count = ngx.shared.waf_limit:get(token)
local endtime = config['cc']['endtime']
local waf_limit = config['cc']['limit']
local cycle = config['cc']['cycle']
if count then
if count > limit then
local safe_count,_ = ngx.shared.drop_sum:get(ip)
if count > waf_limit then
local safe_count, _ = ngx.shared.waf_drop_sum:get(ip)
if not safe_count then
ngx.shared.drop_sum:set(ip,1,86400)
ngx.shared.waf_drop_sum:set(ip, 1, 86400)
safe_count = 1
else
ngx.shared.drop_sum:incr(ip,1)
ngx.shared.waf_drop_sum:incr(ip, 1)
end
local lock_time = (endtime * safe_count)
if lock_time > 86400 then lock_time = 86400 end
ngx.shared.drop_ip:set(ip,retry+1,lock_time)
C:write_log('cc',cycle..'秒内累计超过'..limit..'次请求,封锁' .. lock_time .. '秒')
C:write_drop_ip('cc',lock_time)
if not server_name then
insert_ip_list(ip,lock_time,os.time(),'1111')
else
insert_ip_list(ip,lock_time,os.time(),server_name)
end
ngx.shared.waf_drop_ip:set(ip, 1, lock_time)
local reason = cycle..'秒内累计超过'..waf_limit..'次请求,封锁' .. lock_time .. '秒'
C:write_log('cc', reason)
C:log(params, 'cc',reason)
ngx.exit(config['cc']['status'])
return true
else
ngx.shared.limit:incr(token,1)
ngx.shared.waf_limit:incr(token, 1)
end
else
ngx.shared.limit:set(token,1,cycle)
ngx.shared.waf_drop_sum:set(ip, 1, 86400)
ngx.shared.waf_limit:set(token, 1, cycle)
end
return false
end
-- 是否符合开强制验证条件
local function is_open_waf_cc_increase()
if config['safe_verify']['open'] then
return true
end
if site_config[server_name]['safe_verify']['open'] then
return true
end
if cpu_percent >= config['safe_verify']['cpu'] then
return true
end
if cpu_percent >= site_config[server_name]['safe_verify']['cpu'] then
return true
end
return false
end
--强制验证是否使用正常浏览器访问网站
function waf_cc_increase()
if not config['cc']['open'] or not site_cc then return false end
if not site_config[server_name] then return false end
if not site_config[server_name]['cc']['increase'] then return false end
local function waf_cc_increase()
if not is_open_waf_cc_increase() then return false end
local ip = params['ip']
local uri = params['uri']
local cache_token = ngx.md5(ip .. '_' .. server_name)
--判断是否已经通过验证
if ngx.shared.btwaf:get(cache_token) then return false end
if cc_uri_white() then
ngx.shared.btwaf:delete(cache_token .. '_key')
ngx.shared.btwaf:set(cache_token,1,60)
return false
if ngx.shared.waf_limit:get(cache_token) then return false end
local cache_rand_key = ip..':rand'
local cache_rand = ngx.shared.waf_limit:get(cache_rand_key)
if not cache_rand then
cache_rand = C:get_random(8)
ngx.shared.waf_limit:set(cache_rand_key,cache_rand,30)
end
if security_verification() then return false end
send_check_heml(cache_token)
local make_token = "waf_unbind_"..cache_rand.."_"..cache_token
local make_uri_str = "?token="..make_token
local make_uri = "/"..make_uri_str
if params['uri_request_args']['token'] then
local args_token = params['uri_request_args']['token']
if args_token == make_token then
ngx.shared.waf_limit:set(cache_token, 1, config['safe_verify']['time'])
local data = get_return_state(0, "ok")
ngx.say(json.encode(data))
ngx.exit(200)
end
end
local cc_html = ngx.re.gsub(cc_safe_js_html, "{uri}", make_uri_str)
C:return_html(200, cc_html)
end
function waf_url()
local function waf_url()
if not config['get']['open'] or not C:is_site_config('get') then return false end
--正则--
if C:is_ngx_match(url_rules,params["uri"],'url') then
-- C:D("waf_url:"..json.encode(url_rules)..":uri:"..params["uri"])
if C:ngx_match_list(url_rules, params["uri"]) then
C:write_log('url','regular')
C:return_html(config['get']['status'],get_html)
C:return_html(config['get']['status'], get_html)
return true
end
return false
end
function waf_scan_black()
local function waf_scan_black()
-- 扫描软件禁止
if not config['scan']['open'] or not C:is_site_config('scan') then return false end
if C:is_ngx_match(scan_black_rules['cookie'],params["request_header"]["cookie"],false) then
C:write_log('scan','regular')
ngx.exit(config['scan']['status'])
return true
end
if C:is_ngx_match(scan_black_rules['args'],params["request_uri"],false) then
if not params["cookie"] then
if C:ngx_match_string(scan_black_rules['cookie'], tostring(params["cookie"]),'scan') then
C:write_log('scan','regular')
ngx.exit(config['scan']['status'])
return true
end
end
if C:ngx_match_string(scan_black_rules['args'], params["request_uri"], 'scan') then
C:write_log('scan','regular')
ngx.exit(config['scan']['status'])
return true
end
for key,value in pairs(params["request_header"])
do
if C:is_ngx_match(scan_black_rules['header'], key, false) then
if C:ngx_match_string(scan_black_rules['header'], key, 'scan') then
C:write_log('scan','regular')
ngx.exit(config['scan']['status'])
return true
@@ -309,253 +389,120 @@ function waf_scan_black()
return false
end
function waf_post_referer()
if params['method'] ~= "POST" then return false end
if C:is_ngx_match(referer_local, params['request_header']['Referer'],'post') then
C:write_log('post_referer','regular')
C:return_html(config['post']['status'],post_html)
return true
end
return false
end
function waf_post()
local function waf_post()
if not config['post']['open'] or not C:is_site_config('post') then return false end
if params['method'] ~= "POST" then return false end
if waf_post_referer() then return true end
content_length = tonumber(params["request_header"]['content-length'])
max_len = 640 * 1020000
local content_length = tonumber(params["request_header"]['content-length'])
local max_len = 640 * 1020000
if content_length > max_len then return false end
if C:get_boundary() then return false end
ngx.req.read_body()
request_args = ngx.req.get_post_args()
if not request_args then
return false
local request_args = params['uri_request_args']
if not request_args then return false end
for key, val in pairs(request_args) do
if type(val) == "table" then
if type(val[1]) == "boolean" then
return false
end
data = table.concat(val, ", ")
else
data = val
end
end
if C:is_ngx_match(post_rules,request_args,'post') then
-- C:D("post:"..json.encode(data))
if C:ngx_match_list(post_rules, data) then
C:write_log('post','regular')
C:return_html(config['post']['status'],post_html)
C:return_html(config['post']['status'], post_html)
return true
end
return false
end
local function X_Forwarded()
function post_data_chekc()
if params['method'] =="POST" then
if C:return_post_data() then return false end
ngx.req.read_body()
request_args = ngx.req.get_post_args()
if not request_args then return false end
if request_header then
if not request_header['Content-Type'] then return false end
av = string.match(request_header['Content-Type'],"=.+")
end
if not av then return false end
ac = split(av,'=')
if not ac then return false end
list_list=nil
for i,v in ipairs(ac)
do
list_list='--'..v
end
if not list_list then return false end
aaa=nil
for k,v in pairs(request_args)
do
aaa=v
end
if not aaa then return false end
if tostring(aaa) == 'true' then return false end
if type(aaa) ~= "string" then return false end
data_len=split(aaa,list_list)
--return return_message(200,data_len)
if not data_len then return false end
if arrlen(data_len) ==0 then return false end
if C:is_ngx_match(post_rules,data_len,'post') then
C:write_log('post','regular')
C:return_html(config['post']['status'],post_html)
return true
end
end
end
function X_Forwarded()
if params['method'] ~= "GET" then return false end
if not config['get']['open'] or not C:is_site_config('get') then return false end
if C:is_ngx_match(args_rules,params["request_header"]['X-forwarded-For'],'args') then
if not params["request_header"]['X-forwarded-For'] then return false end
if C:ngx_match_list(args_rules, params["request_header"]['X-forwarded-For']) then
C:write_log('args','regular')
C:return_html(config['get']['status'],get_html)
C:return_html(config['get']['status'], get_html)
return true
end
return false
end
function post_X_Forwarded()
local function post_X_Forwarded()
if not config['post']['open'] or not C:is_site_config('post') then return false end
if params['method'] ~= "POST" then return false end
if C:is_ngx_match(post_rules,params["request_header"]['X-forwarded-For'],'post') then
if not params["request_header"]['X-forwarded-For'] then return false end
if C:is_ngx_match_list(post_rules, params["request_header"]['X-forwarded-For']) then
C:write_log('post','regular')
C:return_html(config['post']['status'],post_html)
C:return_html(config['post']['status'], post_html)
return true
end
return false
end
function php_path()
if site_config[server_name] == nil then return false end
for _,rule in ipairs(site_config[server_name]['disable_php_path'])
do
if ngx_match(uri,rule .. "/?.*\\.php$","isjo") then
C:write_log('php_path','regular')
C:return_html(config['other']['status'],other_html)
return C:return_message(200,uri)
end
end
return false
end
function url_path()
if site_config[server_name] == nil then return false end
for _,rule in ipairs(site_config[server_name]['disable_path'])
do
if ngx_match(uri,rule,"isjo") then
C:write_log('path','regular')
C:return_html(config['other']['status'],other_html)
return true
end
end
return false
end
function url_ext()
local function url_ext()
if site_config[server_name] == nil then return false end
for _,rule in ipairs(site_config[server_name]['disable_ext'])
do
if ngx_match(uri,"\\."..rule.."$","isjo") then
C:write_log('url_ext','regular')
C:return_html(config['other']['status'],other_html)
if C:ngx_match_string("\\."..rule.."$", params['uri'],'url_ext') then
if rule == "php" then
C:write_log('php_path','regular')
else
C:write_log('path','regular')
end
C:return_html(config['other']['status'], other_html)
return true
end
end
return false
end
function url_rule_ex()
if site_config[server_name] == nil then return false end
if method == "POST" and not request_args then
content_length=tonumber(request_header['content-length'])
max_len = 640 * 102400000
request_args = nil
if content_length < max_len then
ngx.req.read_body()
request_args = ngx.req.get_post_args()
end
end
for _,rule in ipairs(site_config[server_name]['url_rule'])
do
if ngx_match(uri,rule[1],"isjo") then
if C:is_ngx_match(rule[2],uri_request_args,false) then
C:write_log('url_rule','regular')
C:return_html(config['other']['status'],other_html)
return true
end
if params['method'] == "POST" and request_args ~= nil then
if C:is_ngx_match(rule[2],request_args,'post') then
C:write_log('post','regular')
C:return_html(config['other']['status'],other_html)
return true
end
end
end
end
return false
end
function url_tell()
if site_config[server_name] == nil then return false end
for _,rule in ipairs(site_config[server_name]['url_tell'])
do
if ngx_match(uri,rule[1],"isjo") then
if uri_request_args[rule[2]] ~= rule[3] then
C:write_log('url_tell','regular')
C:return_html(config['other']['status'],other_html)
return true
end
end
end
return false
end
function disable_upload_ext(ext)
local function disable_upload_ext(ext)
if not ext then return false end
ext = string.lower(ext)
if is_key(site_config[server_name]['disable_upload_ext'],ext) then
C:write_log('upload_ext','上传扩展名黑名单')
if C:is_key(site_config[server_name]['disable_upload_ext'], ext) then
C:write_log('upload_ext', '上传扩展名黑名单')
C:return_html(config['other']['status'],other_html)
return true
end
return false
end
function data_in_php(data)
if not data then
return false
else
if C:is_ngx_match('php',data,'post') then
C:write_log('upload_ext','上传扩展名黑名单')
C:return_html(config['other']['status'],other_html)
return true
else
return false
end
end
end
function post_data()
local function post_data()
if params["method"] ~= "POST" then return false end
content_length = tonumber(params["request_header"]['content-length'])
-- C:D("content-length:"..params["request_header"]['content-length'])
local content_length = tonumber(params["request_header"]['content-length'])
if not content_length then return false end
max_len = 2560 * 1024000
local max_len = 2560 * 1024000
if content_length > max_len then return false end
local boundary = C:get_boundary()
-- C:D("boundary:".. tostring( boundary) )
if boundary then
ngx.req.read_body()
local data = ngx.req.get_body_data()
if not data then return false end
local tmp = ngx.re.match(data,[[filename=\"(.+)\.(.*)\"]])
if not tmp then return false end
if not tmp[2] then return false end
local tmp2=ngx.re.match(ngx.req.get_body_data(),[[Content-Type:[^\+]{45}]])
--return return_message(200,tmp2[0])
if not tmp or not tmp[2] then return false end
-- C:D("upload_ext:".. tostring(tmp[2]) )
disable_upload_ext(tmp[2])
if tmp2 == nil then return false end
data_in_php(tmp2[0])
end
return false
end
function waf_cookie()
local function waf_cookie()
if not config['cookie']['open'] or not C:is_site_config('cookie') then return false end
if not params["request_header"]['cookie'] then return false end
if type(params["request_header"]['cookie']) ~= "string" then return false end
request_cookie = string.lower(params["request_header"]['cookie'])
if C:is_ngx_match(cookie_rules,request_cookie,'cookie') then
if C:ngx_match_list(cookie_rules,request_cookie,'cookie') then
C:write_log('cookie','regular')
C:return_html(config['cookie']['status'],cookie_html)
return true
@@ -563,55 +510,43 @@ function waf_cookie()
return false
end
function waf_referer()
if params["method"] ~= "GET" then return false end
if not config['get']['open'] or not C:is_site_config('get') then return false end
if C:is_ngx_match(referer_local,params["request_header"]['Referer'],'args') then
C:write_log('get_referer','regular')
C:return_html(config['get']['status'], get_html)
return true
end
return false
end
function waf()
min_route()
-- white ip
if waf_ip_white() then return true end
waf_ip_black()
-- black ip
if waf_ip_black() then return true end
waf_drop()
waf_user_agent()
-- 封禁ip返回
if waf_drop_ip() then return true end
waf_url()
-- ua check
if waf_user_agent() then return true end
if waf_url() then return true end
if params["method"] == "GET" then
waf_referer()
waf_cookie()
end
-- cc setting
if waf_cc_increase() then return true end
if waf_cc() then return true end
if params["method"] == "POST" then
waf_referer()
waf_cookie()
end
-- cookie检查
if waf_cookie() then return true end
-- args参数拦截
if waf_get_args() then return true end
waf_args()
waf_scan_black()
-- 扫描软件禁止
if waf_scan_black() then return true end
waf_post()
post_data_chekc()
local server_name = params["server_name"]
if site_config[server_name] then
X_Forwarded()
post_X_Forwarded()
php_path()
url_path()
url_ext()
url_rule_ex()
url_tell()
post_data()
if waf_post() then return true end
if site_config[server_name] and site_config[server_name]['open'] then
if X_Forwarded() then return true end
if post_X_Forwarded() then return true end
if url_ext() then return true end
if post_data() then return true end
end
end
+31
View File
@@ -0,0 +1,31 @@
local json = require "cjson"
local waf_root = "{$WAF_ROOT}"
local cpath = waf_root.."/waf/"
local __C = require "common"
local C = __C:getInstance()
local function timer_stats_total_log(premature)
C:timer_stats_total()
end
ngx.shared.waf_limit:set("cpu_usage", 0, 10)
function timer_every_get_cpu(premature)
local cpu_percent = C:read_file_body(waf_root.."/cpu.info")
if cpu_percent then
ngx.shared.waf_limit:set("cpu_usage", tonumber(cpu_percent), 10)
else
ngx.shared.waf_limit:set("cpu_usage", 0, 10)
end
end
if 0 == ngx.worker.id() then
ngx.timer.every(5, timer_every_get_cpu)
-- 异步执行
ngx.timer.every(3, timer_stats_total_log)
end
-1
View File
@@ -1 +0,0 @@
waf()
+1 -1
View File
@@ -1 +1 @@
[[1, "(HTTrack|Apache-HttpClient|harvest|audit|dirbuster|pangolin|nmap|sqln|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|zmeu|BabyKrokodil|netsparker|httperf| SF/)", "\u5173\u952e\u8bcd\u8fc7\u6ee41", 0]]
[[1,"(HTTrack|Apache-HttpClient|harvest|audit|dirbuster|pangolin|nmap|sqln|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|zmeu|BabyKrokodil|netsparker|httperf| SF/)","关键词过滤1",0],[1,"(ApacheBench)","AB测试",0]]
+1 -1
View File
@@ -1 +1 @@
{"rules":{"user_agent":0,"cookie":0,"post":0,"args":0,"url":0,"cc":0},"sites":{},"total":0}
{"rules":{"path":0,"php_path":0,"upload_ext":0,"user_agent":0,"scan":0,"cookie":0,"post":0,"args":0,"url":0,"cc":0},"sites":{},"total":0}
-24
View File
@@ -1,24 +0,0 @@
\.\./
\:\$
\$\{
/\*|--
\b(or|xor|and)\b.*(=|<|>|'|")
select.+(from|limit)
(?:(union(.*?)select))
having|load_file
sleep\((\s*)(\d*)(\s*)\)
benchmark\((.*)\,(.*)\)
base64_decode\(
(?:from\W+information_schema\W)
(?:(?:current_)user|database|schema|connection_id)\s*\(
(?:etc\/\W*passwd)
into(\s+)+(?:dump|out)file\s*
group\s+by.+\(
xwork.MethodAccessor
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
xwork\.MethodAccessor
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
java\.lang
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
(onmouseover|onerror|onload)\=
-1
View File
@@ -1 +0,0 @@
10.0.68.75
-20
View File
@@ -1,20 +0,0 @@
\.\./
\:\$
\$\{
select.+(from|limit)
(?:(union(.*?)select))
having|rongjitest
sleep\((\s*)(\d*)(\s*)\)
benchmark\((.*)\,(.*)\)
base64_decode\(
(?:from\W+information_schema\W)
(?:(?:current_)user|database|schema|connection_id)\s*\(
(?:etc\/\W*passwd)
into(\s+)+(?:dump|out)file\s*
group\s+by.+\(
xwork.MethodAccessor
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
xwork\.MethodAccessor
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
java\.lang
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
-7
View File
@@ -1,7 +0,0 @@
#ip 60/60 1800
#ip+uri 60/60 1800
#ip+domain+CookieParam:sessionid 60/60 1800
#ip+GetParam:userid 60/60 1800
#ip+PostParam:userid 60/60 1800
#$ip+header:imei 30/60 1800
ip+uri 60/60 3600
-18
View File
@@ -1,18 +0,0 @@
select.+(from|limit)
(?:(union(.*?)select))
\b(or|xor|and)\b.*(=|<|>|'|")
having|load_file
sleep\((\s*)(\d*)(\s*)\)
benchmark\((.*)\,(.*)\)
base64_decode\(
(?:from\W+information_schema\W)
into(\s+)+(?:dump|out)file\s*
group\s+by.+\(
xwork.MethodAccessor
(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|alert|showmodaldialog)\(
xwork\.MethodAccessor
(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/
java\.lang
\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[
\<(iframe|script|body|img|layer|div|meta|style|base|object|input)
(onmouseover|onerror|onload)\=
-39
View File
@@ -1,39 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>网站防火墙</title>
<style>
*{margin:0;padding:0;color:#444}
body{font-size:14px;font-family:"宋体"}
.main{width:600px;margin:10% auto;}
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
.content{background-color:#f3f7f9; height:280px;border:1px dashed #c6d9b6;padding:20px}
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
.t2{margin-bottom:8px; font-weight:bold}
ol{margin:0 0 20px 22px;padding:0;}
ol li{line-height:30px}
</style>
</head>
<body>
<div class="main">
<div class="title">网站防火墙</div>
<div class="content">
<p class="t1">您的请求带有不合法参数,已被网站管理员设置拦截!</p>
<p class="t2">可能原因:</p>
<ol>
<li>您提交的内容包含危险的攻击请求</li>
</ol>
<p class="t2">如何解决:</p>
<ol>
<li>检查提交内容;</li>
<li>如网站托管,请联系空间提供商;</li>
<li>普通网站访客,请联系网站管理员;</li>
<li>这是误报,请联系网站管理员;</li>
</ol>
</div>
</div>
</body>
</html>
-9
View File
@@ -1,9 +0,0 @@
\.(svn|htaccess|mysql_history|bash_history|git|DS_Store|idea|user\.ini)
\.(bak|inc|old|mdb|sh|sql|php~|swp|java|class)$
(vhost|bbs|host|wwwroot|www|site|root|backup|data|ftp|db|admin|website|web).*\.(rar|sql|zip|tar\.gz|tar)
(elastic|jmx-console|jmxinvokerservlet)
java\.lang
/CSV/
/(hack|shell|spy|phpspy)\.php$
(manager|host-manager)/html$
/(attachments|upimg|images|css|uploadfiles|html|uploads|templets|static|template|data|forumdata|upload|includes|cache|avatar)/(\\w+).(php|jsp)
-1
View File
@@ -1 +0,0 @@
(HTTrack|Apache-HttpClient|harvest|audit|dirbuster|pangolin|nmap|sqln|hydra|Parser|libwww|BBBike|sqlmap|w3af|owasp|Nikto|fimap|havij|zmeu|BabyKrokodil|netsparker|httperf|bench| SF/)
-2
View File
@@ -1,2 +0,0 @@
127.0.0.1
^192\.168\.
+3
View File
@@ -64,6 +64,9 @@ Install_openresty()
--with-http_slice_module \
--with-http_stub_status_module \
--with-http_realip_module
# --without-luajit-gc64
# --with-debug
# 用于调式
make -j${cpuCore} && make install && make clean
+1
View File
@@ -5,6 +5,7 @@ group = {$PHP_GROUP}
listen = /run/php/php{$PHP_VERSION}-fpm.sock
listen.owner = {$PHP_USER}
listen.group = {$PHP_GROUP}
listen.backlog = 4096
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
+39
View File
@@ -1,3 +1,41 @@
<style type="text/css">
.bt-w-main{
height: 600px;
}
.session_clear_list {
border:1px solid #ececec;
margin-bottom: 15px;
width: 270px;
}
.session_clear_list .line {
padding: 0;
border-bottom: 1px solid #ececec;
width: 270px;
}
.session_clear_list .line:last-child {
border-bottom: 0px;
}
.session_clear_list .line span{
width: auto;
height: 35px;
line-height: 35px;
text-align: left;
padding: 0 5px;
}
.session_clear_list .line span:first-child {
width: 170px;
border-right: 1px solid #ececec;
background: #f7f7f7;
float: left;
}
</style>
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
@@ -13,6 +51,7 @@
<p onclick="disableFunc($('.plugin_version').attr('version'));">禁用函数</p>
<p onclick="getFpmConfig($('.plugin_version').attr('version'));">性能调整</p>
<p onclick="getFpmStatus($('.plugin_version').attr('version'));">负载状况</p>
<p onclick="getSessionConfig($('.plugin_version').attr('version'));" title="session管理">会话管理</p>
<p onclick="pluginLogs('php-apt',$('.plugin_version').attr('version'),'fpm_log');">FPM日志</p>
<p onclick="pluginLogs('php-apt',$('.plugin_version').attr('version'),'fpm_slow_log');">慢日志</p>
<p onclick="getPhpinfo($('.plugin_version').attr('version'));">PHPIFNO</p>
+182
View File
@@ -490,6 +490,180 @@ def getFpmStatus(version):
return mw.returnJson(True, "OK", data)
def getSessionConf(version):
filename = getConf(version)
if not os.path.exists(filename):
return mw.returnJson(False, '指定PHP版本不存在!')
phpini = mw.readFile(filename)
rep = r'session.save_handler\s*=\s*([0-9A-Za-z_& ~]+)(\s*;?|\r?\n)'
save_handler = re.search(rep, phpini)
if save_handler:
save_handler = save_handler.group(1)
else:
save_handler = "files"
reppath = r'\nsession.save_path\s*=\s*"tcp\:\/\/([\d\.]+):(\d+).*\r?\n'
passrep = r'\nsession.save_path\s*=\s*"tcp://[\w\.\?\:]+=(.*)"\r?\n'
memcached = r'\nsession.save_path\s*=\s*"([\d\.]+):(\d+)"'
save_path = re.search(reppath, phpini)
if not save_path:
save_path = re.search(memcached, phpini)
passwd = re.search(passrep, phpini)
port = ""
if passwd:
passwd = passwd.group(1)
else:
passwd = ""
if save_path:
port = save_path.group(2)
save_path = save_path.group(1)
else:
save_path = ""
data = {"save_handler": save_handler, "save_path": save_path,
"passwd": passwd, "port": port}
return mw.returnJson(True, 'ok', data)
def setSessionConf(version):
args = getArgs()
ip = args['ip']
port = args['port']
passwd = args['passwd']
save_handler = args['save_handler']
if save_handler != "file":
iprep = r"(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})"
if not re.search(iprep, ip):
return mw.returnJson(False, '请输入正确的IP地址')
try:
port = int(port)
if port >= 65535 or port < 1:
return mw.returnJson(False, '请输入正确的端口号')
except:
return mw.returnJson(False, '请输入正确的端口号')
prep = r"[\~\`\/\=]"
if re.search(prep, passwd):
return mw.returnJson(False, '请不要输入以下特殊字符 " ~ ` / = "')
filename = getConf(version)
if not os.path.exists(filename):
return mw.returnJson(False, '指定PHP版本不存在!')
phpini = mw.readFile(filename)
session_tmp = getServerDir() + "/tmp/session"
rep = r'session.save_handler\s*=\s*(.+)\r?\n'
val = r'session.save_handler = ' + save_handler + '\n'
phpini = re.sub(rep, val, phpini)
content = mw.execShell(
'cat /etc/php/' + version + '/fpm/conf.d/*' + " | grep -v '^;' |tr -s '\n'")
content = content[0]
if save_handler == "memcached":
if not re.search("memcached.so", phpini):
return mw.returnJson(False, '请先安装%s扩展' % save_handler)
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "%s:%s" \n' % (ip, port)
if re.search(rep, phpini):
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "' + "/var/lib/php/sessions" + '"',
'\n;session.save_path = "' + "/var/lib/php/sessions" + '"' + val, phpini)
if save_handler == "memcache":
if not content.find('memcache') > -1:
return mw.returnJson(False, '请先安装%s扩展' % save_handler)
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "%s:%s" \n' % (ip, port)
if re.search(rep, phpini):
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "' + "/var/lib/php/sessions" + '"',
'\n;session.save_path = "' + "/var/lib/php/sessions" + '"' + val, phpini)
if save_handler == "redis":
if not content.find('redis') > -1:
return mw.returnJson(False, '请先安装%s扩展' % save_handler)
if passwd:
passwd = "?auth=" + passwd
else:
passwd = ""
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "tcp://%s:%s%s"\n' % (ip, port, passwd)
res = re.search(rep, phpini)
if res:
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "' + "/var/lib/php/sessions" + '"',
'\n;session.save_path = "' + "/var/lib/php/sessions" + '"' + val, phpini)
if save_handler == "file":
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "' + session_tmp + '"\n'
if re.search(rep, phpini):
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "' + "/var/lib/php/sessions" + '"',
'\n;session.save_path = "' + "/var/lib/php/sessions" + '"' + val, phpini)
mw.writeFile(filename, phpini)
reload(version)
return mw.returnJson(True, '设置成功!')
def getSessionCount_Origin(version):
session_tmp = getServerDir() + "/tmp/session"
d = ["/tmp", "/var/lib/php/sessions", session_tmp]
count = 0
for i in d:
if not os.path.exists(i):
mw.execShell('mkdir -p %s' % i)
list = os.listdir(i)
for l in list:
if os.path.isdir(i + "/" + l):
l1 = os.listdir(i + "/" + l)
for ll in l1:
if "sess_" in ll:
count += 1
continue
if "sess_" in l:
count += 1
s = "find /tmp -mtime +1 |grep 'sess_' | wc -l"
old_file = int(mw.execShell(s)[0].split("\n")[0])
s = "find " + session_tmp + " -mtime +1 |grep 'sess_'|wc -l"
old_file += int(mw.execShell(s)[0].split("\n")[0])
return {"total": count, "oldfile": old_file}
def getSessionCount(version):
data = getSessionCount_Origin(version)
return mw.returnJson(True, 'ok!', data)
def cleanSessionOld(version):
s = "find /tmp -mtime +1 |grep 'sess_'|xargs rm -f"
mw.execShell(s)
session_tmp = getServerDir() + "/tmp/session"
s = "find " + session_tmp + " -mtime +1 |grep 'sess_' |xargs rm -f"
mw.execShell(s)
old_file_conf = getSessionCount_Origin(version)["oldfile"]
if old_file_conf == 0:
return mw.returnJson(True, '清理成功')
else:
return mw.returnJson(True, '清理失败')
def getDisableFunc(version):
filename = getConf(version)
if not os.path.exists(filename):
@@ -688,6 +862,14 @@ if __name__ == "__main__":
print(setFpmConfig(version))
elif func == 'get_fpm_status':
print(getFpmStatus(version))
elif func == 'get_session_conf':
print(getSessionConf(version))
elif func == 'set_session_conf':
print(setSessionConf(version))
elif func == 'get_session_count':
print(getSessionCount(version))
elif func == 'clean_session_old':
print(cleanSessionOld(version))
elif func == 'get_disable_func':
print(getDisableFunc(version))
elif func == 'set_disable_func':
+145
View File
@@ -368,6 +368,151 @@ function disableFunc(version) {
$(".soft-man-con").html(con);
});
}
function getSessionConfig(version){
phpPost('get_session_conf', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
if(!rdata.status){
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
return;
}
var rdata = rdata.data;
var cacheList = "<option value='file' " + (rdata.save_handler == "file" ? 'selected' : '') + ">file</option>" +
"<option value='redis' " + (rdata.save_handler == "redis" ? 'selected' : '') + ">redis</option>" +
"<option value='memcache' " + (rdata.save_handler == "memcache" ? 'selected' : '') + ">memcache</option>" +
"<option value='memcached' " + (rdata.save_handler == "memcached" ? 'selected' : '') + ">memcached</option>";
var info = rdata.save_path.split(":");
var con = "<div class='conf_p'>" +
"<p class='line'><span class='span_tit'>存储模式:</span><select class='bt-input-text' name='save_handler' style='width:200px;'>" + cacheList + "</select></p>" +
"<p class='line'><span class='span_tit'>IP地址:</span><input class='bt-input-text' type='text' name='ip' style='width:200px;' value='"+ info[0] +"' /></p>" +
"<p class='line'><span class='span_tit'>端口:</span><input class='bt-input-text' type='text' name='port' style='width:200px;' value='"+rdata.port+"' /></p>" +
"<p class='line'><span class='span_tit'>密码:</span><input class='bt-input-text' type='text' name='passwd' style='width:200px;' value='"+rdata.passwd+"' /></p>" +
"<p class='line'><div class='mtb15' style='margin-left:100px;'><button class='btn btn-success btn-sm' onclick='setSessionConfig(\"" + version + "\",1)'>保存</button></div></p>" +
"</div>\
<ul class='help-info-text c7'>\
<li>若你的站点并发比较高,使用Redis,Memcache能有效提升PHP并发能力</li>\
<li>若调整Session模式后,网站访问异常,请切换回原来的模式</li>\
<li>切换Session模式会使在线的用户会话丢失,请在流量小的时候切换</li>\
</ul>\
<div id='session_clear' class='session_clear' style='border-top: #ccc 1px dashed;padding-top: 15px;margin-top: 15px;'>\
</div>\
</div>";
$(".soft-man-con").html(con);
if (rdata.save_handler == 'file'){
$('input[name="ip"]').attr('disabled','disabled');
$('input[name="port"]').attr('disabled','disabled');
$('input[name="passwd"]').attr('placeholder','如果没有密码留空');
$('input[name="passwd"]').attr('disabled','disabled');
}
// change event
$("select[name='save_handler']").change(function() {
var type = $(this).val();
var passwd = $('input[name="passwd"]').val();
if (passwd == ""){
$('input[name="passwd"]').attr('placeholder','如果没有密码留空');
}
var ip = $('input[name="ip"]').val();
if (ip == ""){
$('input[name="ip"]').val('127.0.0.1');
}
switch (type) {
case 'redis':
var port = $('input[name="port"]').val();
if (port == ""){
$('input[name="port"]').val('6379');
}
$('input[name="ip"]').removeAttr('disabled');
$('input[name="port"]').removeAttr('disabled');
$('input[name="passwd"]').removeAttr('disabled');
break;
case 'file':
$('input[name="ip"]').val("").attr('disabled','disabled');
$('input[name="port"]').val("").attr('disabled','disabled');
$('input[name="passwd"]').val("").attr('disabled','disabled');
break;
case 'memcache':
var port = $('input[name="port"]').val();
if (port == ""){
$('input[name="port"]').val('11211');
}
$('input[name="ip"]').removeAttr('disabled');
$('input[name="port"]').removeAttr('disabled');
$('input[name="passwd"]').removeAttr('disabled');
break;
case 'memcached':
var port = $('input[name="port"]').val();
if (port == ""){
$('input[name="port"]').val('11211');
}
$('input[name="ip"]').removeAttr('disabled');
$('input[name="port"]').removeAttr('disabled');
$('input[name="passwd"]').removeAttr('disabled');
break;
}
});
//load session stats
phpPost('get_session_count', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
if(!rdata.status){
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
return;
}
var rdata = rdata.data;
var html_var = "<div class='clear_title' style='padding-bottom:15px;'>清理Session文件</div>\
<div class='clear_conter'>\
<div class='session_clear_list'>\
<div class='line'><span>总Session文件数量</span><span>"+rdata.total+"</span></div>\
<div class='line'><span>可清理的Session文件数量</span><span>"+rdata.oldfile+"</span></div>\
</div>\
<button id='clean_func' class='btn btn-success btn-sm clear_session_file'>清理session文件</button>";
$("#session_clear").html(html_var);
$('#clean_func').click(function(){
phpPost('clean_session_old', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
showMsg(rdata.msg,function(){
getSessionConfig(version);
},{ icon: rdata.status ? 1 : 2 });
});
});
});
});
}
function setSessionConfig(version){
var ip = $('input[name="ip"]').val();
var port = $('input[name="port"]').val();
var passwd = $('input[name="passwd"]').val();
var save_handler = $("select[name='save_handler']").val();
var data = {
ip:ip,
port:port,
passwd:passwd,
save_handler:save_handler,
};
phpPost('set_session_conf', version, data, function(ret_data){
var rdata = $.parseJSON(ret_data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
//设置禁用函数
function setDisableFunc(version, act, fs) {
var fsArr = fs.split(',');
+2
View File
@@ -5,6 +5,8 @@ group = {$PHP_GROUP}
listen = /var/opt/remi/php{$PHP_VERSION}/run/php-fpm/www.sock
listen.owner = {$PHP_USER}
listen.group = {$PHP_GROUP}
listen.backlog = 4096
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
+38
View File
@@ -1,3 +1,40 @@
<style type="text/css">
.bt-w-main{
height: 600px;
}
.session_clear_list {
border:1px solid #ececec;
margin-bottom: 15px;
width: 270px;
}
.session_clear_list .line {
padding: 0;
border-bottom: 1px solid #ececec;
width: 270px;
}
.session_clear_list .line:last-child {
border-bottom: 0px;
}
.session_clear_list .line span{
width: auto;
height: 35px;
line-height: 35px;
text-align: left;
padding: 0 5px;
}
.session_clear_list .line span:first-child {
width: 170px;
border-right: 1px solid #ececec;
background: #f7f7f7;
float: left;
}
</style>
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
@@ -13,6 +50,7 @@
<p onclick="disableFunc($('.plugin_version').attr('version'));">禁用函数</p>
<p onclick="getFpmConfig($('.plugin_version').attr('version'));">性能调整</p>
<p onclick="getFpmStatus($('.plugin_version').attr('version'));">负载状况</p>
<p onclick="getSessionConfig($('.plugin_version').attr('version'));" title="session管理">会话管理</p>
<p onclick="pluginLogs('php-yum',$('.plugin_version').attr('version'),'fpm_log');">FPM日志</p>
<p onclick="pluginLogs('php-yum',$('.plugin_version').attr('version'),'fpm_slow_log');">慢日志</p>
<p onclick="getPhpinfo($('.plugin_version').attr('version'));">PHPIFNO</p>
+182
View File
@@ -492,6 +492,180 @@ def getFpmStatus(version):
return mw.returnJson(True, "OK", data)
def getSessionConf(version):
filename = getConf(version)
if not os.path.exists(filename):
return mw.returnJson(False, '指定PHP版本不存在!')
phpini = mw.readFile(filename)
rep = r'session.save_handler\s*=\s*([0-9A-Za-z_& ~]+)(\s*;?|\r?\n)'
save_handler = re.search(rep, phpini)
if save_handler:
save_handler = save_handler.group(1)
else:
save_handler = "files"
reppath = r'\nsession.save_path\s*=\s*"tcp\:\/\/([\d\.]+):(\d+).*\r?\n'
passrep = r'\nsession.save_path\s*=\s*"tcp://[\w\.\?\:]+=(.*)"\r?\n'
memcached = r'\nsession.save_path\s*=\s*"([\d\.]+):(\d+)"'
save_path = re.search(reppath, phpini)
if not save_path:
save_path = re.search(memcached, phpini)
passwd = re.search(passrep, phpini)
port = ""
if passwd:
passwd = passwd.group(1)
else:
passwd = ""
if save_path:
port = save_path.group(2)
save_path = save_path.group(1)
else:
save_path = ""
data = {"save_handler": save_handler, "save_path": save_path,
"passwd": passwd, "port": port}
return mw.returnJson(True, 'ok', data)
def setSessionConf(version):
args = getArgs()
ip = args['ip']
port = args['port']
passwd = args['passwd']
save_handler = args['save_handler']
if save_handler != "file":
iprep = r"(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})"
if not re.search(iprep, ip):
return mw.returnJson(False, '请输入正确的IP地址')
try:
port = int(port)
if port >= 65535 or port < 1:
return mw.returnJson(False, '请输入正确的端口号')
except:
return mw.returnJson(False, '请输入正确的端口号')
prep = r"[\~\`\/\=]"
if re.search(prep, passwd):
return mw.returnJson(False, '请不要输入以下特殊字符 " ~ ` / = "')
filename = getConf(version)
if not os.path.exists(filename):
return mw.returnJson(False, '指定PHP版本不存在!')
phpini = mw.readFile(filename)
session_tmp = getServerDir() + "/tmp/session"
rep = r'session.save_handler\s*=\s*(.+)\r?\n'
val = r'session.save_handler = ' + save_handler + '\n'
phpini = re.sub(rep, val, phpini)
content = mw.execShell('cat /etc/opt/remi/php' +
version + "/php.d/* | grep -v '^;' |tr -s '\n'")
content = content[0]
if save_handler == "memcached":
if not content.find("memcached.so") > -1:
return mw.returnJson(False, '请先安装%s扩展' % save_handler)
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "%s:%s" \n' % (ip, port)
if re.search(rep, phpini):
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "/tmp"',
'\n;session.save_path = "/tmp"' + val, phpini)
if save_handler == "memcache":
if not content.find("memcache.so") > -1:
return mw.returnJson(False, '请先安装%s扩展' % save_handler)
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "%s:%s" \n' % (ip, port)
if re.search(rep, phpini):
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "/tmp"',
'\n;session.save_path = "/tmp"' + val, phpini)
if save_handler == "redis":
if not content.find("redis.so") > -1:
return mw.returnJson(False, '请先安装%s扩展' % save_handler)
if passwd:
passwd = "?auth=" + passwd
else:
passwd = ""
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "tcp://%s:%s%s"\n' % (ip, port, passwd)
res = re.search(rep, phpini)
if res:
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "/tmp"',
'\n;session.save_path = "/tmp"' + val, phpini)
if save_handler == "file":
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "' + session_tmp + '"\n'
if re.search(rep, phpini):
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "/tmp"',
'\n;session.save_path = "/tmp"' + val, phpini)
mw.writeFile(filename, phpini)
restart(version)
return mw.returnJson(True, '设置成功!')
def getSessionCount_Origin(version):
session_tmp = getServerDir() + "/tmp/session"
d = ["/tmp", session_tmp]
count = 0
for i in d:
if not os.path.exists(i):
mw.execShell('mkdir -p %s' % i)
list = os.listdir(i)
for l in list:
if os.path.isdir(i + "/" + l):
l1 = os.listdir(i + "/" + l)
for ll in l1:
if "sess_" in ll:
count += 1
continue
if "sess_" in l:
count += 1
s = "find /tmp -mtime +1 |grep 'sess_' | wc -l"
old_file = int(mw.execShell(s)[0].split("\n")[0])
s = "find " + session_tmp + " -mtime +1 |grep 'sess_'|wc -l"
old_file += int(mw.execShell(s)[0].split("\n")[0])
return {"total": count, "oldfile": old_file}
def getSessionCount(version):
data = getSessionCount_Origin(version)
return mw.returnJson(True, 'ok!', data)
def cleanSessionOld(version):
s = "find /tmp -mtime +1 |grep 'sess_'|xargs rm -f"
mw.execShell(s)
session_tmp = getServerDir() + "/tmp/session"
s = "find " + session_tmp + " -mtime +1 |grep 'sess_' |xargs rm -f"
mw.execShell(s)
old_file_conf = getSessionCount_Origin(version)["oldfile"]
if old_file_conf == 0:
return mw.returnJson(True, '清理成功')
else:
return mw.returnJson(True, '清理失败')
def getDisableFunc(version):
filename = getConf(version)
if not os.path.exists(filename):
@@ -689,6 +863,14 @@ if __name__ == "__main__":
print(setFpmConfig(version))
elif func == 'get_fpm_status':
print(getFpmStatus(version))
elif func == 'get_session_conf':
print(getSessionConf(version))
elif func == 'set_session_conf':
print(setSessionConf(version))
elif func == 'get_session_count':
print(getSessionCount(version))
elif func == 'clean_session_old':
print(cleanSessionOld(version))
elif func == 'get_disable_func':
print(getDisableFunc(version))
elif func == 'set_disable_func':
+141
View File
@@ -340,6 +340,147 @@ function getFpmStatus(version){
});
}
function getSessionConfig(version){
phpPost('get_session_conf', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
if(!rdata.status){
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
return;
}
var rdata = rdata.data;
var cacheList = "<option value='file' " + (rdata.save_handler == "file" ? 'selected' : '') + ">file</option>" +
"<option value='redis' " + (rdata.save_handler == "redis" ? 'selected' : '') + ">redis</option>" +
"<option value='memcache' " + (rdata.save_handler == "memcache" ? 'selected' : '') + ">memcache</option>" +
"<option value='memcached' " + (rdata.save_handler == "memcached" ? 'selected' : '') + ">memcached</option>";
var info = rdata.save_path.split(":");
var con = "<div class='conf_p'>" +
"<p class='line'><span class='span_tit'>存储模式:</span><select class='bt-input-text' name='save_handler' style='width:200px;'>" + cacheList + "</select></p>" +
"<p class='line'><span class='span_tit'>IP地址:</span><input class='bt-input-text' type='text' name='ip' style='width:200px;' value='"+ info[0] +"' /></p>" +
"<p class='line'><span class='span_tit'>端口:</span><input class='bt-input-text' type='text' name='port' style='width:200px;' value='"+rdata.port+"' /></p>" +
"<p class='line'><span class='span_tit'>密码:</span><input class='bt-input-text' type='text' name='passwd' style='width:200px;' value='"+rdata.passwd+"' /></p>" +
"<p class='line'><div class='mtb15' style='margin-left:100px;'><button class='btn btn-success btn-sm' onclick='setSessionConfig(\"" + version + "\",1)'>保存</button></div></p>" +
"</div>\
<ul class='help-info-text c7'>\
<li>若你的站点并发比较高,使用Redis,Memcache能有效提升PHP并发能力</li>\
<li>若调整Session模式后,网站访问异常,请切换回原来的模式</li>\
<li>切换Session模式会使在线的用户会话丢失,请在流量小的时候切换</li>\
</ul>\
<div id='session_clear' class='session_clear' style='border-top: #ccc 1px dashed;padding-top: 15px;margin-top: 15px;'>\
</div>\
</div>";
$(".soft-man-con").html(con);
if (rdata.save_handler == 'file'){
$('input[name="ip"]').attr('disabled','disabled');
$('input[name="port"]').attr('disabled','disabled');
$('input[name="passwd"]').attr('placeholder','如果没有密码留空');
$('input[name="passwd"]').attr('disabled','disabled');
}
// change event
$("select[name='save_handler']").change(function() {
var type = $(this).val();
var passwd = $('input[name="passwd"]').val();
if (passwd == ""){
$('input[name="passwd"]').attr('placeholder','如果没有密码留空');
}
var ip = $('input[name="ip"]').val();
if (ip == ""){
$('input[name="ip"]').val('127.0.0.1');
}
switch (type) {
case 'redis':
var port = $('input[name="port"]').val();
if (port == ""){
$('input[name="port"]').val('6379');
}
$('input[name="ip"]').removeAttr('disabled');
$('input[name="port"]').removeAttr('disabled');
$('input[name="passwd"]').removeAttr('disabled');
break;
case 'file':
$('input[name="ip"]').val("").attr('disabled','disabled');
$('input[name="port"]').val("").attr('disabled','disabled');
$('input[name="passwd"]').val("").attr('disabled','disabled');
break;
case 'memcache':
var port = $('input[name="port"]').val();
if (port == ""){
$('input[name="port"]').val('11211');
}
$('input[name="ip"]').removeAttr('disabled');
$('input[name="port"]').removeAttr('disabled');
$('input[name="passwd"]').removeAttr('disabled');
break;
case 'memcached':
var port = $('input[name="port"]').val();
if (port == ""){
$('input[name="port"]').val('11211');
}
$('input[name="ip"]').removeAttr('disabled');
$('input[name="port"]').removeAttr('disabled');
$('input[name="passwd"]').removeAttr('disabled');
break;
}
});
//load session stats
phpPost('get_session_count', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
if(!rdata.status){
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
return;
}
var rdata = rdata.data;
var html_var = "<div class='clear_title' style='padding-bottom:15px;'>清理Session文件</div>\
<div class='clear_conter'>\
<div class='session_clear_list'>\
<div class='line'><span>总Session文件数量</span><span>"+rdata.total+"</span></div>\
<div class='line'><span>可清理的Session文件数量</span><span>"+rdata.oldfile+"</span></div>\
</div>\
<button id='clean_func' class='btn btn-success btn-sm clear_session_file'>清理session文件</button>";
$("#session_clear").html(html_var);
$('#clean_func').click(function(){
phpPost('clean_session_old', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
showMsg(rdata.msg,function(){
getSessionConfig(version);
},{ icon: rdata.status ? 1 : 2 });
});
});
});
});
}
function setSessionConfig(version){
var ip = $('input[name="ip"]').val();
var port = $('input[name="port"]').val();
var passwd = $('input[name="passwd"]').val();
var save_handler = $("select[name='save_handler']").val();
var data = {
ip:ip,
port:port,
passwd:passwd,
save_handler:save_handler,
};
phpPost('set_session_conf', version, data, function(ret_data){
var rdata = $.parseJSON(ret_data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
//禁用函数
function disableFunc(version) {
phpPost('get_disable_func', version,'',function(data){
+3
View File
@@ -1,9 +1,12 @@
[www]
user = {$PHP_USER}
group = {$PHP_GROUP}
listen = /tmp/php-cgi-{$PHP_VERSION}.sock
listen.owner = {$PHP_USER}
listen.group = {$PHP_GROUP}
listen.backlog = 4096
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
+40 -1
View File
@@ -1,6 +1,43 @@
<style type="text/css">
.bt-w-main{
height: 642px;
}
.session_clear_list {
border:1px solid #ececec;
margin-bottom: 15px;
width: 270px;
}
.session_clear_list .line {
padding: 0;
border-bottom: 1px solid #ececec;
width: 270px;
}
.session_clear_list .line:last-child {
border-bottom: 0px;
}
.session_clear_list .line span{
width: auto;
height: 35px;
line-height: 35px;
text-align: left;
padding: 0 5px;
}
.session_clear_list .line span:first-child {
width: 170px;
border-right: 1px solid #ececec;
background: #f7f7f7;
float: left;
}
</style>
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
<div class="bt-w-main" >
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('php', $('.plugin_version').attr('version'));">服务</p>
<p onclick="pluginInitD('php', $('.plugin_version').attr('version'));">自启动</p>
@@ -13,6 +50,7 @@
<p onclick="disableFunc($('.plugin_version').attr('version'));">禁用函数</p>
<p onclick="getFpmConfig($('.plugin_version').attr('version'));">性能调整</p>
<p onclick="getFpmStatus($('.plugin_version').attr('version'));">负载状况</p>
<p onclick="getSessionConfig($('.plugin_version').attr('version'));" title="session管理">会话管理</p>
<p onclick="pluginLogs('php',$('.plugin_version').attr('version'),'fpm_log');">FPM日志</p>
<p onclick="pluginLogs('php',$('.plugin_version').attr('version'),'fpm_slow_log');">慢日志</p>
<p onclick="getPhpinfo($('.plugin_version').attr('version'));">PHPIFNO</p>
@@ -24,6 +62,7 @@
</div>
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=php&f=js/php.js", function(){
pluginService('php', $('.plugin_version').attr('version'));
+179
View File
@@ -632,6 +632,176 @@ def getFpmStatus(version):
return mw.returnJson(True, "OK", data)
def getSessionConf(version):
filename = getConf(version)
if not os.path.exists(filename):
return mw.returnJson(False, '指定PHP版本不存在!')
phpini = mw.readFile(filename)
rep = r'session.save_handler\s*=\s*([0-9A-Za-z_& ~]+)(\s*;?|\r?\n)'
save_handler = re.search(rep, phpini)
if save_handler:
save_handler = save_handler.group(1)
else:
save_handler = "files"
reppath = r'\nsession.save_path\s*=\s*"tcp\:\/\/([\d\.]+):(\d+).*\r?\n'
passrep = r'\nsession.save_path\s*=\s*"tcp://[\w\.\?\:]+=(.*)"\r?\n'
memcached = r'\nsession.save_path\s*=\s*"([\d\.]+):(\d+)"'
save_path = re.search(reppath, phpini)
if not save_path:
save_path = re.search(memcached, phpini)
passwd = re.search(passrep, phpini)
port = ""
if passwd:
passwd = passwd.group(1)
else:
passwd = ""
if save_path:
port = save_path.group(2)
save_path = save_path.group(1)
else:
save_path = ""
data = {"save_handler": save_handler, "save_path": save_path,
"passwd": passwd, "port": port}
return mw.returnJson(True, 'ok', data)
def setSessionConf(version):
args = getArgs()
ip = args['ip']
port = args['port']
passwd = args['passwd']
save_handler = args['save_handler']
if save_handler != "file":
iprep = r"(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})"
if not re.search(iprep, ip):
return mw.returnJson(False, '请输入正确的IP地址')
try:
port = int(port)
if port >= 65535 or port < 1:
return mw.returnJson(False, '请输入正确的端口号')
except:
return mw.returnJson(False, '请输入正确的端口号')
prep = r"[\~\`\/\=]"
if re.search(prep, passwd):
return mw.returnJson(False, '请不要输入以下特殊字符 " ~ ` / = "')
filename = getConf(version)
if not os.path.exists(filename):
return mw.returnJson(False, '指定PHP版本不存在!')
phpini = mw.readFile(filename)
session_tmp = getServerDir() + "/tmp/session"
rep = r'session.save_handler\s*=\s*(.+)\r?\n'
val = r'session.save_handler = ' + save_handler + '\n'
phpini = re.sub(rep, val, phpini)
if save_handler == "memcached":
if not re.search("memcached.so", phpini):
return mw.returnJson(False, '请先安装%s扩展' % save_handler)
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "%s:%s" \n' % (ip, port)
if re.search(rep, phpini):
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "' + session_tmp + '"',
'\n;session.save_path = "' + session_tmp + '"' + val, phpini)
if save_handler == "memcache":
if not re.search("memcache.so", phpini):
return mw.returnJson(False, '请先安装%s扩展' % save_handler)
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "%s:%s" \n' % (ip, port)
if re.search(rep, phpini):
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "' + session_tmp + '"',
'\n;session.save_path = "' + session_tmp + '"' + val, phpini)
if save_handler == "redis":
if not re.search("redis.so", phpini):
return mw.returnJson(False, '请先安装%s扩展' % save_handler)
if passwd:
passwd = "?auth=" + passwd
else:
passwd = ""
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "tcp://%s:%s%s"\n' % (ip, port, passwd)
res = re.search(rep, phpini)
if res:
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "' + session_tmp + '"',
'\n;session.save_path = "' + session_tmp + '"' + val, phpini)
if save_handler == "file":
rep = r'\nsession.save_path\s*=\s*(.+)\r?\n'
val = r'\nsession.save_path = "' + session_tmp + '"\n'
if re.search(rep, phpini):
phpini = re.sub(rep, val, phpini)
else:
phpini = re.sub('\n;session.save_path = "' + session_tmp + '"',
'\n;session.save_path = "' + session_tmp + '"' + val, phpini)
mw.writeFile(filename, phpini)
reload(version)
return mw.returnJson(True, '设置成功!')
def getSessionCount_Origin(version):
session_tmp = getServerDir() + "/tmp/session"
d = [session_tmp]
count = 0
for i in d:
if not os.path.exists(i):
mw.execShell('mkdir -p %s' % i)
list = os.listdir(i)
for l in list:
if os.path.isdir(i + "/" + l):
l1 = os.listdir(i + "/" + l)
for ll in l1:
if "sess_" in ll:
count += 1
continue
if "sess_" in l:
count += 1
s = "find /tmp -mtime +1 |grep 'sess_' | wc -l"
old_file = int(mw.execShell(s)[0].split("\n")[0])
s = "find " + session_tmp + " -mtime +1 |grep 'sess_'|wc -l"
old_file += int(mw.execShell(s)[0].split("\n")[0])
return {"total": count, "oldfile": old_file}
def getSessionCount(version):
data = getSessionCount_Origin(version)
return mw.returnJson(True, 'ok!', data)
def cleanSessionOld(version):
s = "find /tmp -mtime +1 |grep 'sess_'|xargs rm -f"
mw.execShell(s)
session_tmp = getServerDir() + "/tmp/session"
s = "find " + session_tmp + " -mtime +1 |grep 'sess_' |xargs rm -f"
mw.execShell(s)
old_file_conf = getSessionCount_Origin(version)["oldfile"]
if old_file_conf == 0:
return mw.returnJson(True, '清理成功')
else:
return mw.returnJson(True, '清理失败')
def getDisableFunc(version):
filename = getConf(version)
if not os.path.exists(filename):
@@ -794,6 +964,7 @@ def installPreInspection(version):
return 'fedora[{}]不可安装'.format(sysId)
return 'ok'
if __name__ == "__main__":
if len(sys.argv) < 3:
@@ -847,6 +1018,14 @@ if __name__ == "__main__":
print(setFpmConfig(version))
elif func == 'get_fpm_status':
print(getFpmStatus(version))
elif func == 'get_session_conf':
print(getSessionConf(version))
elif func == 'set_session_conf':
print(setSessionConf(version))
elif func == 'get_session_count':
print(getSessionCount(version))
elif func == 'clean_session_old':
print(cleanSessionOld(version))
elif func == 'get_disable_func':
print(getDisableFunc(version))
elif func == 'set_disable_func':
+146 -14
View File
@@ -1,14 +1,3 @@
function str2Obj(str){
var data = {};
kv = str.split('&');
for(i in kv){
v = kv[i].split('=');
data[v[0]] = v[1];
}
return data;
}
function phpPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
@@ -18,7 +7,7 @@ function phpPost(method, version, args,callback){
req_data['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(str2Obj(args));
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
@@ -46,7 +35,7 @@ function phpPostCallbak(method, version, args,callback){
args['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(str2Obj(args));
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
@@ -194,7 +183,7 @@ function getFpmConfig(version){
"<option value='3' " + (rdata.max_children == 100 ? 'selected' : '') + ">100并发</option>" +
"<option value='4' " + (rdata.max_children == 200 ? 'selected' : '') + ">200并发</option>" +
"<option value='5' " + (rdata.max_children == 300 ? 'selected' : '') + ">300并发</option>" +
"<option value='6' " + (rdata.max_children == 500 ? 'selected' : '') + ">500并发</option>"
"<option value='6' " + (rdata.max_children == 500 ? 'selected' : '') + ">500并发</option>";
var pms = [{ 'name': 'static', 'title': '静态' }, { 'name': 'dynamic', 'title': '动态' }];
var pmList = '';
for (var i = 0; i < pms.length; i++) {
@@ -340,6 +329,149 @@ function getFpmStatus(version){
});
}
function getSessionConfig(version){
phpPost('get_session_conf', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
if(!rdata.status){
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
return;
}
var rdata = rdata.data;
var cacheList = "<option value='file' " + (rdata.save_handler == "file" ? 'selected' : '') + ">file</option>" +
"<option value='redis' " + (rdata.save_handler == "redis" ? 'selected' : '') + ">redis</option>" +
"<option value='memcache' " + (rdata.save_handler == "memcache" ? 'selected' : '') + ">memcache</option>" +
"<option value='memcached' " + (rdata.save_handler == "memcached" ? 'selected' : '') + ">memcached</option>";
var info = rdata.save_path.split(":");
var con = "<div class='conf_p'>" +
"<p class='line'><span class='span_tit'>存储模式:</span><select class='bt-input-text' name='save_handler' style='width:200px;'>" + cacheList + "</select></p>" +
"<p class='line'><span class='span_tit'>IP地址:</span><input class='bt-input-text' type='text' name='ip' style='width:200px;' value='"+ info[0] +"' /></p>" +
"<p class='line'><span class='span_tit'>端口:</span><input class='bt-input-text' type='text' name='port' style='width:200px;' value='"+rdata.port+"' /></p>" +
"<p class='line'><span class='span_tit'>密码:</span><input class='bt-input-text' type='text' name='passwd' style='width:200px;' value='"+rdata.passwd+"' /></p>" +
"<p class='line'><div class='mtb15' style='margin-left:100px;'><button class='btn btn-success btn-sm' onclick='setSessionConfig(\"" + version + "\",1)'>保存</button></div></p>" +
"</div>\
<ul class='help-info-text c7'>\
<li>若你的站点并发比较高,使用Redis,Memcache能有效提升PHP并发能力</li>\
<li>若调整Session模式后,网站访问异常,请切换回原来的模式</li>\
<li>切换Session模式会使在线的用户会话丢失,请在流量小的时候切换</li>\
</ul>\
<div id='session_clear' class='session_clear' style='border-top: #ccc 1px dashed;padding-top: 15px;margin-top: 15px;'>\
</div>\
</div>";
$(".soft-man-con").html(con);
if (rdata.save_handler == 'file'){
$('input[name="ip"]').attr('disabled','disabled');
$('input[name="port"]').attr('disabled','disabled');
$('input[name="passwd"]').attr('placeholder','如果没有密码留空');
$('input[name="passwd"]').attr('disabled','disabled');
}
// change event
$("select[name='save_handler']").change(function() {
var type = $(this).val();
var passwd = $('input[name="passwd"]').val();
if (passwd == ""){
$('input[name="passwd"]').attr('placeholder','如果没有密码留空');
}
var ip = $('input[name="ip"]').val();
if (ip == ""){
$('input[name="ip"]').val('127.0.0.1');
}
switch (type) {
case 'redis':
var port = $('input[name="port"]').val();
if (port == ""){
$('input[name="port"]').val('6379');
}
$('input[name="ip"]').removeAttr('disabled');
$('input[name="port"]').removeAttr('disabled');
$('input[name="passwd"]').removeAttr('disabled');
break;
case 'file':
$('input[name="ip"]').val("").attr('disabled','disabled');
$('input[name="port"]').val("").attr('disabled','disabled');
$('input[name="passwd"]').val("").attr('disabled','disabled');
break;
case 'memcache':
var port = $('input[name="port"]').val();
if (port == ""){
$('input[name="port"]').val('11211');
}
$('input[name="ip"]').removeAttr('disabled');
$('input[name="port"]').removeAttr('disabled');
$('input[name="passwd"]').removeAttr('disabled');
break;
case 'memcached':
var port = $('input[name="port"]').val();
if (port == ""){
$('input[name="port"]').val('11211');
}
$('input[name="ip"]').removeAttr('disabled');
$('input[name="port"]').removeAttr('disabled');
$('input[name="passwd"]').removeAttr('disabled');
break;
}
});
//load session stats
phpPost('get_session_count', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
if(!rdata.status){
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
return;
}
var rdata = rdata.data;
var html_var = "<div class='clear_title' style='padding-bottom:15px;'>清理Session文件</div>\
<div class='clear_conter'>\
<div class='session_clear_list'>\
<div class='line'><span>总Session文件数量</span><span>"+rdata.total+"</span></div>\
<div class='line'><span>可清理的Session文件数量</span><span>"+rdata.oldfile+"</span></div>\
</div>\
<button id='clean_func' class='btn btn-success btn-sm clear_session_file'>清理session文件</button>";
$("#session_clear").html(html_var);
$('#clean_func').click(function(){
phpPost('clean_session_old', version, '', function(ret_data){
var rdata = $.parseJSON(ret_data.data);
showMsg(rdata.msg,function(){
getSessionConfig(version);
},{ icon: rdata.status ? 1 : 2 });
});
});
});
});
}
function setSessionConfig(version){
var ip = $('input[name="ip"]').val();
var port = $('input[name="port"]').val();
var passwd = $('input[name="passwd"]').val();
var save_handler = $("select[name='save_handler']").val();
var data = {
ip:ip,
port:port,
passwd:passwd,
save_handler:save_handler,
};
phpPost('set_session_conf', version, data, function(ret_data){
var rdata = $.parseJSON(ret_data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
//禁用函数
function disableFunc(version) {
phpPost('get_disable_func', version,'',function(data){
+1 -1
View File
@@ -1,7 +1,7 @@
daemonize yes
pidfile {$SERVER_PATH}/redis/redis_6379.pid
bind 127.0.0.1
bind 0.0.0.0
port 6379
requirepass admin
+13 -3
View File
@@ -125,7 +125,7 @@ def redisOp(method):
data = mw.execShell('systemctl ' + method + ' redis')
if data[1] == '':
return 'ok'
return 'fail'
return data[1]
data = mw.execShell(file + ' start')
if data[1] == '':
@@ -154,6 +154,10 @@ def reload():
def runInfo():
s = status()
if s == 'stop':
return mw.returnJson(False, '未启动')
requirepass = ""
conf = getServerDir() + '/redis.conf'
@@ -163,9 +167,15 @@ def runInfo():
if tmp:
requirepass = tmp.groups()[1]
cmd = getServerDir() + "/bin/redis-cli info"
default_ip = '0.0.0.0'
findDebian = mw.execShell('cat /etc/issue |grep Debian')
if findDebian[0] != '':
default_ip = mw.getLocalIp()
cmd = getServerDir() + "/bin/redis-cli -h " + default_ip + " info"
if requirepass != "":
cmd = getServerDir() + '/bin/redis-cli -a "' + requirepass + '" info'
cmd = getServerDir() + '/bin/redis-cli -h ' + default_ip + \
' -a "' + requirepass + '" info'
data = mw.execShell(cmd)[0]
res = [
-1
View File
@@ -5,7 +5,6 @@ After=network.target
[Service]
Type=forking
ExecStart={$SERVER_PATH}/redis/bin/redis-server {$SERVER_PATH}/redis/redis.conf
ExecStop={$SERVER_PATH}/redis/redis-cli shutdown
ExecReload=/bin/kill -USR2 $MAINPID
Restart=on-failure
+5
View File
@@ -69,6 +69,11 @@ function redisStatus(version) {
redisPost('run_info',version, {},function(data){
var rdata = $.parseJSON(data.data);
// if (!rdata.status){
// layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
// return;
// }
hit = (parseInt(rdata.keyspace_hits) / (parseInt(rdata.keyspace_hits) + parseInt(rdata.keyspace_misses)) * 100).toFixed(2);
var con = '<div class="divtable">\
<table class="table table-hover table-bordered" style="width: 490px;">\
+8 -7
View File
@@ -117,7 +117,7 @@ def swapOp(method):
return 'ok'
return 'fail'
data = mw.execShell(file + ' start')
data = mw.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return 'fail'
@@ -136,7 +136,7 @@ def restart():
def reload():
return swapOp('reload')
return 'ok'
def initdStatus():
@@ -185,14 +185,15 @@ def changeSwap():
size = args['size']
swapOp('stop')
os.system('dd if=/dev/zero of=' + getServerDir() +
'/swapfile bs=1M count=' + size)
os.system('mkswap ' + getServerDir() + '/swapfile')
os.system('chmod 600 ' + getServerDir() + '/swapfile')
gsdir = getServerDir()
cmd = 'dd if=/dev/zero of=' + gsdir + '/swapfile bs=1M count=' + size
cmd += ' && mkswap ' + gsdir + '/swapfile && chmod 600 ' + gsdir + '/swapfile'
msg = mw.execShell(cmd)
swapOp('start')
return mw.returnJson(True, "修改成功!")
return mw.returnJson(True, "修改成功:\n" + msg[0])
if __name__ == "__main__":
func = sys.argv[1]
+31 -14
View File
@@ -1,18 +1,35 @@
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
net.ipv4.icmp_echo_ignore_all=0
net.ipv4.tcp_fin_timeout = 6
net.ipv4.tcp_keepalive_time = 30
net.ipv4.tcp_max_tw_buckets = 8000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 30000
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.ip_local_port_range = 1025 61000
net.ipv4.tcp_keepalive_intvl = 3
net.ipv4.tcp_keepalive_probes = 2
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.tcp_max_tw_buckets = 6000
net.ipv4.tcp_sack = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_rmem = 4096 87380 4194304
net.ipv4.tcp_wmem = 4096 16384 4194304
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 262144
net.core.somaxconn = 262144
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_fin_timeout = 1
net.ipv4.tcp_keepalive_time = 30
net.ipv4.ip_local_port_range = 1024 65000
vm.overcommit_memory=1
+1 -1
View File
@@ -1,2 +1,2 @@
lua_shared_dict mw_total 50m;
lua_shared_dict mw_total 100m;
include {$SERVER_APP}/lua/webstats_log.lua;
+35 -15
View File
@@ -77,11 +77,11 @@ def status():
return 'start'
def loadLuaLogFile():
def loadLuaFile(name):
lua_dir = getServerDir() + "/lua"
lua_dst = lua_dir + "/webstats_log.lua"
lua_dst = lua_dir + "/" + name
lua_tpl = getPluginDir() + '/lua/webstats_log.lua'
lua_tpl = getPluginDir() + '/lua/' + name
content = mw.readFile(lua_tpl)
content = content.replace('{$SERVER_APP}', getServerDir())
content = content.replace('{$ROOT_PATH}', mw.getServerDir())
@@ -98,7 +98,7 @@ def loadConfigFile():
dst_conf_json = getServerDir() + "/lua/config.json"
mw.writeFile(dst_conf_json, json.dumps(content))
dst_conf_lua = getServerDir() + "/lua/config.lua"
dst_conf_lua = getServerDir() + "/lua/webstats_config.lua"
listToLuaFile(dst_conf_lua, content)
@@ -125,9 +125,16 @@ def loadLuaSiteFile():
ddata["default"] = "unset"
else:
ddata["default"] = dlist[0]
mw.writeFile(default_json, json.dumps(ddata))
lua_site = lua_dir + "/sites.lua"
lua_site = lua_dir + "/webstats_sites.lua"
tmp = {
"name": "unset",
"domain": [],
}
content.append(tmp)
listToLuaFile(lua_site, content)
@@ -205,7 +212,14 @@ def initDreplace():
if not os.path.exists(log_path):
mw.execShell('mkdir -p ' + log_path)
loadLuaLogFile()
file_list = [
'webstats_common.lua',
'webstats_log.lua',
]
for fl in file_list:
loadLuaFile(fl)
loadConfigFile()
loadLuaSiteFile()
loadDebugLogFile()
@@ -222,28 +236,35 @@ def start():
if not mw.isAppleSystem():
mw.execShell("chown -R www:www " + getServerDir())
mw.restartWeb()
mw.opWeb("reload")
return 'ok'
def stop():
path = luaConf()
os.remove(path)
mw.restartWeb()
if os.path.exists(path):
os.remove(path)
import tool_task
tool_task.removeBgTask()
mw.opWeb("restart")
return 'ok'
def restart():
initDreplace()
mw.opWeb("reload")
return 'ok'
def reload():
initDreplace()
loadLuaLogFile()
loadDebugLogFile()
mw.restartWeb()
mw.opWeb("reload")
return 'ok'
@@ -294,7 +315,7 @@ def setGlobalConf():
content['global']['exclude_url'] = exclude_url_val
mw.writeFile(conf, json.dumps(content))
conf_lua = getServerDir() + "/lua/config.lua"
conf_lua = getServerDir() + "/lua/webstats_config.lua"
listToLuaFile(conf_lua, content)
mw.restartWeb()
return mw.returnJson(True, '设置成功')
@@ -387,7 +408,7 @@ def setSiteConf():
content[domain] = site_conf
mw.writeFile(conf, json.dumps(content))
conf_lua = getServerDir() + "/lua/config.lua"
conf_lua = getServerDir() + "/lua/webstats_config.lua"
listToLuaFile(conf_lua, content)
mw.restartWeb()
return mw.returnJson(True, '设置成功')
@@ -622,7 +643,7 @@ def getLogsList():
limit = str(page_size) + ' offset ' + str(page_size * (page - 1))
conn = pSqliteDb('web_logs', domain)
field = 'time,ip,domain,server_name,method,protocol,status_code,request_headers,ip_list,client_port,body_length,user_agent,referer,request_time,uri,body_length'
field = 'time,ip,domain,server_name,method,is_spider,protocol,status_code,request_headers,ip_list,client_port,body_length,user_agent,referer,request_time,uri,body_length'
condition = ''
conn = conn.field(field)
conn = conn.where("1=1", ())
@@ -1101,7 +1122,6 @@ def getUriStatList():
conn = conn.where("day>? and flow>?", (0, 0,))
clist = conn.order("flow desc").limit("50").inquiry(origin_field)
# print(clist)
total_req = 0
total_flow = 0
+1 -1
View File
@@ -4,7 +4,7 @@
"name": "webstats",
"title": "网站统计",
"shell": "install.sh",
"versions":["0.2.0"],
"versions":["0.2.2"],
"tip": "soft",
"install_pre_inspection":true,
"checks": "server/webstats",
+18 -14
View File
@@ -24,12 +24,14 @@ if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
get_latest_release() {
curl -sL "https://api.github.com/repos/$1/releases/latest" | grep '"tag_name":' | cut -d'"' -f4
}
Install_App()
{
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/source/webstats
mkdir -p $serverPath/webstats
# 下载源码安装包
@@ -88,29 +90,31 @@ Install_App()
# https://github.com/P3TERX/GeoLite.mmdb
pip install geoip2
if [ ! -f $serverPath/webstats/GeoLite2-City.mmdb ];then
# pip install geoip2
wget --no-check-certificate -O $serverPath/webstats/GeoLite2-City.mmdb https://git.io/GeoLite2-City.mmdb
# if [ ! -f $serverPath/webstats/GeoLite2-City.mmdb ];then
# wget --no-check-certificate -O $serverPath/webstats/GeoLite2-City.mmdb https://github.com/P3TERX/GeoLite.mmdb/releases/download/2022.10.16/GeoLite2-City.mmdb
# fi
# 缓存数据
GEO_VERSION=$(get_latest_release "P3TERX/GeoLite.mmdb")
if [ ! -f $serverPath/source/webstats/GeoLite2-City.mmdb ];then
wget --no-check-certificate -O $serverPath/source/webstats/GeoLite2-City.mmdb https://github.com/P3TERX/GeoLite.mmdb/releases/download/${GEO_VERSION}/GeoLite2-City.mmdb
fi
# GeoLite2-Country.mmdb
if [ -f $serverPath/source/webstats/GeoLite2-City.mmdb ];then
cp -rf $serverPath/source/webstats/GeoLite2-City.mmdb $serverPath/webstats/GeoLite2-City.mmdb
fi
echo "${VERSION}" > $serverPath/webstats/version.pl
echo '安装完成' > $install_tmp
if [ "$sys_os" != "Darwin" ];then
cd $rootPath && python3 ${rootPath}/plugins/webstats/index.py start
fi
cd $rootPath && python3 ${rootPath}/plugins/webstats/index.py start
}
Uninstall_App()
{
if [ "$sys_os" != "Darwin" ];then
cd $rootPath && python3 ${rootPath}/plugins/webstats/index.py stop
fi
cd $rootPath && python3 ${rootPath}/plugins/webstats/index.py stop
rm -rf $serverPath/webstats
echo "Uninstall_redis" > $install_tmp
echo "卸载完成" > $install_tmp
}
action=$1
+1 -1
View File
@@ -247,7 +247,7 @@ wsPost('get_global_conf', '' ,{}, function(rdata){
$('#setAll').click(function(){
var args = "name=webstats&func=reload";
layer.confirm('您真的要同步所有站点吗?', {icon:3,closeBtn: 2}, function() {
layer.confirm('您真的要同步所有站点吗?', {icon:3,closeBtn: 1}, function() {
var e = layer.msg('正在同步,请稍候...', {icon: 16,time: 0});
$.post("/plugins/run", args, function(g) {
layer.close(e);
+32 -13
View File
@@ -2032,7 +2032,7 @@ function wsTableErrorLogRequest(page){
type: 1,
title: "【"+res.domain + "】详情信息",
area: '600px',
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div class="pd15 lib-box">\
<div style="height:80px;"><table class="table" style="border:#ddd 1px solid; margin-bottom:10px">\
@@ -2110,7 +2110,7 @@ laydate.render({
$(this).removeClass('cur');
});
var timeA = value.split('-')
var timeA = value.split('-');
var start = $.trim(timeA[0]+'-'+timeA[1]+'-'+timeA[2])
var end = $.trim(timeA[3]+'-'+timeA[4]+'-'+timeA[5])
query_txt = toUnixTime(start + " 00:00:00") + "-"+ toUnixTime(end + " 00:00:00")
@@ -2193,12 +2193,37 @@ function wsTableLogRequest(page){
args['search_uri'] = search_uri;
args['tojs'] = 'wsTableLogRequest';
var spider_table = {
"1":"百度",
"2":"必应",
"3":"奇虎360",
"4":"Google",
"5":"头条",
"6":"搜狗",
"7":"有道",
"8":"搜搜",
"9":"Dnspod",
"10":"Yandex",
"11":"一搜",
"12":"其他",
}
wsPost('get_logs_list', '' ,args, function(rdata){
var rdata = $.parseJSON(rdata.data);
var list = '';
var data = rdata.data.data;
if (data.length > 0){
for(i in data){
var spider_tip = '';
if (data[i]['is_spider']>0){
spider_tip_name = spider_table[data[i]['is_spider']]
spider_tip = '<div data-toggle="tooltip" title="'+spider_tip_name+'爬虫" style="cursor:pointer;margin:3px;float:left;width:8px;height:8px;line-height:40px;border-radius:50%;background-color:#ccc;"></div>';
}
list += '<tr>';
list += '<td>' + getLocalTime(data[i]['time'])+'</td>';
list += '<td><span class="overflow_hide" style="width:100px;">' + data[i]['domain'] +'</span></td>';
@@ -2206,7 +2231,7 @@ function wsTableLogRequest(page){
list += '<td>' + toSize(data[i]['body_length']) +'</td>';
list += '<td>' + toSecond(data[i]['request_time']) +'</td>';
list += '<td><span class="overflow_hide" style="width:130px;">' + data[i]['uri'] +'</span></td>';
list += '<td><span class="overflow_hide" style="width:60px;">' + data[i]['status_code']+'/' + data[i]['method'] +'</span></td>';
list += '<td>'+spider_tip+'<span class="overflow_hide" style="width:60px;">' + data[i]['status_code']+'/' + data[i]['method'] +'</span></td>';
list += '<td><a data-id="'+i+'" href="javascript:;" class="btlink details" title="详情">详情</a></td>';
list += '</tr>';
}
@@ -2241,7 +2266,7 @@ function wsTableLogRequest(page){
type: 1,
title: "【"+res.domain + "】详情信息",
area: '600px',
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div class="pd15 lib-box">\
<div style="height:80px;"><table class="table" style="border:#ddd 1px solid; margin-bottom:10px">\
@@ -2264,6 +2289,8 @@ function wsTableLogRequest(page){
</div>',
});
});
$('[data-toggle="tooltip"]').tooltip();
});
}
@@ -2322,7 +2349,7 @@ var html = '<div>\
<option value="8">搜搜</option>\
<option value="9">Dnspod</option>\
<option value="10">Yandex</option>\
<option value="12">神马</option>\
<option value="11">一搜</option>\
<option value="12">其他</option>\
</select>\
<span style="margin-left:10px;">URL过滤: </span>\
@@ -2420,11 +2447,3 @@ wsPost('get_default_site','',{},function(rdata){
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
# echo $rootPath
resty=$rootPath/openresty/bin/resty
RUN_CMD=$resty
if [ ! -f $resty ];then
RUN_CMD=/www/server/openresty/bin/resty
fi
# test
# $RUN_CMD simple.lua
# $RUN_CMD test_today.lua
# $RUN_CMD test_time.lua
# $RUN_CMD test_ngx_find.lua
$RUN_CMD test_match_spider.lua
+18
View File
@@ -0,0 +1,18 @@
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end
for i = 1, 100 do
target()
end
collectgarbage()
ngx.update_time()
local begin = ngx.now()
local N = 1e7
for i = 1, N do
target()
end
ngx.update_time()
ngx.say("elapsed: ", (ngx.now() - begin) / N)
@@ -0,0 +1,106 @@
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end
for i = 1, 100 do
target()
end
-- 以上为预热操作
collectgarbage()
local function match_spider(ua)
-- 匹配蜘蛛请求
local is_spider = false
local spider_name = ""
local spider_match = ""
local spider_table = {
["baidu"] = 1, -- check
["bing"] = 2, -- check
["qh360"] = 3, -- check
["google"] = 4,
["bytes"] = 5, -- check
["sogou"] = 6, -- check
["youdao"] = 7,
["soso"] = 8,
["dnspod"] = 9,
["yandex"] = 10,
["yisou"] = 11,
["other"] = 12,
["mpcrawler"] = 13,
["yahoo"] = 14, -- check
["duckduckgo"] = 15
}
local find_spider, _ = ngx.re.match(ua, "(Baiduspider|Bytespider|360Spider|Sogou web spider|Sosospider|Googlebot|bingbot|AdsBot-Google|Google-Adwords|YoudaoBot|Yandex|DNSPod-Monitor|YisouSpider|mpcrawler)", "ijo")
if find_spider then
is_spider = true
spider_match = string.lower(find_spider[0])
if string.find(spider_match, "baidu", 1, true) then
spider_name = "baidu"
elseif string.find(spider_match, "bytes", 1, true) then
spider_name = "bytes"
elseif string.find(spider_match, "360", 1, true) then
spider_name = "qh360"
elseif string.find(spider_match, "sogou", 1, true) then
spider_name = "sogou"
elseif string.find(spider_match, "soso", 1, true) then
spider_name = "soso"
elseif string.find(spider_match, "google", 1, true) then
spider_name = "google"
elseif string.find(spider_match, "bingbot", 1, true) then
spider_name = "bing"
elseif string.find(spider_match, "youdao", 1, true) then
spider_name = "youdao"
elseif string.find(spider_match, "dnspod", 1, true) then
spider_name = "dnspod"
elseif string.find(spider_match, "yandex", 1, true) then
spider_name = "yandex"
elseif string.find(spider_match, "yisou", 1, true) then
spider_name = "yisou"
elseif string.find(spider_match, "mpcrawler", 1, true) then
spider_name = "mpcrawler"
end
end
if is_spider then
return is_spider, spider_name, spider_table[spider_name]
end
-- Curl|Yahoo|HeadlessChrome|包含bot|Wget|Spider|Crawler|Scrapy|zgrab|python|java|Adsbot|DuckDuckGo
find_spider, _ = ngx.re.match(ua, "(Yahoo|Slurp|DuckDuckGo)", "ijo")
if res then
spider_match = string.lower(find_spider[0])
if string.find(spider_match, "yahoo", 1, true) then
spider_name = "yahoo"
elseif string.find(spider_match, "slurp", 1, true) then
spider_name = "yahoo"
elseif string.find(spider_match, "duckduckgo", 1, true) then
spider_name = "duckduckgo"
end
return true, spider_name, spider_table[spider_name]
end
return false, "", 0
end
-- local is_spider, request_spider, spider_index = match_spider("Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)")
-- ngx.say(is_spider,request_spider, spider_index)
ngx.update_time()
local begin = ngx.now()
local N = 1e6
for i = 1, N do
match_spider("Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)")
end
ngx.update_time()
ngx.say("match_spider elapsed: ", (ngx.now() - begin) / N)
@@ -0,0 +1,35 @@
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end
for i = 1, 100 do
target()
end
-- 以上为预热操作
collectgarbage()
local spider_match = "aa 220"
ngx.update_time()
local begin = ngx.now()
local N = 1e7
for i = 1, N do
ngx.re.find(spider_match, "360", "ijo")
end
ngx.update_time()
ngx.say("ngx.re.find elapsed: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = ngx.now()
local N = 1e7
for i = 1, N do
string.find(spider_match, "360", 1, true)
end
ngx.update_time()
ngx.say("string.find elapsed: ", (ngx.now() - begin) / N)
+118
View File
@@ -0,0 +1,118 @@
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end
for i = 1, 100 do
target()
end
-- 以上为预热操作
collectgarbage()
local function get_store_key()
return os.date("%Y%m%d%H", os.time())
end
local function get_store_key2()
return os.date("%Y%m%d%H", ngx.time())
end
local function get_end_time()
local s_time = os.time()
local n_date = os.date("*t",s_time + 86400)
n_date.hour = 0
n_date.min = 0
n_date.sec = 0
local d_time = os.time(n_date)
return d_time - s_time
end
local function get_end_time2()
local s_time = ngx.time()
local n_date = os.date("*t",s_time + 86400)
n_date.hour = 0
n_date.min = 0
n_date.sec = 0
local d_time = ngx.time(n_date)
return d_time - s_time
end
local function get_update_field(field, value)
return field.."="..field.."+"..value
end
local function get_update_field2(field, value)
return field.."="..field.."+"..tostring(value)
end
ngx.update_time()
local begin = ngx.now()
local N = 1e3
for i = 1, N do
get_store_key()
end
ngx.update_time()
ngx.say("get_store_key elapsed: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = ngx.now()
local N = 1e3
for i = 1, N do
get_store_key2()
end
ngx.update_time()
ngx.say("get_store_key2 elapsed: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = ngx.now()
local N = 1e5
for i = 1, N do
get_end_time()
end
ngx.update_time()
ngx.say("get_end_time elapsed: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = ngx.now()
local N = 1e5
for i = 1, N do
get_end_time2()
end
ngx.update_time()
ngx.say("get_end_time2 elapsed: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = ngx.now()
local N = 1e9
for i = 1, N do
get_update_field("ss","1")
end
ngx.update_time()
ngx.say("get_update_field elapsed: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = ngx.now()
local N = 1e9
for i = 1, N do
get_update_field2("ss",1)
end
ngx.update_time()
ngx.say("get_update_field2 elapsed: ", (ngx.now() - begin) / N)
+33
View File
@@ -0,0 +1,33 @@
local function target()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
end
for i = 1, 100 do
target()
end
-- 以上为预热操作
collectgarbage()
ngx.update_time()
local begin = ngx.now()
local N = 1e6
for i = 1, N do
os.date("%Y%m%d")
-- ngx.say(t)
end
ngx.update_time()
ngx.say("os.date elapsed: ", (ngx.now() - begin) / N)
ngx.update_time()
local begin = ngx.now()
local N = 1e6
for i = 1, N do
ngx.re.gsub(ngx.today(),'-','')
-- ngx.say(t)
end
ngx.update_time()
ngx.say("ngx.today() elapsed: ", (ngx.now() - begin) / N)
+122
View File
@@ -0,0 +1,122 @@
# coding:utf-8
import sys
import io
import os
import time
import json
import os
import sys
import time
import string
import json
import hashlib
import shlex
import datetime
import subprocess
import re
from random import Random
TEST_URL = "http://t1.cn/"
# TEST_URL = "https://www.zzzvps.com/"
def httpGet(url, timeout=10):
import urllib.request
try:
req = urllib.request.urlopen(url, timeout=timeout)
result = req.read().decode('utf-8')
return result
except Exception as e:
return str(e)
def httpPost(url, data, timeout=10):
"""
发送POST请求
@url 被请求的URL地址(必需)
@data POST参数,可以是字符串或字典(必需)
@timeout 超时时间默认60秒
return string
"""
if sys.version_info[0] == 2:
try:
import urllib
import urllib2
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
data = urllib.urlencode(data)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req, timeout=timeout)
return response.read()
except Exception as ex:
return str(ex)
else:
try:
import urllib.request
import ssl
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:
pass
data = urllib.parse.urlencode(data).encode('utf-8')
req = urllib.request.Request(url, data)
response = urllib.request.urlopen(req, timeout=timeout)
result = response.read()
if type(result) == bytes:
result = result.decode('utf-8')
return result
except Exception as ex:
return str(ex)
def httpGet__UA(url, ua, timeout=10):
import urllib.request
headers = {'user-agent': ua}
try:
req = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(req)
result = response.read().decode('utf-8')
return result
except Exception as e:
return str(e)
def test_OK():
'''
目录保存
'''
url = TEST_URL + "ok.txt"
print("ok test start")
url_val = httpGet__UA(
url, "Mozilla / 5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit / 537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36")
print(url_val)
print("ok test end")
def test_Spider():
'''
目录保存
'''
url = TEST_URL + "ok.txt"
print("spider test start")
url_val = httpGet__UA(
url, "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.5249.103 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)")
print(url_val)
print("spider test end")
def test_start():
test_OK()
test_Spider()
if __name__ == "__main__":
os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/webstats && sh install.sh uninstall 0.2.2 && sh install.sh install 0.2.2')
os.system('cd /Users/midoks/Desktop/mwdev/server/mdserver-web/ && python3 plugins/openresty/index.py stop && python3 plugins/openresty/index.py start')
test_start()
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
python3 index.py
+5 -5
View File
@@ -54,7 +54,7 @@ function modifyAuthPath() {
type: 1,
area: "500px",
title: "修改安全入口",
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: false,
content: '<div class="bt-form bt-form pd20 pb70">\
@@ -131,7 +131,7 @@ function setPassword(a) {
type: 1,
area: "290px",
title: '修改密码',
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: false,
content: "<div class='bt-form pd20 pb70'>\
@@ -187,7 +187,7 @@ function setUserName(a) {
type: 1,
area: "290px",
title: '修改面板用户名',
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: false,
content: "<div class='bt-form pd20 pb70'>\
@@ -238,7 +238,7 @@ function setPanelSSL(){
<input type="checkbox" id="checkSSL" /><label style="font-weight: 400;margin: 3px 5px 0px;" for="checkSSL">我已了经解详情,并愿意承担风险</label>\
<a target="_blank" class="btlink" href="https://www.bt.cn/bbs/thread-4689-1-1.html" style="float: right;">了解详情</a>\
</p>';
layer.confirm(msg,{title:'设置面板SSL',closeBtn:2,icon:3,area:'550px',cancel:function(){
layer.confirm(msg,{title:'设置面板SSL',closeBtn:1,icon:3,area:'550px',cancel:function(){
if(status == 0){
$("#panelSSL").prop("checked",false);
}
@@ -302,7 +302,7 @@ function getPanelSSL(){
type: 1,
area: "600px",
title: '自定义面板证书',
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: false,
content:certBody
+1 -1
View File
@@ -180,7 +180,7 @@ function setControl(act, value=false){
//清理记录
function closeControl(){
layer.confirm('您真的清空所有监控记录吗?',{title:'清空记录',icon:3,closeBtn:2}, function() {
layer.confirm('您真的清空所有监控记录吗?',{title:'清空记录',icon:3,closeBtn:1}, function() {
loadT = layer.msg('正在处理,请稍候...',{icon:16,time:0})
$.post('/system/set_control','type=del',function(rdata){
layer.close(loadT);
+3 -3
View File
@@ -24,7 +24,7 @@ function getLogs(id){
title:lan.crontab.task_log_title,
area: ['60%','500px'],
shadeClose:false,
closeBtn:2,
closeBtn:1,
content:'<div class="setchmod bt-form pd20 pb70">'
+'<pre id="crontab-log" style="overflow: auto; border: 0px none; line-height:23px;padding: 15px; margin: 0px; white-space: pre-wrap; height: 405px; background-color: rgb(51,51,51);color:#f1f1f1;border-radius:0px;font-family:"></pre>'
+'<div class="bt-form-submit-btn" style="margin-top: 0px;">'
@@ -93,7 +93,7 @@ function getCronData(page){
// 设置计划任务状态
function setTaskStatus(id,status){
var confirm = layer.confirm(status == '0'?'计划任务暂停后将无法继续运行,您真的要停用这个计划任务吗?':'该计划任务已停用,是否要启用这个计划任务', {title:'提示',icon:3,closeBtn:2},function(index) {
var confirm = layer.confirm(status == '0'?'计划任务暂停后将无法继续运行,您真的要停用这个计划任务吗?':'该计划任务已停用,是否要启用这个计划任务', {title:'提示',icon:3,closeBtn:1},function(index) {
if (index > 0) {
var loadT = layer.msg('正在设置状态,请稍后...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/crontab/set_cron_status',{id:id},function(rdata){
@@ -610,7 +610,7 @@ function editTaskInfo(id){
area: ['850px','450px'],
skin:'layer-create-content',
shadeClose:false,
closeBtn:2,
closeBtn:1,
content:'<div class="setting-con ptb20">\
<div class="clearfix plan ptb10">\
<span class="typename c4 pull-left f14 text-right mr20">任务类型</span>\
+10 -10
View File
@@ -196,7 +196,7 @@ function recycleBin(type){
layer.open({
type: 1,
shift: 5,
closeBtn: 2,
closeBtn: 1,
area: ['80%','606px'],
title: lan.files.recycle_bin_title,
content: tablehtml
@@ -841,7 +841,7 @@ function createFile(type, path) {
layer.open({
type: 1,
shift: 5,
closeBtn: 2,
closeBtn: 1,
area: '320px',
title: '新建空白文件',
content: '<div class="bt-form pd20 pb70">\
@@ -881,7 +881,7 @@ function createDir(type, path) {
layer.open({
type: 1,
shift: 5,
closeBtn: 2,
closeBtn: 1,
area: '320px',
title: '新建目录',
content: '<div class="bt-form pd20 pb70">\
@@ -981,7 +981,7 @@ function downloadFile(action){
layer.open({
type: 1,
shift: 5,
closeBtn: 2,
closeBtn: 1,
area: '500px',
btn:["确定","关闭"],
title: lan.files.down_title,
@@ -1034,7 +1034,7 @@ function reName(type, fileName) {
layer.open({
type: 1,
shift: 5,
closeBtn: 2,
closeBtn: 1,
area: '320px',
title: '重命名',
btn:["确定","保存"],
@@ -1185,7 +1185,7 @@ function zip(dirName,submits) {
layer.open({
type: 1,
shift: 5,
closeBtn: 2,
closeBtn: 1,
area: '650px',
title: lan.files.zip_title,
content: '<div class="bt-form pd20 pb70">'
@@ -1241,7 +1241,7 @@ function unZip(fileName,type) {
layer.open({
type: 1,
shift: 5,
closeBtn: 2,
closeBtn: 1,
area: '490px',
title: '解压文件',
content: '<div class="bt-form pd20 pb70">'
@@ -1299,7 +1299,7 @@ function getImage(fileName){
var imgUrl = '/files/download?filename='+fileName;
layer.open({
type:1,
closeBtn: 2,
closeBtn: 1,
title:false,
area: '500px',
shadeClose: true,
@@ -1319,7 +1319,7 @@ function uploadFiles(){
var path = $("#DirPathPlace input").val()+"/";
layer.open({
type:1,
closeBtn: 2,
closeBtn: 1,
title:lan.files.up_title,
area: ['500px','300px'],
shadeClose:false,
@@ -1364,7 +1364,7 @@ function setChmod(action,fileName){
// console.log(rdata);
layer.open({
type:1,
closeBtn: 2,
closeBtn: 1,
title: '设置权限['+fileName+']',
area: '400px',
shadeClose:false,
+8 -8
View File
@@ -527,7 +527,7 @@ function checkUpdate() {
}
if (rdata.status === false) {
layer.confirm(rdata.msg, { title: lan.index.update_check, icon: 1, closeBtn: 2, btn: [lan.public.know, lan.public.close] });
layer.confirm(rdata.msg, { title: lan.index.update_check, icon: 1, closeBtn: 1, btn: [lan.public.know, lan.public.close] });
return;
}
layer.msg(rdata.msg, { icon: 1 });
@@ -610,7 +610,7 @@ function reBoot() {
type: 1,
title: '重启服务器或者面板',
area: '330px',
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div class="rebt-con"><div class="rebt-li"><a data-id="server" href="javascript:;">重启服务器</a></div><div class="rebt-li"><a data-id="panel" href="javascript:;">重启面板</a></div></div>'
});
@@ -620,7 +620,7 @@ function reBoot() {
var type = $(this).attr('data-id');
switch (type) {
case 'panel':
layer.confirm('即将重启面板服务,继续吗?', { title: '重启面板服务', closeBtn: 2, icon: 3 }, function () {
layer.confirm('即将重启面板服务,继续吗?', { title: '重启面板服务', closeBtn: 1, icon: 3 }, function () {
var loadT = layer.load();
$.post('/system/restart','',function (rdata) {
layer.close(loadT);
@@ -634,7 +634,7 @@ function reBoot() {
type: 1,
title: '安全重启服务器',
area: ['500px', '280px'],
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: "<div class='bt-form bt-window-restart'>\
<div class='pd15'>\
@@ -692,7 +692,7 @@ function reBoot() {
//修复面板
function repPanel() {
layer.confirm(lan.index.rep_panel_msg, { title: lan.index.rep_panel_title, closeBtn: 2, icon: 3 }, function() {
layer.confirm(lan.index.rep_panel_msg, { title: lan.index.rep_panel_title, closeBtn: 1, icon: 3 }, function() {
var loadT = layer.msg(lan.index.rep_panel_the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.get('/system?action=RepPanel', function(rdata) {
layer.close(loadT);
@@ -750,7 +750,7 @@ function showDanger(num, port) {
type: 1,
area: ['720px', '410px'],
title: '安全提醒(如你想放弃任何安全提醒通知,请删除宝塔安全登录插件)',
closeBtn: 2,
closeBtn: 1,
shift: 5,
content: '<div class="pd20">\
<table class="f14 showDanger"><tbody>\
@@ -769,7 +769,7 @@ function showDanger(num, port) {
//加载关键数据总数
loadKeyDataCount();
function loadKeyDataCount(){
var plist = ['mysql', 'csvn', 'gogs'];
var plist = ['mysql', 'gogs','gitea'];
for (var i = 0; i < plist.length; i++) {
pname = plist[i];
function call(pname){
@@ -784,7 +784,7 @@ function loadKeyDataCount(){
}
var html = '<li class="sys-li-box col-xs-3 col-sm-3 col-md-3 col-lg-3">\
<p class="name f15 c9">'+pname+'</p>\
<div class="val"><a class="btlink" onclick="softMain(\''+pname+'\',\''+rdata['data']['ver']+'\')">'+rdata['data']['count']+'</a></div></li>';
<div class="val"><a class="btlink" onclick="softMain(\''+pname+'\',\''+pname+'\',\''+rdata['data']['ver']+'\')">'+rdata['data']['count']+'</a></div></li>';
$('#index_overview').append(html);
},'json');
}
+9 -9
View File
@@ -204,7 +204,7 @@ function changePath(d) {
type: 1,
area: "650px",
title: '选择目录',
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: false,
content: "<div class='changepath'><div class='path-top'><button type='button' class='btn btn-default btn-sm' onclick='backFile()'><span class='glyphicon glyphicon-share-alt'></span>返回</button>\
@@ -554,7 +554,7 @@ function onlineEditFile(k, f) {
var r = layer.open({
type: 1,
shift: 5,
closeBtn: 2,
closeBtn: 1,
area: ["90%", "90%"],
title: lan.bt.edit_title+"[" + f + "]",
content: '<form class="bt-form pd20 pb70"><div class="line"><p style="color:red;margin-bottom:10px">'+lan.bt.edit_ps+' <select class="bt-input-text" name="encoding" style="width: 74px;position: absolute;top: 31px;right: 19px;height: 22px;z-index: 9999;border-radius: 0;">' + n + '</select></p><textarea class="mCustomScrollbar bt-input-text" id="textBody" style="width:100%;margin:0 auto;line-height: 1.8;position: relative;top: 10px;" value="" /> </div> <div class="bt-form-submit-btn" style="position:absolute; bottom:0; width:100%"> <button type="button" class="btn btn-danger btn-sm btn-editor-close">'+lan.public.close+'</button> <button id="OnlineEditFileBtn" type="button" class="btn btn-success btn-sm">'+lan.public.save+'</button> </div> </form>'
@@ -638,7 +638,7 @@ function safeMessage(j, h, g, f) {
type: 1,
title: j,
area: "350px",
closeBtn: 2,
closeBtn: 1,
shadeClose: true,
content: "<div class='bt-form webDelete pd20 pb70'><p>" + h + "</p>" + f + "<div class='vcode'>"+lan.bt.cal_msg+"<span class='text'>" + sumtext + "</span>=<input type='number' id='vcodeResult' value=''></div><div class='bt-form-submit-btn'><button type='button' class='btn btn-danger btn-sm bt-cancel'>"+lan.public.cancel+"</button> <button type='button' id='toSubmit' class='btn btn-success btn-sm' >"+lan.public.ok+"</button></div></div>"
});
@@ -718,7 +718,7 @@ $(function() {
});
$("#dologin").click(function() {
layer.confirm('您真的要退出面板吗?', {icon:3,closeBtn: 2}, function() {
layer.confirm('您真的要退出面板吗?', {icon:3,closeBtn: 1}, function() {
window.location.href = "/login?dologin=True"
});
return false
@@ -1030,7 +1030,7 @@ function bindPanel(a,type,ip,btid,url,user,pw){
type: 1,
area: "400px",
title: titleName,
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: false,
content: "<div class='bt-form pd20 pb70'>\
@@ -1106,7 +1106,7 @@ function messageBox() {
type: 1,
title: '消息盒子',
area: "670px",
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div class="bt-form">\
<div class="bt-w-main">\
@@ -1459,7 +1459,7 @@ function webShell() {
type: 1,
title: "本地终端",
area: ['685px','435px'],
closeBtn: 2,
closeBtn: 1,
shadeClose: false,
content: '<div class="term-box"><div id="term"></div></div>\
<div class="shell-text-input">\
@@ -1661,7 +1661,7 @@ function pluginOpService(a, b, v) {
case "restart":d = '重启';break;
case "reload":d = '重载';break;
}
layer.confirm( msgTpl('您真的要{1}{2}{3}服务吗?', [d,a,v]), {icon:3,closeBtn: 2}, function() {
layer.confirm( msgTpl('您真的要{1}{2}{3}服务吗?', [d,a,v]), {icon:3,closeBtn: 1}, function() {
var e = layer.msg(msgTpl('正在{1}{2}{3}服务,请稍候...',[d,a,v]), {icon: 16,time: 0});
$.post("/plugins/run", c, function(g) {
layer.close(e);
@@ -1937,7 +1937,7 @@ function pluginOpInitD(a, _version, b) {
case "initd_install":d = '加载';break;
case "initd_uninstall":d = '卸载';break;
}
layer.confirm( msgTpl('您真的要{1}{2}{3}服务吗?', [d,a,_version]), {icon:3,closeBtn: 2}, function() {
layer.confirm( msgTpl('您真的要{1}{2}{3}服务吗?', [d,a,_version]), {icon:3,closeBtn: 1}, function() {
var e = layer.msg(msgTpl('正在{1}{2}{3}服务,请稍候...',[d,a,_version]), {icon: 16,time: 0});
$.post("/plugins/run", c, function(g) {
layer.close(e);
+14 -14
View File
@@ -233,7 +233,7 @@ function webAddPage(type) {
skin: 'demo-class',
area: '640px',
title: '添加网站',
closeBtn: 2,
closeBtn: 1,
shift: 0,
shadeClose: false,
content: "<form class='bt-form pd20 pb70' id='addweb'>\
@@ -673,7 +673,7 @@ function DomainRoot(id, name,msg) {
skin: 'demo-class',
area: '450px',
title: lan.site.domain_man,
closeBtn: 2,
closeBtn: 1,
shift: 0,
shadeClose: true,
content: "<div class='divtable padding-10'>\
@@ -869,7 +869,7 @@ function getBackup(id,name,page) {
skin: 'demo-class',
area: '700px',
title: '打包备份',
closeBtn: 2,
closeBtn: 1,
shift: 0,
shadeClose: false,
content: "<div class='bt-form ptb15 mlr15' id='webBackup'>\
@@ -918,7 +918,7 @@ function setIndex(id){
type: 1,
area: '500px',
title: lan.site.setindex,
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: true,
content:"<form class='bt-form' id='SetIndex'><div class='SetIndex'>"
@@ -964,7 +964,7 @@ function getDefaultSite(){
type: 1,
area: '530px',
title: '设置默认站点',
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: true,
content:'<div class="bt-form ptb15 pb70">\
@@ -1021,7 +1021,7 @@ function webEdit(id,website,endTime,addtime){
type: 1,
area: '640px',
title: '站点修改['+website+'] -- 添加时间['+addtime+']',
closeBtn: 2,
closeBtn: 1,
shift: 0,
content: "<div class='bt-form'>"
+"<div class='bt-w-menu pull-left' style='height: 565px;'>"
@@ -1363,7 +1363,7 @@ function showRewrite(rdata){
type: 1,
area: '500px',
title: '配置伪静态规则',
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: true,
content:webBakHtml
@@ -1430,7 +1430,7 @@ function to301(siteName, type, obj){
skin: 'demo-class',
area: '650px',
title: type == 1 ? '创建重定向' : '修改重定向[' + obj.redirectname + ']',
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: false,
content: "<form id='form_redirect' class='divtable pd20' style='padding-bottom: 60px'>" +
@@ -1632,7 +1632,7 @@ function toProxy(siteName, type, obj) {
type: 1,
area: '650px',
title: "创建反向代理",
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: false,
btn: ['提交','关闭'],
@@ -2381,7 +2381,7 @@ function setRewriteTel(act){
aindex = layer.open({
type: 1,
shift: 5,
closeBtn: 2,
closeBtn: 1,
area: '320px', //宽高
title: '保存为Rewrite模板',
content: '<div class="bt-form pd20 pb70">\
@@ -2408,7 +2408,7 @@ function siteDefaultPage(){
type: 1,
area: '460px',
title: '修改默认页',
closeBtn: 2,
closeBtn: 1,
shift: 0,
content: '<div class="changeDefault pd20">\
<button class="btn btn-default btn-sm mg10" style="width:188px" onclick="changeDefault(1)">默认文档</button>\
@@ -2465,7 +2465,7 @@ function setClassType(){
type: 1,
area: '350px',
title: '网站分类管理',
closeBtn: 2,
closeBtn: 1,
shift: 0,
content: '<div class="bt-form edit_site_type">\
<div class="divtable mtb15" style="overflow:auto">\
@@ -2523,7 +2523,7 @@ function editClassType(id,name){
type: 1,
area: '350px',
title: '修改分类管理【' + name + '】',
closeBtn: 2,
closeBtn: 1,
shift: 0,
content: "<form class='bt-form bt-form pd20 pb70' id='mod_pwd'>\
<div class='line'>\
@@ -2563,7 +2563,7 @@ function moveClassTYpe(){
type: 1,
area: '350px',
title: '设置站点分类',
closeBtn: 2,
closeBtn: 1,
shift: 0,
content: '<div class="bt-form edit_site_type">\
<div class="divtable mtb15" style="overflow:auto;height:80px;">\
+23 -21
View File
@@ -107,7 +107,7 @@ function getSList(isdisplay) {
var mupdate = '';//(plugin.versions[n] == plugin.updates[n]) '' : '<a class="btlink" onclick="softUpdate(\'' + plugin.name + '\',\'' + plugin.versions[n].version + '\',\'' + plugin.updates[n] + '\')">更新</a> | ';
// if (plugin.versions[n] == '') mupdate = '';
handle = mupdate + '<a class="btlink" onclick="softMain(\'' + plugin.name + '\',\'' + plugin.title + '\',\'' + plugin.setup_version + '\')">设置</a> | <a class="btlink" onclick="uninstallVersion(\'' + plugin.name + '\',\'' + plugin.setup_version + '\',' + plugin.uninstall_pre_inspection +')">卸载</a>';
handle = mupdate + '<a class="btlink" onclick="softMain(\'' + plugin.name + '\',\'' + plugin.title + '\',\'' + plugin.setup_version + '\')">设置</a> | <a class="btlink" onclick="uninstallVersion(\'' + plugin.name + '\',\'' + plugin.title +'\',\'' + plugin.setup_version + '\',' + plugin.uninstall_pre_inspection +')">卸载</a>';
titleClick = 'onclick="softMain(\'' + plugin.name + '\',\'' + plugin.title + '\',\'' + plugin.setup_version + '\')" style="cursor:pointer"';
softPath = '<span class="glyphicon glyphicon-folder-open" title="' + plugin.path + '" onclick="openPath(\'' + plugin.path + '\')"></span>';
@@ -189,7 +189,7 @@ function runInstall(data){
function addVersion(name, ver, type, obj, title, install_pre_inspection) {
var option = '';
var titlename = name;
var titlename = title.replace("-"+ver,"");
if (ver.indexOf('|') >= 0){
var veropt = ver.split("|");
var selectVersion = '';
@@ -198,14 +198,14 @@ function addVersion(name, ver, type, obj, title, install_pre_inspection) {
}
option = "<select id='selectVersion' class='bt-input-text' style='margin-left:30px'>" + selectVersion + "</select>";
} else {
option = '<span id="selectVersion">' + name + ' ' + ver + '</span>';
option = '<span id="selectVersion" val="' + name + ' ' + ver + '">【' + titlename + '】 ' + ver + '</span>';
}
layer.open({
type: 1,
title: titlename + "软件安装",
title: "【"+titlename + "】软件安装",
area: '350px',
closeBtn: 2,
closeBtn: 1,
shadeClose: true,
btn: ['提交','关闭'],
content: "<div class='bt-form pd20 c6'>\
@@ -218,27 +218,28 @@ function addVersion(name, ver, type, obj, title, install_pre_inspection) {
installTips();
},
yes:function(index,layero){
// console.log(index,layero)
var info = $("#selectVersion").val().toLowerCase();
if (info == ''){
info = $("#selectVersion").text().toLowerCase();
info = $("#selectVersion").attr('val').toLowerCase();
}
var name = info.split(" ")[0];
var version = info.split(" ")[1];
var info_split = info.split(' ');
var name = info_split[0];
var version = info_split[1];
var type = $('.fangshi').prop("checked") ? '1' : '0';
var data = "name=" + name + "&version=" + version + "&type=" + type;
// console.log(data);
var request_args = "name=" + name + "&version=" + version + "&type=" + type;
if (install_pre_inspection){
//安装检查
installPreInspection(name, version, function(){
runInstall(data);
runInstall(request_args);
flySlow('layui-layer-btn0');
});
return;
}
runInstall(data);
runInstall(request_args);
flySlow('layui-layer-btn0');
}
});
}
@@ -261,8 +262,9 @@ function uninstallPreInspection(name, ver, callback){
}
function runUninstallVersion(name, version){
layer.confirm(msgTpl('您真的要卸载[{1}-{2}]吗?', [name, version]), { icon: 3, closeBtn: 2 }, function() {
function runUninstallVersion(name, title, version){
var title = title.replace("-"+version,"");
layer.confirm(msgTpl('您真的要卸载【{1}-{2}】吗?', [title, version]), { icon: 3, closeBtn: 1 }, function() {
var data = 'name=' + name + '&version=' + version;
var loadT = layer.msg('正在处理,请稍候...', { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/plugins/uninstall', data, function(rdata) {
@@ -274,14 +276,14 @@ function runUninstallVersion(name, version){
}
function uninstallVersion(name, version,uninstall_pre_inspection) {
function uninstallVersion(name, title, version, uninstall_pre_inspection) {
if (uninstall_pre_inspection) {
uninstallPreInspection(name,version,function(){
runUninstallVersion(name,version);
uninstallPreInspection(name,title,version,function(){
runUninstallVersion(name,title,version);
});
return;
}
runUninstallVersion(name,version);
runUninstallVersion(name,title,version);
}
@@ -431,7 +433,7 @@ function importPlugin(file){
type: 1,
area: "500px",
title: "安装第三方插件包",
closeBtn: 2,
closeBtn: 1,
shift: 5,
shadeClose: false,
content: '<style>\

Some files were not shown because too many files have changed in this diff Show More