Compare commits

...

78 Commits

Author SHA1 Message Date
kr328
f16b0048f3 Chore: update dependencies 2022-04-25 23:13:05 +08:00
kr328
17b3a0d0ed Chore: update clash core 2022-04-25 23:12:54 +08:00
kr328
1e9f38f2bb Chore: bump version 2022-04-25 12:25:50 +08:00
Kr328
ef8f9e5738 Chore: create FUNDING.yml 2022-04-25 12:12:59 +08:00
kr328
bf59ead3b2 Feature: close all connections on reset 2022-04-20 00:39:46 +08:00
kr328
5dbd94e42c Chore: update issue template 2022-04-15 14:31:10 +08:00
kr328
b92fc860eb Chore: bump version 2022-04-14 14:13:56 +08:00
kr328
20bdf171ee Feature: add zero-copy support 2022-04-14 14:13:38 +08:00
kr328
5a6ca2ce12 Chore: bump version 2022-04-11 20:59:27 +08:00
kr328
636941da70 Fix: add *.jd.com to system proxy blacklist 2022-04-11 20:49:00 +08:00
kr328
5bc3975591 Fix: fix traffic format 2022-04-11 20:49:00 +08:00
kr328
5e54e4561c Chore: minor default dns config changes 2022-04-11 20:49:00 +08:00
kr328
a7b560b576 Fix: LoadDefault should not apply dns patch 2022-04-11 20:49:00 +08:00
kr328
5f9d4c1572 Chore: minor default dns changes 2022-04-11 20:49:00 +08:00
kr328
a83ecb8b22 Chore: update clash core 2022-04-11 20:49:00 +08:00
Goooler
1cc88cc04f Chore: cache go on CI (#1440) 2022-03-22 20:36:31 +08:00
Goooler
92bce6c2c6 Chore: optimize CI (#1414)
* Bump checkout action to v3

* Bump setup-java action to v3 & Java 17

* Bump setup-go action to v3

* Use gradle-build-action

* Go 1.18

* Insert a new line
2022-03-22 18:41:06 +08:00
kr328
ab96790c73 Chore: update dependencies 2022-03-22 13:48:02 +08:00
kr328
d5618321e9 Chore: update clash core 2022-03-22 13:47:11 +08:00
Kr328
4b8fc6ae9a Chore: update dependencies 2022-02-21 19:48:35 +08:00
人工知能
152e24748b Chore: update zh-rTW translate (#1386)
* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml
2022-02-21 19:40:06 +08:00
Kr328
2efdf21130 Chore: update clash core 2022-02-21 19:24:48 +08:00
Kr328
e99c2b64b0 Fix: add mark for issues template 2022-02-21 11:22:16 +08:00
Kr328
3915d9549e Chore: ignore .github on build 2022-02-21 11:21:00 +08:00
Kr328
23077537f9 Fix: fix issue template 2022-02-21 11:19:43 +08:00
Kr328
de0cbd6b29 Chore: refactor issue template 2022-02-21 11:15:41 +08:00
Kr328
d0efa0690a Chore: fix bug report form 2022-02-21 01:50:30 +08:00
Kr328
5b6d04d558 Chore: replace bug report with issues forms 2022-02-21 01:46:07 +08:00
Kr328
791794f59d Chore: bump version 2022-01-15 00:15:02 +08:00
Kr328
6a6465ae5b Chore: update dependencies 2022-01-15 00:13:05 +08:00
Kr328
056a78c7c4 Improve: update default fake filter list 2022-01-15 00:07:52 +08:00
YeyeBBC
11b0025faf Slightly adjust QuickSettings Tile icon and App icon, making the cat more visually centred rather than geometrically centred. (#1341) 2022-01-15 00:02:25 +08:00
Kr328
3009b29e0c Chore: update dependencies 2022-01-14 23:59:14 +08:00
Kr328
5d52d970a3 Chore: clean code 2022-01-14 23:59:00 +08:00
Kr328
aef0b84275 Fix: disable tproxy & redir by default 2022-01-14 23:58:46 +08:00
Kr328
12c704d89c Chore: reformat build.gradle.kts 2022-01-14 23:40:41 +08:00
Kr328
38e070a565 Chore: update clash core 2022-01-14 23:39:33 +08:00
Kr328
c7d33c684b Chore: clean build gradle 2022-01-14 23:20:01 +08:00
Kr328
b2661d31fd Chore: update dependencies 2022-01-14 23:10:16 +08:00
kr328
53aa718674 Improve: patch all dns to core 2021-11-21 19:56:06 +08:00
okhowang
c173114368 Fix: crash with app icon (#1260) 2021-11-21 17:41:21 +08:00
kr328
7006cb516c Chore: update clash core 2021-11-21 17:17:33 +08:00
kr328
7809c30052 Refactor: refactor network observer 2021-11-21 16:55:55 +08:00
kr328
7e46d75159 Chore: update default fake-ip-filter 2021-11-21 13:54:31 +08:00
kr328
87f96b9ec7 Chore: bump version 2021-11-21 13:38:09 +08:00
kr328
3920f338f6 Chore: filter out premium build if unavailable 2021-11-21 13:38:01 +08:00
kr328
2565231867 Chore: remove unused ErrInvalidType 2021-11-21 13:31:34 +08:00
kr328
b7af3f7341 Fix: fix update profile dial 2021-11-21 13:31:25 +08:00
kr328
d93a7af534 Fix: fix network observe 2021-11-21 13:01:56 +08:00
kr328
1dcc8307ee Chore: remove unused patch proxy group 2021-11-21 13:01:44 +08:00
kr328
9936a9469d Fix: fix tun local addr 2021-11-21 13:01:27 +08:00
kr328
0e245b8936 Fix: downgrade kotlin version 2021-11-16 21:04:18 +08:00
kr328
226c11dda3 Chore: bump version 2021-11-16 20:29:46 +08:00
kr328
8330054a81 Chore: update dependencies 2021-11-16 20:29:36 +08:00
kr328
c7cb1dab38 Improve: disable network observer on screen off 2021-11-16 20:23:54 +08:00
kr328
a3686c16d4 Chore: update dependencies 2021-11-16 20:03:54 +08:00
kr328
b2a6a6a1ac Chore: update tun2socket 2021-11-16 19:59:34 +08:00
kr328
e3e9a8ccc3 Fix: fix tunnel dialer 2021-11-16 19:59:22 +08:00
kr328
7058c7a4cd Chore: update dependencies 2021-11-16 19:58:50 +08:00
kr328
2591de1c1d Chore: bump version 2021-11-14 21:09:02 +08:00
kr328
d20f19c08f Fix: fix network observer 2021-11-14 20:56:57 +08:00
kr328
a5ba4b4d23 Chore: update clash core 2021-11-14 20:55:35 +08:00
kr328
094815a098 Improve: remove loopback block & add allow bypass 2021-11-14 20:42:52 +08:00
kr328
5224fa656c Chore: clean compat code 2021-11-14 20:33:37 +08:00
kr328
73550164a8 Refactor: refactor network observer 2021-11-14 20:33:25 +08:00
kr328
48a9ab313e Chore: mark foss is default 2021-11-14 19:45:33 +08:00
kr328
25936c8361 Fix: fix dns fake-ip patch 2021-11-14 19:40:02 +08:00
kr328
3397cdd95f Chore: update dependencies 2021-11-14 19:17:06 +08:00
kr328
69f8ff2688 Chore: update clash core 2021-11-14 15:45:31 +08:00
kr328
41ab062103 Refactor: migrate to tun2socket 2021-11-14 14:50:11 +08:00
Kr328
c78431a0fb Chore: bump version 2021-10-15 11:07:10 +08:00
Kr328
3b33216961 Chore: update dependencies 2021-10-15 11:07:00 +08:00
Kr328
6373636d57 Chore: update clash core 2021-10-15 10:42:00 +08:00
Kr328
04a1f9987e Chore: update tun2socket 2021-10-15 10:41:54 +08:00
Kr328
90d286cd5a Chore: update gitignore 2021-09-26 10:04:35 +08:00
Kr328
1826d108a5 Chore: bump version 2021-09-24 11:24:05 +08:00
Goooler
a5619bb0ee Chore: add cache action in CI (#1201) 2021-09-24 11:15:07 +08:00
Goooler
5c1fadaba2 Chore: update dependencies (#1198) 2021-09-24 11:13:10 +08:00
85 changed files with 1475 additions and 1814 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: [Kr328]

View File

@@ -1,57 +0,0 @@
---
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**
Paste configure file which **removed server info**
```yaml
# paste here
```
**Logs**
Paste logs to help detect problem
```
<paste here>
```

View File

@@ -0,0 +1,106 @@
name: "[English] Bug Report"
description: "Create a report to help us debug bugs"
title: "[BUG] "
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
NOTE: Be sure to put a clear and concise title **AFTER** `[BUG]` in the text box above.
NOTE: We do not provide any services such as proxies, DO NOT feedback any problems not caused by this application here.
<!-- template -->
- type: textarea
id: description
attributes:
label: "Describe the bug"
description: "A clear and concise description of what the bug is."
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: "To Reproduce"
description: "Steps to reproduce the behavior:"
value: |
Step 1: ...
Step 2: ...
Step 3: ...
...
validations:
required: true
- type: textarea
id: device-info
attributes:
label: "Device Info"
description: |
Input your device information.
Example:
- Device: Pixel 4
- ROM: AOSP
- Android Version: 10
value: |
- Device:
- ROM:
- Android Version:
validations:
required: true
- type: textarea
id: app-info
attributes:
label: "Application Info"
description: |
Input application you are using information.
Example:
```
- Version: 2.5.4-premium
- APK filename: cfa-2.5.4-premium-arm64-v8a-release.apk
- Distribution Channel: Google Play
```
value: |
- Version:
- APK filename:
- Distribution Channel:
validations:
required: true
- type: textarea
id: configure
attributes:
render: yml
label: "Configure File"
description: |
Please paste or upload the configuration file here.
TIPS: If you only have a subscription link, please use your browser to download it.
**NOTE: Please remove proxies from the configuration file before uploading it.**
**NOTE: Please remove proxies from the configuration file before uploading it.**
**NOTE: Please remove proxies from the configuration file before uploading it.**
validations:
required: true
- type: textarea
id: logs
attributes:
render: raw
label: "Logs"
description: |
Please paste or upload the log file here.
TIPS: Please use the `Logcat` in application or `adb logcat`. `adb logcat` would be better.
validations:
required: true
- type: textarea
id: screenshot
attributes:
label: "Screenshot"
description: "If applicable, add screenshots to help explain your problem."
placeholder: "Optional"
- type: textarea
id: additional
attributes:
label: "Additional"
description: "Add any other context about the problem here."

View File

@@ -1,24 +0,0 @@
---
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.

View File

@@ -0,0 +1,26 @@
name: "[English] Feature Request"
description: "Create a report to help us improve"
title: "[Feature Request] "
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request!
NOTE: Be sure to put a clear and concise title **AFTER** `[Feature Request]` in the text box above.
<!-- template -->
- type: textarea
id: "description"
attributes:
label: "Feature Description"
description: |
A clear and concise description of the feature.
validations:
required: true
- type: textarea
id: "additional"
attributes:
label: "Additional"
description: |
Add any other context or screenshots about the feature request here.

View File

@@ -1,55 +0,0 @@
---
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
# 在此粘贴
```
**日志**
粘贴日志以帮助侦测错误
```
<在此粘贴>
```

View File

@@ -0,0 +1,107 @@
name: "[简体中文] 错误报告"
description: "创建错误报告以帮助我们修正应用"
title: "[BUG] "
body:
- type: markdown
attributes:
value: |
感谢您在百忙之中填写此错误报告。
注意: 请务必在上方文本框的 `[BUG]` **之后**填写清晰明了的标题。
注意:这里不提供像是代理服务器之类的服务,请不要反馈非应用自身引起的问题。
<!-- template -->
- type: textarea
id: description
attributes:
label: "描述此错误"
description: "请清晰简洁的描述你遇到的错误。"
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: "如何复现该错误"
description: "复现步骤:"
value: |
步骤 1: ...
步骤 2: ...
步骤 3: ...
...
validations:
required: true
- type: textarea
id: device-info
attributes:
label: "设备信息"
description: |
输入您正在使用的设备信息。
例子:
- 机型: Pixel 4
- 系统类型: MIUI/AOSP
- Android 版本: 10
value: |
- 机型:
- 系统类型:
- Android 版本:
validations:
required: true
- type: textarea
id: app-info
attributes:
label: "应用信息"
description: |
输入您正在使用的应用信息。
例子:
```
- 版本: 2.5.4-premium
- 安装包文件名: cfa-2.5.4-premium-arm64-v8a-release.apk
- 应用来源: Google Play
```
value: |
- 版本:
- 安装包文件名:
- 应用来源:
validations:
required: true
- type: textarea
id: configure
attributes:
render: yml
label: "配置文件"
description: |
请在此粘贴和上传配置文件。
提示:如果您仅有一个订阅链接,请使用浏览器打开此链接以下载配置文件。
**注意: 请在上传配置文件前,移除其中的代理服务器信息。**
**注意: 请在上传配置文件前,移除其中的代理服务器信息。**
**注意: 请在上传配置文件前,移除其中的代理服务器信息。**
validations:
required: true
- type: textarea
id: logs
attributes:
render: raw
label: "日志"
description: |
请在此粘贴或上传日志。
提示: 请使用应用内的 `Logcat` 或 `adb logcat` 捕获日志. `adb logcat` 能更好地帮助侦测问题.
validations:
required: true
- type: textarea
id: screenshot
attributes:
label: "屏幕截图"
description: "如果适用,请在此粘贴或上传屏幕截图。"
placeholder: "可选"
- type: textarea
id: additional
attributes:
label: "附加信息"
description: "其他的可能与改错误相关的信息。"
placeholder: "可选"

View File

@@ -1,21 +0,0 @@
---
name: "[简体中文] 功能请求"
about: 你希望的能够在应用中增加的功能
title: "[Feature Request] "
labels: ''
assignees: ''
---
<!-- 请务必在上方文本框处 [Feature Request] 后填入清晰明了的标题 -->
<!-- 请务必在上方文本框处 [Feature Request] 后填入清晰明了的标题 -->
<!-- 请务必在上方文本框处 [Feature Request] 后填入清晰明了的标题 -->
**功能描述**
请清晰的描述你想要的功能
**描述你希望的实现方式**
清晰的描述应用应该如何实现该功能
**附加信息**
其他的与改功能相关的附加信息

View File

@@ -0,0 +1,26 @@
name: "[简体中文] 功能请求"
description: "您希望的能够在应用中增加功能"
title: "[Feature Request] "
body:
- type: markdown
attributes:
value: |
感谢您在百忙之中填写此功能请求报告。
注意: 请务必在上方文本框的 `[Feature Request]` **之后**填写清晰明了的标题。
<!-- template -->
- type: textarea
id: "description"
attributes:
label: "功能描述"
description: |
简介明了的描述此功能。
validations:
required: true
- type: textarea
id: "additional"
attributes:
label: "附加信息"
description: |
与此功能相关的其他附加信息。

View File

@@ -4,6 +4,7 @@ on:
branches:
- main
paths-ignore:
- '.github/**'
- '.idea/**'
- '.gitattributes'
- '.gitignore'
@@ -13,6 +14,7 @@ on:
- 'NOTICE'
pull_request:
paths-ignore:
- '.github/**'
- '.idea/**'
- '.gitattributes'
- '.gitignore'
@@ -20,22 +22,33 @@ on:
- '**.md'
- 'LICENSE'
- 'NOTICE'
jobs:
BuildUnsigned:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Java
uses: actions/setup-java@v2
uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: 11
distribution: 'zulu'
java-version: 17
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: 1.17
go-version: 1.18
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Build
run: ./gradlew --no-daemon app:assembleFossRelease
uses: gradle/gradle-build-action@v2
with:
arguments: --no-daemon app:assembleFossRelease

4
.gitignore vendored
View File

@@ -59,5 +59,5 @@ google-services.json
# logs
*.log
# Ignore sum
/core/src/main/golang/go.sum
# MacOS
.DS_Store

View File

@@ -12,19 +12,19 @@ dependencies {
implementation(project(":design"))
implementation(project(":common"))
implementation(deps.kotlin.coroutine)
implementation(deps.androidx.core)
implementation(deps.androidx.activity)
implementation(deps.androidx.fragment)
implementation(deps.androidx.appcompat)
implementation(deps.androidx.coordinator)
implementation(deps.androidx.recyclerview)
implementation(deps.google.material)
implementation(libs.kotlin.coroutine)
implementation(libs.androidx.core)
implementation(libs.androidx.activity)
implementation(libs.androidx.fragment)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.coordinator)
implementation(libs.androidx.recyclerview)
implementation(libs.google.material)
val premiumImplementation by configurations
premiumImplementation(deps.appcenter.analytics)
premiumImplementation(deps.appcenter.crashes)
premiumImplementation(libs.appcenter.analytics)
premiumImplementation(libs.appcenter.crashes)
}
tasks.getByName("clean", type = Delete::class) {

View File

@@ -234,12 +234,12 @@ abstract class BaseActivity<D : Design<*>> :
window.statusBarColor = resolveThemedColor(android.R.attr.statusBarColor)
window.navigationBarColor = resolveThemedColor(android.R.attr.navigationBarColor)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT >= 23) {
window.isLightStatusBarsCompat =
resolveThemedBoolean(android.R.attr.windowLightStatusBar)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
if (Build.VERSION.SDK_INT >= 27) {
window.isLightNavigationBarCompat =
resolveThemedBoolean(android.R.attr.windowLightNavigationBar)
}

View File

@@ -1,7 +1,5 @@
package com.github.kr328.clash
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.ComponentName
@@ -9,12 +7,13 @@ import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Binder
import android.os.Build
import android.os.IBinder
import android.os.IInterface
import androidx.core.app.NotificationChannelCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.github.kr328.clash.common.compat.getColorCompat
import com.github.kr328.clash.common.compat.pendingIntentFlags
import com.github.kr328.clash.common.log.Log
import com.github.kr328.clash.common.util.intent
import com.github.kr328.clash.core.model.LogMessage
@@ -126,16 +125,12 @@ class LogcatService : Service(), CoroutineScope by CoroutineScope(Dispatchers.De
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
return
NotificationManagerCompat.from(this)
.createNotificationChannel(
NotificationChannel(
NotificationChannelCompat.Builder(
CHANNEL_ID,
getString(R.string.clash_logcat),
NotificationManager.IMPORTANCE_DEFAULT
)
NotificationManagerCompat.IMPORTANCE_DEFAULT
).setName(getString(R.string.clash_logcat)).build()
)
}
@@ -152,7 +147,7 @@ class LogcatService : Service(), CoroutineScope by CoroutineScope(Dispatchers.De
R.id.nf_logcat_status,
LogcatActivity::class.intent
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP),
PendingIntent.FLAG_UPDATE_CURRENT
pendingIntentFlags(PendingIntent.FLAG_UPDATE_CURRENT)
)
)
.build()

View File

@@ -9,7 +9,12 @@
android:translateY="103.4632">
<path
android:fillColor="#1E4376"
android:pathData="M47.211,168.128C70.531,-34.962 67.471,13.788 94.071,43.818c13.45,-1.52 27.24,-3.47 40.82,-0.67c2.64,0.13 5.42,1.86 7.71,0.18c4.12,-6.27 7.35,-13.54 11.35,-20c12.19,-24.44 12.85,19.54 15.48,26.52c5.23,32.99 10.89,64.46 14.67,97.59c0.31,10.72 5.74,32.92 1.08,33.56c-49.36,5.23 -147.71,3.91 -160.84,-6.3c-15.85,-10.5 -15.18,-35.33 2.03,-43.72c3.63,-2.03 10.68,-3.72 11.94,0.7c-2.41,4.99 -8.79,5.77 -12.12,11.17C16.621,158.948 33.111,168.888 47.211,168.128zM87.841,74.008c-10.42,0.52 -9.59,14.89 -0.07,15.18C98.191,88.668 97.361,74.298 87.841,74.008zM149.121,89.188c10.46,-0.34 9.85,-14.71 0.38,-15.18C139.031,74.348 139.651,88.718 149.121,89.188zM107.871,99.228c2.16,3.48 5.28,3.29 9.79,0.16c3.81,3.17 8.06,3.28 9.18,-0.19c-3.78,1.17 -7.04,0.79 -9.4,-3.49C115.371,100.108 112.071,100.428 107.871,99.228z"
android:pathData="M37.7,168.1C61.1-35,58,13.8,84.6,43.8c13.5-1.5,27.2-3.5,40.8-0.7c2.6,0.1,5.4,1.9,7.7,0.2
c4.1-6.3,7.4-13.5,11.4-20c12.2-24.4,12.8,19.5,15.5,26.5c5.2,33,10.9,64.5,14.7,97.6c0.3,10.7,5.7,32.9,1.1,33.6
c-49.4,5.2-147.7,3.9-160.8-6.3c-15.8-10.5-15.2-35.3,2-43.7c3.6-2,10.7-3.7,11.9,0.7c-2.4,5-8.8,5.8-12.1,11.2
C7.2,158.9,23.6,168.9,37.7,168.1z M78.4,74c-10.4,0.5-9.6,14.9-0.1,15.2C88.7,88.7,87.9,74.3,78.4,74z M139.7,89.2
c10.5-0.3,9.8-14.7,0.4-15.2C129.6,74.3,130.2,88.7,139.7,89.2z M98.4,99.2c2.2,3.5,5.3,3.3,9.8,0.2c3.8,3.2,8.1,3.3,9.2-0.2
c-3.8,1.2-7,0.8-9.4-3.5C105.9,100.1,102.6,100.4,98.4,99.2z"
tools:ignore="VectorPath" />
</group>
</vector>

View File

@@ -12,51 +12,39 @@ buildscript {
maven("https://maven.kr328.app/releases")
}
dependencies {
classpath(deps.build.android)
classpath(deps.build.kotlin.common)
classpath(deps.build.kotlin.serialization)
classpath(deps.build.ksp)
classpath(deps.build.golang)
classpath(libs.build.android)
classpath(libs.build.kotlin.common)
classpath(libs.build.kotlin.serialization)
classpath(libs.build.ksp)
classpath(libs.build.golang)
}
}
allprojects {
subprojects {
repositories {
mavenCentral()
google()
maven("https://maven.kr328.app/releases")
}
}
subprojects {
val isApp = name == "app"
apply(plugin = if (isApp) "com.android.application" else "com.android.library")
extensions.configure<BaseExtension> {
val minSdkVersion = 21
val targetSdkVersion = 30
val buildVersionCode = 204012
val buildVersionName = "2.4.12"
val defaultDimension = "feature"
ndkVersion = "23.0.7599858"
compileSdkVersion(targetSdkVersion)
defaultConfig {
if (isApp) {
applicationId = "com.github.kr328.clash"
}
minSdk = minSdkVersion
targetSdk = targetSdkVersion
minSdk = 21
targetSdk = 31
versionName = buildVersionName
versionCode = buildVersionCode
versionName = "2.5.8"
versionCode = 205008
resValue("string", "release_name", "v$buildVersionName")
resValue("integer", "release_code", "$buildVersionCode")
resValue("string", "release_name", "v$versionName")
resValue("integer", "release_code", "$versionCode")
externalNativeBuild {
cmake {
@@ -71,6 +59,10 @@ subprojects {
}
}
ndkVersion = "23.0.7599858"
compileSdkVersion(defaultConfig.targetSdk!!)
if (isApp) {
packagingOptions {
excludes.add("DebugProbesKt.bin")
@@ -78,10 +70,11 @@ subprojects {
}
productFlavors {
flavorDimensions(defaultDimension)
flavorDimensions("feature")
create("foss") {
dimension = defaultDimension
isDefault = true
dimension = flavorDimensionList[0]
versionNameSuffix = ".foss"
buildConfigField("boolean", "PREMIUM", "Boolean.parseBoolean(\"false\")")
@@ -91,7 +84,7 @@ subprojects {
}
}
create("premium") {
dimension = defaultDimension
dimension = flavorDimensionList[0]
versionNameSuffix = ".premium"
buildConfigField("boolean", "PREMIUM", "Boolean.parseBoolean(\"true\")")
@@ -148,6 +141,11 @@ subprojects {
}
}
variantFilter {
ignore = name.startsWith("premium") && !project(":core")
.file("src/premium/golang/clash/go.mod").exists()
}
if (isApp) {
this as AppExtension

View File

@@ -6,6 +6,6 @@ plugins {
dependencies {
compileOnly(project(":hideapi"))
implementation(deps.kotlin.coroutine)
implementation(deps.androidx.core)
implementation(libs.kotlin.coroutine)
implementation(libs.androidx.core)
}

View File

@@ -2,6 +2,8 @@ package com.github.kr328.clash.common.compat
import android.app.ActivityThread
import android.app.Application
import android.graphics.drawable.AdaptiveIconDrawable
import android.graphics.drawable.Drawable
import android.os.Build
import com.github.kr328.clash.common.log.Log
@@ -18,3 +20,12 @@ val Application.currentProcessName: String
packageName
}
}
fun Drawable.foreground(): Drawable {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
this is AdaptiveIconDrawable && this.background == null
) {
return this.foreground
}
return this
}

View File

@@ -4,17 +4,12 @@ package com.github.kr328.clash.common.compat
import android.content.Context
import android.graphics.drawable.Drawable
import android.os.Build
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
fun Context.getColorCompat(@ColorRes id: Int): Int {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
this.getColor(id)
} else {
resources.getColor(id)
}
return ContextCompat.getColor(this, id)
}
fun Context.getDrawableCompat(@DrawableRes id: Int): Drawable? {

View File

@@ -7,7 +7,7 @@ import android.text.Html
import android.text.Spanned
fun fromHtmlCompat(content: String): Spanned {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return if (Build.VERSION.SDK_INT >= 24) {
Html.fromHtml(content, Html.FROM_HTML_MODE_COMPACT)
} else {
Html.fromHtml(content)

View File

@@ -3,9 +3,13 @@ package com.github.kr328.clash.common.compat
import android.app.PendingIntent
import android.os.Build
fun pendingIntentFlags(flags: Int, immutable: Boolean = false): Int {
return if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M && immutable) {
flags or PendingIntent.FLAG_IMMUTABLE
fun pendingIntentFlags(flags: Int, mutable: Boolean = false): Int {
return if (Build.VERSION.SDK_INT >= 24) {
if (Build.VERSION.SDK_INT > 30 && mutable) {
flags or PendingIntent.FLAG_MUTABLE
} else {
flags or PendingIntent.FLAG_IMMUTABLE
}
} else {
flags
}

View File

@@ -6,7 +6,7 @@ import android.content.pm.PackageInfo
val PackageInfo.versionCodeCompat: Long
get() {
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
return if (android.os.Build.VERSION.SDK_INT >= 28) {
longVersionCode
} else {
versionCode.toLong()

View File

@@ -8,7 +8,7 @@ import java.util.*
val Configuration.preferredLocale: Locale
get() {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return if (Build.VERSION.SDK_INT >= 24) {
locales[0]
} else {
locale

View File

@@ -5,7 +5,7 @@ import android.content.Intent
import android.os.Build
fun Context.startForegroundServiceCompat(intent: Intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (Build.VERSION.SDK_INT >= 26) {
startForegroundService(intent)
} else {
startService(intent)

View File

@@ -57,9 +57,9 @@ android {
dependencies {
implementation(project(":common"))
implementation(deps.androidx.core)
implementation(deps.kotlin.coroutine)
implementation(deps.kotlin.serialization.json)
implementation(libs.androidx.core)
implementation(libs.kotlin.coroutine)
implementation(libs.kotlin.serialization.json)
}
afterEvaluate {

View File

@@ -1,29 +1,35 @@
module foss
go 1.17
go 1.18
require cfa v0.0.0
require (
cfa/blob v0.0.0 // indirect
github.com/Dreamacro/clash v0.0.0 // indirect
github.com/Dreamacro/clash v1.7.1 // indirect
github.com/Dreamacro/go-shadowsocks2 v0.1.7 // indirect
github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/gofrs/uuid v4.0.0+incompatible // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac // indirect
github.com/kr328/tun2socket-lwip v0.0.0-20210911023118-0b4947e2a9c1 // indirect
github.com/miekg/dns v1.1.43 // indirect
github.com/oschwald/geoip2-golang v1.5.0 // indirect
github.com/gofrs/uuid v4.2.0+incompatible // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/miekg/dns v1.1.47 // indirect
github.com/oschwald/geoip2-golang v1.6.1 // indirect
github.com/oschwald/maxminddb-golang v1.8.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

View File

@@ -1,34 +1,36 @@
github.com/Dreamacro/go-shadowsocks2 v0.1.7 h1:8CtbE1HoPPMfrQZGXmlluq6dO2lL31W6WRRE8fabc4Q=
github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr8kvw8uw3TDwLAJpUc=
github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34 h1:USCTqih5d1bUXUxWNS9ZD5Tx/lb0jXHEtRIIx/F9dMc=
github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34/go.mod h1:YR9wK13TgI5ww8iKWm91MHiSoHC7Oz0U4beCCmtXqLw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac h1:IO6EfdRnPhxgKOsk9DbewdtQZHKZKnGlW7QCUttvNys=
github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd h1:efcJu2Vzz6DoSq245deWNzTz6l/gsqdphm3FjmI88/g=
github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kr328/tun2socket-lwip v0.0.0-20210911023118-0b4947e2a9c1 h1:NJ5NyPHIok6hqdELvrI4bps5lLyfJtFmm0K4c9CB/WM=
github.com/kr328/tun2socket-lwip v0.0.0-20210911023118-0b4947e2a9c1/go.mod h1:JFkXLCpLkNVvLMRkq3gexTlRHfzbqcP5HfFOoq5Mj+g=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
@@ -36,10 +38,10 @@ github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcK
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
github.com/miekg/dns v1.1.47 h1:J9bWiXbqMbnZPcY8Qi2E3EWIBsIm6MZzzJB9VRg5gL8=
github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/oschwald/geoip2-golang v1.6.1 h1:GKxT3yaWWNXSb7vj6D7eoJBns+lGYgx08QO0UcNm0YY=
github.com/oschwald/geoip2-golang v1.6.1/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -52,29 +54,40 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 h1:XMAtQHwKjWHIRwg+8Nj/rzUomQY1q6cM3ncA0wP8GU4=
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg=
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -88,26 +101,37 @@ golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 h1:BonxutuHCTL0rBDnZlKjpGIQFTjyUVTexFOdWkB6Fg0=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=

View File

@@ -54,20 +54,27 @@ int jni_catch_exception(JNIEnv *env) {
return result;
}
void jni_attach_thread(JNIEnv **penv) {
void jni_attach_thread(struct _scoped_jni *jni) {
JavaVM *vm = global_java_vm();
if ((*vm)->AttachCurrentThread(vm, penv, NULL) != JNI_OK) {
if ((*vm)->GetEnv(vm, (void **) &jni->env, JNI_VERSION_1_6) == JNI_OK) {
jni->require_release = 0;
return;
}
if ((*vm)->AttachCurrentThread(vm, &jni->env, NULL) != JNI_OK) {
abort();
}
jni->require_release = 1;
}
void jni_detach_thread(JNIEnv **env) {
(void) env;
void jni_detach_thread(struct _scoped_jni *jni) {
JavaVM *vm = global_java_vm();
(*vm)->DetachCurrentThread(vm);
if (jni->require_release) {
(*vm)->DetachCurrentThread(vm);
}
}
void release_string(char **str) {

View File

@@ -6,21 +6,23 @@
#include <malloc.h>
#include <android/log.h>
struct _scoped_jni {
JNIEnv *env;
int require_release;
};
extern void initialize_jni(JavaVM *vm, JNIEnv *env);
extern jstring jni_new_string(JNIEnv *env, const char *str);
extern char *jni_get_string(JNIEnv *env, jstring str);
extern int jni_catch_exception(JNIEnv *env);
extern void jni_attach_thread(JNIEnv **penv);
extern void jni_detach_thread(JNIEnv **env);
extern void jni_attach_thread(struct _scoped_jni *jni);
extern void jni_detach_thread(struct _scoped_jni *env);
extern void release_string(char **str);
#define ATTACH_JNI() __attribute__((unused, cleanup(jni_detach_thread))) JNIEnv *env = NULL; jni_attach_thread(&env)
#define ATTACH_JNI() __attribute__((unused, cleanup(jni_detach_thread))) \
struct _scoped_jni _jni; \
jni_attach_thread(&_jni); \
JNIEnv *env = _jni.env
#define scoped_string __attribute__((cleanup(release_string))) char*

View File

@@ -107,16 +107,19 @@ Java_com_github_kr328_clash_core_bridge_Bridge_nativeNotifyInstalledAppChanged(J
JNIEXPORT void JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_nativeStartTun(JNIEnv *env, jobject thiz,
jint fd, jint mtu,
jstring dns, jstring blocking,
jint fd,
jstring gateway,
jstring portal,
jstring dns,
jobject cb) {
TRACE_METHOD();
scoped_string _blocking = get_string(blocking);
scoped_string _gateway = get_string(gateway);
scoped_string _portal = get_string(portal);
scoped_string _dns = get_string(dns);
jobject _interface = new_global(cb);
startTun(fd, mtu, _dns, _blocking, _interface);
startTun(fd, _gateway, _portal, _dns, _interface);
}
JNIEXPORT void JNICALL

View File

@@ -1,3 +1,28 @@
module cfa
go 1.17
go 1.18
require (
github.com/Dreamacro/clash v1.7.1
github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34
github.com/dlclark/regexp2 v1.4.0
github.com/miekg/dns v1.1.43
github.com/oschwald/geoip2-golang v1.5.0
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
gopkg.in/yaml.v2 v2.4.0
)
require (
github.com/Dreamacro/go-shadowsocks2 v0.1.7 // indirect
github.com/gofrs/uuid v4.0.0+incompatible // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac // indirect
github.com/oschwald/maxminddb-golang v1.8.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f // indirect
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
golang.org/x/text v0.3.6 // indirect
)

View File

@@ -0,0 +1,117 @@
github.com/Dreamacro/clash v1.7.1 h1:8iYYiyVf7ZAztwoFeTFihs5rI9Jjic0ZKmf05vQxzFU=
github.com/Dreamacro/clash v1.7.1/go.mod h1:C9eLMAlDZSLrkdzGQdOHyeldwRjDbcGR2kaL80KdzGw=
github.com/Dreamacro/go-shadowsocks2 v0.1.7 h1:8CtbE1HoPPMfrQZGXmlluq6dO2lL31W6WRRE8fabc4Q=
github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr8kvw8uw3TDwLAJpUc=
github.com/Kr328/tun2socket v0.0.0-20211231120722-962f339492e8 h1:4Ceb/pU/u7fKGMCE2DNrWIEHkoR1ELRlYJXzbFOR+E0=
github.com/Kr328/tun2socket v0.0.0-20211231120722-962f339492e8/go.mod h1:YR9wK13TgI5ww8iKWm91MHiSoHC7Oz0U4beCCmtXqLw=
github.com/Kr328/tun2socket v0.0.0-20220317122653-4050a94cb4dd h1:rNOyFw+I4VjTtMvONd+OgG9Z/++C7NnomvL5mFGjznk=
github.com/Kr328/tun2socket v0.0.0-20220317122653-4050a94cb4dd/go.mod h1:YR9wK13TgI5ww8iKWm91MHiSoHC7Oz0U4beCCmtXqLw=
github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34 h1:USCTqih5d1bUXUxWNS9ZD5Tx/lb0jXHEtRIIx/F9dMc=
github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34/go.mod h1:YR9wK13TgI5ww8iKWm91MHiSoHC7Oz0U4beCCmtXqLw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac h1:IO6EfdRnPhxgKOsk9DbewdtQZHKZKnGlW7QCUttvNys=
github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg=
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c h1:DHcbWVXeY+0Y8HHKR+rbLwnoh2F4tNCY7rTiHJ30RmA=
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -2,7 +2,6 @@ package app
import (
"net"
"strings"
"syscall"
"cfa/native/platform"
@@ -16,10 +15,15 @@ func MarkSocket(fd int) {
}
func QuerySocketUid(source, target net.Addr) int {
protocol := syscall.IPPROTO_TCP
var protocol int
if strings.HasPrefix(source.String(), "udp") {
switch source.Network() {
case "udp", "udp4", "udp6":
protocol = syscall.IPPROTO_UDP
case "tcp", "tcp4", "tcp6":
protocol = syscall.IPPROTO_TCP
default:
return -1
}
if PlatformVersion() < 29 {

View File

@@ -4,28 +4,35 @@ var (
defaultNameServers = []string{
"223.5.5.5",
"119.29.29.29",
"8.8.8.8",
"1.1.1.1",
}
defaultFallback = []string{
"https://1.1.1.1/dns-query",
"https://doh.pub/dns-query",
"8.8.4.4",
"1.0.0.1",
}
defaultFakeIPFilter = []string{
// stun services
// Stun Services
"+.stun.*.*",
"+.stun.*.*.*",
"+.stun.*.*.*.*",
"+.stun.*.*.*.*.*",
// Google Voices
"lens.l.google.com",
"stun.l.google.com",
// Nintendo Switch
"*.n.n.srv.nintendo.net",
// PlayStation
"+.stun.playstation.net",
// XBox
"xbox.*.*.microsoft.com",
"*.*.xboxlive.com",
// Microsoft
"*.msftncsi.com",
"*.msftconnecttest.com",
// Bilibili CDN
"*.mcdn.bilivideo.cn",
}
localNetwork = []string{
"0.0.0.0/8",
"127.0.0.0/8",
}
defaultFakeIPRange = "28.0.0.0/8"
)

View File

@@ -27,7 +27,7 @@ var client = &http.Client{
DisableKeepAlives: true,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
DialContext: dialer.DefaultTunnelDialer,
DialContext: dialer.DialTunnelContext,
},
Timeout: 60 * time.Second,
}
@@ -124,7 +124,7 @@ func FetchAndValid(
return err
}
forEachProviders(rawCfg, func(index int, total int, name string, provider map[string]interface{}) {
forEachProviders(rawCfg, func(index int, total int, name string, provider map[string]any) {
bytes, _ := json.Marshal(&Status{
Action: "FetchProviders",
Args: []string{name},

View File

@@ -9,7 +9,6 @@ import (
"gopkg.in/yaml.v2"
"cfa/native/app"
"github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/config"
@@ -87,18 +86,10 @@ func Load(path string) error {
}
func LoadDefault() {
rawConfig, _ := config.UnmarshalRawConfig([]byte{})
_ = patchDns(rawConfig, constant.Path.HomeDir())
cfg, err := config.ParseRawConfig(rawConfig)
cfg, err := config.Parse([]byte{})
if err != nil {
panic(err.Error())
}
executor.ApplyConfig(cfg, true)
}
func init() {
LoadDefault()
}

View File

@@ -14,7 +14,7 @@ const (
OverrideSlotSession
)
const defaultPersistOverride = `{"dns":{"enable": false}}`
const defaultPersistOverride = `{"dns":{"enable": false}, "redir-port": 0, "tproxy-port": 0}`
const defaultSessionOverride = `{}`
var sessionOverride = defaultSessionOverride
@@ -65,4 +65,4 @@ func ClearOverride(slot OverrideSlot) {
case OverrideSlotSession:
sessionOverride = defaultSessionOverride
}
}
}

View File

@@ -5,29 +5,23 @@ import (
"errors"
"fmt"
"strings"
"time"
"github.com/dlclark/regexp2"
"cfa/native/common"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/config"
"github.com/Dreamacro/clash/dns"
)
const (
defaultHealthCheckUrl = "https://www.gstatic.com/generate_204"
defaultHealthCheckInterval = time.Hour
)
var processors = []processor{
patchOverride,
patchGeneral,
patchProfile,
patchDns,
patchProviders,
patchProxyGroup,
validConfig,
}
@@ -54,35 +48,35 @@ func patchGeneral(cfg *config.RawConfig, _ string) error {
func patchProfile(cfg *config.RawConfig, _ string) error {
cfg.Profile.StoreSelected = false
cfg.Profile.StoreFakeIP = true
return nil
}
func patchDns(cfg *config.RawConfig, _ string) error {
if !cfg.DNS.Enable {
cfg.DNS.Enable = true
cfg.DNS.IPv6 = false
cfg.DNS.NameServer = defaultNameServers
cfg.DNS.Fallback = defaultFallback
cfg.DNS.FallbackFilter.GeoIP = false
cfg.DNS.FallbackFilter.IPCIDR = localNetwork
cfg.DNS.EnhancedMode = dns.MAPPING
cfg.DNS.FakeIPRange = "198.18.0.0/16"
cfg.DNS.DefaultNameserver = defaultNameServers
cfg.DNS.FakeIPFilter = defaultFakeIPFilter
cfg.DNS = config.RawDNS{
Enable: true,
UseHosts: true,
DefaultNameserver: defaultNameServers,
NameServer: defaultNameServers,
EnhancedMode: C.DNSFakeIP,
FakeIPRange: defaultFakeIPRange,
FakeIPFilter: defaultFakeIPFilter,
}
cfg.ClashForAndroid.AppendSystemDNS = true
}
if cfg.ClashForAndroid.AppendSystemDNS {
cfg.DNS.NameServer = append(cfg.DNS.NameServer, "dhcp://" + dns.SystemDNSPlaceholder)
cfg.DNS.NameServer = append(cfg.DNS.NameServer, "dhcp://"+dns.SystemDNSPlaceholder)
}
return nil
}
func patchProviders(cfg *config.RawConfig, profileDir string) error {
forEachProviders(cfg, func(index int, total int, key string, provider map[string]interface{}) {
forEachProviders(cfg, func(index int, total int, key string, provider map[string]any) {
if path, ok := provider["path"].(string); ok {
provider["path"] = profileDir + "/providers/" + common.ResolveAsRoot(path)
}
@@ -91,20 +85,6 @@ func patchProviders(cfg *config.RawConfig, profileDir string) error {
return nil
}
func patchProxyGroup(cfg *config.RawConfig, _ string) error {
for _, g := range cfg.ProxyGroup {
if _, exist := g["url"]; !exist {
g["url"] = defaultHealthCheckUrl
}
if _, exist := g["interval"]; !exist {
g["interval"] = int(defaultHealthCheckInterval.Seconds())
}
}
return nil
}
func validConfig(cfg *config.RawConfig, _ string) error {
if len(cfg.Proxy) == 0 && len(cfg.ProxyProvider) == 0 {
return errors.New("profile does not contain `proxies` or `proxy-providers`")

View File

@@ -1,4 +1,4 @@
// +build !premium
//go:build !premium
package config
@@ -8,7 +8,7 @@ import (
"github.com/Dreamacro/clash/config"
)
func forEachProviders(rawCfg *config.RawConfig, fun func(index int, total int, key string, provider map[string]interface{})) {
func forEachProviders(rawCfg *config.RawConfig, fun func(index int, total int, key string, provider map[string]any)) {
total := len(rawCfg.ProxyProvider)
index := 0

View File

@@ -1,4 +1,4 @@
// +build premium
//go:build premium
package config
@@ -8,7 +8,7 @@ import (
"github.com/Dreamacro/clash/config"
)
func forEachProviders(rawCfg *config.RawConfig, fun func(index int, total int, key string, provider map[string]interface{})) {
func forEachProviders(rawCfg *config.RawConfig, fun func(index int, total int, key string, provider map[string]any)) {
total := len(rawCfg.ProxyProvider) + len(rawCfg.RuleProvider)
index := 0

View File

@@ -6,11 +6,12 @@ import (
"cfa/blob"
"cfa/native/app"
"cfa/native/platform"
"github.com/Dreamacro/clash/component/process"
"github.com/Dreamacro/clash/log"
"cfa/native/app"
"cfa/native/platform"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/mmdb"
"github.com/Dreamacro/clash/constant"

View File

@@ -1,3 +1,5 @@
//go:build !premium
package main
//#include "bridge.h"

View File

@@ -0,0 +1,75 @@
//go:build premium
package main
//#include "bridge.h"
import "C"
import (
"strings"
"time"
"unsafe"
"github.com/Dreamacro/clash/log"
)
type message struct {
Level string `json:"level"`
Message string `json:"message"`
Time int64 `json:"time"`
}
func init() {
go func() {
sub := log.Subscribe()
defer log.UnSubscribe(sub)
for msg := range sub {
cPayload := C.CString(msg.Payload)
switch msg.LogLevel {
case log.INFO:
C.log_info(cPayload)
case log.ERROR:
C.log_error(cPayload)
case log.WARNING:
C.log_warn(cPayload)
case log.DEBUG:
C.log_debug(cPayload)
case log.SILENT:
C.log_verbose(cPayload)
}
}
}()
}
//export subscribeLogcat
func subscribeLogcat(remote unsafe.Pointer) {
go func(remote unsafe.Pointer) {
sub := log.Subscribe()
defer log.UnSubscribe(sub)
for msg := range sub {
if msg.LogLevel < log.Level() && !strings.HasPrefix(msg.Payload, "[APP]") {
continue
}
rMsg := &message{
Level: msg.LogLevel.String(),
Message: msg.Payload,
Time: time.Now().UnixNano() / 1000 / 1000,
}
if C.logcat_received(remote, marshalJson(rMsg)) != 0 {
C.release_object(remote)
log.Debugln("Logcat subscriber closed")
break
}
}
}(remote)
log.Infoln("[APP] Logcat level: %s", log.Level().String())
}

View File

@@ -36,6 +36,7 @@ func coreInit(home, versionName C.c_string, sdkVersion C.int) {
func reset() {
config.LoadDefault()
tunnel.ResetStatistic()
tunnel.CloseAllConnections()
runtime.GC()
}

View File

@@ -5,6 +5,8 @@ import "C"
import (
"context"
"io"
"sync"
"unsafe"
"golang.org/x/sync/semaphore"
@@ -13,7 +15,11 @@ import (
"cfa/native/tun"
)
var rTunLock sync.Mutex
var rTun *remoteTun
type remoteTun struct {
closer io.Closer
callback unsafe.Pointer
closed bool
@@ -21,7 +27,7 @@ type remoteTun struct {
}
func (t *remoteTun) markSocket(fd int) {
_ = t.limit.Acquire(context.TODO(), 1)
_ = t.limit.Acquire(context.Background(), 1)
defer t.limit.Release(1)
if t.closed {
@@ -32,7 +38,7 @@ func (t *remoteTun) markSocket(fd int) {
}
func (t *remoteTun) querySocketUid(protocol int, source, target string) int {
_ = t.limit.Acquire(context.TODO(), 1)
_ = t.limit.Acquire(context.Background(), 1)
defer t.limit.Release(1)
if t.closed {
@@ -42,38 +48,61 @@ func (t *remoteTun) querySocketUid(protocol int, source, target string) int {
return int(C.query_socket_uid(t.callback, C.int(protocol), C.CString(source), C.CString(target)))
}
func (t *remoteTun) stop() {
_ = t.limit.Acquire(context.Background(), 4)
func (t *remoteTun) close() {
_ = t.limit.Acquire(context.TODO(), 4)
defer t.limit.Release(4)
t.closed = true
if t.closer != nil {
_ = t.closer.Close()
}
app.ApplyTunContext(nil, nil)
C.release_object(t.callback)
}
//export startTun
func startTun(fd, mtu C.int, gateway, dns C.c_string, callback unsafe.Pointer) C.int {
func startTun(fd C.int, gateway, portal, dns C.c_string, callback unsafe.Pointer) C.int {
rTunLock.Lock()
defer rTunLock.Unlock()
if rTun != nil {
rTun.close()
rTun = nil
}
f := int(fd)
m := int(mtu)
g := C.GoString(gateway)
p := C.GoString(portal)
d := C.GoString(dns)
remote := &remoteTun{callback: callback, closed: false, limit: semaphore.NewWeighted(4)}
app.ApplyTunContext(remote.markSocket, remote.querySocketUid)
if tun.Start(f, m, g, d, remote.stop) != nil {
app.ApplyTunContext(nil, nil)
closer, err := tun.Start(f, g, p, d)
if err != nil {
remote.close()
return 1
}
remote.closer = closer
rTun = remote
return 0
}
//export stopTun
func stopTun() {
tun.Stop()
rTunLock.Lock()
defer rTunLock.Unlock()
if rTun != nil {
rTun.close()
rTun = nil
}
}

View File

@@ -1,39 +0,0 @@
package tun
import "github.com/Dreamacro/clash/log"
func (a *adapter) rx() {
log.Infoln("[ATUN] Device rx started")
defer log.Infoln("[ATUN] Device rx exited")
defer a.once.Do(a.stop)
defer a.close()
buf := make([]byte, a.mtu)
for {
n, err := a.device.Read(buf)
if err != nil {
return
}
_, _ = a.stack.Link().Write(buf[:n])
}
}
func (a *adapter) tx() {
log.Infoln("[ATUN] Device tx started")
defer log.Infoln("[ATUN] Device tx exited")
defer a.once.Do(a.stop)
defer a.close()
buf := make([]byte, a.mtu)
for {
n, err := a.stack.Link().Read(buf)
if err != nil {
return
}
_, _ = a.device.Write(buf[:n])
}
}

View File

@@ -0,0 +1,25 @@
//go:build !premium
package tun
import (
"net"
"strconv"
C "github.com/Dreamacro/clash/constant"
)
func createMetadata(lAddr, rAddr *net.TCPAddr) *C.Metadata {
return &C.Metadata{
NetWork: C.TCP,
Type: C.SOCKS5,
SrcIP: lAddr.IP,
DstIP: rAddr.IP,
SrcPort: strconv.Itoa(lAddr.Port),
DstPort: strconv.Itoa(rAddr.Port),
AddrType: C.AtypIPv4,
Host: "",
RawSrcAddr: lAddr,
RawDstAddr: rAddr,
}
}

View File

@@ -0,0 +1,29 @@
//go:build premium
package tun
import (
"net"
"net/netip"
"strconv"
C "github.com/Dreamacro/clash/constant"
)
func createMetadata(lAddr, rAddr *net.TCPAddr) *C.Metadata {
srcAddr, _ := netip.AddrFromSlice(lAddr.IP)
dstAddr, _ := netip.AddrFromSlice(rAddr.IP)
return &C.Metadata{
NetWork: C.TCP,
Type: C.SOCKS5,
SrcIP: srcAddr,
DstIP: dstAddr,
SrcPort: strconv.Itoa(lAddr.Port),
DstPort: strconv.Itoa(rAddr.Port),
AddrType: C.AtypIPv4,
Host: "",
RawSrcAddr: lAddr,
RawDstAddr: rAddr,
}
}

View File

@@ -1,105 +0,0 @@
package tun
import (
"encoding/binary"
"io"
"net"
"strconv"
"time"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel"
)
const defaultDnsReadTimeout = time.Second * 30
func (a *adapter) tcp() {
log.Infoln("[ATUN] TCP listener started")
defer log.Infoln("[ATUN] TCP listener exited")
defer a.stack.Close()
accept:
for {
conn, err := a.stack.TCP().Accept()
if err != nil {
return
}
sAddr := conn.LocalAddr().(*net.TCPAddr)
tAddr := conn.RemoteAddr().(*net.TCPAddr)
// handle dns messages
if a.hijackTCPDNS(conn, tAddr) {
continue
}
// drop all connections connect to blocking list
for _, b := range a.blocking {
if b.Contains(tAddr.IP) {
_ = conn.Close()
continue accept
}
}
metadata := &C.Metadata{
NetWork: C.TCP,
Type: C.SOCKS5,
SrcIP: sAddr.IP,
DstIP: tAddr.IP,
SrcPort: strconv.Itoa(sAddr.Port),
DstPort: strconv.Itoa(tAddr.Port),
AddrType: C.AtypIPv4,
Host: "",
RawSrcAddr: sAddr,
RawDstAddr: tAddr,
}
tunnel.TCPIn() <- context.NewConnContext(conn, metadata)
}
}
func (a *adapter) hijackTCPDNS(conn net.Conn, tAddr *net.TCPAddr) bool {
if !shouldHijackDns(a.dns, tAddr.IP, tAddr.Port) {
return false
}
go func() {
defer conn.Close()
for {
if err := conn.SetReadDeadline(time.Now().Add(defaultDnsReadTimeout)); err != nil {
return
}
var length uint16
if binary.Read(conn, binary.BigEndian, &length) != nil {
return
}
data := make([]byte, length)
_, err := io.ReadFull(conn, data)
if err != nil {
return
}
rb, err := relayDns(data)
if err != nil {
continue
}
if binary.Write(conn, binary.BigEndian, uint16(len(rb))) != nil {
return
}
if _, err := conn.Write(rb); err != nil {
return
}
}
}()
return true
}

View File

@@ -1,91 +1,162 @@
package tun
import (
"encoding/binary"
"io"
"net"
"os"
"strings"
"sync"
"syscall"
"time"
"github.com/kr328/tun2socket-lwip"
"github.com/Kr328/tun2socket"
"github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/pool"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5"
"github.com/Dreamacro/clash/tunnel"
)
type adapter struct {
device *os.File
stack tun2socket.Stack
blocking []*net.IPNet
dns net.IP
mtu int
once sync.Once
stop func()
}
var _, ipv4LoopBack, _ = net.ParseCIDR("127.0.0.0/8")
var lock sync.Mutex
var instance *adapter
func (a *adapter) close() {
_ = a.stack.Close()
_ = a.device.Close()
}
func Start(fd, mtu int, dns string, blocking string, stop func()) error {
lock.Lock()
defer lock.Unlock()
if instance != nil {
instance.close()
}
_ = syscall.SetNonblock(fd, true)
func Start(fd int, gateway, portal, dns string) (io.Closer, error) {
log.Debugln("TUN: fd = %d, gateway = %s, portal = %s, dns = %s", fd, gateway, portal, dns)
device := os.NewFile(uintptr(fd), "/dev/tun")
stack, err := tun2socket.NewStack(mtu)
ip, network, err := net.ParseCIDR(gateway)
if err != nil {
panic(err.Error())
} else {
network.IP = ip
}
stack, err := tun2socket.StartTun2Socket(device, network, net.ParseIP(portal))
if err != nil {
_ = device.Close()
return err
return nil, err
}
dn := net.ParseIP(dns)
dnsAddr := net.ParseIP(dns)
var blk []*net.IPNet
tcp := func() {
defer stack.TCP().Close()
defer log.Debugln("TCP: closed")
for _, b := range strings.Split(blocking, ";") {
_, n, err := net.ParseCIDR(b)
if err != nil {
device.Close()
for stack.TCP().SetDeadline(time.Time{}) == nil {
conn, err := stack.TCP().Accept()
if err != nil {
log.Debugln("Accept connection: %v", err)
return err
continue
}
lAddr := conn.LocalAddr().(*net.TCPAddr)
rAddr := conn.RemoteAddr().(*net.TCPAddr)
if ipv4LoopBack.Contains(rAddr.IP) {
conn.Close()
continue
}
if shouldHijackDns(dnsAddr, rAddr.IP, rAddr.Port) {
go func() {
defer conn.Close()
buf := pool.Get(pool.UDPBufferSize)
defer pool.Put(buf)
for {
conn.SetReadDeadline(time.Now().Add(C.DefaultTCPTimeout))
length := uint16(0)
if err := binary.Read(conn, binary.BigEndian, &length); err != nil {
return
}
if int(length) > len(buf) {
return
}
n, err := conn.Read(buf[:length])
if err != nil {
return
}
msg, err := relayDns(buf[:n])
if err != nil {
return
}
_, _ = conn.Write(msg)
}
}()
continue
}
tunnel.TCPIn() <- context.NewConnContext(conn, createMetadata(lAddr, rAddr))
}
blk = append(blk, n)
}
instance = &adapter{
device: device,
stack: stack,
blocking: blk,
dns: dn,
mtu: mtu,
once: sync.Once{},
stop: stop,
udp := func() {
defer stack.UDP().Close()
defer log.Debugln("UDP: closed")
for {
buf := pool.Get(pool.UDPBufferSize)
n, lRAddr, rRAddr, err := stack.UDP().ReadFrom(buf)
if err != nil {
return
}
raw := buf[:n]
lAddr := lRAddr.(*net.UDPAddr)
rAddr := rRAddr.(*net.UDPAddr)
if ipv4LoopBack.Contains(rAddr.IP) {
pool.Put(buf)
continue
}
if shouldHijackDns(dnsAddr, rAddr.IP, rAddr.Port) {
go func() {
defer pool.Put(buf)
msg, err := relayDns(raw)
if err != nil {
return
}
_, _ = stack.UDP().WriteTo(msg, rAddr, lAddr)
}()
continue
}
pkt := &packet{
local: lAddr,
data: raw,
writeBack: func(b []byte, addr net.Addr) (int, error) {
return stack.UDP().WriteTo(b, addr, lAddr)
},
drop: func() {
pool.Put(buf)
},
}
tunnel.UDPIn() <- inbound.NewPacket(socks5.ParseAddrToSocksAddr(rAddr), pkt, C.SOCKS5)
}
}
go instance.rx()
go instance.tx()
go instance.tcp()
go instance.udp()
go tcp()
go udp()
go udp()
return nil
}
func Stop() {
lock.Lock()
defer lock.Unlock()
if instance != nil {
instance.close()
}
instance = nil
return stack, nil
}

View File

@@ -2,21 +2,13 @@ package tun
import (
"net"
"github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/pool"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5"
"github.com/Dreamacro/clash/tunnel"
"github.com/kr328/tun2socket-lwip"
)
type packet struct {
stack tun2socket.Stack
local *net.UDPAddr
data []byte
local *net.UDPAddr
data []byte
writeBack func(b []byte, addr net.Addr) (int, error)
drop func()
}
func (pkt *packet) Data() []byte {
@@ -24,76 +16,13 @@ func (pkt *packet) Data() []byte {
}
func (pkt *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
return pkt.stack.UDP().WriteTo(b, pkt.local, addr)
return pkt.writeBack(b, addr)
}
func (pkt *packet) Drop() {
pool.Put(pkt.data)
pkt.drop()
}
func (pkt *packet) LocalAddr() net.Addr {
return &net.UDPAddr{
IP: pkt.local.IP,
Port: pkt.local.Port,
Zone: "",
}
}
func (a *adapter) udp() {
log.Infoln("[ATUN] UDP receiver started")
defer log.Infoln("[ATUN] UDP receiver exited")
defer a.stack.Close()
read:
for {
buf := pool.Get(a.mtu)
n, lAddr, rAddr, err := a.stack.UDP().ReadFrom(buf)
if err != nil {
return
}
sAddr := lAddr.(*net.UDPAddr)
tAddr := rAddr.(*net.UDPAddr)
// handle dns messages
if a.hijackUDPDNS(buf[:n], sAddr, tAddr) {
continue
}
// drop all packet send to blocking list
for _, b := range a.blocking {
if b.Contains(tAddr.IP) {
continue read
}
}
pkt := &packet{
stack: a.stack,
local: sAddr,
data: buf[:n],
}
tunnel.UDPIn() <- inbound.NewPacket(socks5.ParseAddrToSocksAddr(tAddr), pkt, C.SOCKS5)
}
}
func (a *adapter) hijackUDPDNS(pkt []byte, sAddr, tAddr *net.UDPAddr) bool {
if !shouldHijackDns(a.dns, tAddr.IP, tAddr.Port) {
return false
}
go func() {
answer, err := relayDns(pkt)
if err != nil {
return
}
_, _ = a.stack.UDP().WriteTo(answer, sAddr, tAddr)
pool.Put(pkt)
}()
return true
return pkt.local
}

View File

@@ -5,6 +5,12 @@ import (
"github.com/Dreamacro/clash/tunnel/statistic"
)
func CloseAllConnections() {
for _, c := range statistic.DefaultManager.Snapshot().Connections {
_ = c.Close()
}
}
func closeMatch(filter func(conn C.Conn) bool) {
for _, c := range statistic.DefaultManager.Snapshot().Connections {
if cc, ok := c.(C.Conn); ok {

View File

@@ -0,0 +1,43 @@
package tunnel
import (
"context"
"net"
"strings"
"github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
CTX "github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/tunnel"
)
func init() {
dialer.DefaultTunnelDialer = func(context context.Context, network, address string) (net.Conn, error) {
if !strings.HasPrefix(network, "tcp") {
return nil, net.UnknownNetworkError("unsupported network")
}
host, port, err := net.SplitHostPort(address)
if err != nil {
return nil, err
}
left, right := net.Pipe()
metadata := &C.Metadata{
NetWork: C.TCP,
Type: C.HTTPCONNECT,
SrcIP: loopback,
SrcPort: "65535",
DstPort: port,
AddrType: C.AtypDomainName,
Host: host,
RawSrcAddr: left.RemoteAddr(),
RawDstAddr: left.LocalAddr(),
}
tunnel.TCPIn() <- CTX.NewConnContext(right, metadata)
return left, nil
}
}

View File

@@ -0,0 +1,7 @@
//go:build !premium
package tunnel
import "net"
var loopback = net.ParseIP("127.0.0.1")

View File

@@ -0,0 +1,7 @@
//go:build premium
package tunnel
import "net/netip"
var loopback = netip.MustParseAddr("127.0.0.1")

View File

@@ -1,9 +1,8 @@
// +build !premium
//go:build !premium
package tunnel
import (
"errors"
"fmt"
"time"
@@ -12,8 +11,6 @@ import (
"github.com/Dreamacro/clash/tunnel"
)
var ErrInvalidType = errors.New("invalid type")
type Provider struct {
Name string `json:"name"`
VehicleType string `json:"vehicleType"`

View File

@@ -1,4 +1,4 @@
// +build premium
//go:build premium
package tunnel
@@ -49,7 +49,7 @@ func QueryProviders() []*Provider {
for _, p := range providers {
updatedAt := time.Time{}
if s, ok := p.(P.UpdatableProvider); ok {
if s, ok := p.(P.UpdatableProvider[any]); ok {
updatedAt = s.UpdatedAt()
}

View File

@@ -7,7 +7,7 @@ import (
"reflect"
)
func marshalJson(obj interface{}) *C.char {
func marshalJson(obj any) *C.char {
res, err := json.Marshal(obj)
if err != nil {
panic(err.Error())
@@ -16,7 +16,7 @@ func marshalJson(obj interface{}) *C.char {
return C.CString(string(res))
}
func marshalString(obj interface{}) *C.char {
func marshalString(obj any) *C.char {
if obj == nil {
return nil
}

View File

@@ -64,13 +64,13 @@ object Clash {
fun startTun(
fd: Int,
mtu: Int,
gateway: String,
portal: String,
dns: String,
blocking: String,
markSocket: (Int) -> Boolean,
querySocketUid: (protocol: Int, source: InetSocketAddress, target: InetSocketAddress) -> Int
) {
Bridge.nativeStartTun(fd, mtu, dns, blocking, object : TunInterface {
Bridge.nativeStartTun(fd, gateway, portal, dns, object : TunInterface {
override fun markSocket(fd: Int) {
markSocket(fd)
}

View File

@@ -4,6 +4,7 @@ import android.os.Build
import android.os.ParcelFileDescriptor
import androidx.annotation.Keep
import com.github.kr328.clash.common.Global
import com.github.kr328.clash.common.log.Log
import kotlinx.coroutines.CompletableDeferred
import java.io.File
@@ -18,7 +19,7 @@ object Bridge {
external fun nativeNotifyDnsChanged(dnsList: String)
external fun nativeNotifyTimeZoneChanged(name: String, offset: Int)
external fun nativeNotifyInstalledAppChanged(uidList: String)
external fun nativeStartTun(fd: Int, mtu: Int, dns: String, blocking: String, cb: TunInterface)
external fun nativeStartTun(fd: Int, gateway: String, portal: String, dns: String, cb: TunInterface)
external fun nativeStopTun()
external fun nativeStartHttp(listenAt: String): String?
external fun nativeStopHttp()
@@ -63,6 +64,8 @@ object Bridge {
val versionName = ctx.packageManager.getPackageInfo(ctx.packageName, 0).versionName
val sdkVersion = Build.VERSION.SDK_INT
Log.d("Home = $home")
nativeInit(home, versionName, sdkVersion)
}
}

View File

@@ -14,8 +14,7 @@ import kotlinx.serialization.modules.SerializersModule
object Parcelizer {
private class ParcelDecoder(private val parcel: Parcel) : Decoder, CompositeDecoder {
@ExperimentalSerializationApi
override val serializersModule: SerializersModule = EmptySerializersModule
override val serializersModule: SerializersModule = SerializersModule {}
@ExperimentalSerializationApi
override fun decodeSequentially(): Boolean = true
@@ -122,8 +121,7 @@ object Parcelizer {
}
private class ParcelEncoder(private val parcel: Parcel) : Encoder, CompositeEncoder {
@ExperimentalSerializationApi
override val serializersModule: SerializersModule = EmptySerializersModule
override val serializersModule: SerializersModule = SerializersModule {}
override fun encodeBooleanElement(
descriptor: SerialDescriptor,

View File

@@ -22,17 +22,17 @@ private fun trafficString(scaled: Long): String {
scaled > 1024 * 1024 * 1024 * 100L -> {
val data = scaled / 1024 / 1024 / 1024
"${data / 100}.${data % 100} GiB"
String.format("%.2f GiB", data.toFloat() / 100)
}
scaled > 1024 * 1024 * 100L -> {
val data = scaled / 1024 / 1024
"${data / 100}.${data % 100} MiB"
String.format("%.2f MiB", data.toFloat() / 100)
}
scaled > 1024 * 100L -> {
val data = scaled / 1024
"${data / 100}.${data % 100} KiB"
String.format("%.2f KiB", data.toFloat() / 100)
}
else -> {
"$scaled Bytes"

View File

@@ -1,40 +1,53 @@
module premium
go 1.17
go 1.18
require cfa v0.0.0
require (
cfa/blob v0.0.0 // indirect
github.com/Dreamacro/clash v0.0.0 // indirect
github.com/Dreamacro/go-shadowsocks2 v0.1.7 // indirect
github.com/Dreamacro/clash v1.7.1 // indirect
github.com/Dreamacro/go-shadowsocks2 v0.1.8 // indirect
github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34 // indirect
github.com/avast/apkparser v0.0.0-20210223100516-186f320f9bfc // indirect
github.com/avast/apkverifier v0.0.0-20210524110121-dfe686b45d88 // indirect
github.com/avast/apkverifier v0.0.0-20210916093748-2146ff7c4b7f // indirect
github.com/cilium/ebpf v0.8.1 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/gofrs/uuid v4.0.0+incompatible // indirect
github.com/florianl/go-tc v0.4.0 // indirect
github.com/gofrs/uuid v4.2.0+incompatible // indirect
github.com/google/btree v1.0.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41 // indirect
github.com/josharian/native v1.0.0 // indirect
github.com/klauspost/compress v1.11.13 // indirect
github.com/kr328/tun2socket-lwip v0.0.0-20210911023118-0b4947e2a9c1 // indirect
github.com/miekg/dns v1.1.43 // indirect
github.com/oschwald/geoip2-golang v1.5.0 // indirect
github.com/oschwald/maxminddb-golang v1.8.0 // indirect
github.com/mdlayher/netlink v1.6.0 // indirect
github.com/mdlayher/socket v0.1.1 // indirect
github.com/miekg/dns v1.1.48 // indirect
github.com/openacid/low v0.1.21 // indirect
github.com/oschwald/geoip2-golang v1.7.0 // indirect
github.com/oschwald/maxminddb-golang v1.9.0 // indirect
github.com/samber/lo v1.11.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
go.starlark.net v0.0.0-20210901212718-87f333178d59 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd // indirect
go.uber.org/atomic v1.9.0 // indirect
go4.org/intern v0.0.0-20210108033219-3eb7198706b2 // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f // indirect
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37 // indirect
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 // indirect
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
golang.org/x/tools v0.1.9 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gvisor.dev/gvisor v0.0.0-20210904021812-0d58674c658a // indirect
inet.af/netaddr v0.0.0-20210903134321-85fa6c94624e // indirect
gvisor.dev/gvisor v0.0.0-20220311014831-b314d81fbac7 // indirect
inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 // indirect
)
replace cfa => ../../main/golang

File diff suppressed because it is too large Load Diff

View File

@@ -9,13 +9,13 @@ dependencies {
implementation(project(":core"))
implementation(project(":service"))
implementation(deps.kotlin.coroutine)
implementation(deps.androidx.core)
implementation(deps.androidx.appcompat)
implementation(deps.androidx.activity)
implementation(deps.androidx.coordinator)
implementation(deps.androidx.recyclerview)
implementation(deps.androidx.fragment)
implementation(deps.androidx.viewpager)
implementation(deps.google.material)
implementation(libs.kotlin.coroutine)
implementation(libs.androidx.core)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.activity)
implementation(libs.androidx.coordinator)
implementation(libs.androidx.recyclerview)
implementation(libs.androidx.fragment)
implementation(libs.androidx.viewpager)
implementation(libs.google.material)
}

View File

@@ -71,9 +71,9 @@ class NetworkSettingsDesign(
)
switch(
value = srvStore::blockLoopback,
title = R.string.block_loopback,
summary = R.string.block_loopback_summary,
value = srvStore::allowBypass,
title = R.string.allow_bypass,
summary = R.string.allow_bypass_summary,
configure = vpnDependencies::add,
)

View File

@@ -2,12 +2,13 @@ package com.github.kr328.clash.design.util
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import com.github.kr328.clash.common.compat.foreground
import com.github.kr328.clash.design.model.AppInfo
fun PackageInfo.toAppInfo(pm: PackageManager): AppInfo {
return AppInfo(
packageName = packageName,
icon = applicationInfo.loadIcon(pm),
icon = applicationInfo.loadIcon(pm).foreground(),
label = applicationInfo.loadLabel(pm).toString(),
installTime = firstInstallTime,
updateDate = lastUpdateTime,

View File

@@ -1,29 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="access_control_packages_summary">為軟體設定訪問權限</string>
<string name="access_control_packages_summary">配置應用程式存取權</string>
<string name="about">關於</string>
<string name="access_control_mode">訪問控制模式</string>
<string name="access_control_packages">訪問控制軟體套件清單</string>
<string name="append_system_dns">加作業系統 DNS</string>
<string name="application_broken">軟體損毀</string>
<string name="access_control_mode">存取控制套件</string>
<string name="access_control_packages">存取控制應用程式套件清單</string>
<string name="append_system_dns">加作業系統 DNS</string>
<string name="application_broken">應用程式損毀</string>
<string name="application_name">Clash for Android</string>
<string name="auto_update">自動更新</string>
<string name="behavior">行為</string>
<string name="bypass_private_network">過私有網路</string>
<string name="bypass_private_network_summary">過私有網路位址</string>
<string name="bypass_private_network">過私有網路</string>
<string name="bypass_private_network_summary">過私有網路位址</string>
<string name="cancel">取消</string>
<string name="clash_logcat">Clash 日誌檔採集工具</string>
<string name="clash_logcat">Clash Logcat</string>
<string name="create_profile">建立設定檔</string>
<string name="dark_mode">深色模式</string>
<string name="default_">預設</string>
<string name="delay"></string>
<string name="delay"></string>
<string name="delete">刪除</string>
<string name="delete_all_logs">刪除所有日誌檔</string>
<string name="delete_all_logs_warn">所有歷史日誌檔將丟失</string>
<string name="detail">內容</string>
<string name="delete_all_logs_warn">所有歷史日誌將被刪除</string>
<string name="detail">詳細資料</string>
<string name="direct_mode">直連模式</string>
<string name="disabled"></string>
<string name="dns_hijacking">DNS 劫持</string>
<string name="disabled"></string>
<string name="dns_hijacking">DNS 攔截攻擊</string>
<string name="dns_hijacking_summary">處理所有 DNS 封包</string>
<string name="duplicate">複製</string>
<string name="edit">編輯</string>
@@ -36,8 +36,8 @@
<string name="file_exported">檔案已匯出</string>
<string name="format_minutes">%d 分鐘</string>
<string name="format_profile_activated">%s 已啟用</string>
<string name="format_traffic_forwarded">%s 已轉</string>
<string name="global_mode">全域模式</string>
<string name="format_traffic_forwarded">%s 已轉</string>
<string name="global_mode">全域模式</string>
<string name="history">歷史</string>
<string name="import_from_file">從檔案匯入</string>
<string name="import_from_url">從 URL 匯入</string>
@@ -50,46 +50,46 @@
<string name="name">名稱</string>
<string name="network">網路</string>
<string name="new_profile">新設定檔</string>
<string name="not_selected">未選</string>
<string name="not_selected">未選</string>
<string name="ok">確認</string>
<string name="profile">設定檔</string>
<string name="profile_name">設定檔名稱</string>
<string name="profiles">設定檔</string>
<string name="properties">參數</string>
<string name="properties">性質</string>
<string name="proxy">Proxy</string>
<string name="recently">最近</string>
<string name="route_system_traffic">自動轉作業系統流量</string>
<string name="routing_via_vpn_service">通過 VpnService 自動轉所有作業系統流量</string>
<string name="route_system_traffic">自動轉作業系統流量</string>
<string name="routing_via_vpn_service">通過 VpnService 自動轉所有作業系統流量</string>
<string name="rule_mode">規則模式</string>
<string name="running">運作</string>
<string name="running">執行</string>
<string name="settings">設定</string>
<string name="show_traffic">顯示流量</string>
<string name="show_traffic_summary">在通知中自動重新整理流量</string>
<string name="allow_clash_auto_restart">允許 Clash 自動重新啟動</string>
<string name="auto_restart">自動重新啟動</string>
<string name="stopped">已停止</string>
<string name="help"></string>
<string name="tap_to_start">點此啟動</string>
<string name="help"></string>
<string name="tap_to_start">輕觸以啟動</string>
<string name="update">更新</string>
<string name="url">URL</string>
<string name="vpn_service_options">VpnService 選項</string>
<string name="options_unavailable">選項在 Clash 運作時不可用</string>
<string name="search"></string>
<string name="system_apps">作業系統軟體</string>
<string name="options_unavailable">選項在 Clash 執行時不可用</string>
<string name="search"></string>
<string name="system_apps">系統應用</string>
<string name="update_time">更新時間</string>
<string name="package_name">軟體套件名稱</string>
<string name="package_name">套件名稱</string>
<string name="install_time">安裝時間</string>
<string name="clash_for_android">Clash for Android</string>
<string name="feedback">回饋</string>
<string name="github_issues">Github Issues</string>
<string name="tips_properties"><![CDATA[僅接受 <strong>Clash 設定檔</strong>(包含<strong>Proxy</strong>/<strong>規則</strong>)]]></string>
<string name="tips_properties"><![CDATA[僅接受 <strong>Clash 設定檔</strong> (包含<strong>Proxy</strong> /<strong>規則</strong>)]]></string>
<string name="loading">載入中</string>
<string name="tips_help"><![CDATA[Clash for Android 是一個<strong>免費軟體</strong>並且我們<strong>不</strong>為其提供任何服務, <strong>請務必不要回報非軟體自身引起的問題</strong>]]></string>
<string name="donate">抖內</string>
<string name="allow_all_apps">允許所有軟體</string>
<string name="allow_selected_apps">僅允許已選取的軟體</string>
<string name="deny_selected_apps">不允許已選取的軟體</string>
<string name="no_profile_selected">沒有選取設定檔</string>
<string name="tips_help"><![CDATA[Clash for Android 是一個<strong>免費應用程式</strong>並且我們<strong>不</strong>為其提供任何服務, <strong>請務必不要回報非應用程式自身引起的問題</strong>]]></string>
<string name="donate">捐助</string>
<string name="allow_all_apps">允許所有應用</string>
<string name="allow_selected_apps">僅允許已選擇的應用</string>
<string name="deny_selected_apps">不允許已選擇的應用</string>
<string name="no_profile_selected">未選擇設定檔</string>
<string name="copied">已複製</string>
<string name="script_mode">腳本模式</string>
<string name="google_play">Google Play</string>
@@ -97,10 +97,10 @@
<string name="select_all">全選</string>
<string name="select_invert">反選</string>
<string name="select_none">清除</string>
<string name="app">軟體</string>
<string name="follow_system_android_10">跟隨作業系統 (Android 10+)</string>
<string name="always_dark">總是深色模式</string>
<string name="always_light">總是淺色模式</string>
<string name="app">應用</string>
<string name="follow_system_android_10">系統預設 (Android 10+)</string>
<string name="always_dark">深色</string>
<string name="always_light">淺色</string>
<string name="service">服務</string>
<string name="accept_http_content">僅接受 http(s) 和 content 類型</string>
<string name="at_least_15_minutes">至少 15 分鐘</string>
@@ -109,36 +109,36 @@
<string name="dns">DNS</string>
<string name="http_port">HTTP 埠</string>
<string name="socks_port">Socks 埠</string>
<string name="mixed_port">複合</string>
<string name="allow_lan">允許來自區域網路的連</string>
<string name="mixed_port">Mixed </string>
<string name="allow_lan">允許來自區域網路的連</string>
<string name="bind_address">監聽位址</string>
<string name="log_level">日誌檔級別</string>
<string name="log_level">日誌層次</string>
<string name="ipv6">IPv6</string>
<string name="hosts">Hosts</string>
<string name="enabled">已啟用</string>
<string name="info">消息</string>
<string name="info">資訊</string>
<string name="warning">警告</string>
<string name="error">錯誤</string>
<string name="debug">調試</string>
<string name="debug">偵錯</string>
<string name="silent">停用</string>
<string name="format_elements">%d 個條目</string>
<string name="strategy">策略</string>
<string name="enhanced_mode">增強模式</string>
<string name="name_server">Name Server</string>
<string name="fallback">Fallback Name Server</string>
<string name="default_name_server">Default Name Server</string>
<string name="name_server">名稱伺服器</string>
<string name="fallback">後饋名稱伺服器</string>
<string name="default_name_server">預設名稱伺服器</string>
<string name="fakeip_filter">FakeIP 過濾器</string>
<string name="geoip_fallback">GeoIP Fallback</string>
<string name="ipcidr_fallback">IPCIDR Fallback</string>
<string name="geoip_fallback">GeoIP 後饋</string>
<string name="ipcidr_fallback">IPCIDR 後饋</string>
<string name="use_built_in">使用內建</string>
<string name="mapping">Real-IP 至 域名映射</string>
<string name="fakeip">Fake-IP 至 域名映射</string>
<string name="mapping">Real-IP 至域名映射</string>
<string name="fakeip">Fake-IP 至域名映射</string>
<string name="sort">排序</string>
<string name="layout">佈局</string>
<string name="single">單欄</string>
<string name="multiple">多欄</string>
<string name="not_selectable">不可選</string>
<string name="providers">外部資源</string>
<string name="not_selectable">不可選</string>
<string name="providers">提供者</string>
<string name="unavailable">不可用</string>
<string name="_new">新增</string>
<string name="value"></string>
@@ -178,13 +178,13 @@
<string name="force_enable">強制啟用</string>
<string name="document">文件</string>
<string name="clash_wiki">Clash Wiki</string>
<string name="invalid_file_name">不規範檔案名稱</string>
<string name="invalid_file_name">無效的檔案名稱</string>
<string name="reset_override_settings">重置覆寫設定</string>
<string name="reset_override_settings_message">所有的覆寫設定將會被抹除</string>
<string name="key"></string>
<string name="more">更多</string>
<string name="save">儲存</string>
<string name="delay_test">測試</string>
<string name="delay_test">測試</string>
<string name="format_provider_type">%1$s(%2$s)</string>
<string name="rule">規則</string>
<string name="http">HTTP</string>
@@ -196,21 +196,21 @@
<string name="close">關閉</string>
<string name="keyword">關鍵字</string>
<string name="invalid_log_file">無效的日誌檔</string>
<string name="application_crashed">軟體崩潰</string>
<string name="application_broken_tips">軟體缺少必要的運作元件,這通常是由於下載了不完整的 apk 而導致。</string>
<string name="application_crashed">應用程式崩潰</string>
<string name="application_broken_tips">應用程式缺少必要的執行元件,這通常是由於下載了不完整的 Apk 而導致。</string>
<string name="reinstall">重新安裝</string>
<string name="github_releases">Github Releases</string>
<string name="unable_to_start_vpn">無法啟動 VPN 元件</string>
<string name="request_donate_tips">如果您覺得本軟體對您有幫助歡迎在 [助] 中給予開發者一點抖內</string>
<string name="request_donate">抖內</string>
<string name="version_updated">軟體已更新</string>
<string name="request_donate_tips">如果您覺得本應用對您有幫助歡迎在 [助] 中給予開發人員一些捐助</string>
<string name="request_donate">捐助</string>
<string name="version_updated">應用已更新</string>
<string name="version_updated_tips">設定已被清除,舊版設定檔需要再次儲存。</string>
<string name="active_unsaved_tips">設定檔需要在啟用之前儲存</string>
<string name="mode_switch_tips">僅在本次工作階段中有效</string>
<string name="import_">匯入</string>
<string name="sources">原始碼</string>
<string name="clash_core">Clash 核心</string>
<string name="name_server_policy">Name Server 策</string>
<string name="block_loopback">阻止本地迴環</string>
<string name="block_loopback_summary">阻止本地迴環連結</string>
<string name="name_server_policy">Name Server </string>
<string name="block_loopback">攔截本地回送</string>
<string name="block_loopback_summary">攔截本地回送連結</string>
</resources>

View File

@@ -214,4 +214,6 @@
<string name="block_loopback">阻止本地回环</string>
<string name="block_loopback_summary">阻止本地回环连接</string>
<string name="geoip_fallback_code">GeoIP Fallback 区域代码</string>
<string name="allow_bypass">允许应用绕过</string>
<string name="allow_bypass_summary">允许其他应用绕过 VPN</string>
</resources>

View File

@@ -122,6 +122,8 @@
<string name="dns_hijacking_summary">Handle all dns packet</string>
<string name="block_loopback">Block Loopback</string>
<string name="block_loopback_summary">Block loopback connections</string>
<string name="allow_bypass">Allow Bypass</string>
<string name="allow_bypass_summary">Allows all apps to bypass this VPN connection</string>
<string name="system_proxy">System Proxy</string>
<string name="system_proxy_summary">Attach http proxy to VpnService</string>
<string name="access_control_mode">Access Control Mode</string>

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionSha256Sum=a8da5b02437a60819cad23e10fc7e9cf32bcb57029d9cb277e26eeff76ce014b
distributionSha256Sum=a9a7b7baba105f6557c9dcf9c3c6e8f7e57e6b49889c5f1d133f015d0727e4be

10
gradlew vendored
View File

@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright ? 2015-2021 the original authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -32,10 +32,10 @@
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions ?$var?, ?${var}?, ?${var:-default}?, ?${var+SET}?,
# ?${var#prefix}?, ?${var%suffix}?, and ?$( cmd )?;
# * compound commands having a testable exit status, especially ?case?;
# * various built-in commands including ?command?, ?set?, and ?ulimit?.
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#

View File

@@ -7,19 +7,19 @@ plugins {
}
dependencies {
ksp(deps.kaidl.compiler)
kapt(deps.androidx.room.compiler)
implementation(project(":core"))
implementation(project(":common"))
implementation(deps.kotlin.coroutine)
implementation(deps.kotlin.serialization.json)
implementation(deps.androidx.core)
implementation(deps.androidx.room.runtime)
implementation(deps.androidx.room.ktx)
implementation(deps.kaidl.runtime)
implementation(deps.rikkax.multiprocess)
ksp(libs.kaidl.compiler)
kapt(libs.androidx.room.compiler)
implementation(libs.kotlin.coroutine)
implementation(libs.kotlin.serialization.json)
implementation(libs.androidx.core)
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.ktx)
implementation(libs.kaidl.runtime)
implementation(libs.rikkax.multiprocess)
}
afterEvaluate {

View File

@@ -1,12 +1,10 @@
package com.github.kr328.clash.service
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.os.Binder
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationChannelCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.github.kr328.clash.common.compat.getColorCompat
@@ -95,26 +93,20 @@ class ProfileWorker : BaseService() {
}
private fun createChannels() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
return
NotificationManagerCompat.from(this).createNotificationChannels(
NotificationManagerCompat.from(this).createNotificationChannelsCompat(
listOf(
NotificationChannel(
NotificationChannelCompat.Builder(
SERVICE_CHANNEL,
getString(R.string.profile_service_status),
NotificationManager.IMPORTANCE_LOW
),
NotificationChannel(
NotificationManagerCompat.IMPORTANCE_LOW
).setName(getString(R.string.profile_service_status)).build(),
NotificationChannelCompat.Builder(
STATUS_CHANNEL,
getString(R.string.profile_process_status),
NotificationManager.IMPORTANCE_LOW
),
NotificationChannel(
NotificationManagerCompat.IMPORTANCE_LOW
).setName(getString(R.string.profile_process_status)).build(),
NotificationChannelCompat.Builder(
RESULT_CHANNEL,
getString(R.string.profile_process_result),
NotificationManager.IMPORTANCE_DEFAULT
)
NotificationManagerCompat.IMPORTANCE_DEFAULT
).setName(getString(R.string.profile_process_result)).build()
)
)
}

View File

@@ -1,5 +1,6 @@
package com.github.kr328.clash.service
import android.annotation.TargetApi
import android.app.PendingIntent
import android.content.Intent
import android.net.ProxyInfo
@@ -61,9 +62,9 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
true
}
network.onEvent { e ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
setUnderlyingNetworks(e.network?.let { arrayOf(it) })
network.onEvent { n ->
if (Build.VERSION.SDK_INT in 22..28) @TargetApi(22) {
setUnderlyingNetworks(n?.let { arrayOf(it) })
}
false
@@ -182,12 +183,12 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
)
// Metered
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (Build.VERSION.SDK_INT >= 29) {
setMetered(false)
}
// System Proxy
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && store.systemProxy) {
if (Build.VERSION.SDK_INT >= 29 && store.systemProxy) {
listenHttp()?.let {
setHttpProxy(
ProxyInfo.buildDirectProxy(
@@ -199,16 +200,15 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
}
}
val blocking = mutableListOf("$TUN_GATEWAY/$TUN_SUBNET_PREFIX")
if (store.blockLoopback) {
blocking.add(NET_SUBNET_LOOPBACK)
if (store.allowBypass) {
allowBypass()
}
TunModule.TunDevice(
fd = establish()?.detachFd()
?: throw NullPointerException("Establish VPN rejected by system"),
mtu = TUN_MTU,
blocking = blocking.joinToString(";"),
gateway = "$TUN_GATEWAY/$TUN_SUBNET_PREFIX",
portal = TUN_PORTAL,
dns = if (store.dnsHijacking) NET_ANY else TUN_DNS,
)
}
@@ -220,9 +220,9 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
private const val TUN_MTU = 9000
private const val TUN_SUBNET_PREFIX = 30
private const val TUN_GATEWAY = "172.19.0.1"
private const val TUN_DNS = "172.19.0.2"
private const val TUN_PORTAL = "172.19.0.2"
private const val TUN_DNS = TUN_PORTAL
private const val NET_ANY = "0.0.0.0"
private const val NET_SUBNET_LOOPBACK = "127.0.0.0/8"
private val HTTP_PROXY_LOCAL_LIST: List<String> = listOf(
"localhost",
@@ -238,6 +238,6 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
"172.31.*",
"192.168.*"
)
private val HTTP_PROXY_BLACK_LIST: List<String> = listOf("*zhihu.com", "*zhimg.com")
private val HTTP_PROXY_BLACK_LIST: List<String> = listOf("*zhihu.com", "*zhimg.com", "*jd.com")
}
}

View File

@@ -29,6 +29,7 @@ class DynamicNotificationModule(service: Service) : Module<Unit>(service) {
.setOnlyAlertOnce(true)
.setShowWhen(false)
.setContentTitle("Not Selected")
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
.setContentIntent(
PendingIntent.getActivity(
service,

View File

@@ -1,102 +1,128 @@
package com.github.kr328.clash.service.clash.module
import android.annotation.TargetApi
import android.app.Service
import android.net.*
import android.os.Build
import androidx.core.content.getSystemService
import com.github.kr328.clash.common.log.Log
import com.github.kr328.clash.core.Clash
import com.github.kr328.clash.service.util.resolveDns
import com.github.kr328.clash.service.util.resolvePrimaryDns
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.withContext
import java.util.concurrent.TimeUnit
class NetworkObserveModule(service: Service) :
Module<NetworkObserveModule.NetworkChanged>(service) {
data class NetworkChanged(val network: Network?)
class NetworkObserveModule(service: Service) : Module<Network?>(service) {
private data class Action(val type: Type, val network: Network) {
enum class Type { Available, Lost, Changed }
}
private val connectivity = service.getSystemService<ConnectivityManager>()!!
private val networks: Channel<Network?> = Channel(Channel.CONFLATED)
private val actions = Channel<Action>(Channel.UNLIMITED)
private val request = NetworkRequest.Builder().apply {
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
if (Build.VERSION.SDK_INT == 23) { // workarounds for OEM bugs
removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
removeCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL)
}
}.build()
private val callback = object : ConnectivityManager.NetworkCallback() {
private var internet: Boolean = false
private var network: Network? = null
override fun onAvailable(network: Network) {
this.network = network
networks.trySend(network)
}
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
val internet = networkCapabilities
.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
if (this.network == network && this.internet != internet) {
this.internet = internet
networks.trySend(network)
}
actions.trySendBlocking(Action(Action.Type.Available, network))
}
override fun onLost(network: Network) {
if (this.network == network) {
networks.trySend(null)
}
actions.trySendBlocking(Action(Action.Type.Lost, network))
}
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
if (this.network == network) {
networks.trySend(network)
}
actions.trySendBlocking(Action(Action.Type.Changed, network))
}
}
override suspend fun run() {
try {
if (Build.VERSION.SDK_INT in 24..27) @TargetApi(24) {
connectivity.registerDefaultNetworkCallback(callback)
} else {
connectivity.requestNetwork(request, callback)
}
connectivity.registerNetworkCallback(request, callback)
} catch (e: Exception) {
Log.w("Observe network changed: $e", e)
Log.w("Observe network failed: $e", e)
return
}
try {
while (true) {
val network = networks.receive()
val networks = mutableSetOf<Network>()
val dns = connectivity.resolveDns(network)
while (true) {
val action = actions.receive()
val resolveDefault = when (action.type) {
Action.Type.Available -> {
networks.add(action.network)
true
}
Action.Type.Lost -> {
networks.remove(action.network)
true
}
Action.Type.Changed -> {
false
}
}
val dns = networks.mapNotNull {
connectivity.resolvePrimaryDns(it)
}
Clash.notifyDnsChanged(dns)
Log.d("Network changed, system dns = $dns")
Log.d("DNS: $dns")
enqueueEvent(NetworkChanged(network))
if (resolveDefault) {
val network = networks.maxByOrNull { net ->
connectivity.getNetworkCapabilities(net)?.let { cap ->
TRANSPORT_PRIORITY.indexOfFirst { cap.hasTransport(it) }
} ?: -1
}
enqueueEvent(network)
Log.d("Network: $network of $networks")
}
}
} finally {
withContext(NonCancellable) {
connectivity.unregisterNetworkCallback(callback)
enqueueEvent(null)
Clash.notifyDnsChanged(emptyList())
runCatching {
connectivity.unregisterNetworkCallback(callback)
}
}
}
}
companion object {
private val TRANSPORT_PRIORITY = sequence {
yield(NetworkCapabilities.TRANSPORT_CELLULAR)
if (Build.VERSION.SDK_INT >= 27) {
yield(NetworkCapabilities.TRANSPORT_LOWPAN)
}
yield(NetworkCapabilities.TRANSPORT_BLUETOOTH)
if (Build.VERSION.SDK_INT >= 26) {
yield(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
}
yield(NetworkCapabilities.TRANSPORT_WIFI)
if (Build.VERSION.SDK_INT >= 31) {
yield(NetworkCapabilities.TRANSPORT_USB)
}
yield(NetworkCapabilities.TRANSPORT_ETHERNET)
}.toList()
}
}

View File

@@ -1,11 +1,9 @@
package com.github.kr328.clash.service.clash.module
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationChannelCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.github.kr328.clash.common.compat.getColorCompat
@@ -23,6 +21,7 @@ class StaticNotificationModule(service: Service) : Module<Unit>(service) {
.setColor(service.getColorCompat(R.color.color_clash))
.setOnlyAlertOnce(true)
.setShowWhen(false)
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
.setContentIntent(
PendingIntent.getActivity(
service,
@@ -56,14 +55,11 @@ class StaticNotificationModule(service: Service) : Module<Unit>(service) {
const val CHANNEL_ID = "clash_status_channel"
fun createNotificationChannel(service: Service) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
return
NotificationManagerCompat.from(service).createNotificationChannel(
NotificationChannel(
NotificationChannelCompat.Builder(
CHANNEL_ID,
service.getText(R.string.clash_service_status_channel),
NotificationManager.IMPORTANCE_LOW
)
NotificationManagerCompat.IMPORTANCE_LOW
).setName(service.getText(R.string.clash_service_status_channel)).build()
)
}

View File

@@ -15,8 +15,8 @@ import java.security.SecureRandom
class TunModule(private val vpn: VpnService) : Module<Unit>(vpn) {
data class TunDevice(
val fd: Int,
val mtu: Int,
val blocking: String,
val gateway: String,
val portal: String,
val dns: String,
)
@@ -28,7 +28,7 @@ class TunModule(private val vpn: VpnService) : Module<Unit>(vpn) {
source: InetSocketAddress,
target: InetSocketAddress,
): Int {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
if (Build.VERSION.SDK_INT < 29)
return -1
return runCatching { connectivity.getConnectionOwnerUid(protocol, source, target) }
@@ -56,9 +56,9 @@ class TunModule(private val vpn: VpnService) : Module<Unit>(vpn) {
fun attach(device: TunDevice) {
Clash.startTun(
fd = device.fd,
mtu = device.mtu,
gateway = device.gateway,
portal = device.portal,
dns = device.dns,
blocking = device.blocking,
markSocket = vpn::protect,
querySocketUid = this::queryUid
)

View File

@@ -46,8 +46,8 @@ class ServiceStore(context: Context) {
defaultValue = true
)
var blockLoopback by store.boolean(
key = "block_loopback",
var allowBypass by store.boolean(
key = "allow_bypass",
defaultValue = true
)

View File

@@ -3,9 +3,8 @@ package com.github.kr328.clash.service.util
import android.net.ConnectivityManager
import android.net.Network
fun ConnectivityManager.resolveDns(network: Network?): List<String> {
return network?.run(this::getLinkProperties)
?.dnsServers
?.map { it.asSocketAddressText(53) }
?: emptyList()
}
fun ConnectivityManager.resolvePrimaryDns(network: Network?): String? {
val properties = getLinkProperties(network) ?: return null
return properties.dnsServers.firstOrNull()?.asSocketAddressText(53)
}

View File

@@ -7,6 +7,11 @@
android:tint="@color/color_clash">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M47.211,168.128C70.531,-34.962 67.471,13.788 94.071,43.818c13.45,-1.52 27.24,-3.47 40.82,-0.67c2.64,0.13 5.42,1.86 7.71,0.18c4.12,-6.27 7.35,-13.54 11.35,-20c12.19,-24.44 12.85,19.54 15.48,26.52c5.23,32.99 10.89,64.46 14.67,97.59c0.31,10.72 5.74,32.92 1.08,33.56c-49.36,5.23 -147.71,3.91 -160.84,-6.3c-15.85,-10.5 -15.18,-35.33 2.03,-43.72c3.63,-2.03 10.68,-3.72 11.94,0.7c-2.41,4.99 -8.79,5.77 -12.12,11.17C16.621,158.948 33.111,168.888 47.211,168.128zM87.841,74.008c-10.42,0.52 -9.59,14.89 -0.07,15.18C98.191,88.668 97.361,74.298 87.841,74.008zM149.121,89.188c10.46,-0.34 9.85,-14.71 0.38,-15.18C139.031,74.348 139.651,88.718 149.121,89.188zM107.871,99.228c2.16,3.48 5.28,3.29 9.79,0.16c3.81,3.17 8.06,3.28 9.18,-0.19c-3.78,1.17 -7.04,0.79 -9.4,-3.49C115.371,100.108 112.071,100.428 107.871,99.228z"
android:pathData="M40,163.1C62.1-28,59.3,17.9,84.3,46.2c12.7-1.4,25.6-3.3,38.4-0.7c2.4,0.1,5.1,1.8,7.2,0.2
c3.9-5.9,7-12.7,10.7-18.8c11.5-22.9,12,18.3,14.6,24.9c4.9,31,10.3,60.7,13.8,91.8c0.3,10.1,5.4,30.9,1,31.6
c-46.5,4.9-138.9,3.7-151.2-5.9c-14.9-9.9-14.3-33.2,1.9-41.1c3.4-1.9,10.1-3.5,11.2,0.7c-2.3,4.7-8.3,5.5-11.4,10.5
C11.4,154.4,27,163.8,40.2,163.1z M78.4,74.6c-9.8,0.5-9,14-0.1,14.3C88.2,88.4,87.4,74.8,78.4,74.6z M136.1,88.9
c9.9-0.3,9.2-13.8,0.4-14.3C126.6,74.8,127.2,88.4,136.1,88.9z M97.3,98.3c2.1,3.3,5,3.1,9.2,0.2c3.6,3,7.6,3.1,8.7-0.2
c-3.6,1.1-6.6,0.8-8.8-3.3C104.4,99.1,101.3,99.4,97.3,98.3z"
tools:ignore="VectorPath" />
</vector>

View File

@@ -1,7 +1,3 @@
@file:Suppress("UnstableApiUsage")
enableFeaturePreview("VERSION_CATALOGS")
rootProject.name = "ClashForAndroid"
include(":app")
@@ -11,51 +7,59 @@ include(":design")
include(":common")
include(":hideapi")
pluginManagement {
repositories {
mavenLocal()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
versionCatalogs {
create("deps") {
val agp = "7.0.2"
val ksp = "1.5.30-1.0.0"
val kotlin = "1.5.30"
create("libs") {
val agp = "7.1.3"
val kotlin = "1.6.21"
val ksp = "$kotlin-1.0.5"
val golang = "1.0.4"
val coroutine = "1.5.2"
val coreKtx = "1.6.0"
val activity = "1.3.1"
val fragment = "1.3.6"
val appcompat = "1.3.1"
val coordinator = "1.1.0"
val coroutine = "1.6.1"
val coreKtx = "1.7.0"
val activity = "1.4.0"
val fragment = "1.4.1"
val appcompat = "1.4.1"
val coordinator = "1.2.0"
val recyclerview = "1.2.1"
val viewpager = "1.0.0"
val material = "1.4.0"
val appcenter = "4.3.1"
val serialization = "1.2.2"
val material = "1.5.0"
val appcenter = "4.4.3"
val serialization = "1.3.2"
val kaidl = "1.15"
val room = "2.3.0"
val room = "2.4.2"
val multiprocess = "1.0.0"
alias("build-android").to("com.android.tools.build:gradle:$agp")
alias("build-kotlin-common").to("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin")
alias("build-kotlin-serialization").to("org.jetbrains.kotlin:kotlin-serialization:$kotlin")
alias("build-ksp").to("com.google.devtools.ksp:symbol-processing-gradle-plugin:$ksp")
alias("build-golang").to("com.github.kr328.golang:gradle-plugin:$golang")
alias("kotlin-coroutine").to("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine")
alias("kotlin-serialization-json").to("org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization")
alias("androidx-core").to("androidx.core:core-ktx:$coreKtx")
alias("androidx-activity").to("androidx.activity:activity:$activity")
alias("androidx-fragment").to("androidx.fragment:fragment:$fragment")
alias("androidx-appcompat").to("androidx.appcompat:appcompat:$appcompat")
alias("androidx-coordinator").to("androidx.coordinatorlayout:coordinatorlayout:$coordinator")
alias("androidx-recyclerview").to("androidx.recyclerview:recyclerview:$recyclerview")
alias("androidx-viewpager").to("androidx.viewpager2:viewpager2:$viewpager")
alias("androidx-room-compiler").to("androidx.room:room-compiler:$room")
alias("androidx-room-runtime").to("androidx.room:room-runtime:$room")
alias("androidx-room-ktx").to("androidx.room:room-ktx:$room")
alias("google-material").to("com.google.android.material:material:$material")
alias("appcenter-analytics").to("com.microsoft.appcenter:appcenter-analytics:$appcenter")
alias("appcenter-crashes").to("com.microsoft.appcenter:appcenter-crashes:$appcenter")
alias("kaidl-compiler").to("com.github.kr328.kaidl:kaidl:$kaidl")
alias("kaidl-runtime").to("com.github.kr328.kaidl:kaidl-runtime:$kaidl")
alias("rikkax-multiprocess").to("dev.rikka.rikkax.preference:multiprocess:$multiprocess")
library("build-android", "com.android.tools.build:gradle:$agp")
library("build-kotlin-common", "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin")
library("build-kotlin-serialization", "org.jetbrains.kotlin:kotlin-serialization:$kotlin")
library("build-ksp", "com.google.devtools.ksp:symbol-processing-gradle-plugin:$ksp")
library("build-golang", "com.github.kr328.golang:gradle-plugin:$golang")
library("kotlin-coroutine", "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine")
library("kotlin-serialization-json", "org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization")
library("androidx-core", "androidx.core:core-ktx:$coreKtx")
library("androidx-activity", "androidx.activity:activity:$activity")
library("androidx-fragment", "androidx.fragment:fragment:$fragment")
library("androidx-appcompat", "androidx.appcompat:appcompat:$appcompat")
library("androidx-coordinator", "androidx.coordinatorlayout:coordinatorlayout:$coordinator")
library("androidx-recyclerview", "androidx.recyclerview:recyclerview:$recyclerview")
library("androidx-viewpager", "androidx.viewpager2:viewpager2:$viewpager")
library("androidx-room-compiler", "androidx.room:room-compiler:$room")
library("androidx-room-runtime", "androidx.room:room-runtime:$room")
library("androidx-room-ktx", "androidx.room:room-ktx:$room")
library("google-material", "com.google.android.material:material:$material")
library("appcenter-analytics", "com.microsoft.appcenter:appcenter-analytics:$appcenter")
library("appcenter-crashes", "com.microsoft.appcenter:appcenter-crashes:$appcenter")
library("kaidl-compiler", "com.github.kr328.kaidl:kaidl:$kaidl")
library("kaidl-runtime", "com.github.kr328.kaidl:kaidl-runtime:$kaidl")
library("rikkax-multiprocess", "dev.rikka.rikkax.preference:multiprocess:$multiprocess")
}
}
}