Compare commits

..
463 Commits
Author SHA1 Message Date
Kr328 de8d6c0945 update clash license 2020-06-21 19:55:16 +08:00
Kr328 f0ec5d353c clean up repo 2020-06-21 19:51:58 +08:00
Kr328 7ac60771bc close source 2020-06-21 19:48:47 +08:00
Kr328 88999fc572 update version 2020-06-13 22:12:01 +08:00
Kr328 3a2ebce4c0 use default dispatcher instead of main 2020-06-13 21:53:24 +08:00
Kr328 acb718edad unregister handler before delete global reference 2020-06-13 20:10:55 +08:00
Kr328 389ecb3e8f update version 2020-06-13 19:07:26 +08:00
Kr328 160b96d829 fix crash on find method ClashException 2020-06-13 19:03:42 +08:00
Kr328 5b80873810 remove unused proguard rule 2020-06-13 19:03:10 +08:00
Kr328 9cae7f9ad7 add default fake ip filter list 2020-06-13 14:08:14 +08:00
Kr328 1333c554a9 load only libbridge.so 2020-06-13 14:07:51 +08:00
Kr328 4d6000af22 update tun2socket 2020-06-13 14:07:33 +08:00
Kr328 3601d1166b fix default fake ip filter 2020-06-13 11:11:55 +08:00
Kr328 7691a96996 fix native integer type overflow 2020-06-13 02:37:12 +08:00
Kr328 db215a5510 update clash core & add default fake-ip filter 2020-06-13 01:38:02 +08:00
Kr328 17c17452b3 refactor build script dependencies define 2020-06-13 01:05:30 +08:00
Kr328 d7b0fa5e29 add windows build compat 2020-06-13 00:25:18 +08:00
Kr328 a0b5e595c8 Merge pull request #413 from goomadao/fix-gradle
Fix build on macOS and Windows
2020-06-12 19:06:10 +08:00
goomadao 728cc0d10b Fix build on macOS and Windows 2020-06-12 16:31:38 +08:00
Kr328 514c84ec7e remove unused debug log output 2020-06-12 13:55:19 +08:00
Kr328 f4af98f54a add increase max connection & clean up code 2020-06-12 00:38:21 +08:00
Kr328 e1f4fef157 version 1.3.1 2020-06-12 00:00:26 +08:00
Kr328 2004f2392a version 1.3.1 2020-06-11 23:49:15 +08:00
Kr328 d7f0cf91c7 refactor clash bridge 2020-06-11 23:48:44 +08:00
Kr328 f34d71eb88 refactor clash bridge 2020-06-11 15:57:34 +08:00
Kr328 b0ed302d5e refactor clash bridge 2020-06-10 21:24:38 +08:00
Kr328 a4b74a7523 update tun2socket & rename token 2020-06-10 21:24:38 +08:00
Kr328 8581f53b20 refactor clash bridge 2020-06-10 21:24:38 +08:00
Kr328 432fa115e2 refactor clash bridge 2020-06-10 21:24:38 +08:00
Kr328 2759f59029 refactor clash bridge 2020-06-10 21:24:38 +08:00
Kr328 d24496a01e refactor clash bridge 2020-06-10 21:24:38 +08:00
Kr328 123bf65c55 refactor clash bridge 2020-06-10 21:24:38 +08:00
Kr328 f6263940f1 update clash core 2020-06-10 21:24:37 +08:00
Kr328 cba3d2d848 refactor clash bridge 2020-06-10 21:24:37 +08:00
Kr328 cecb1522fe refactor build clash scripts 2020-06-10 21:24:37 +08:00
Kr328 fd6ecda520 Merge pull request #412 from Ximu-Luya/master
Provide string translation for Hong Kong and Taiwan
2020-06-10 21:23:21 +08:00
Ximu 147df6c180 Provide string translation for Hong Kong and Taiwan 2020-06-10 19:03:46 +08:00
Ximu 8d6310d0ea Merge pull request #1 from Kr328/master
update issue template
2020-06-02 04:06:41 -05:00
Kr328 c455dfc7df update issue template 2020-06-01 23:35:03 +08:00
Kr328 e381319ae8 update tun2socket 2020-05-24 18:57:26 +08:00
Kr328 297b39625f update clash core & tun2socket 2020-05-24 13:03:55 +08:00
Kr328 b42d762fa0 update clash core 2020-05-14 21:33:29 +08:00
Kr328 f23e6e82b0 update tun2socket 2020-05-11 18:23:11 +08:00
Kr328 2af11c29a5 fix bypass private route comment 2020-05-03 22:43:44 +08:00
Kr328 b0bf57e715 reject all localhost traffic 2020-05-03 21:33:49 +08:00
Kr328 cdd0e3dd30 fix break connection 2020-05-03 00:51:51 +08:00
Kr328 5823955c71 update clash core 2020-05-03 00:50:34 +08:00
Kr328 714c9a554f break connection if set proxy for selector 2020-05-03 00:50:14 +08:00
Kr328 e621324b48 update clash core 2020-05-03 00:29:45 +08:00
Kr328 dfe1e7ecd9 exclude 127.0.0.0/8 from route table 2020-05-03 00:17:55 +08:00
Kr328 4c3380d822 update clash core & tun2socket 2020-04-29 13:22:36 +08:00
Kr328 1d68516cdb fix receivers & service connection leak 2020-04-24 00:49:03 +08:00
Kr328 821bb49914 update issue template 2020-04-23 19:33:28 +08:00
Kr328 c95993a629 fix crash on uploaded 2020-04-23 19:15:46 +08:00
Kr328 e6495f5e1f add uploaded feedback 2020-04-23 19:15:16 +08:00
Kr328 c104942b5f update version 2020-04-23 19:13:34 +08:00
Kr328 59835667aa add report logcat button 2020-04-23 19:04:51 +08:00
Kr328 8a98eea8fa improve core log 2020-04-23 18:52:23 +08:00
Kr328 3dc20b9e70 update issue template 2020-04-23 16:29:17 +08:00
Kr328 d8ab6fd755 update tun2socket version 2020-04-23 13:10:22 +08:00
Kr328 cc499a7897 improve package name modify 2020-04-23 12:14:05 +08:00
Kr328 76f5261b20 Revert "Fix tun start at second user"
This reverts commit 94a0282c
2020-04-23 11:08:36 +08:00
Kr328 6a506b761f update tun2socket 2020-04-23 11:06:50 +08:00
Kr328 fe966f9c5d Revert "Fix tun start at second user"
This reverts commit 94a0282c
2020-04-23 10:52:59 +08:00
Kr328 bcf7f793ec add stop tun on destroy & update version 2020-04-23 10:51:20 +08:00
Kr328 75de6ce041 add full crash logcat report 2020-04-23 00:12:07 +08:00
Kr328 4417a85ef7 update version 2020-04-23 00:09:24 +08:00
Kr328 9e0b67c04a add dump AndroidRuntime tag 2020-04-23 00:06:53 +08:00
Kr328 8cd203e7b0 detect vpn establish failure 2020-04-23 00:03:05 +08:00
Kr328 211160f7f8 Rename fields to let lint happy :) 2020-04-22 13:25:50 +08:00
Kr328 2afc7262eb Update version 2020-04-22 11:25:01 +08:00
Kr328 94a0282c70 Fix tun start at second user 2020-04-22 11:05:10 +08:00
Kr328 96b78829ab Fix cancel profile auto update 2020-04-22 00:25:22 +08:00
Kr328 35d5a90b2a Improve database migrations 2020-04-21 23:50:01 +08:00
Kr328 50d73ad498 update version & dependencies 2020-04-21 22:38:43 +08:00
Kr328 d1f8bc3062 fix delete profile not cancel auto update 2020-04-21 22:32:16 +08:00
Kr328 d3353b1aa5 fix update interval reset 2020-04-21 22:29:21 +08:00
Kr328 cd48fb4e08 fix dialer hook 2020-04-21 22:27:09 +08:00
Kr328 f70738ecf5 update clash core 2020-04-21 22:18:40 +08:00
Kr328 2d63466597 update tun2socket 2020-04-21 21:43:35 +08:00
Kr328 ecf67443fb remove reduce zero ip detect 2020-04-20 12:35:07 +08:00
Kr328 43987ad111 remove reduce zero ip detect 2020-04-20 12:34:27 +08:00
Kr328 5fbd6c6196 Update bug report issue 2020-04-19 02:06:12 +08:00
Kr328 1ec7f1f7e9 Merge branch 'master' into dev 2020-04-19 02:01:39 +08:00
Kr328 c5104c241a add basic url auth support 2020-04-18 20:41:20 +08:00
Kr328 021ba3519d format export log file entry 2020-04-17 13:50:10 +08:00
Kr328 119f74cd05 fix profile edit fragment cast crash 2020-04-17 00:19:39 +08:00
Kr328 f0b61c9e1f cleanup code 2020-04-16 22:40:27 +08:00
Kr328 a573631068 use set directly instead of toList 2020-04-16 22:36:45 +08:00
Kr328 a12444b258 add tun start failure detect 2020-04-16 21:52:11 +08:00
Kr328 17257228a9 Update clash core & add udp packet recycle 2020-04-16 21:26:33 +08:00
Kr328 53b6a9dfc1 Fix pack mmdb failure if downloadGepip before assembleClashCore 2020-04-16 12:13:43 +08:00
Kr328 c45f8ddfc3 Add simple package name modify detect 2020-04-16 11:05:49 +08:00
Kr328 e04c9c15ff Fix Database migrations 2020-04-16 11:03:43 +08:00
Kr328 d5cb363579 Update core 2020-04-15 21:17:26 +08:00
Kr328 0748021ffa Fix cloned profile type 2020-04-15 20:44:49 +08:00
Kr328 1d21368385 Fix database migrations 2020-04-15 13:16:50 +08:00
Kr328 2a5865397a fix DatabaseMigrations.kt 2020-04-15 12:25:28 +08:00
Kr328 f5f378f3b0 update clash core 2020-04-15 11:14:37 +08:00
Kr328 861d5fa871 Update tun2socket 2020-04-15 11:07:02 +08:00
Kr328 4518825aca update tun2socket & update build tools 2020-04-15 01:29:50 +08:00
Kr328 260ebc83ff fix access control & remove context support in fetch.go 2020-04-14 23:44:41 +08:00
Kr328 640cf3e75c add scroll view to support activity 2020-04-14 20:25:13 +08:00
Kr328 7466990e0c update version 1.1.11 -> 1.2.0 2020-04-14 20:07:07 +08:00
Kr328 b41715686c cleanup code & rename util -> utils 2020-04-14 19:50:56 +08:00
Kr328 bca2a7a520 decrease waiting time 2020-04-14 19:47:32 +08:00
Kr328 545c43fe2c fix external profile 2020-04-14 19:47:16 +08:00
Kr328 eaf16318de fix external intent lost & replace application observer 2020-04-14 19:17:24 +08:00
Kr328 a809f94a02 add profile notification intent & detect is modified 2020-04-14 18:47:43 +08:00
Kr328 541862cda8 change routing system traffic string 2020-04-14 14:28:54 +08:00
Kr328 7ab2df9afe fix profile reload detect 2020-04-14 14:25:18 +08:00
Kr328 c45c4a1ad8 fix profile edit 2020-04-14 14:18:41 +08:00
Kr328 2b71f9a9f7 remove channels on migration 2020-04-14 13:57:28 +08:00
Kr328 3db2e1c618 fix profile edit & cleanup code 2020-04-14 12:25:20 +08:00
Kr328 d24617d842 add clone profile detect 2020-04-14 11:03:30 +08:00
Kr328 29dc8dc492 fix as Entity.Profile 2020-04-14 10:48:29 +08:00
Kr328 57b8ce3d7f rename ProfileMetadata.kt -> Profile.kt 2020-04-14 10:47:14 +08:00
Kr328 1536c9f056 fix auto update 2020-04-14 10:45:55 +08:00
Kr328 c2280555d3 fix dns hijacking 2020-04-14 02:17:07 +08:00
Kr328 532760e71a add loading notification 2020-04-14 02:16:58 +08:00
Kr328 6da7eff62c fix reload logic 2020-04-14 02:07:19 +08:00
Kr328 a75192b6bf improve code by Inspect Code 2020-04-14 01:23:15 +08:00
Kr328 f4ceebb12c rename ipc -> transact 2020-04-14 01:03:29 +08:00
Kr328 151327e9ba add waiting status for profile service 2020-04-14 00:58:07 +08:00
Kr328 a343678bad fix auto restart 2020-04-14 00:55:24 +08:00
Kr328 1b2c97d381 bug fix 2020-04-13 23:48:40 +08:00
Kr328 d034eb6f4b remove unused resources 2020-04-13 16:35:09 +08:00
Kr328 08dc165450 rename makeSnackbar & remove modified detect 2020-04-13 16:28:59 +08:00
Kr328 50eef54ab6 update support activity 2020-04-13 16:28:13 +08:00
Kr328 a75bdd457f profile ui refactored 2020-04-13 14:59:24 +08:00
Kr328 d5d219789f add clone support 2020-04-13 12:15:37 +08:00
Kr328 04eed1a768 broadcast with permission 2020-04-13 12:00:48 +08:00
Kr328 87d17bcb9a remove providers only on new profile 2020-04-13 11:58:01 +08:00
Kr328 2d3bd5c5cf add temp acquire 2020-04-13 11:45:05 +08:00
Kr328 12d76a2ad1 cleanup code 2020-04-13 11:13:04 +08:00
Kr328 a0026b1bb3 add timeout to profile processor 2020-04-13 11:12:45 +08:00
Kr328 761f11fa5f move utils to common 2020-04-13 11:12:28 +08:00
Kr328 a7b28692ea remove sync map 2020-04-13 10:48:05 +08:00
Kr328 daac6e1e5c service refactored 2020-04-13 10:46:02 +08:00
Kr328 8c9b7e4a01 decrease mtu 2020-04-11 19:49:20 +08:00
Kr328 1b0778141c update README.md 2020-04-10 14:35:27 +08:00
Kr328 96ed63b704 update README.md 2020-04-10 14:34:32 +08:00
Kr328 bb07bc639d update README.md 2020-04-10 13:49:25 +08:00
Kr328 c3eb4b2f51 update clash core 2020-04-10 13:45:51 +08:00
Kr328 9deeb37f21 add auto signing with properties 2020-04-10 13:45:16 +08:00
Kr328 0befdc0d34 clean up code 2020-04-09 23:19:59 +08:00
Kr328 606a21dff0 add documents provider 2020-04-09 14:39:57 +08:00
Kr328 ef6a37fb7c remove default network detect logs 2020-04-08 16:23:37 +08:00
Kr328 2f7b8c4b59 fix default network detect 2020-04-08 16:21:22 +08:00
Kr328 968e82b072 move load.go init to patch.go 2020-04-08 16:14:09 +08:00
Kr328 0240eea776 android: add fake pool host override 2020-04-08 11:13:40 +08:00
Kr328 dc8d94fa31 remove ipv6 for VpnService 2020-04-08 11:11:38 +08:00
Kr328 f6ec8cc882 update tun2socket & remove ipv6 for VpnService 2020-04-08 11:10:13 +08:00
Kr328 b648d21068 use ServiceStatusProvider instead of requery database 2020-04-08 02:05:05 +08:00
Kr328 2b63997b22 cleanup code 2020-04-08 01:58:14 +08:00
Kr328 198daaf720 add restore selected proxy 2020-04-08 01:57:50 +08:00
Kr328 a1847dc6f2 update core & broadcast on loaded & stop on load failure 2020-04-08 01:42:21 +08:00
Kr328 8ebb3a5f31 fix dns hijack not working 2020-04-08 01:00:06 +08:00
Kr328 7cf3dc2bf2 clean up code 2020-04-08 00:44:28 +08:00
Kr328 2346095323 increase mtu 2020-04-08 00:43:47 +08:00
Kr328 40ae2d456c rename module component -> common 2020-04-08 00:42:41 +08:00
Kr328 3152bcaaa6 refactor clash core context 2020-04-08 00:42:22 +08:00
Kr328 c69c41c57f refactor clash core context 2020-04-03 01:08:04 +08:00
Kr328 ea1f424b33 refactor clash core context 2020-04-02 00:44:26 +08:00
Kr328 1ef828497c remove gc period 2020-04-01 14:45:53 +08:00
Kr328 88b28faa48 add component module & clean up code 2020-04-01 14:45:06 +08:00
Kr328 7bfaacf936 call gc period to decrease ram usage 2020-04-01 01:12:50 +08:00
Kr328 05d8dae4e0 fix notification not show profile 2020-04-01 00:52:36 +08:00
Kr328 27cd92b4b1 recycle dns udp packet 2020-03-31 23:21:02 +08:00
Kr328 4b6b5b5d95 update core 2020-03-30 16:51:39 +08:00
Kr328 6468575a42 fix fake ip filter not working 2020-03-30 16:38:33 +08:00
Kr328 5ea22cecad update tun2socket & fix crash on tcp dns query 2020-03-30 13:09:36 +08:00
Kr328 c8205d3f95 update tun2socket 2020-03-29 20:14:45 +08:00
Kr328 639377760c update tun2socket 2020-03-29 15:25:39 +08:00
Kr328 a9323f0528 update tun2socket & core & mtu 2020-03-28 23:41:52 +08:00
Kr328 2e31e90225 update core 2020-03-28 14:49:11 +08:00
Kr328 9d5b8188eb fix patch bug 2020-03-28 14:39:28 +08:00
Kr328 1f9e330f6a fix patch bug 2020-03-28 13:56:54 +08:00
Kr328 a69776fe33 update clash core 2020-03-28 12:31:48 +08:00
Kr328 d42dc46b8c use tun2socket instead of netstack 2020-03-28 12:30:26 +08:00
Kr328 c37dc2f874 fix delete geoip database on rebuild 2020-03-28 12:29:28 +08:00
Kr328 9c20f13f95 update dependencies 2020-03-27 23:59:33 +08:00
Kr328 e958e7f675 Update 03-bug-report-zh-cn.md 2020-03-22 20:45:20 +08:00
Kr328 68113e694e update issue template 2020-03-22 13:04:50 +08:00
Kr328 88aec66ef8 Merge branch 'master' into dev 2020-03-21 16:13:55 +08:00
Kr328 f500596621 update README.md 2020-03-21 16:11:03 +08:00
Kr328 df5bafd0bb update README.md 2020-03-21 16:01:35 +08:00
Kr328 01fe9deb20 update issue template 2020-03-20 13:16:43 +08:00
Kr328 4e44298e98 sorted github issue 2020-03-19 19:46:12 +08:00
Kr328 a7c3a05c23 add application info request 2020-03-19 19:09:20 +08:00
Kr328 05fa36497b rename issues template file 2020-03-19 18:56:41 +08:00
Kr328 e6f8ae265e Add issue templates 2020-03-19 18:53:05 +08:00
Kr328 d107847747 remove unused General.Mode serializer 2020-03-19 15:21:20 +08:00
Kr328 ea8e270df6 add auto activity name detect 2020-03-19 15:16:50 +08:00
Kr328 4bc40e0663 update dependencies 2020-03-19 15:16:39 +08:00
Kr328 5e6ccd990a update dependencies 2020-03-19 12:29:34 +08:00
Kr328 1a8d673742 update clash core 2020-03-03 22:48:54 +08:00
Kr328 a4069aa6f6 remove unused var 2020-03-03 22:01:07 +08:00
Kr328 3cfb90c078 use kotlin build script 2020-03-03 21:50:30 +08:00
Kr328 594949d3f0 format code & update core 2020-02-28 23:52:58 +08:00
Kr328 8fd34b5258 improve apk broken detect & fix udp crash 2020-02-28 14:00:38 +08:00
Kr328 1161482a5b fix udp crash 2020-02-28 11:19:06 +08:00
Kr328 8a123e7a0d improve network settings 2020-02-28 01:13:11 +08:00
Kr328 4ef3a20929 add vpn component detect 2020-02-28 00:32:49 +08:00
Kr328 16c2e9b694 increase refresh interval 2020-02-28 00:24:24 +08:00
Kr328 c9a9d310ef update version 2020-02-28 00:22:21 +08:00
Kr328 84996a5652 update apk broken detect 2020-02-27 16:30:57 +08:00
Kr328 115afc5735 update apk broken detect 2020-02-27 16:30:34 +08:00
Kr328 2ae75e876d fix uri case 2020-02-27 16:03:28 +08:00
Kr328 126291d544 improve duplicate profile 2020-02-27 14:26:47 +08:00
Kr328 37db81f6b1 improve profile update & update clash core 2020-02-27 14:05:00 +08:00
Kr328 a3cfd10d39 fix udp crash 2020-02-26 16:31:59 +08:00
Kr328 0e61f02046 fix typo 2020-02-26 15:20:22 +08:00
Kr328 d8b1c0b7b8 remove debug symbol of clash core 2020-02-26 14:58:29 +08:00
Kr328 8bf908b731 remove default disallow package 2020-02-26 14:53:30 +08:00
Kr328 568f1f12e7 fix crash on ipv6 enable & reduce provider call 2020-02-26 14:06:46 +08:00
Kr328 ca739a5e2f add abi split 2020-02-26 13:53:42 +08:00
Kr328 7833f747d5 format & cleanup 2020-02-26 13:33:44 +08:00
Kr328 977519b383 change crash reporter
fix crash on log polling
fix crash on udp write back
fix goroutine leak
fix default rule inject
2020-02-26 13:32:29 +08:00
Kr328 b39b3812d0 add crash reporter 2020-02-25 20:53:39 +08:00
Kr328 f7dddb41fa add crash reporter 2020-02-25 20:53:26 +08:00
Kr328 053300919c add crash reporter 2020-02-25 20:38:55 +08:00
Kr328 93dff86383 clear dumper 2020-02-25 14:42:06 +08:00
Kr328 1b7e9c6b12 add golang crash dumper 2020-02-25 14:41:53 +08:00
Kr328 f072cd0839 update dependencies 2020-02-25 12:43:58 +08:00
Kr328 f626a0fc5c fix ipv6 support
https://github.com/shadowsocks/shadowsocks-android/commit/cc840c9fddb3f4f6677005de18f1fcb387b84064#diff-e089fe63dcb3674c0a1e459a95508e3e
2020-02-24 20:33:29 +08:00
Kr328 63da12f046 1.1.4 2020-02-23 23:50:41 +08:00
Kr328 ce1beafb08 fix proxies active cache 2020-02-23 23:22:32 +08:00
Kr328 f6ecc5c953 remove reduce recreate call 2020-02-23 22:55:10 +08:00
Kr328 de87e3fd74 add crash log 2020-02-23 22:54:13 +08:00
Kr328 e34a7a3081 update version 2020-02-22 23:42:28 +08:00
Kr328 ecb1678e48 fix not start vpn after request 2020-02-22 23:41:34 +08:00
Kr328 ca395033a5 update clash core 2020-02-22 23:27:42 +08:00
Kr328 8095451e14 remove testing code 2020-02-22 23:27:00 +08:00
Kr328 c0435ead01 fix tun leak 2020-02-22 23:23:50 +08:00
Kr328 d346344e17 simple ui adjust 2020-02-22 23:23:22 +08:00
Kr328 68d6af4255 fix notification cancel delay 2020-02-22 22:24:45 +08:00
Kr328 253d465d32 Merge pull request #135 from tsln1998/fix_windows_build
fix source path on windows
2020-02-22 21:57:16 +08:00
Kr328 7ab7c8abee fix receiver leak 2020-02-22 21:43:28 +08:00
Kr328 ea3aee0883 fix proxy only not load profile default 2020-02-22 21:19:33 +08:00
Kr328 b4a5d7b1be Use single service to handle clash 2020-02-22 21:17:29 +08:00
tsln1998 028346713e fix source path on windows 2020-02-22 18:15:40 +08:00
Kr328 d519bc1a23 update README.md 2020-02-22 01:48:38 +08:00
Kr328 a6d5fbc2ca update PRIVACY_POLICY.md 2020-02-22 01:46:45 +08:00
Kr328 e9a6bc2fbc add delay for proxies 2020-02-22 01:13:15 +08:00
Kr328 ef42612c4b change launchMode & fix tile icon size 2020-02-22 00:51:04 +08:00
Kr328 f4b421c953 1.1.1 2020-02-22 00:35:25 +08:00
Kr328 14aa981ca4 update base version 2020-02-20 23:33:50 +08:00
Kr328 515942274d bug fix 2020-02-20 23:33:30 +08:00
Kr328 03785f427a fix start on boot reset alarm 2020-02-20 15:14:07 +08:00
Kr328 5cc1f43a03 add option margin end 2020-02-20 15:11:56 +08:00
Kr328 a557255099 fix access control mode & packages 2020-02-20 15:02:47 +08:00
Kr328 932778b153 add request ua & add tile long press action 2020-02-20 14:44:05 +08:00
Kr328 1e8cadb878 add app broken detect 2020-02-20 14:27:37 +08:00
Kr328 eba2869c1b bug fix & cleanup code 2020-02-20 13:43:38 +08:00
Kr328 121108c416 bug fix & add tile 2020-02-20 03:13:56 +08:00
Kr328 780dfda610 add README.md 2020-02-20 01:43:54 +08:00
Kr328 3dd3431401 add settings migration 2020-02-20 01:40:52 +08:00
Kr328 ba8a6247f5 add tips for profiles 2020-02-20 01:21:59 +08:00
Kr328 5f1ee513f2 fix 1 -> 2 migration 2020-02-20 00:54:16 +08:00
Kr328 17fd5954a0 add support click action 2020-02-19 22:57:10 +08:00
Kr328 87e4061879 add about 2020-02-19 22:52:46 +08:00
Kr328 5c1ce96239 fix auto update 2020-02-19 22:41:42 +08:00
Kr328 ef058f223d update build scripts 2020-02-19 15:47:26 +08:00
Kr328 ab03e551da add package list 2020-02-19 15:28:32 +08:00
Kr328 168a097111 add zh-cn 2020-02-19 13:57:59 +08:00
Kr328 232572114c Merge remote-tracking branch 'private/dev' into dev 2020-02-19 02:56:55 +08:00
Kr328 54c67f83ab add zh-cn 2020-02-19 02:56:33 +08:00
Kr328 e63f210cc8 add zh-cn 2020-02-19 02:56:32 +08:00
Kr328 48169224c0 add settings 2020-02-19 02:46:38 +08:00
Kr328 f2d99a50a7 add settings 2020-02-19 02:21:48 +08:00
Kr328 bfa3c8375b new method to detect default network 2020-02-18 16:50:36 +08:00
Kr328 34697da10c new method to detect default network 2020-02-18 00:30:59 +08:00
Kr328 3e7d7f5d60 add dns patch 2020-02-18 15:16:43 +08:00
Kr328 8a4149c800 fix broadcast 2020-02-18 01:17:05 +08:00
Kr328 0d7650cbc0 add logs activity 2020-02-18 00:53:18 +08:00
Kr328 72932a255d add basic multiple language support 2020-02-17 01:54:12 +08:00
Kr328 4848a0f6d9 fix auto proxy scroll 2020-02-17 00:43:31 +08:00
Kr328 a5064fdd4f proxy activity refactored 2020-02-17 00:16:41 +08:00
Kr328 5d4b6b4fb5 add prefix merger 2020-02-16 15:54:22 +08:00
Kr328 d5a0299d91 [WIP] UI refactor 2020-02-16 02:04:54 +08:00
Kr328 718388db51 [WIP] UI refactor 2020-02-15 14:42:09 +08:00
Kr328 01d9d231b5 [WIP] UI refactor 2020-02-15 01:03:23 +08:00
Kr328 88e0425736 [WIP] UI refactor 2020-02-14 20:17:58 +08:00
Kr328 05f2a12baf refactor file storage logic 2020-02-13 16:34:13 +08:00
Kr328 c9d3b8e836 [WIP] UI logic refactor 2020-02-12 00:14:09 +08:00
Kr328 33fbd378c0 [WIP] UI logic refactor 2020-02-11 16:20:36 +08:00
Kr328 f76bed2f8b add profile process service 2020-02-09 00:53:40 +08:00
Kr328 23027b8813 [WIP] refactor profile service 2020-02-08 02:30:09 +08:00
Kr328 896c57aa03 ProfileService refactored 2020-02-02 16:15:24 +08:00
Kr328 ee6458a60e [WIP] refactor UI 2020-01-26 14:47:59 +08:00
Kr328 114456a1f2 [WIP] refactor UI 2020-01-22 13:23:27 +08:00
Kr328 cca7ec81e1 service refactored 2020-01-21 20:27:05 +08:00
Kr328 e9e59f6026 service refactored 2020-01-21 20:23:02 +08:00
Kr328 a29c95ceef service refactored 2020-01-21 20:17:31 +08:00
Kr328 c60d8cfb53 [WIP] refactor service 2020-01-21 13:24:58 +08:00
Kr328 4ee8679d29 [WIP] refactor service 2020-01-20 23:31:14 +08:00
Kr328 419c6301dd [WIP] refactor services 2020-01-20 12:09:11 +08:00
Kr328 e979bec321 [WIP] refactor service 2020-01-17 00:17:40 +08:00
Kr328 fa6ac580d0 [WIP] refactor service 2020-01-16 23:42:10 +08:00
Kr328 a44bb05345 [WIP] refactor services 2020-01-14 15:45:57 +08:00
Kr328 19ddb86430 [WIP] refactor clash bridge 2020-01-12 23:43:52 +08:00
Kr328 1eb6f59167 trim gopath for output 2020-01-11 21:25:22 +08:00
Kr328 2ba82ebd97 migrate to netstack 2020-01-11 21:05:59 +08:00
Kr328 00163fbfd4 update submodule 2020-01-11 14:15:10 +08:00
Kr328 0ef8734856 fix udp reject 2019-12-22 15:55:46 +08:00
Kr328 a4151fb198 cleanup code & update version code 2019-12-21 11:56:02 +08:00
Kr328 292ba5af95 add feedback id (use Build.ID & PackageArchive.lastUpdateTime) 2019-12-21 11:55:13 +08:00
Kr328 90456263ae add google play & split apk detect 2019-12-21 10:59:06 +08:00
Kr328 bc3f7d0549 use 172.31.255.252/30 instead of 172.19.0.0/30 2019-12-20 11:01:45 +08:00
Kr328 382f083fd1 fix crash on tile start
reset clash bandwidth on start
add version name to about dialog
2019-12-20 10:51:55 +08:00
Kr328 a287e287b9 fix tun 2019-12-19 22:35:11 +08:00
Kr328 166558433e decrease start on boot delay 2019-12-19 21:54:31 +08:00
Kr328 1915b005a9 change start activity flags 2019-12-19 21:52:55 +08:00
Kr328 ed63036329 fix crash on proxy only mode 2019-12-19 21:44:15 +08:00
Kr328 a49899add3 update clash core 2019-12-19 21:03:00 +08:00
Kr328 85072e4520 fix broadcast on sysstack 2019-12-19 21:02:13 +08:00
Kr328 a31f864ab8 fix bugs 2019-12-17 14:25:11 +08:00
Kr328 5bcbc4563e fix bugs 2019-12-17 13:59:54 +08:00
Kr328 62910f5e7e try fix bugs & disable ipv6 for default dns 2019-12-17 13:51:32 +08:00
Kr328 b3ff9abc0d refactor service 2019-12-16 23:06:13 +08:00
Kr328 eccc9bd886 refactor event service dispatch 2019-12-16 18:57:23 +08:00
Kr328 0bd1fcf51b fix crash on close 2019-12-15 16:03:48 +08:00
Kr328 51acbc75f5 fix crash on close 2019-12-15 16:01:48 +08:00
Kr328 c3cd2351a5 redirect tun initial 2019-12-15 14:06:36 +08:00
Kr328 dde7f77c29 add golang output to source sets 2019-12-14 15:24:57 +08:00
Kr328 dafba83b8d auto build clash bind 2019-12-14 14:42:00 +08:00
Kr328 ba472b5768 fix libclash.so not found 2019-12-11 10:21:56 +08:00
Kr328 c4f4c157bd try fix app bundle not extract native libs 2019-12-11 09:29:59 +08:00
Kr328 5ddeaf2783 add privacy policy 2019-12-10 22:58:13 +08:00
Kr328 1b87bc0417 finish activity on import successfully 2019-12-10 22:35:31 +08:00
Kr328 a154230bca fix some bugs 2019-12-10 22:28:43 +08:00
Kr328 4b498d7dc7 update tile on clash reload 2019-12-10 14:59:19 +08:00
Kr328 41b263a7ee fix fabric 2019-12-10 14:21:02 +08:00
Kr328 ddeff030e3 update version code 2019-12-10 14:17:54 +08:00
Kr328 d48beadcbc fix empty tile name 2019-12-10 14:14:26 +08:00
Kr328 7238e919c5 fix tile service clash start failure 2019-12-10 13:45:08 +08:00
Kr328 7cd52a84db update version & remove log runControlNoException 2019-12-10 13:22:40 +08:00
Kr328 e97a2d58c8 add crashlytics 2019-12-10 13:10:56 +08:00
Kr328 340fa28c6a add marquee text view 2019-12-10 11:33:35 +08:00
Kr328 6c58f552b8 tile title = profile name 2019-12-10 11:23:47 +08:00
Kr328 7cc53bbf32 add clash://install-config handler 2019-12-10 11:14:13 +08:00
Kr328 88ef4d2f10 fix dns hijacking not working 2019-12-10 01:22:02 +08:00
Kr328 968ef77896 update version 2019-12-10 00:33:08 +08:00
Kr328 64803bef1e compatible with legacy rules 2019-12-10 00:32:32 +08:00
Kr328 d7df27b91d adjust ui 2019-12-10 00:24:00 +08:00
Kr328 32b6608f11 update version code 2019-12-09 23:54:45 +08:00
Kr328 a665acaf63 fix profile event 2019-12-09 23:52:33 +08:00
Kr328 e2073b5f7c disable colorized 2019-12-09 23:51:59 +08:00
Kr328 475dd96ac2 adjust text 2019-12-09 23:45:28 +08:00
Kr328 9fe2ec39ae adjust ui 2019-12-09 23:42:53 +08:00
Kr328 9cca3c958e fix access control order 2019-12-09 01:08:35 +08:00
Kr328 903c201f2d update version code 2019-12-09 01:04:32 +08:00
Kr328 2b47776554 fix profile scroll not working & pin selected access control apps 2019-12-09 01:03:05 +08:00
Kr328 41a2e7effc fix proxy name display & profile not fully display 2019-12-09 00:41:13 +08:00
Kr328 6947118d2e update version code 2019-12-09 00:13:50 +08:00
Kr328 3b7a0b0101 fix start on boot display 2019-12-09 00:06:04 +08:00
Kr328 19dcc4a1fa use profile log level 2019-12-08 23:57:29 +08:00
Kr328 8ec689a893 fix restore selected proxy after update profile 2019-12-08 23:55:40 +08:00
Kr328 a1d623c42b use marquee for proxy name overflow 2019-12-08 23:50:45 +08:00
Kr328 9a893fc0a0 fix form adapter dialog title 2019-12-08 23:49:36 +08:00
Kr328 f13abcbe49 fix url test not working after refreshing 2019-12-08 23:47:35 +08:00
Kr328 24e1732091 add back button on action bar & add dns hijacking option 2019-12-08 23:40:24 +08:00
Kr328 8a2826c242 Merge pull request #7 from ccg2018/fix-open-app-main
fix(launch): when open the app from launcher, stay current activity
2019-12-08 22:42:47 +08:00
Kr328 b36f19f4c4 Merge pull request #4 from ccg2018/tile
feat(Tile): long click to open in app
2019-12-08 22:42:05 +08:00
CCG 9967601e3e fix(launch): when open the app from launcher, stay current activity 2019-12-08 20:07:05 +08:00
CCG c330bf8238 feat(Tile): long click to open in app 2019-12-08 17:26:33 +08:00
Kr328 b38d9ec95e update version code & add README.md NOTICE 2019-12-08 12:22:09 +08:00
Kr328 1069ba1991 use proxy order from GLOBAL & add tile 2019-12-07 15:48:45 +08:00
Kr328 ea29017687 Revert "keep proxy original order"
This reverts commit b41b9267
2019-12-07 15:22:02 +08:00
Kr328 b41b9267bd keep proxy original order 2019-12-07 15:01:05 +08:00
Kr328 5ffa1aeb1d add rule extra param 2019-12-07 08:45:04 +08:00
Kr328 d2b91341f0 fix default fallback dns not working 2019-12-07 08:24:23 +08:00
Kr328 5e69959cf5 fix profile delete file 2019-12-07 07:39:23 +08:00
Kr328 845f1b37ca add IP-CIDR6 parse 2019-12-07 07:36:46 +08:00
Kr328 21fb12ef71 fix crash by obfs 2019-12-07 07:10:13 +08:00
Kr328 53fa597556 add simple error notice 2019-12-07 06:03:08 +08:00
Kr328 adffebadbc add feedback & about 2019-12-07 05:51:27 +08:00
Kr328 ea93c0b3ab add log 2019-12-07 05:06:58 +08:00
Kr328 ea3b63fd80 Create LICENSE 2019-12-07 01:51:30 +08:00
Kr328 bda542d2e5 add url test 2019-12-07 01:30:35 +08:00
Kr328 a72c2d8abb url profile update 2019-12-06 14:18:30 +08:00
Kr328 8ad202cc07 fix double click in access control & add ramdom http listener 2019-12-06 00:41:57 +08:00
Kr328 bc8cea7bd8 clean up code 2019-12-06 00:37:28 +08:00
Kr328 8878070efc fix typo & add profile reload event 2019-12-05 23:48:10 +08:00
Kr328 4e2dceef48 format code 2019-12-05 07:33:51 +08:00
Kr328 c9973393ff add import from url (1/3) 2019-12-05 00:11:04 +08:00
Kr328 f0aba3758d rebase "comzyh/add-water" & add dns config fallback 2019-12-03 11:32:52 +08:00
Kr328 d8e5e74444 update ui text 2019-12-03 09:25:26 +08:00
Kr328 0a05d76850 application settings & start on boot 2019-12-02 23:55:00 +08:00
Kr328 996d82dfbf proxy mode ui 2019-12-02 22:53:16 +08:00
Kr328 961f9c7633 add black/white list 2019-12-02 21:43:19 +08:00
Kr328 e7d59ec633 fix bypass loopback 2019-12-02 16:51:17 +08:00
Kr328 32828a6ee9 fix load profile return nil invalid selected 2019-12-02 00:21:36 +08:00
Kr328 e8a48c0f0d settings draft 2019-12-01 23:41:39 +08:00
Kr328 afbebb4c8b redirect ALL dns to clash dns 2019-12-01 15:16:20 +08:00
Kr328 a911a0c4dd fix dns redirect 2019-12-01 14:38:38 +08:00
Kr328 fe9047ee40 fix profile 2019-11-30 23:09:26 +08:00
Kr328 bd159ecb6e add selector persistence 2019-11-30 21:26:08 +08:00
Kr328 1e8a57e949 refactor proxy list 2019-11-30 16:41:14 +08:00
Kr328 f418a3649e split traffic 2019-11-30 14:43:07 +08:00
Kr328 fa99b3f981 add ipv6 dnsredirect 2019-11-30 02:32:23 +08:00
Kr328 2661f01c19 reset submodule 2019-11-30 02:08:27 +08:00
Kr328 8633ab2de6 remove event 2019-11-30 02:00:03 +08:00
Kr328 70c8bb19a7 fix buffer & dns nil 2019-11-30 01:58:06 +08:00
Kr328 cdf7107d5a fix typo 2019-11-30 01:37:50 +08:00
Kr328 c11a1bb2a3 use comzyh/add-water 2019-11-30 01:30:05 +08:00
Kr328 8466662226 proxy activity 2019-11-29 00:19:45 +08:00
Kr328 7765d14588 proxy activity 2019-11-28 23:49:11 +08:00
Kr328 8968469310 refactor Parcels 2019-11-27 12:04:39 +08:00
Kr328 d7d36f32a3 fix bugs 2019-11-27 00:03:20 +08:00
Kr328 aa4b6c23bb proxy activity 2019-11-26 23:30:51 +08:00
Kr328 ceae371826 proxy activity 2019-11-26 23:14:46 +08:00
Kr328 7fba8b09cc dynamic disable notification update 2019-11-26 13:53:40 +08:00
Kr328 527f99ea00 dynamic disable notification update 2019-11-26 13:52:28 +08:00
Kr328 db1efcb85d dynamic disable notification update 2019-11-26 13:50:41 +08:00
Kr328 456c853923 new default network observer 2019-11-26 00:48:01 +08:00
Kr328 e5abd0cba8 notification 2019-11-26 00:24:20 +08:00
Kr328 f61013d99d basic function 2019-11-25 20:19:06 +08:00
Kr328 4768bd92dc profile framework 2019-11-25 17:25:40 +08:00
Kr328 9023809c89 service event framework 2019-11-25 17:01:20 +08:00
Kr328 e14e91a2a4 notification 2019-11-25 00:52:13 +08:00
Kr328 0e6cb05796 event framework 2019-11-25 00:35:06 +08:00
Kr328 da532df009 create event poll 2019-11-24 21:47:40 +08:00
Kr328 9aa20c6715 create event poll 2019-11-24 21:47:30 +08:00
Kr328 c7107e9d9b create event poll 2019-11-24 17:35:12 +08:00
Kr328 f882375cfa create event poll 2019-11-24 17:25:46 +08:00
Kr328 a6abb51046 create event poll 2019-11-24 16:29:13 +08:00
Kr328 438392ddf6 use serializable for parcelable 2019-11-24 14:10:48 +08:00
Kr328 6646593c5b add query proxies 2019-11-24 12:54:58 +08:00
Kr328 ab4b8b5057 add query proxies 2019-11-24 11:19:06 +08:00
Kr328 3b03624f32 use custom view 2019-11-23 14:06:10 +08:00
Kr328 7270f94930 fix metered vpn 2019-11-23 04:10:34 +08:00
Kr328 838d492334 fix metered vpn 2019-11-23 03:44:23 +08:00
Kr328 600537af9c basic proxy function available 2019-11-23 02:58:08 +08:00
Kr328 774d83ed9f new profile activity 2019-11-22 19:22:51 +08:00
Kr328 e3c5fb1a8c profiles activity 2019-11-22 09:56:57 +08:00
Kr328 f237879921 fix margin 2019-11-22 00:10:47 +08:00
Kr328 765892e768 set default state to stopped 2019-11-22 00:05:23 +08:00
Kr328 5caa778a71 fix tun unable to close 2019-11-21 23:58:52 +08:00
Kr328 f2a0e4877a use object instance instead of int 2019-11-21 23:43:00 +08:00
Kr328 7d04980e30 main activity 2019-11-21 23:40:35 +08:00
Kr328 565415d8d1 add layout id 2019-11-21 21:54:35 +08:00
Kr328 3f91c10c10 MainActivity 2019-11-21 21:49:53 +08:00
Kr328 96b8fe110b MainActivity 2019-11-21 00:15:00 +08:00
Kr328 d0aa037b4c add database 2019-11-20 22:48:59 +08:00
Kr328 792190b5f4 split ui / service 2019-11-20 18:13:28 +08:00
Kr328 d332b6941a split ui / service 2019-11-20 18:13:05 +08:00
Kr328 cd1a8bf5e4 cleanup code 2019-11-20 17:44:31 +08:00
Kr328 5c7e00ce59 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	app/src/main/java/com/github/kr328/clash/ClashService.kt
2019-11-20 17:41:35 +08:00
Kr328 2b1c32faf7 IClashService 2019-11-20 17:37:12 +08:00
Kr328 b98d5a5ce0 clash service 2019-11-20 12:10:33 +08:00
Kr328 4c84616797 clash service 2019-11-20 00:40:12 +08:00
Kr328 b1d22f3c3c clash service 2019-11-19 23:20:50 +08:00
Kr328 e8a3335e21 tun device work fine 2019-11-19 14:36:17 +08:00
Kr328 6cecb23dd8 clash process starter 2019-11-19 11:49:15 +08:00
Kr328 9987a83334 use kotlin for core 2019-11-19 09:30:41 +08:00
Kr328 fe194eac76 tun device private 2019-11-19 09:27:18 +08:00
Kr328 21b9d0fa27 use start process instead of jni 2019-11-19 09:23:54 +08:00
Kr328 cf4e1c5b95 new impl for clash core 2019-11-19 00:06:19 +08:00
Kr328 e624618be6 try 2019-11-15 16:21:24 +08:00
Kr328 fa6e5841bf add load default 2019-11-15 09:15:27 +08:00
Kr328 c3ebd9d6e3 initial commit 2019-11-15 08:12:33 +08:00
53 changed files with 382 additions and 2833 deletions

No files matched your search

@@ -0,0 +1,57 @@
---
name: "[English] Bug report"
about: Create a report to help us improve
title: "[BUG] "
labels: ''
assignees: ''
---
<!-- Be sure to put a clear title after [BUG] in the text box above -->
<!-- Be sure to put a clear title after [BUG] in the text box above -->
<!-- Be sure to put a clear title after [BUG] in the text box above -->
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Device Info (please complete the following information):**
- Device: [e.g. Pixel 4]
- ROM: [e.g: AOSP]
- ROM Version:
- Android Version [e.g. 10]
**Application Info (please complete the following information):**
- Version: [e.g. 1.1.10]
- Apk File Name: [e.g. app-release-arm64-v8a.apk]
- Distribution Channel: [e.g. Google Play]
**Additional context**
Add any other context about the problem here.
**Configure**
If applicable, paste **removed server info** configure
```yaml
# paste here
```
**Logs**
If applicable, paste logs to help detect problem
```
<paste here>
```
@@ -0,0 +1,24 @@
---
name: "[English] Feature request"
about: Suggest an idea for this app
title: "[Feature Request] "
labels: ''
assignees: ''
---
<!-- Be sure to put a clear title after [Feature Request] in the text box above -->
<!-- Be sure to put a clear title after [Feature Request] in the text box above -->
<!-- Be sure to put a clear title after [Feature Request] in the text box above -->
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
@@ -0,0 +1,55 @@
---
name: "[简体中文] 创建错误报告"
about: 创建错误报告以帮助我们改进应用
title: "[BUG] "
labels: ''
assignees: ''
---
<!-- 请务必在上方文本框处 [BUG] 后填入清晰明了的标题 -->
<!-- 请务必在上方文本框处 [BUG] 后填入清晰明了的标题 -->
<!-- 请务必在上方文本框处 [BUG] 后填入清晰明了的标题 -->
**描述出现的错误**
请简洁的描述你遇到的错误
**如何复现该错误**
复现步骤:
1. ...
2. ...
3. ...
4. ...
**预期行为**
清晰简单的描述你预期的应用应该表现的行为
**屏幕截图**
如果适用, 上传屏幕截图以帮助描述错误
**设备信息 (请完成以下信息):**
- 机型: [例如: Pixel 4]
- 系统/ROM: [例如: MIUI 11]
- Android 版本 [例如: 10]
- ROM版本 [例如: 20.3.19]
**应用信息**
- 版本: [例如: 1.1.10]
- 安装包文件名: [例如: app-release-arm64-v8a.apk]
- 应用来源: [例如: Google Play]
**附加信息**
其他的可能与改错误相关的信息
**配置文件**
如果适用, 在此粘贴 **去除服务器信息的** 的 **配置文件**
```yaml
# 在此粘贴
```
**日志**
如果适用, 粘贴日志以帮助侦测错误
```
<在此粘贴>
```
@@ -0,0 +1,21 @@
---
name: "[简体中文] 功能请求"
about: 你希望的能够在应用中增加的功能
title: "[Feature Request] "
labels: ''
assignees: ''
---
<!-- 请务必在上方文本框处 [Feature Request] 后填入清晰明了的标题 -->
<!-- 请务必在上方文本框处 [Feature Request] 后填入清晰明了的标题 -->
<!-- 请务必在上方文本框处 [Feature Request] 后填入清晰明了的标题 -->
**功能描述**
请清晰的描述你想要的功能
**描述你希望的实现方式**
清晰的描述应用应该如何实现该功能
**附加信息**
其他的与改功能相关的附加信息
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
-15
View File
@@ -1,15 +0,0 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# dep
vendor
-27
View File
@@ -1,27 +0,0 @@
language: go
sudo: false
go:
- "1.10"
before_install:
- go get -u github.com/golang/dep/cmd/dep
install:
- "$GOPATH/bin/dep ensure"
env:
global:
- NAME=clash
- BINDIR=bin
script:
- go test ./...
before_deploy: make -j releases
deploy:
provider: releases
prerelease: true
skip_cleanup: true
api_key:
secure: dp1tc1h0er7aaAZ1hY0Xk/cUKwB0ifsAjg6e0M/Ad5NC87oucP6ESNFkDu0e9rUS1yB826/VnVGzNE/Z5zdjXVzPft+g5v5oRxzI4BKLhf07t9s+x8Z+3sApTxdsC5BvcN9x+5yRbpDLQ3biDPxSFu86j7m2pkEWw6XYNZO3/5y+RZXX7zu+d4MzTLUaA2kWl7KQAP0tEJNuw9ACDhpkw7LYbU/8q3E76prOTeme5/AT6Gxj7XhKUNP27lazhhqBSWM14ybPANqojNLEfMFHN/Eu2phYO07MuLTd4zuOIuw9y65kgvTFcHRlORjwUhnviXyA69obQejjgDI1WDOtU4PqpFaSLrxWtKI6k5VNWHARYggDm/wKl0WG7F0Kgio1KiGGhDg2yrbseXr/zBNaDhBtTFh6XJffqqwmgby1PXB6PWwfvWXooJMaQiFZczLWeMBl8v6XbSN6jtMTh/PQlKai6BcDd4LM8GQ7VHpSeff4qXEU4Vpnadjgs8VDPOHng6/HV+wDs8q2LrlMbnxLWxbCjOMUB6w7YnSrwH9owzKSoUs/531I4tTCRQIgipJtTK2b881/8osVjdMGS1mDXhBWO+OM0LCAdORJz+kN4PIkXXvKLt6jX74k6z4M3swFaqqtlTduN2Yy/ErsjguQO1VZfHmcpNssmJXI5QB9sxA=
file: bin/*
file_glob: true
on:
repo: Dreamacro/clash
branch: master
tags: true
-19
View File
@@ -1,19 +0,0 @@
FROM golang:latest as builder
RUN wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz -O /tmp/GeoLite2-Country.tar.gz && \
tar zxvf /tmp/GeoLite2-Country.tar.gz -C /tmp && \
cp /tmp/GeoLite2-Country_*/GeoLite2-Country.mmdb /Country.mmdb
RUN curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh && \
mkdir -p /go/src/github.com/Dreamacro/clash
WORKDIR /go/src/github.com/Dreamacro/clash
COPY . /go/src/github.com/Dreamacro/clash
RUN dep ensure && \
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '-w -s' -o /clash && \
chmod +x /clash
FROM alpine:latest
RUN apk --no-cache add ca-certificates && \
mkdir -p /root/.config/clash
COPY --from=builder /Country.mmdb /root/.config/clash/
COPY --from=builder /clash .
EXPOSE 7890 7891
ENTRYPOINT ["/clash"]
Generated
-97
View File
@@ -1,97 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/Yawning/chacha20"
packages = ["."]
revision = "e3b1f968fc6397b51d963fee8ec8711a47bc0ce8"
[[projects]]
name = "github.com/eapache/queue"
packages = ["."]
revision = "44cc805cf13205b55f69e14bcb69867d1ae92f98"
version = "v1.1.0"
[[projects]]
name = "github.com/go-chi/chi"
packages = ["."]
revision = "e83ac2304db3c50cf03d96a2fcd39009d458bc35"
version = "v3.3.2"
[[projects]]
name = "github.com/go-chi/render"
packages = ["."]
revision = "3215478343fbc559bd3fc08f7031bb134d6bdad5"
version = "v1.0.1"
[[projects]]
name = "github.com/oschwald/geoip2-golang"
packages = ["."]
revision = "7118115686e16b77967cdbf55d1b944fe14ad312"
version = "v1.2.1"
[[projects]]
name = "github.com/oschwald/maxminddb-golang"
packages = ["."]
revision = "c5bec84d1963260297932a1b7a1753c8420717a7"
version = "v1.3.0"
[[projects]]
name = "github.com/riobard/go-shadowsocks2"
packages = [
"core",
"shadowaead",
"shadowstream",
"socks"
]
revision = "8346403248229fc7e10d7a259de8e9352a9d8830"
version = "v0.1.0"
[[projects]]
name = "github.com/sirupsen/logrus"
packages = ["."]
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
version = "v1.0.5"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = [
"chacha20poly1305",
"hkdf",
"internal/chacha20",
"internal/subtle",
"poly1305",
"ssh/terminal"
]
revision = "027cca12c2d63e3d62b670d901e8a2c95854feec"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = [
"cpu",
"unix",
"windows"
]
revision = "6c888cc515d3ed83fc103cf1d84468aad274b0a7"
[[projects]]
name = "gopkg.in/eapache/channels.v1"
packages = ["."]
revision = "47238d5aae8c0fefd518ef2bee46290909cf8263"
version = "v1.1.0"
[[projects]]
name = "gopkg.in/ini.v1"
packages = ["."]
revision = "06f5f3d67269ccec1fe5fe4134ba6e982984f7f5"
version = "v1.37.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "c3c901e4e393a2df9e421924d3a4d85ec73642e36dcbc1ddca5fc13159220e86"
solver-name = "gps-cdcl"
solver-version = 1
-58
View File
@@ -1,58 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[[constraint]]
name = "github.com/go-chi/chi"
version = "3.3.2"
[[constraint]]
name = "github.com/go-chi/render"
version = "1.0.1"
[[constraint]]
name = "github.com/oschwald/geoip2-golang"
version = "1.2.1"
[[constraint]]
name = "github.com/riobard/go-shadowsocks2"
version = "0.1.0"
[[constraint]]
name = "github.com/sirupsen/logrus"
version = "1.0.5"
[[constraint]]
name = "gopkg.in/eapache/channels.v1"
version = "1.1.0"
[[constraint]]
name = "gopkg.in/ini.v1"
version = "1.37.0"
[prune]
go-tests = true
unused-packages = true
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 Dreamacro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-23
View File
@@ -1,23 +0,0 @@
NAME=clash
BINDIR=bin
GOBUILD=CGO_ENABLED=0 go build -ldflags '-w -s'
all: linux macos
linux:
GOARCH=amd64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
macos:
GOARCH=amd64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
win64:
GOARCH=amd64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
releases: linux macos win64
chmod +x $(BINDIR)/$(NAME)-*
gzip $(BINDIR)/$(NAME)-linux
gzip $(BINDIR)/$(NAME)-macos
zip -m -j $(BINDIR)/$(NAME)-win64.zip $(BINDIR)/$(NAME)-win64.exe
clean:
rm $(BINDIR)/*
+160
View File
@@ -0,0 +1,160 @@
3th-party software licenses
* Clash
==========================================================================
closed-source assurance
* Android Open Source Project
* Android X Support Library
==========================================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
+50
View File
@@ -0,0 +1,50 @@
## Privacy Policy
The Clash for Android is built as an Open Source software. This app is provided by personal at no cost and is intended for use as is.
This page is used to inform visitors regarding our policies with the collection, use, and disclosure of Personal Information if anyone decided to use our app.
If you choose to use our app, then you agree to the collection and use of information in relation to this policy. The Personal Information that we collect is used for providing and improving the app. We will not use or share your information with anyone except as described in this Privacy Policy.
The terms used in this Privacy Policy have the same meanings as in our Terms and Conditions, which is accessible at Clash for Android unless otherwise defined in this Privacy Policy.
**Information Collection and Use**
For a better experience, while using our app, we may require you to provide us with certain personally identifiable information. The information that we request will be retained by us and used as described in this privacy policy.
The app does use third party services that may collect information used to identify you.
Link to privacy policy of third party service providers used by the app
* [Google Play Services](https://www.google.com/policies/privacy/)
* [AppCenter](https://docs.microsoft.com/en-us/appcenter/gdpr/)
**Log Data**
We want to inform you that whenever you use our app, in a case of an error in the app we collect data and information (through third party products) on your phone called Log Data. This Log Data may include information such as your device Internet Protocol (“IP”) address, device name, operating system version, the configuration of the app when utilizing our App, the time and date of your use of the app, and other statistics.
**Cookies**
Cookies are files with a small amount of data that are commonly used as anonymous unique identifiers. These are sent to your browser from the websites that you visit and are stored on your device's internal memory.
This app does not use these “cookies” explicitly. However, the app may use third party code and libraries that use “cookies” to collect information and improve their services. You have the option to either accept or refuse these cookies and know when a cookie is being sent to your device. If you choose to refuse our cookies, you may not be able to use some portions of this app.
**Security**
We value your trust in providing us your Personal Information, thus we are striving to use commercially acceptable means of protecting it. But remember that no method of transmission over the internet, or method of electronic storage is 100% secure and reliable, and we cannot guarantee its absolute security.
**Links to Other Sites**
This app may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by us. Therefore, we strongly advise you to review the Privacy Policy of these websites. We have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services.
**Children’s Privacy**
These Services do not address anyone under the age of 13\. We do not knowingly collect personally identifiable information from children under 13\. In the case we discover that a child under 13 has provided us with personal information, we immediately delete this from our servers. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact us so that we will be able to do necessary actions.
**Changes to This Privacy Policy**
We may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. We will notify you of any changes by posting the new Privacy Policy on this page. These changes are effective immediately after they are posted on this page.
**Contact Us**
If you have any questions or suggestions about our Privacy Policy, do not hesitate to contact us.
+14 -78
View File
@@ -1,97 +1,33 @@
<h1 align="center">
<img src="https://github.com/Dreamacro/clash/raw/master/docs/logo.png" alt="Clash" width="200">
<br>
Clash
<br>
</h1>
## Clash for Android
<h4 align="center">A rule based proxy in Go.</h4>
A Graphical user interface of [clash](https://github.com/Dreamacro/clash) for Android
<p align="center">
<a href="https://travis-ci.org/Dreamacro/clash">
<img src="https://img.shields.io/travis/Dreamacro/clash.svg?style=flat-square"
alt="Travis-CI">
</a>
<a href="https://goreportcard.com/report/github.com/Dreamacro/clash">
<img src="https://goreportcard.com/badge/github.com/Dreamacro/clash?style=flat-square">
</a>
<a href="https://app.fossa.io/projects/git%2Bgithub.com%2FDreamacro%2Fclash?ref=badge_shield" alt="FOSSA Status"><img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2FDreamacro%2Fclash.svg?type=shield"/></a>
<a href="https://github.com/Dreamacro/clash/releases">
<img src="https://img.shields.io/github/release/Dreamacro/clash/all.svg?style=flat-square">
</a>
</p>
<a href="https://play.google.com/store/apps/details?id=com.github.kr328.clash"><img width="200px" alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png"/></a> or [Releases](https://github.com/Kr328/ClashForAndroid/releases)
## Features
### Feature
- HTTP/HTTPS and SOCKS proxy
- Surge like configuration
- GeoIP rule support
Fully feature of [Clash Premium](https://github.com/Dreamacro/clash/releases)
## Install
You can build from source:
### Requirement
```sh
go get -u -v github.com/Dreamacro/clash
```
* Android 7.0+
* `armeabi-v7a` , `arm64-v8a`, `x86` or `x86_64` Architecture
Pre-built binaries are available: [release](https://github.com/Dreamacro/clash/releases)
Requires Go >= 1.10.
### 3rd Part License
## Daemon
See also [NOTICE](./NOTICE)
Unfortunately, there is no native elegant way to implement golang's daemon.
So we can use third-party daemon tools like pm2, supervisor, and so on.
In the case of [pm2](https://github.com/Unitech/pm2), we can start the daemon this way:
### Privacy Policy
```sh
pm2 start clash
```
See also [PRIVACY_POLICY.md](./PRIVACY_POLICY.md)
If you have Docker installed, you can run clash directly using `docker-compose`.
[Run clash in docker](https://github.com/Dreamacro/clash/wiki/Run-clash-in-docker)
## Config
### NOTICE
Configuration file at `$HOME/.config/clash/config.ini`
**Clash for Android** now uses **closed-source** upstream branches. According to the upstream license agreement, Clash for Android also needs to **close source**.
Below is a simple demo configuration file:
```ini
[General]
port = 7890
socks-port = 7891
# A RESTful API for clash
external-controller = 127.0.0.1:8080
[Proxy]
# name = ss, server, port, cipher, password
# The types of cipher are consistent with go-shadowsocks2
# support AEAD_AES_128_GCM AEAD_AES_192_GCM AEAD_AES_256_GCM AEAD_CHACHA20_POLY1305 AES-128-CTR AES-192-CTR AES-256-CTR AES-128-CFB AES-192-CFB AES-256-CFB CHACHA20-IETF XCHACHA20
Proxy1 = ss, server1, port, AEAD_CHACHA20_POLY1305, password
Proxy2 = ss, server2, port, AEAD_CHACHA20_POLY1305, password
[Proxy Group]
# url-test select which proxy will be used by benchmarking speed to a URL.
# name = url-test, [proxys], url, interval(second)
Proxy = url-test, Proxy1, Proxy2, http://www.google.com/generate_204, 300
[Rule]
DOMAIN-SUFFIX,google.com,Proxy
DOMAIN-KEYWORD,google,Proxy
DOMAIN-SUFFIX,ad.com,REJECT
GEOIP,CN,DIRECT
FINAL,,Proxy # note: there is two ","
```
## License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FDreamacro%2Fclash.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FDreamacro%2Fclash?ref=badge_large)
## TODO
- [ ] Complementing the necessary rule operators
-53
View File
@@ -1,53 +0,0 @@
package adapters
import (
"io"
"net"
C "github.com/Dreamacro/clash/constant"
)
// DirectAdapter is a directly connected adapter
type DirectAdapter struct {
conn net.Conn
}
// ReadWriter is used to handle network traffic
func (d *DirectAdapter) ReadWriter() io.ReadWriter {
return d.conn
}
// Close is used to close connection
func (d *DirectAdapter) Close() {
d.conn.Close()
}
// Conn is used to http request
func (d *DirectAdapter) Conn() net.Conn {
return d.conn
}
type Direct struct {
traffic *C.Traffic
}
func (d *Direct) Name() string {
return "Direct"
}
func (d *Direct) Type() C.AdapterType {
return C.Direct
}
func (d *Direct) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
c, err := net.Dial("tcp", net.JoinHostPort(addr.String(), addr.Port))
if err != nil {
return
}
c.(*net.TCPConn).SetKeepAlive(true)
return &DirectAdapter{conn: NewTrafficTrack(c, d.traffic)}, nil
}
func NewDirect(traffic *C.Traffic) *Direct {
return &Direct{traffic: traffic}
}
-54
View File
@@ -1,54 +0,0 @@
package adapters
import (
"io"
"net"
C "github.com/Dreamacro/clash/constant"
)
// RejectAdapter is a reject connected adapter
type RejectAdapter struct {
}
// ReadWriter is used to handle network traffic
func (r *RejectAdapter) ReadWriter() io.ReadWriter {
return &NopRW{}
}
// Close is used to close connection
func (r *RejectAdapter) Close() {}
// Conn is used to http request
func (r *RejectAdapter) Conn() net.Conn {
return nil
}
type Reject struct {
}
func (r *Reject) Name() string {
return "Reject"
}
func (r *Reject) Type() C.AdapterType {
return C.Reject
}
func (r *Reject) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
return &RejectAdapter{}, nil
}
func NewReject() *Reject {
return &Reject{}
}
type NopRW struct{}
func (rw *NopRW) Read(b []byte) (int, error) {
return len(b), nil
}
func (rw *NopRW) Write(b []byte) (int, error) {
return 0, io.EOF
}
-65
View File
@@ -1,65 +0,0 @@
package adapters
import (
"errors"
C "github.com/Dreamacro/clash/constant"
)
type Selector struct {
name string
selected C.Proxy
proxys map[string]C.Proxy
}
func (s *Selector) Name() string {
return s.name
}
func (s *Selector) Type() C.AdapterType {
return C.Selector
}
func (s *Selector) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
return s.selected.Generator(addr)
}
func (s *Selector) Now() string {
return s.selected.Name()
}
func (s *Selector) All() []string {
var all []string
for k, _ := range s.proxys {
all = append(all, k)
}
return all
}
func (s *Selector) Set(name string) error {
proxy, exist := s.proxys[name]
if !exist {
return errors.New("Proxy does not exist")
}
s.selected = proxy
return nil
}
func NewSelector(name string, proxys map[string]C.Proxy) (*Selector, error) {
if len(proxys) == 0 {
return nil, errors.New("Provide at least one proxy")
}
mapping := make(map[string]C.Proxy)
var init string
for k, v := range proxys {
mapping[k] = v
init = k
}
s := &Selector{
name: name,
proxys: mapping,
selected: proxys[init],
}
return s, nil
}
-109
View File
@@ -1,109 +0,0 @@
package adapters
import (
"bytes"
"fmt"
"io"
"net"
"net/url"
"strconv"
C "github.com/Dreamacro/clash/constant"
"github.com/riobard/go-shadowsocks2/core"
"github.com/riobard/go-shadowsocks2/socks"
)
// ShadowsocksAdapter is a shadowsocks adapter
type ShadowsocksAdapter struct {
conn net.Conn
}
// ReadWriter is used to handle network traffic
func (ss *ShadowsocksAdapter) ReadWriter() io.ReadWriter {
return ss.conn
}
// Close is used to close connection
func (ss *ShadowsocksAdapter) Close() {
ss.conn.Close()
}
func (ss *ShadowsocksAdapter) Conn() net.Conn {
return ss.conn
}
type ShadowSocks struct {
server string
name string
cipher core.Cipher
traffic *C.Traffic
}
func (ss *ShadowSocks) Name() string {
return ss.name
}
func (ss *ShadowSocks) Type() C.AdapterType {
return C.Shadowsocks
}
func (ss *ShadowSocks) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
c, err := net.Dial("tcp", ss.server)
if err != nil {
return nil, fmt.Errorf("%s connect error", ss.server)
}
c.(*net.TCPConn).SetKeepAlive(true)
c = ss.cipher.StreamConn(c)
_, err = c.Write(serializesSocksAddr(addr))
return &ShadowsocksAdapter{conn: NewTrafficTrack(c, ss.traffic)}, err
}
func NewShadowSocks(name string, ssURL string, traffic *C.Traffic) (*ShadowSocks, error) {
var key []byte
server, cipher, password, _ := parseURL(ssURL)
ciph, err := core.PickCipher(cipher, key, password)
if err != nil {
return nil, fmt.Errorf("ss %s initialize error: %s", server, err.Error())
}
return &ShadowSocks{
server: server,
name: name,
cipher: ciph,
traffic: traffic,
}, nil
}
func parseURL(s string) (addr, cipher, password string, err error) {
u, err := url.Parse(s)
if err != nil {
return
}
addr = u.Host
if u.User != nil {
cipher = u.User.Username()
password, _ = u.User.Password()
}
return
}
func serializesSocksAddr(addr *C.Addr) []byte {
var buf [][]byte
aType := uint8(addr.AddrType)
p, _ := strconv.Atoi(addr.Port)
port := []byte{uint8(p >> 8), uint8(p & 0xff)}
switch addr.AddrType {
case socks.AtypDomainName:
len := uint8(len(addr.Host))
host := []byte(addr.Host)
buf = [][]byte{{aType, len}, host, port}
case socks.AtypIPv4:
host := addr.IP.To4()
buf = [][]byte{{aType}, host, port}
case socks.AtypIPv6:
host := addr.IP.To16()
buf = [][]byte{{aType}, host, port}
}
return bytes.Join(buf, []byte(""))
}
-168
View File
@@ -1,168 +0,0 @@
package adapters
import (
"fmt"
"net"
"net/http"
"net/url"
"sync"
"time"
C "github.com/Dreamacro/clash/constant"
)
type URLTest struct {
name string
proxys []C.Proxy
url *url.URL
rawURL string
addr *C.Addr
fast C.Proxy
delay time.Duration
done chan struct{}
}
func (u *URLTest) Name() string {
return u.name
}
func (u *URLTest) Type() C.AdapterType {
return C.URLTest
}
func (u *URLTest) Now() string {
return u.fast.Name()
}
func (u *URLTest) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
return u.fast.Generator(addr)
}
func (u *URLTest) Close() {
u.done <- struct{}{}
}
func (u *URLTest) loop() {
tick := time.NewTicker(u.delay)
go u.speedTest()
Loop:
for {
select {
case <-tick.C:
go u.speedTest()
case <-u.done:
break Loop
}
}
}
func (u *URLTest) speedTest() {
wg := sync.WaitGroup{}
wg.Add(len(u.proxys))
c := make(chan interface{})
fast := selectFast(c)
timer := time.NewTimer(u.delay)
for _, p := range u.proxys {
go func(p C.Proxy) {
err := getUrl(p, u.addr, u.rawURL)
if err == nil {
c <- p
}
wg.Done()
}(p)
}
go func() {
wg.Wait()
close(c)
}()
select {
case <-timer.C:
// Wait for fast to return or close.
<-fast
case p, open := <-fast:
if open {
u.fast = p.(C.Proxy)
}
}
}
func getUrl(proxy C.Proxy, addr *C.Addr, rawURL string) (err error) {
instance, err := proxy.Generator(addr)
if err != nil {
return
}
defer instance.Close()
transport := &http.Transport{
Dial: func(string, string) (net.Conn, error) {
return instance.Conn(), nil
},
// from http.DefaultTransport
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
client := http.Client{Transport: transport}
req, err := client.Get(rawURL)
if err != nil {
return
}
req.Body.Close()
return nil
}
func selectFast(in chan interface{}) chan interface{} {
out := make(chan interface{})
go func() {
p, open := <-in
if open {
out <- p
}
close(out)
for range in {
}
}()
return out
}
func NewURLTest(name string, proxys []C.Proxy, rawURL string, delay time.Duration) (*URLTest, error) {
u, err := url.Parse(rawURL)
if err != nil {
return nil, err
}
port := u.Port()
if port == "" {
if u.Scheme == "https" {
port = "443"
} else if u.Scheme == "http" {
port = "80"
} else {
return nil, fmt.Errorf("%s scheme not Support", rawURL)
}
}
addr := &C.Addr{
AddrType: C.AtypDomainName,
Host: u.Hostname(),
IP: nil,
Port: port,
}
urlTest := &URLTest{
name: name,
proxys: proxys[:],
rawURL: rawURL,
url: u,
addr: addr,
fast: proxys[0],
delay: delay,
done: make(chan struct{}),
}
go urlTest.loop()
return urlTest, nil
}
-28
View File
@@ -1,28 +0,0 @@
package adapters
import (
"net"
C "github.com/Dreamacro/clash/constant"
)
type TrafficTrack struct {
net.Conn
traffic *C.Traffic
}
func (tt *TrafficTrack) Read(b []byte) (int, error) {
n, err := tt.Conn.Read(b)
tt.traffic.Down() <- int64(n)
return n, err
}
func (tt *TrafficTrack) Write(b []byte) (int, error) {
n, err := tt.Conn.Write(b)
tt.traffic.Up() <- int64(n)
return n, err
}
func NewTrafficTrack(conn net.Conn, traffic *C.Traffic) *TrafficTrack {
return &TrafficTrack{traffic: traffic, Conn: conn}
}
-53
View File
@@ -1,53 +0,0 @@
package constant
import (
"io"
"net"
)
// Adapter Type
const (
Direct AdapterType = iota
Reject
Selector
Shadowsocks
URLTest
)
type ProxyAdapter interface {
ReadWriter() io.ReadWriter
Conn() net.Conn
Close()
}
type ServerAdapter interface {
Addr() *Addr
Connect(ProxyAdapter)
Close()
}
type Proxy interface {
Name() string
Type() AdapterType
Generator(addr *Addr) (ProxyAdapter, error)
}
// AdapterType is enum of adapter type
type AdapterType int
func (at AdapterType) String() string {
switch at {
case Direct:
return "Direct"
case Reject:
return "Reject"
case Selector:
return "Selector"
case Shadowsocks:
return "Shadowsocks"
case URLTest:
return "URLTest"
default:
return "Unknow"
}
}
-40
View File
@@ -1,40 +0,0 @@
package constant
import (
"net"
)
// Socks addr type
const (
AtypIPv4 = 1
AtypDomainName = 3
AtypIPv6 = 4
TCP = iota
UDP
)
type NetWork int
func (n *NetWork) String() string {
if *n == TCP {
return "tcp"
}
return "udp"
}
// Addr is used to store connection address
type Addr struct {
NetWork NetWork
AddrType int
Host string
IP *net.IP
Port string
}
func (addr *Addr) String() string {
if addr.Host == "" {
return addr.IP.String()
}
return addr.Host
}
-119
View File
@@ -1,119 +0,0 @@
package constant
import (
"archive/tar"
"compress/gzip"
"io"
"net/http"
"os"
"os/user"
"path"
"strings"
log "github.com/sirupsen/logrus"
"gopkg.in/ini.v1"
)
const (
Name = "clash"
DefalutHTTPPort = 7890
DefalutSOCKSPort = 7891
)
var (
HomeDir string
ConfigPath string
MMDBPath string
)
type General struct {
Mode *string `json:"mode,omitempty"`
AllowLan *bool `json:"allow-lan,omitempty"`
Port *int `json:"port,omitempty"`
SocksPort *int `json:"socks-port,omitempty"`
}
func init() {
currentUser, err := user.Current()
if err != nil {
dir := os.Getenv("HOME")
if dir == "" {
log.Fatalf("Can't get current user: %s", err.Error())
}
HomeDir = dir
} else {
HomeDir = currentUser.HomeDir
}
dirPath := path.Join(HomeDir, ".config", Name)
if _, err := os.Stat(dirPath); os.IsNotExist(err) {
if err := os.MkdirAll(dirPath, 0777); err != nil {
log.Fatalf("Can't create config directory %s: %s", dirPath, err.Error())
}
}
ConfigPath = path.Join(dirPath, "config.ini")
if _, err := os.Stat(ConfigPath); os.IsNotExist(err) {
log.Info("Can't find config, create a empty file")
os.OpenFile(ConfigPath, os.O_CREATE|os.O_WRONLY, 0644)
}
MMDBPath = path.Join(dirPath, "Country.mmdb")
if _, err := os.Stat(MMDBPath); os.IsNotExist(err) {
log.Info("Can't find MMDB, start download")
err := downloadMMDB(MMDBPath)
if err != nil {
log.Fatalf("Can't download MMDB: %s", err.Error())
}
}
}
func downloadMMDB(path string) (err error) {
resp, err := http.Get("http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz")
if err != nil {
return
}
defer resp.Body.Close()
gr, err := gzip.NewReader(resp.Body)
if err != nil {
return
}
defer gr.Close()
tr := tar.NewReader(gr)
for {
h, err := tr.Next()
if err == io.EOF {
break
} else if err != nil {
return err
}
if !strings.HasSuffix(h.Name, "GeoLite2-Country.mmdb") {
continue
}
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, tr)
if err != nil {
return err
}
}
return nil
}
func GetConfig() (*ini.File, error) {
if _, err := os.Stat(ConfigPath); os.IsNotExist(err) {
return nil, err
}
return ini.LoadSources(
ini.LoadOptions{AllowBooleanKeys: true},
ConfigPath,
)
}
-7
View File
@@ -1,7 +0,0 @@
package constant
// ProxySignal is used to handle graceful shutdown of proxy
type ProxySignal struct {
Done chan<- struct{}
Closed <-chan struct{}
}
-36
View File
@@ -1,36 +0,0 @@
package constant
// Rule Type
const (
DomainSuffix RuleType = iota
DomainKeyword
GEOIP
IPCIDR
FINAL
)
type RuleType int
func (rt RuleType) String() string {
switch rt {
case DomainSuffix:
return "DomainSuffix"
case DomainKeyword:
return "DomainKeyword"
case GEOIP:
return "GEOIP"
case IPCIDR:
return "IPCIDR"
case FINAL:
return "FINAL"
default:
return "Unknow"
}
}
type Rule interface {
RuleType() RuleType
IsMatch(addr *Addr) bool
Adapter() string
Payload() string
}
-55
View File
@@ -1,55 +0,0 @@
package constant
import (
"time"
)
type Traffic struct {
up chan int64
down chan int64
upCount int64
downCount int64
upTotal int64
downTotal int64
interval time.Duration
}
func (t *Traffic) Up() chan<- int64 {
return t.up
}
func (t *Traffic) Down() chan<- int64 {
return t.down
}
func (t *Traffic) Now() (up int64, down int64) {
return t.upTotal, t.downTotal
}
func (t *Traffic) handle() {
go t.handleCh(t.up, &t.upCount, &t.upTotal)
go t.handleCh(t.down, &t.downCount, &t.downTotal)
}
func (t *Traffic) handleCh(ch <-chan int64, count *int64, total *int64) {
ticker := time.NewTicker(t.interval)
for {
select {
case n := <-ch:
*count += n
case <-ticker.C:
*total = *count
*count = 0
}
}
}
func NewTraffic(interval time.Duration) *Traffic {
t := &Traffic{
up: make(chan int64),
down: make(chan int64),
interval: interval,
}
go t.handle()
return t
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

-31
View File
@@ -1,31 +0,0 @@
package hub
import (
"github.com/Dreamacro/clash/proxy"
T "github.com/Dreamacro/clash/tunnel"
)
var (
tunnel = T.GetInstance()
listener = proxy.Instance()
)
type Error struct {
Error string `json:"error"`
}
type Errors struct {
Errors map[string]string `json:"errors"`
}
func formatErrors(errorsMap map[string]error) (bool, Errors) {
errors := make(map[string]string)
hasError := false
for key, err := range errorsMap {
if err != nil {
errors[key] = err.Error()
hasError = true
}
}
return hasError, Errors{Errors: errors}
}
-74
View File
@@ -1,74 +0,0 @@
package hub
import (
"fmt"
"net/http"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/proxy"
T "github.com/Dreamacro/clash/tunnel"
"github.com/go-chi/chi"
"github.com/go-chi/render"
)
func configRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", getConfigs)
r.Put("/", updateConfigs)
return r
}
var modeMapping = map[string]T.Mode{
"Global": T.Global,
"Rule": T.Rule,
"Direct": T.Direct,
}
func getConfigs(w http.ResponseWriter, r *http.Request) {
info := listener.Info()
mode := tunnel.GetMode().String()
info.Mode = &mode
render.JSON(w, r, info)
}
func updateConfigs(w http.ResponseWriter, r *http.Request) {
general := &C.General{}
err := render.DecodeJSON(r.Body, general)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: "Format error",
})
return
}
// update errors
var proxyErr, modeErr error
// update proxy
listener := proxy.Instance()
proxyErr = listener.Update(general.AllowLan, general.Port, general.SocksPort)
// update mode
if general.Mode != nil {
mode, ok := modeMapping[*general.Mode]
if !ok {
modeErr = fmt.Errorf("Mode error")
} else {
tunnel.SetMode(mode)
}
}
hasError, errors := formatErrors(map[string]error{
"proxy": proxyErr,
"mode": modeErr,
})
if hasError {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, errors)
return
}
w.WriteHeader(http.StatusNoContent)
}
-129
View File
@@ -1,129 +0,0 @@
package hub
import (
"fmt"
"net/http"
A "github.com/Dreamacro/clash/adapters"
C "github.com/Dreamacro/clash/constant"
"github.com/go-chi/chi"
"github.com/go-chi/render"
)
func proxyRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", getProxys)
r.Get("/{name}", getProxy)
r.Put("/{name}", updateProxy)
return r
}
type SampleProxy struct {
Type string `json:"type"`
}
type Selector struct {
Type string `json:"type"`
Now string `json:"now"`
All []string `json:"all"`
}
type URLTest struct {
Type string `json:"type"`
Now string `json:"now"`
}
func transformProxy(proxy C.Proxy) interface{} {
t := proxy.Type()
switch t {
case C.Selector:
selector := proxy.(*A.Selector)
return Selector{
Type: t.String(),
Now: selector.Now(),
All: selector.All(),
}
case C.URLTest:
return URLTest{
Type: t.String(),
Now: proxy.(*A.URLTest).Now(),
}
default:
return SampleProxy{
Type: proxy.Type().String(),
}
}
}
type GetProxysResponse struct {
Proxys map[string]interface{} `json:"proxys"`
}
func getProxys(w http.ResponseWriter, r *http.Request) {
_, rawProxys := tunnel.Config()
proxys := make(map[string]interface{})
for name, proxy := range rawProxys {
proxys[name] = transformProxy(proxy)
}
render.JSON(w, r, GetProxysResponse{Proxys: proxys})
}
func getProxy(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
_, proxys := tunnel.Config()
proxy, exist := proxys[name]
if !exist {
w.WriteHeader(http.StatusNotFound)
render.JSON(w, r, Error{
Error: "Proxy not found",
})
return
}
render.JSON(w, r, transformProxy(proxy))
}
type UpdateProxyRequest struct {
Name string `json:"name"`
}
func updateProxy(w http.ResponseWriter, r *http.Request) {
req := UpdateProxyRequest{}
if err := render.DecodeJSON(r.Body, &req); err != nil {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: "Format error",
})
return
}
name := chi.URLParam(r, "name")
_, proxys := tunnel.Config()
proxy, exist := proxys[name]
if !exist {
w.WriteHeader(http.StatusNotFound)
render.JSON(w, r, Error{
Error: "Proxy not found",
})
return
}
selector, ok := proxy.(*A.Selector)
if !ok {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: "Proxy can't update",
})
return
}
if err := selector.Set(req.Name); err != nil {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: fmt.Sprintf("Selector update error: %s", err.Error()),
})
return
}
w.WriteHeader(http.StatusNoContent)
}
-53
View File
@@ -1,53 +0,0 @@
package hub
import (
"net/http"
"github.com/go-chi/chi"
"github.com/go-chi/render"
)
func ruleRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", getRules)
r.Put("/", updateRules)
return r
}
type Rule struct {
Name string `json:"name"`
Payload string `json:"type"`
}
type GetRulesResponse struct {
Rules []Rule `json:"rules"`
}
func getRules(w http.ResponseWriter, r *http.Request) {
rulesCfg, _ := tunnel.Config()
var rules []Rule
for _, rule := range rulesCfg {
rules = append(rules, Rule{
Name: rule.RuleType().String(),
Payload: rule.Payload(),
})
}
w.WriteHeader(http.StatusOK)
render.JSON(w, r, GetRulesResponse{
Rules: rules,
})
}
func updateRules(w http.ResponseWriter, r *http.Request) {
err := tunnel.UpdateConfig()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
render.JSON(w, r, Error{
Error: err.Error(),
})
return
}
w.WriteHeader(http.StatusNoContent)
}
-109
View File
@@ -1,109 +0,0 @@
package hub
import (
"encoding/json"
"net/http"
"time"
T "github.com/Dreamacro/clash/tunnel"
"github.com/go-chi/chi"
"github.com/go-chi/render"
log "github.com/sirupsen/logrus"
)
type Traffic struct {
Up int64 `json:"up"`
Down int64 `json:"down"`
}
func NewHub(addr string) {
r := chi.NewRouter()
r.Get("/traffic", traffic)
r.Get("/logs", getLogs)
r.Mount("/configs", configRouter())
r.Mount("/proxys", proxyRouter())
r.Mount("/rules", ruleRouter())
err := http.ListenAndServe(addr, r)
if err != nil {
log.Fatalf("External controller error: %s", err.Error())
}
}
func traffic(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
tick := time.NewTicker(time.Second)
t := tunnel.Traffic()
for range tick.C {
up, down := t.Now()
if err := json.NewEncoder(w).Encode(Traffic{
Up: up,
Down: down,
}); err != nil {
break
}
w.(http.Flusher).Flush()
}
}
type GetLogs struct {
Level string `json:"level"`
}
type Log struct {
Type string `json:"type"`
Payload string `json:"payload"`
}
func getLogs(w http.ResponseWriter, r *http.Request) {
req := &GetLogs{}
render.DecodeJSON(r.Body, req)
if req.Level == "" {
req.Level = "info"
}
mapping := map[string]T.LogLevel{
"info": T.INFO,
"debug": T.DEBUG,
"error": T.ERROR,
"warning": T.WARNING,
}
level, ok := mapping[req.Level]
if !ok {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: "Level error",
})
return
}
src := tunnel.Log()
sub, err := src.Subscribe()
defer src.UnSubscribe(sub)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
render.JSON(w, r, Error{
Error: err.Error(),
})
return
}
render.Status(r, http.StatusOK)
for elm := range sub {
log := elm.(T.Log)
if log.LogLevel > level {
continue
}
if err := json.NewEncoder(w).Encode(Log{
Type: log.Type(),
Payload: log.Payload,
}); err != nil {
break
}
w.(http.Flusher).Flush()
}
}
-39
View File
@@ -1,39 +0,0 @@
package main
import (
"os"
"os/signal"
"syscall"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/hub"
"github.com/Dreamacro/clash/proxy"
"github.com/Dreamacro/clash/tunnel"
log "github.com/sirupsen/logrus"
)
func main() {
if err := tunnel.GetInstance().UpdateConfig(); err != nil {
log.Fatalf("Parse config error: %s", err.Error())
}
if err := proxy.Instance().Run(); err != nil {
log.Fatalf("Proxy listen error: %s", err.Error())
}
// Hub
cfg, err := C.GetConfig()
if err != nil {
log.Fatalf("Read config error: %s", err.Error())
}
section := cfg.Section("General")
if key, err := section.GetKey("external-controller"); err == nil {
go hub.NewHub(key.Value())
}
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
}
-3
View File
@@ -1,3 +0,0 @@
package observable
type Iterable <-chan interface{}
-67
View File
@@ -1,67 +0,0 @@
package observable
import (
"errors"
"sync"
)
type Observable struct {
iterable Iterable
listener *sync.Map
done bool
doneLock sync.RWMutex
}
func (o *Observable) process() {
for item := range o.iterable {
o.listener.Range(func(key, value interface{}) bool {
elm := value.(*Subscriber)
elm.Emit(item)
return true
})
}
o.close()
}
func (o *Observable) close() {
o.doneLock.Lock()
o.done = true
o.doneLock.Unlock()
o.listener.Range(func(key, value interface{}) bool {
elm := value.(*Subscriber)
elm.Close()
return true
})
}
func (o *Observable) Subscribe() (Subscription, error) {
o.doneLock.RLock()
done := o.done
o.doneLock.RUnlock()
if done == true {
return nil, errors.New("Observable is closed")
}
subscriber := newSubscriber()
o.listener.Store(subscriber.Out(), subscriber)
return subscriber.Out(), nil
}
func (o *Observable) UnSubscribe(sub Subscription) {
elm, exist := o.listener.Load(sub)
if !exist {
return
}
subscriber := elm.(*Subscriber)
o.listener.Delete(subscriber.Out())
subscriber.Close()
}
func NewObservable(any Iterable) *Observable {
observable := &Observable{
iterable: any,
listener: &sync.Map{},
}
go observable.process()
return observable
}
-124
View File
@@ -1,124 +0,0 @@
package observable
import (
"runtime"
"sync"
"testing"
"time"
)
func iterator(item []interface{}) chan interface{} {
ch := make(chan interface{})
go func() {
time.Sleep(100 * time.Millisecond)
for _, elm := range item {
ch <- elm
}
close(ch)
}()
return ch
}
func TestObservable(t *testing.T) {
iter := iterator([]interface{}{1, 2, 3, 4, 5})
src := NewObservable(iter)
data, err := src.Subscribe()
if err != nil {
t.Error(err)
}
count := 0
for range data {
count = count + 1
}
if count != 5 {
t.Error("Revc number error")
}
}
func TestObservable_MutilSubscribe(t *testing.T) {
iter := iterator([]interface{}{1, 2, 3, 4, 5})
src := NewObservable(iter)
ch1, _ := src.Subscribe()
ch2, _ := src.Subscribe()
count := 0
var wg sync.WaitGroup
wg.Add(2)
waitCh := func(ch <-chan interface{}) {
for range ch {
count = count + 1
}
wg.Done()
}
go waitCh(ch1)
go waitCh(ch2)
wg.Wait()
if count != 10 {
t.Error("Revc number error")
}
}
func TestObservable_UnSubscribe(t *testing.T) {
iter := iterator([]interface{}{1, 2, 3, 4, 5})
src := NewObservable(iter)
data, err := src.Subscribe()
if err != nil {
t.Error(err)
}
src.UnSubscribe(data)
_, open := <-data
if open {
t.Error("Revc number error")
}
}
func TestObservable_SubscribeClosedSource(t *testing.T) {
iter := iterator([]interface{}{1})
src := NewObservable(iter)
data, _ := src.Subscribe()
<-data
_, closed := src.Subscribe()
if closed == nil {
t.Error("Observable should be closed")
}
}
func TestObservable_UnSubscribeWithNotExistSubscription(t *testing.T) {
sub := Subscription(make(chan interface{}))
iter := iterator([]interface{}{1})
src := NewObservable(iter)
src.UnSubscribe(sub)
}
func TestObservable_SubscribeGoroutineLeak(t *testing.T) {
// waiting for other goroutine recycle
time.Sleep(120 * time.Millisecond)
init := runtime.NumGoroutine()
iter := iterator([]interface{}{1, 2, 3, 4, 5})
src := NewObservable(iter)
max := 100
var list []Subscription
for i := 0; i < max; i++ {
ch, _ := src.Subscribe()
list = append(list, ch)
}
var wg sync.WaitGroup
wg.Add(max)
waitCh := func(ch <-chan interface{}) {
for range ch {
}
wg.Done()
}
for _, ch := range list {
go waitCh(ch)
}
wg.Wait()
now := runtime.NumGoroutine()
if init != now {
t.Errorf("Goroutine Leak: init %d now %d", init, now)
}
}
-35
View File
@@ -1,35 +0,0 @@
package observable
import (
"sync"
"gopkg.in/eapache/channels.v1"
)
type Subscription <-chan interface{}
type Subscriber struct {
buffer *channels.InfiniteChannel
once sync.Once
}
func (s *Subscriber) Emit(item interface{}) {
s.buffer.In() <- item
}
func (s *Subscriber) Out() Subscription {
return s.buffer.Out()
}
func (s *Subscriber) Close() {
s.once.Do(func() {
s.buffer.Close()
})
}
func newSubscriber() *Subscriber {
sub := &Subscriber{
buffer: channels.NewInfiniteChannel(),
}
return sub
}
-77
View File
@@ -1,77 +0,0 @@
package http
import (
"io"
"net"
"net/http"
"time"
C "github.com/Dreamacro/clash/constant"
)
type HttpAdapter struct {
addr *C.Addr
r *http.Request
w http.ResponseWriter
done chan struct{}
}
func (h *HttpAdapter) Close() {
h.done <- struct{}{}
}
func (h *HttpAdapter) Addr() *C.Addr {
return h.addr
}
func (h *HttpAdapter) Connect(proxy C.ProxyAdapter) {
req := http.Transport{
Dial: func(string, string) (net.Conn, error) {
return proxy.Conn(), nil
},
// from http.DefaultTransport
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
resp, err := req.RoundTrip(h.r)
if err != nil {
return
}
defer resp.Body.Close()
header := h.w.Header()
for k, vv := range resp.Header {
for _, v := range vv {
header.Add(k, v)
}
}
h.w.WriteHeader(resp.StatusCode)
var writer io.Writer = h.w
if len(resp.TransferEncoding) > 0 && resp.TransferEncoding[0] == "chunked" {
writer = ChunkWriter{Writer: h.w}
}
io.Copy(writer, resp.Body)
}
type ChunkWriter struct {
io.Writer
}
func (cw ChunkWriter) Write(b []byte) (int, error) {
n, err := cw.Writer.Write(b)
if err == nil {
cw.Writer.(http.Flusher).Flush()
}
return n, err
}
func NewHttp(host string, w http.ResponseWriter, r *http.Request) (*HttpAdapter, chan struct{}) {
done := make(chan struct{})
return &HttpAdapter{
addr: parseHttpAddr(host),
r: r,
w: w,
done: done,
}, done
}
-35
View File
@@ -1,35 +0,0 @@
package http
import (
"bufio"
"io"
"net"
C "github.com/Dreamacro/clash/constant"
)
type HttpsAdapter struct {
addr *C.Addr
conn net.Conn
rw *bufio.ReadWriter
}
func (h *HttpsAdapter) Close() {
h.conn.Close()
}
func (h *HttpsAdapter) Addr() *C.Addr {
return h.addr
}
func (h *HttpsAdapter) Connect(proxy C.ProxyAdapter) {
go io.Copy(h.conn, proxy.ReadWriter())
io.Copy(proxy.ReadWriter(), h.conn)
}
func NewHttps(host string, conn net.Conn) *HttpsAdapter {
return &HttpsAdapter{
addr: parseHttpAddr(host),
conn: conn,
}
}
-109
View File
@@ -1,109 +0,0 @@
package http
import (
"context"
"net"
"net/http"
"strings"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/tunnel"
"github.com/riobard/go-shadowsocks2/socks"
log "github.com/sirupsen/logrus"
)
var (
tun = tunnel.GetInstance()
)
func NewHttpProxy(addr string) (*C.ProxySignal, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
done := make(chan struct{})
closed := make(chan struct{})
signal := &C.ProxySignal{
Done: done,
Closed: closed,
}
server := &http.Server{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodConnect {
handleTunneling(w, r)
} else {
handleHTTP(w, r)
}
}),
}
go func() {
log.Infof("HTTP proxy listening at: %s", addr)
server.Serve(l)
}()
go func() {
<-done
server.Shutdown(context.Background())
l.Close()
closed <- struct{}{}
}()
return signal, nil
}
func handleHTTP(w http.ResponseWriter, r *http.Request) {
addr := r.Host
// padding default port
if !strings.Contains(addr, ":") {
addr += ":80"
}
req, done := NewHttp(addr, w, r)
tun.Add(req)
<-done
}
func handleTunneling(w http.ResponseWriter, r *http.Request) {
hijacker, ok := w.(http.Hijacker)
if !ok {
return
}
conn, _, err := hijacker.Hijack()
if err != nil {
return
}
// w.WriteHeader(http.StatusOK) doesn't works in Safari
conn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
tun.Add(NewHttps(r.Host, conn))
}
func parseHttpAddr(target string) *C.Addr {
host, port, _ := net.SplitHostPort(target)
ipAddr, err := net.ResolveIPAddr("ip", host)
var resolveIP *net.IP
if err == nil {
resolveIP = &ipAddr.IP
}
var addType int
ip := net.ParseIP(host)
switch {
case ip == nil:
addType = socks.AtypDomainName
case ip.To4() == nil:
addType = socks.AtypIPv6
default:
addType = socks.AtypIPv4
}
return &C.Addr{
NetWork: C.TCP,
AddrType: addType,
Host: host,
IP: resolveIP,
Port: port,
}
}
-143
View File
@@ -1,143 +0,0 @@
package proxy
import (
"fmt"
"sync"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/proxy/http"
"github.com/Dreamacro/clash/proxy/socks"
log "github.com/sirupsen/logrus"
)
var (
listener *Listener
once sync.Once
)
type Listener struct {
httpPort int
socksPort int
allowLan bool
// signal for update
httpSignal *C.ProxySignal
socksSignal *C.ProxySignal
}
// Info returns the proxys's current configuration
func (l *Listener) Info() (info C.General) {
return C.General{
Port: &l.httpPort,
SocksPort: &l.socksPort,
AllowLan: &l.allowLan,
}
}
func (l *Listener) Update(allowLan *bool, httpPort *int, socksPort *int) error {
if allowLan != nil {
l.allowLan = *allowLan
}
var socksErr, httpErr error
if allowLan != nil || httpPort != nil {
newHTTPPort := l.httpPort
if httpPort != nil {
newHTTPPort = *httpPort
}
httpErr = l.updateHTTP(newHTTPPort)
}
if allowLan != nil || socksPort != nil {
newSocksPort := l.socksPort
if socksPort != nil {
newSocksPort = *socksPort
}
socksErr = l.updateSocks(newSocksPort)
}
if socksErr != nil && httpErr != nil {
return fmt.Errorf("%s\n%s", socksErr.Error(), httpErr.Error())
} else if socksErr != nil {
return socksErr
} else if httpErr != nil {
return httpErr
} else {
return nil
}
}
func (l *Listener) updateHTTP(port int) error {
if l.httpSignal != nil {
signal := l.httpSignal
signal.Done <- struct{}{}
<-signal.Closed
l.httpSignal = nil
}
signal, err := http.NewHttpProxy(l.genAddr(port))
if err != nil {
return err
}
l.httpSignal = signal
l.httpPort = port
return nil
}
func (l *Listener) updateSocks(port int) error {
if l.socksSignal != nil {
signal := l.socksSignal
signal.Done <- struct{}{}
<-signal.Closed
l.socksSignal = nil
}
signal, err := socks.NewSocksProxy(l.genAddr(port))
if err != nil {
return err
}
l.socksSignal = signal
l.socksPort = port
return nil
}
func (l *Listener) genAddr(port int) string {
host := "127.0.0.1"
if l.allowLan {
host = ""
}
return fmt.Sprintf("%s:%d", host, port)
}
func (l *Listener) Run() error {
return l.Update(&l.allowLan, &l.httpPort, &l.socksPort)
}
func newListener() *Listener {
cfg, err := C.GetConfig()
if err != nil {
log.Fatalf("Read config error: %s", err.Error())
}
general := cfg.Section("General")
port := general.Key("port").RangeInt(C.DefalutHTTPPort, 1, 65535)
socksPort := general.Key("socks-port").RangeInt(C.DefalutSOCKSPort, 1, 65535)
allowLan := general.Key("allow-lan").MustBool()
return &Listener{
httpPort: port,
socksPort: socksPort,
allowLan: allowLan,
}
}
func Instance() *Listener {
once.Do(func() {
listener = newListener()
})
return listener
}
-118
View File
@@ -1,118 +0,0 @@
package socks
import (
"io"
"net"
"strconv"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/tunnel"
"github.com/riobard/go-shadowsocks2/socks"
log "github.com/sirupsen/logrus"
)
var (
tun = tunnel.GetInstance()
)
func NewSocksProxy(addr string) (*C.ProxySignal, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
done := make(chan struct{})
closed := make(chan struct{})
signal := &C.ProxySignal{
Done: done,
Closed: closed,
}
go func() {
log.Infof("SOCKS proxy listening at: %s", addr)
for {
c, err := l.Accept()
if err != nil {
if _, open := <-done; !open {
break
}
continue
}
go handleSocks(c)
}
}()
go func() {
<-done
close(done)
l.Close()
closed <- struct{}{}
}()
return signal, nil
}
func handleSocks(conn net.Conn) {
target, err := socks.Handshake(conn)
if err != nil {
conn.Close()
return
}
conn.(*net.TCPConn).SetKeepAlive(true)
tun.Add(NewSocks(target, conn))
}
type SocksAdapter struct {
conn net.Conn
addr *C.Addr
}
func (s *SocksAdapter) Close() {
s.conn.Close()
}
func (s *SocksAdapter) Addr() *C.Addr {
return s.addr
}
func (s *SocksAdapter) Connect(proxy C.ProxyAdapter) {
go io.Copy(s.conn, proxy.ReadWriter())
io.Copy(proxy.ReadWriter(), s.conn)
}
func parseSocksAddr(target socks.Addr) *C.Addr {
var host, port string
var ip net.IP
switch target[0] {
case socks.AtypDomainName:
host = string(target[2 : 2+target[1]])
port = strconv.Itoa((int(target[2+target[1]]) << 8) | int(target[2+target[1]+1]))
ipAddr, err := net.ResolveIPAddr("ip", host)
if err == nil {
ip = ipAddr.IP
}
case socks.AtypIPv4:
ip = net.IP(target[1 : 1+net.IPv4len])
port = strconv.Itoa((int(target[1+net.IPv4len]) << 8) | int(target[1+net.IPv4len+1]))
case socks.AtypIPv6:
ip = net.IP(target[1 : 1+net.IPv6len])
port = strconv.Itoa((int(target[1+net.IPv6len]) << 8) | int(target[1+net.IPv6len+1]))
}
return &C.Addr{
NetWork: C.TCP,
AddrType: int(target[0]),
Host: host,
IP: &ip,
Port: port,
}
}
func NewSocks(target socks.Addr, conn net.Conn) *SocksAdapter {
return &SocksAdapter{
conn: conn,
addr: parseSocksAddr(target),
}
}
-1
View File
@@ -1 +0,0 @@
package socks
-39
View File
@@ -1,39 +0,0 @@
package rules
import (
"strings"
C "github.com/Dreamacro/clash/constant"
)
type DomainKeyword struct {
keyword string
adapter string
}
func (dk *DomainKeyword) RuleType() C.RuleType {
return C.DomainKeyword
}
func (dk *DomainKeyword) IsMatch(addr *C.Addr) bool {
if addr.AddrType != C.AtypDomainName {
return false
}
domain := addr.Host
return strings.Contains(domain, dk.keyword)
}
func (dk *DomainKeyword) Adapter() string {
return dk.adapter
}
func (dk *DomainKeyword) Payload() string {
return dk.keyword
}
func NewDomainKeyword(keyword string, adapter string) *DomainKeyword {
return &DomainKeyword{
keyword: keyword,
adapter: adapter,
}
}
-39
View File
@@ -1,39 +0,0 @@
package rules
import (
"strings"
C "github.com/Dreamacro/clash/constant"
)
type DomainSuffix struct {
suffix string
adapter string
}
func (ds *DomainSuffix) RuleType() C.RuleType {
return C.DomainSuffix
}
func (ds *DomainSuffix) IsMatch(addr *C.Addr) bool {
if addr.AddrType != C.AtypDomainName {
return false
}
domain := addr.Host
return strings.HasSuffix(domain, "."+ds.suffix) || domain == ds.suffix
}
func (ds *DomainSuffix) Adapter() string {
return ds.adapter
}
func (ds *DomainSuffix) Payload() string {
return ds.suffix
}
func NewDomainSuffix(suffix string, adapter string) *DomainSuffix {
return &DomainSuffix{
suffix: suffix,
adapter: adapter,
}
}
-31
View File
@@ -1,31 +0,0 @@
package rules
import (
C "github.com/Dreamacro/clash/constant"
)
type Final struct {
adapter string
}
func (f *Final) RuleType() C.RuleType {
return C.FINAL
}
func (f *Final) IsMatch(addr *C.Addr) bool {
return true
}
func (f *Final) Adapter() string {
return f.adapter
}
func (f *Final) Payload() string {
return ""
}
func NewFinal(adapter string) *Final {
return &Final{
adapter: adapter,
}
}
-50
View File
@@ -1,50 +0,0 @@
package rules
import (
C "github.com/Dreamacro/clash/constant"
"github.com/oschwald/geoip2-golang"
log "github.com/sirupsen/logrus"
)
var mmdb *geoip2.Reader
func init() {
var err error
mmdb, err = geoip2.Open(C.MMDBPath)
if err != nil {
log.Fatalf("Can't load mmdb: %s", err.Error())
}
}
type GEOIP struct {
country string
adapter string
}
func (g *GEOIP) RuleType() C.RuleType {
return C.GEOIP
}
func (g *GEOIP) IsMatch(addr *C.Addr) bool {
if addr.IP == nil {
return false
}
record, _ := mmdb.Country(*addr.IP)
return record.Country.IsoCode == g.country
}
func (g *GEOIP) Adapter() string {
return g.adapter
}
func (g *GEOIP) Payload() string {
return g.country
}
func NewGEOIP(country string, adapter string) *GEOIP {
return &GEOIP{
country: country,
adapter: adapter,
}
}
-42
View File
@@ -1,42 +0,0 @@
package rules
import (
"net"
C "github.com/Dreamacro/clash/constant"
)
type IPCIDR struct {
ipnet *net.IPNet
adapter string
}
func (i *IPCIDR) RuleType() C.RuleType {
return C.IPCIDR
}
func (i *IPCIDR) IsMatch(addr *C.Addr) bool {
if addr.IP == nil {
return false
}
return i.ipnet.Contains(*addr.IP)
}
func (i *IPCIDR) Adapter() string {
return i.adapter
}
func (i *IPCIDR) Payload() string {
return i.ipnet.String()
}
func NewIPCIDR(s string, adapter string) *IPCIDR {
_, ipnet, err := net.ParseCIDR(s)
if err != nil {
}
return &IPCIDR{
ipnet: ipnet,
adapter: adapter,
}
}
-67
View File
@@ -1,67 +0,0 @@
package tunnel
import (
"fmt"
log "github.com/sirupsen/logrus"
)
const (
ERROR LogLevel = iota
WARNING
INFO
DEBUG
)
type LogLevel int
type Log struct {
LogLevel LogLevel
Payload string
}
func (l *Log) Type() string {
switch l.LogLevel {
case INFO:
return "Info"
case WARNING:
return "Warning"
case ERROR:
return "Error"
case DEBUG:
return "Debug"
default:
return "Unknow"
}
}
func print(data Log) {
switch data.LogLevel {
case INFO:
log.Infoln(data.Payload)
case WARNING:
log.Warnln(data.Payload)
case ERROR:
log.Errorln(data.Payload)
case DEBUG:
log.Debugln(data.Payload)
}
}
func (t *Tunnel) subscribeLogs() {
sub, err := t.observable.Subscribe()
if err != nil {
log.Fatalf("Can't subscribe tunnel log: %s", err.Error())
}
for elm := range sub {
data := elm.(Log)
print(data)
}
}
func newLog(logLevel LogLevel, format string, v ...interface{}) Log {
return Log{
LogLevel: logLevel,
Payload: fmt.Sprintf(format, v...),
}
}
-22
View File
@@ -1,22 +0,0 @@
package tunnel
type Mode int
const (
Global Mode = iota
Rule
Direct
)
func (m Mode) String() string {
switch m {
case Global:
return "Global"
case Rule:
return "Rule"
case Direct:
return "Direct"
default:
return "Unknow"
}
}
-259
View File
@@ -1,259 +0,0 @@
package tunnel
import (
"fmt"
"strconv"
"strings"
"sync"
"time"
"github.com/Dreamacro/clash/adapters"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/observable"
R "github.com/Dreamacro/clash/rules"
"gopkg.in/eapache/channels.v1"
)
var (
tunnel *Tunnel
once sync.Once
)
type Tunnel struct {
queue *channels.InfiniteChannel
rules []C.Rule
proxys map[string]C.Proxy
observable *observable.Observable
logCh chan interface{}
configLock *sync.RWMutex
traffic *C.Traffic
mode Mode
selector *adapters.Selector
}
func (t *Tunnel) Add(req C.ServerAdapter) {
t.queue.In() <- req
}
func (t *Tunnel) Traffic() *C.Traffic {
return t.traffic
}
func (t *Tunnel) Config() ([]C.Rule, map[string]C.Proxy) {
return t.rules, t.proxys
}
func (t *Tunnel) Log() *observable.Observable {
return t.observable
}
func (t *Tunnel) SetMode(mode Mode) {
t.mode = mode
}
func (t *Tunnel) GetMode() Mode {
return t.mode
}
func (t *Tunnel) UpdateConfig() (err error) {
cfg, err := C.GetConfig()
if err != nil {
return
}
// empty proxys and rules
proxys := make(map[string]C.Proxy)
rules := []C.Rule{}
proxysConfig := cfg.Section("Proxy")
rulesConfig := cfg.Section("Rule")
groupsConfig := cfg.Section("Proxy Group")
// parse proxy
for _, key := range proxysConfig.Keys() {
proxy := key.Strings(",")
if len(proxy) == 0 {
continue
}
switch proxy[0] {
// ss, server, port, cipter, password
case "ss":
if len(proxy) < 5 {
continue
}
ssURL := fmt.Sprintf("ss://%s:%s@%s:%s", proxy[3], proxy[4], proxy[1], proxy[2])
ss, err := adapters.NewShadowSocks(key.Name(), ssURL, t.traffic)
if err != nil {
return err
}
proxys[key.Name()] = ss
}
}
// parse rules
for _, key := range rulesConfig.Keys() {
rule := strings.Split(key.Name(), ",")
if len(rule) < 3 {
continue
}
rule = trimArr(rule)
switch rule[0] {
case "DOMAIN-SUFFIX":
rules = append(rules, R.NewDomainSuffix(rule[1], rule[2]))
case "DOMAIN-KEYWORD":
rules = append(rules, R.NewDomainKeyword(rule[1], rule[2]))
case "GEOIP":
rules = append(rules, R.NewGEOIP(rule[1], rule[2]))
case "IP-CIDR", "IP-CIDR6":
rules = append(rules, R.NewIPCIDR(rule[1], rule[2]))
case "FINAL":
rules = append(rules, R.NewFinal(rule[2]))
}
}
// parse proxy groups
for _, key := range groupsConfig.Keys() {
rule := strings.Split(key.Value(), ",")
rule = trimArr(rule)
switch rule[0] {
case "url-test":
if len(rule) < 4 {
return fmt.Errorf("URLTest need more than 4 param")
}
proxyNames := rule[1 : len(rule)-2]
delay, _ := strconv.Atoi(rule[len(rule)-1])
url := rule[len(rule)-2]
var ps []C.Proxy
for _, name := range proxyNames {
if p, ok := proxys[name]; ok {
ps = append(ps, p)
}
}
adapter, err := adapters.NewURLTest(key.Name(), ps, url, time.Duration(delay)*time.Second)
if err != nil {
return fmt.Errorf("Config error: %s", err.Error())
}
proxys[key.Name()] = adapter
case "select":
if len(rule) < 3 {
return fmt.Errorf("Selector need more than 3 param")
}
proxyNames := rule[1:]
selectProxy := make(map[string]C.Proxy)
for _, name := range proxyNames {
proxy, exist := proxys[name]
if !exist {
return fmt.Errorf("Proxy %s not exist", name)
}
selectProxy[name] = proxy
}
selector, err := adapters.NewSelector(key.Name(), selectProxy)
if err != nil {
return fmt.Errorf("Selector create error: %s", err.Error())
}
proxys[key.Name()] = selector
}
}
// init proxy
proxys["DIRECT"] = adapters.NewDirect(t.traffic)
proxys["REJECT"] = adapters.NewReject()
t.configLock.Lock()
defer t.configLock.Unlock()
// stop url-test
for _, elm := range t.proxys {
urlTest, ok := elm.(*adapters.URLTest)
if ok {
urlTest.Close()
}
}
s, err := adapters.NewSelector("Proxy", proxys)
if err != nil {
return err
}
t.proxys = proxys
t.rules = rules
t.selector = s
return nil
}
func (t *Tunnel) process() {
queue := t.queue.Out()
for {
elm := <-queue
conn := elm.(C.ServerAdapter)
go t.handleConn(conn)
}
}
func (t *Tunnel) handleConn(localConn C.ServerAdapter) {
defer localConn.Close()
addr := localConn.Addr()
var proxy C.Proxy
switch t.mode {
case Direct:
proxy = t.proxys["DIRECT"]
case Global:
proxy = t.selector
// Rule
default:
proxy = t.match(addr)
}
remoConn, err := proxy.Generator(addr)
if err != nil {
t.logCh <- newLog(WARNING, "Proxy connect error: %s", err.Error())
return
}
defer remoConn.Close()
localConn.Connect(remoConn)
}
func (t *Tunnel) match(addr *C.Addr) C.Proxy {
t.configLock.RLock()
defer t.configLock.RUnlock()
for _, rule := range t.rules {
if rule.IsMatch(addr) {
a, ok := t.proxys[rule.Adapter()]
if !ok {
continue
}
t.logCh <- newLog(INFO, "%v match %s using %s", addr.String(), rule.RuleType().String(), rule.Adapter())
return a
}
}
t.logCh <- newLog(INFO, "%v doesn't match any rule using DIRECT", addr.String())
return t.proxys["DIRECT"]
}
func newTunnel() *Tunnel {
logCh := make(chan interface{})
tunnel := &Tunnel{
queue: channels.NewInfiniteChannel(),
proxys: make(map[string]C.Proxy),
observable: observable.NewObservable(logCh),
logCh: logCh,
configLock: &sync.RWMutex{},
traffic: C.NewTraffic(time.Second),
mode: Rule,
}
go tunnel.process()
go tunnel.subscribeLogs()
return tunnel
}
func GetInstance() *Tunnel {
once.Do(func() {
tunnel = newTunnel()
})
return tunnel
}
-12
View File
@@ -1,12 +0,0 @@
package tunnel
import (
"strings"
)
func trimArr(arr []string) (r []string) {
for _, e := range arr {
r = append(r, strings.Trim(e, " "))
}
return
}