mirror of
https://github.com/MetaCubeX/ClashMetaForAndroid.git
synced 2026-05-09 18:11:26 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4c070cb97 |
57
.github/ISSUE_TEMPLATE/01-bug-report-en.md
vendored
Normal file
57
.github/ISSUE_TEMPLATE/01-bug-report-en.md
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
name: "[English] Bug report"
|
||||
about: Create a report to help us improve
|
||||
title: "[BUG] "
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Be sure to put a clear title after [BUG] in the text box above -->
|
||||
<!-- Be sure to put a clear title after [BUG] in the text box above -->
|
||||
<!-- Be sure to put a clear title after [BUG] in the text box above -->
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Device Info (please complete the following information):**
|
||||
|
||||
- Device: [e.g. Pixel 4]
|
||||
- ROM: [e.g: AOSP]
|
||||
- ROM Version:
|
||||
- Android Version [e.g. 10]
|
||||
|
||||
**Application Info (please complete the following information):**
|
||||
|
||||
- Version: [e.g. 1.1.10]
|
||||
- Apk File Name: [e.g. app-release-arm64-v8a.apk]
|
||||
- Distribution Channel: [e.g. Google Play]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
**Configure**
|
||||
Paste configure file which **removed server info**
|
||||
```yaml
|
||||
# paste here
|
||||
```
|
||||
|
||||
**Logs**
|
||||
Paste logs to help detect problem
|
||||
|
||||
```
|
||||
<paste here>
|
||||
```
|
||||
106
.github/ISSUE_TEMPLATE/01-bug-report-en.yml
vendored
106
.github/ISSUE_TEMPLATE/01-bug-report-en.yml
vendored
@@ -1,106 +0,0 @@
|
||||
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."
|
||||
24
.github/ISSUE_TEMPLATE/02-feature-request-en.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/02-feature-request-en.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
name: "[English] Feature request"
|
||||
about: Suggest an idea for this app
|
||||
title: "[Feature Request] "
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Be sure to put a clear title after [Feature Request] in the text box above -->
|
||||
<!-- Be sure to put a clear title after [Feature Request] in the text box above -->
|
||||
<!-- Be sure to put a clear title after [Feature Request] in the text box above -->
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
26
.github/ISSUE_TEMPLATE/02-feature-request-en.yml
vendored
26
.github/ISSUE_TEMPLATE/02-feature-request-en.yml
vendored
@@ -1,26 +0,0 @@
|
||||
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.
|
||||
55
.github/ISSUE_TEMPLATE/03-bug-report-zh-cn.md
vendored
Normal file
55
.github/ISSUE_TEMPLATE/03-bug-report-zh-cn.md
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
name: "[简体中文] 创建错误报告"
|
||||
about: 创建错误报告以帮助我们改进应用
|
||||
title: "[BUG] "
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- 请务必在上方文本框处 [BUG] 后填入清晰明了的标题 -->
|
||||
<!-- 请务必在上方文本框处 [BUG] 后填入清晰明了的标题 -->
|
||||
<!-- 请务必在上方文本框处 [BUG] 后填入清晰明了的标题 -->
|
||||
|
||||
**描述出现的错误**
|
||||
请简洁的描述你遇到的错误
|
||||
|
||||
**如何复现该错误**
|
||||
复现步骤:
|
||||
1. ...
|
||||
2. ...
|
||||
3. ...
|
||||
4. ...
|
||||
|
||||
**预期行为**
|
||||
清晰简单的描述你预期的应用应该表现的行为
|
||||
|
||||
**屏幕截图**
|
||||
如果适用, 上传屏幕截图以帮助描述错误
|
||||
|
||||
**设备信息 (请完成以下信息):**
|
||||
- 机型: [例如: Pixel 4]
|
||||
- 系统/ROM: [例如: MIUI 11]
|
||||
- Android 版本 [例如: 10]
|
||||
- ROM版本 [例如: 20.3.19]
|
||||
|
||||
**应用信息**
|
||||
- 版本: [例如: 1.1.10]
|
||||
- 安装包文件名: [例如: app-release-arm64-v8a.apk]
|
||||
- 应用来源: [例如: Google Play]
|
||||
|
||||
**附加信息**
|
||||
其他的可能与改错误相关的信息
|
||||
|
||||
**配置文件**
|
||||
在此粘贴 **去除服务器信息的** 的 **配置文件**
|
||||
```yaml
|
||||
# 在此粘贴
|
||||
```
|
||||
|
||||
**日志**
|
||||
粘贴日志以帮助侦测错误
|
||||
```
|
||||
<在此粘贴>
|
||||
```
|
||||
|
||||
107
.github/ISSUE_TEMPLATE/03-bug-report-zh-cn.yml
vendored
107
.github/ISSUE_TEMPLATE/03-bug-report-zh-cn.yml
vendored
@@ -1,107 +0,0 @@
|
||||
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: "可选"
|
||||
21
.github/ISSUE_TEMPLATE/04-feature-request-zh-cn.md
vendored
Normal file
21
.github/ISSUE_TEMPLATE/04-feature-request-zh-cn.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: "[简体中文] 功能请求"
|
||||
about: 你希望的能够在应用中增加的功能
|
||||
title: "[Feature Request] "
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- 请务必在上方文本框处 [Feature Request] 后填入清晰明了的标题 -->
|
||||
<!-- 请务必在上方文本框处 [Feature Request] 后填入清晰明了的标题 -->
|
||||
<!-- 请务必在上方文本框处 [Feature Request] 后填入清晰明了的标题 -->
|
||||
|
||||
**功能描述**
|
||||
请清晰的描述你想要的功能
|
||||
|
||||
**描述你希望的实现方式**
|
||||
清晰的描述应用应该如何实现该功能
|
||||
|
||||
**附加信息**
|
||||
其他的与改功能相关的附加信息
|
||||
@@ -1,26 +0,0 @@
|
||||
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: |
|
||||
与此功能相关的其他附加信息。
|
||||
27
.github/workflows/build-unsigned.yaml
vendored
27
.github/workflows/build-unsigned.yaml
vendored
@@ -4,7 +4,6 @@ on:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
- '.idea/**'
|
||||
- '.gitattributes'
|
||||
- '.gitignore'
|
||||
@@ -14,7 +13,6 @@ on:
|
||||
- 'NOTICE'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
- '.idea/**'
|
||||
- '.gitattributes'
|
||||
- '.gitignore'
|
||||
@@ -22,33 +20,22 @@ on:
|
||||
- '**.md'
|
||||
- 'LICENSE'
|
||||
- 'NOTICE'
|
||||
|
||||
jobs:
|
||||
BuildUnsigned:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
distribution: 'adopt'
|
||||
java-version: 11
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
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-
|
||||
go-version: 1.17
|
||||
- name: Build
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: --no-daemon app:assembleFossRelease
|
||||
run: ./gradlew --no-daemon app:assembleFossRelease
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -59,5 +59,5 @@ google-services.json
|
||||
# logs
|
||||
*.log
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
# Ignore sum
|
||||
/core/src/main/golang/go.sum
|
||||
|
||||
@@ -4,19 +4,24 @@ The Clash for Android is built as an Open Source software. This app is provided
|
||||
|
||||
This page is used to inform visitors regarding our policies with the collection, use, and disclosure of Personal Information if anyone decided to use our app.
|
||||
|
||||
If you choose to use our app, then you agree to the collection and use of information in relation to this policy. The Personal Information that we collect is used for providing and improving the app. We will not use or share your information with anyone except as described in this Privacy Policy.
|
||||
|
||||
The terms used in this Privacy Policy have the same meanings as in our Terms and Conditions, which is accessible at Clash for Android unless otherwise defined in this Privacy Policy.
|
||||
|
||||
**Information Collection and Use**
|
||||
|
||||
We will not upload any of your personally information and that will be stored in the internal storage or memory.
|
||||
For a better experience, while using our app, we may require you to provide us with certain personally identifiable information. The information that we request will be retained by us and used as described in this privacy policy.
|
||||
|
||||
We collect the following information and store it in memory, and such information will be destroyed when the application is fully exited.
|
||||
The app does use third party services that may collect information used to identify you.
|
||||
|
||||
- Installed Applications
|
||||
Link to privacy policy of third party service providers used by the app
|
||||
|
||||
This data is used for the PROCESS-NAME rule.
|
||||
* [Google Play Services](https://www.google.com/policies/privacy/)
|
||||
* [AppCenter](https://docs.microsoft.com/en-us/appcenter/gdpr/)
|
||||
|
||||
**Log Data**
|
||||
|
||||
We do not collect log data unless you use log collector.
|
||||
We want to inform you that whenever you use our app, in a case of an error in the app we collect data and information (through third party products) on your phone called Log Data. This Log Data may include information such as your device Internet Protocol (“IP”) address, device name, operating system version, the configuration of the app when utilizing our App, the time and date of your use of the app, and other statistics.
|
||||
|
||||
**Cookies**
|
||||
|
||||
@@ -32,6 +37,10 @@ We value your trust in providing us your Personal Information, thus we are striv
|
||||
|
||||
This app may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by us. Therefore, we strongly advise you to review the Privacy Policy of these websites. We have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services.
|
||||
|
||||
**Children’s Privacy**
|
||||
|
||||
These Services do not address anyone under the age of 13\. We do not knowingly collect personally identifiable information from children under 13\. In the case we discover that a child under 13 has provided us with personal information, we immediately delete this from our servers. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact us so that we will be able to do necessary actions.
|
||||
|
||||
**Changes to This Privacy Policy**
|
||||
|
||||
We may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. We will notify you of any changes by posting the new Privacy Policy on this page. These changes are effective immediately after they are posted on this page.
|
||||
|
||||
@@ -53,4 +53,4 @@ See also [PRIVACY_POLICY.md](./PRIVACY_POLICY.md)
|
||||
./gradlew app:assembleFossRelease
|
||||
```
|
||||
|
||||
6. Pick `app-<version>-foss-<arch>-release.apk` in `app/build/outputs/apk/foss/release/`
|
||||
6. Pick `app-foss-<arch>-release.apk` in `app/build/outputs/apk/foss/release/`
|
||||
|
||||
@@ -12,14 +12,19 @@ dependencies {
|
||||
implementation(project(":design"))
|
||||
implementation(project(":common"))
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
val premiumImplementation by configurations
|
||||
|
||||
premiumImplementation(deps.appcenter.analytics)
|
||||
premiumImplementation(deps.appcenter.crashes)
|
||||
}
|
||||
|
||||
tasks.getByName("clean", type = Delete::class) {
|
||||
|
||||
14
app/src/foss/java/com/github/kr328/clash/Tracker.kt
Normal file
14
app/src/foss/java/com/github/kr328/clash/Tracker.kt
Normal file
@@ -0,0 +1,14 @@
|
||||
package com.github.kr328.clash
|
||||
|
||||
import android.app.Application
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
object Tracker {
|
||||
fun initialize(application: Application) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
fun uploadLogcat(logcat: String) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -76,8 +76,11 @@ class AccessControlActivity : BaseActivity<AccessControlDesign>() {
|
||||
val data = clipboard?.primaryClip
|
||||
|
||||
if (data != null && data.itemCount > 0) {
|
||||
val packages = data.getItemAt(0).text.split("\n").toSet()
|
||||
val all = design.apps.map(AppInfo::packageName).intersect(packages)
|
||||
val all = withContext(Dispatchers.IO) {
|
||||
val packages = data.getItemAt(0).text.split("\n").toSet()
|
||||
|
||||
design.apps.map(AppInfo::packageName).intersect(packages)
|
||||
}
|
||||
|
||||
selected.clear()
|
||||
selected.addAll(all)
|
||||
@@ -88,12 +91,14 @@ class AccessControlActivity : BaseActivity<AccessControlDesign>() {
|
||||
AccessControlDesign.Request.Export -> {
|
||||
val clipboard = getSystemService<ClipboardManager>()
|
||||
|
||||
val data = ClipData.newPlainText(
|
||||
"packages",
|
||||
selected.joinToString("\n")
|
||||
)
|
||||
withContext(Dispatchers.IO) {
|
||||
val data = ClipData.newPlainText(
|
||||
"packages",
|
||||
selected.joinToString("\n")
|
||||
)
|
||||
|
||||
clipboard?.setPrimaryClip(data)
|
||||
clipboard?.setPrimaryClip(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 >= 23) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
window.isLightStatusBarsCompat =
|
||||
resolveThemedBoolean(android.R.attr.windowLightStatusBar)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 27) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||
window.isLightNavigationBarCompat =
|
||||
resolveThemedBoolean(android.R.attr.windowLightNavigationBar)
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ class FilesActivity : BaseActivity<FilesDesign>() {
|
||||
}
|
||||
is FilesDesign.Request.ExportFile -> {
|
||||
val uri: Uri? = startActivityForResult(
|
||||
ActivityResultContracts.CreateDocument("text/plain"),
|
||||
ActivityResultContracts.CreateDocument(),
|
||||
it.file.name
|
||||
)
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class LogcatActivity : BaseActivity<LogcatDesign>() {
|
||||
}
|
||||
LogcatDesign.Request.Export -> {
|
||||
val output = startActivityForResult(
|
||||
ActivityResultContracts.CreateDocument("text/plain"),
|
||||
ActivityResultContracts.CreateDocument(),
|
||||
file.fileName
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
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
|
||||
@@ -7,13 +9,12 @@ 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
|
||||
@@ -125,12 +126,16 @@ 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(
|
||||
NotificationChannelCompat.Builder(
|
||||
NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
NotificationManagerCompat.IMPORTANCE_DEFAULT
|
||||
).setName(getString(R.string.clash_logcat)).build()
|
||||
getString(R.string.clash_logcat),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -147,7 +152,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),
|
||||
pendingIntentFlags(PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
)
|
||||
.build()
|
||||
|
||||
@@ -19,6 +19,9 @@ class MainApplication : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
// Initialize AppCenter
|
||||
Tracker.initialize(this)
|
||||
|
||||
val processName = currentProcessName
|
||||
|
||||
Log.d("Process $processName started")
|
||||
|
||||
@@ -5,8 +5,10 @@ import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.ServiceConnection
|
||||
import android.os.IBinder
|
||||
import com.github.kr328.clash.Tracker
|
||||
import com.github.kr328.clash.common.log.Log
|
||||
import com.github.kr328.clash.common.util.intent
|
||||
import com.github.kr328.clash.log.SystemLogcat
|
||||
import com.github.kr328.clash.service.RemoteService
|
||||
import com.github.kr328.clash.service.remote.IRemoteService
|
||||
import com.github.kr328.clash.service.remote.unwrap
|
||||
@@ -26,6 +28,8 @@ class Service(private val context: Application, val crashed: () -> Unit) {
|
||||
override fun onServiceDisconnected(name: ComponentName?) {
|
||||
remote.set(null)
|
||||
|
||||
Tracker.uploadLogcat(SystemLogcat.dumpCrash())
|
||||
|
||||
if (System.currentTimeMillis() - lastCrashed < TOGGLE_CRASHED_INTERVAL) {
|
||||
unbind()
|
||||
|
||||
|
||||
@@ -9,12 +9,7 @@
|
||||
android:translateY="103.4632">
|
||||
<path
|
||||
android:fillColor="#1E4376"
|
||||
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"
|
||||
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"
|
||||
tools:ignore="VectorPath" />
|
||||
</group>
|
||||
</vector>
|
||||
|
||||
31
app/src/premium/java/com/github/kr328/clash/Tracker.kt
Normal file
31
app/src/premium/java/com/github/kr328/clash/Tracker.kt
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.github.kr328.clash
|
||||
|
||||
import android.app.Application
|
||||
import com.microsoft.appcenter.AppCenter
|
||||
import com.microsoft.appcenter.analytics.Analytics
|
||||
import com.microsoft.appcenter.crashes.Crashes
|
||||
import com.microsoft.appcenter.crashes.ingestion.models.ErrorAttachmentLog
|
||||
|
||||
object Tracker {
|
||||
fun initialize(application: Application) {
|
||||
if (!BuildConfig.DEBUG) {
|
||||
AppCenter.start(
|
||||
application,
|
||||
BuildConfig.APP_CENTER_KEY,
|
||||
Analytics::class.java, Crashes::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun uploadLogcat(logcat: String) {
|
||||
if (!BuildConfig.DEBUG) {
|
||||
if (logcat.isNotBlank()) {
|
||||
Crashes.trackError(
|
||||
RuntimeException(),
|
||||
mapOf("type" to "app_crashed"),
|
||||
listOf(ErrorAttachmentLog.attachmentWithText(logcat, "logcat.txt"))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,39 +12,51 @@ buildscript {
|
||||
maven("https://maven.kr328.app/releases")
|
||||
}
|
||||
dependencies {
|
||||
classpath(libs.build.android)
|
||||
classpath(libs.build.kotlin.common)
|
||||
classpath(libs.build.kotlin.serialization)
|
||||
classpath(libs.build.ksp)
|
||||
classpath(libs.build.golang)
|
||||
classpath(deps.build.android)
|
||||
classpath(deps.build.kotlin.common)
|
||||
classpath(deps.build.kotlin.serialization)
|
||||
classpath(deps.build.ksp)
|
||||
classpath(deps.build.golang)
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
allprojects {
|
||||
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 = 204013
|
||||
val buildVersionName = "2.4.13"
|
||||
val defaultDimension = "feature"
|
||||
|
||||
ndkVersion = "23.0.7599858"
|
||||
|
||||
compileSdkVersion(targetSdkVersion)
|
||||
|
||||
defaultConfig {
|
||||
if (isApp) {
|
||||
applicationId = "com.github.kr328.clash"
|
||||
}
|
||||
|
||||
minSdk = 21
|
||||
targetSdk = 31
|
||||
minSdk = minSdkVersion
|
||||
targetSdk = targetSdkVersion
|
||||
|
||||
versionName = "2.5.12"
|
||||
versionCode = 205012
|
||||
versionName = buildVersionName
|
||||
versionCode = buildVersionCode
|
||||
|
||||
resValue("string", "release_name", "v$versionName")
|
||||
resValue("integer", "release_code", "$versionCode")
|
||||
resValue("string", "release_name", "v$buildVersionName")
|
||||
resValue("integer", "release_code", "$buildVersionCode")
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
@@ -59,24 +71,17 @@ subprojects {
|
||||
}
|
||||
}
|
||||
|
||||
ndkVersion = "23.0.7599858"
|
||||
|
||||
compileSdkVersion(defaultConfig.targetSdk!!)
|
||||
|
||||
if (isApp) {
|
||||
packagingOptions {
|
||||
resources {
|
||||
excludes.add("DebugProbesKt.bin")
|
||||
}
|
||||
excludes.add("DebugProbesKt.bin")
|
||||
}
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
flavorDimensions("feature")
|
||||
flavorDimensions(defaultDimension)
|
||||
|
||||
create("foss") {
|
||||
isDefault = true
|
||||
dimension = flavorDimensionList[0]
|
||||
dimension = defaultDimension
|
||||
versionNameSuffix = ".foss"
|
||||
|
||||
buildConfigField("boolean", "PREMIUM", "Boolean.parseBoolean(\"false\")")
|
||||
@@ -86,10 +91,23 @@ subprojects {
|
||||
}
|
||||
}
|
||||
create("premium") {
|
||||
dimension = flavorDimensionList[0]
|
||||
dimension = defaultDimension
|
||||
versionNameSuffix = ".premium"
|
||||
|
||||
buildConfigField("boolean", "PREMIUM", "Boolean.parseBoolean(\"true\")")
|
||||
|
||||
val tracker = rootProject.file("tracker.properties")
|
||||
if (tracker.exists()) {
|
||||
val prop = Properties().apply {
|
||||
tracker.inputStream().use(this::load)
|
||||
}
|
||||
|
||||
buildConfigField(
|
||||
"String",
|
||||
"APP_CENTER_KEY",
|
||||
"\"${prop.getProperty("appcenter.key")!!}\""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,11 +148,6 @@ subprojects {
|
||||
}
|
||||
}
|
||||
|
||||
variantFilter {
|
||||
ignore = name.startsWith("premium") && !project(":core")
|
||||
.file("src/premium/golang/clash/go.mod").exists()
|
||||
}
|
||||
|
||||
if (isApp) {
|
||||
this as AppExtension
|
||||
|
||||
|
||||
@@ -6,6 +6,6 @@ plugins {
|
||||
dependencies {
|
||||
compileOnly(project(":hideapi"))
|
||||
|
||||
implementation(libs.kotlin.coroutine)
|
||||
implementation(libs.androidx.core)
|
||||
implementation(deps.kotlin.coroutine)
|
||||
implementation(deps.androidx.core)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ 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
|
||||
|
||||
@@ -20,12 +18,3 @@ 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
|
||||
}
|
||||
|
||||
@@ -4,12 +4,17 @@ 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 ContextCompat.getColor(this, id)
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
this.getColor(id)
|
||||
} else {
|
||||
resources.getColor(id)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.getDrawableCompat(@DrawableRes id: Int): Drawable? {
|
||||
|
||||
@@ -7,7 +7,7 @@ import android.text.Html
|
||||
import android.text.Spanned
|
||||
|
||||
fun fromHtmlCompat(content: String): Spanned {
|
||||
return if (Build.VERSION.SDK_INT >= 24) {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Html.fromHtml(content, Html.FROM_HTML_MODE_COMPACT)
|
||||
} else {
|
||||
Html.fromHtml(content)
|
||||
|
||||
@@ -3,13 +3,9 @@ package com.github.kr328.clash.common.compat
|
||||
import android.app.PendingIntent
|
||||
import android.os.Build
|
||||
|
||||
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
|
||||
}
|
||||
fun pendingIntentFlags(flags: Int, immutable: Boolean = false): Int {
|
||||
return if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M && immutable) {
|
||||
flags or PendingIntent.FLAG_IMMUTABLE
|
||||
} else {
|
||||
flags
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import android.content.pm.PackageInfo
|
||||
|
||||
val PackageInfo.versionCodeCompat: Long
|
||||
get() {
|
||||
return if (android.os.Build.VERSION.SDK_INT >= 28) {
|
||||
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
|
||||
longVersionCode
|
||||
} else {
|
||||
versionCode.toLong()
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.*
|
||||
|
||||
val Configuration.preferredLocale: Locale
|
||||
get() {
|
||||
return if (Build.VERSION.SDK_INT >= 24) {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
locales[0]
|
||||
} else {
|
||||
locale
|
||||
|
||||
@@ -5,7 +5,7 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
|
||||
fun Context.startForegroundServiceCompat(intent: Intent) {
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(intent)
|
||||
} else {
|
||||
startService(intent)
|
||||
|
||||
@@ -57,9 +57,9 @@ android {
|
||||
dependencies {
|
||||
implementation(project(":common"))
|
||||
|
||||
implementation(libs.androidx.core)
|
||||
implementation(libs.kotlin.coroutine)
|
||||
implementation(libs.kotlin.serialization.json)
|
||||
implementation(deps.androidx.core)
|
||||
implementation(deps.kotlin.coroutine)
|
||||
implementation(deps.kotlin.serialization.json)
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
|
||||
Submodule core/src/foss/golang/clash updated: 68b653837d...ec373d289d
@@ -1,36 +1,30 @@
|
||||
module foss
|
||||
|
||||
go 1.18
|
||||
go 1.17
|
||||
|
||||
require cfa v0.0.0
|
||||
|
||||
require (
|
||||
cfa/blob v0.0.0 // indirect
|
||||
github.com/Dreamacro/clash v1.7.1 // indirect
|
||||
github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34 // indirect
|
||||
github.com/Dreamacro/clash v0.0.0 // indirect
|
||||
github.com/Dreamacro/go-shadowsocks2 v0.1.7 // indirect
|
||||
github.com/dlclark/regexp2 v1.4.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-20220504074936-1ca156eafb9f // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/miekg/dns v1.1.49 // indirect
|
||||
github.com/oschwald/geoip2-golang v1.7.0 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.9.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/oschwald/maxminddb-golang v1.8.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // 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-20220525230936-793ad666bf5e // indirect
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 // indirect
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // 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
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f // 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
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace cfa => ../../main/golang
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
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/Dreamacro/go-shadowsocks2 v0.1.7 h1:8CtbE1HoPPMfrQZGXmlluq6dO2lL31W6WRRE8fabc4Q=
|
||||
github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr8kvw8uw3TDwLAJpUc=
|
||||
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.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
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/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.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
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-20220504074936-1ca156eafb9f h1:l1QCwn715k8nYkj4Ql50rzEog3WnMdrd4YYMMwemxEo=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
|
||||
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/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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
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/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,12 +36,12 @@ 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.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8=
|
||||
github.com/miekg/dns v1.1.49/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/oschwald/geoip2-golang v1.7.0 h1:JW1r5AKi+vv2ujSxjKthySK3jo8w8oKWPyXsw+Qs/S8=
|
||||
github.com/oschwald/geoip2-golang v1.7.0/go.mod h1:mdI/C7iK7NVMcIDDtf4bCKMJ7r0o7UwGeCo9eiitCMQ=
|
||||
github.com/oschwald/maxminddb-golang v1.9.0 h1:tIk4nv6VT9OiPyrnDAfJS1s1xKDQMZOsGojab6EjC1Y=
|
||||
github.com/oschwald/maxminddb-golang v1.9.0/go.mod h1:TK+s/Z2oZq0rSl4PSeAEoP0bgm82Cp5HyvYbt8K3zLY=
|
||||
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=
|
||||
@@ -52,40 +52,31 @@ 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.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
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=
|
||||
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-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/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/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-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-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-20220617184016-355a448f1bc9 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc=
|
||||
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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=
|
||||
@@ -95,40 +86,29 @@ golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
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-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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU=
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/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/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=
|
||||
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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -54,27 +54,20 @@ int jni_catch_exception(JNIEnv *env) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void jni_attach_thread(struct _scoped_jni *jni) {
|
||||
void jni_attach_thread(JNIEnv **penv) {
|
||||
JavaVM *vm = global_java_vm();
|
||||
|
||||
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) {
|
||||
if ((*vm)->AttachCurrentThread(vm, penv, NULL) != JNI_OK) {
|
||||
abort();
|
||||
}
|
||||
|
||||
jni->require_release = 1;
|
||||
}
|
||||
|
||||
void jni_detach_thread(struct _scoped_jni *jni) {
|
||||
void jni_detach_thread(JNIEnv **env) {
|
||||
(void) env;
|
||||
|
||||
JavaVM *vm = global_java_vm();
|
||||
|
||||
if (jni->require_release) {
|
||||
(*vm)->DetachCurrentThread(vm);
|
||||
}
|
||||
(*vm)->DetachCurrentThread(vm);
|
||||
}
|
||||
|
||||
void release_string(char **str) {
|
||||
|
||||
@@ -6,23 +6,21 @@
|
||||
#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(struct _scoped_jni *jni);
|
||||
extern void jni_detach_thread(struct _scoped_jni *env);
|
||||
|
||||
extern void jni_attach_thread(JNIEnv **penv);
|
||||
|
||||
extern void jni_detach_thread(JNIEnv **env);
|
||||
|
||||
extern void release_string(char **str);
|
||||
|
||||
#define ATTACH_JNI() __attribute__((unused, cleanup(jni_detach_thread))) \
|
||||
struct _scoped_jni _jni; \
|
||||
jni_attach_thread(&_jni); \
|
||||
JNIEnv *env = _jni.env
|
||||
#define ATTACH_JNI() __attribute__((unused, cleanup(jni_detach_thread))) JNIEnv *env = NULL; jni_attach_thread(&env)
|
||||
|
||||
#define scoped_string __attribute__((cleanup(release_string))) char*
|
||||
|
||||
|
||||
@@ -107,19 +107,16 @@ 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,
|
||||
jstring gateway,
|
||||
jstring portal,
|
||||
jstring dns,
|
||||
jint fd, jint mtu,
|
||||
jstring dns, jstring blocking,
|
||||
jobject cb) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string _gateway = get_string(gateway);
|
||||
scoped_string _portal = get_string(portal);
|
||||
scoped_string _blocking = get_string(blocking);
|
||||
scoped_string _dns = get_string(dns);
|
||||
jobject _interface = new_global(cb);
|
||||
|
||||
startTun(fd, _gateway, _portal, _dns, _interface);
|
||||
startTun(fd, mtu, _dns, _blocking, _interface);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
|
||||
@@ -1,28 +1,3 @@
|
||||
module cfa
|
||||
|
||||
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
|
||||
)
|
||||
go 1.17
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
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-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-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=
|
||||
|
||||
@@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"cfa/native/platform"
|
||||
@@ -15,15 +16,10 @@ func MarkSocket(fd int) {
|
||||
}
|
||||
|
||||
func QuerySocketUid(source, target net.Addr) int {
|
||||
var protocol int
|
||||
protocol := syscall.IPPROTO_TCP
|
||||
|
||||
switch source.Network() {
|
||||
case "udp", "udp4", "udp6":
|
||||
if strings.HasPrefix(source.String(), "udp") {
|
||||
protocol = syscall.IPPROTO_UDP
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
protocol = syscall.IPPROTO_TCP
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
|
||||
if PlatformVersion() < 29 {
|
||||
|
||||
@@ -4,38 +4,28 @@ var (
|
||||
defaultNameServers = []string{
|
||||
"223.5.5.5",
|
||||
"119.29.29.29",
|
||||
"8.8.4.4",
|
||||
"1.0.0.1",
|
||||
"8.8.8.8",
|
||||
"1.1.1.1",
|
||||
}
|
||||
defaultFallback = []string{
|
||||
"https://1.1.1.1/dns-query",
|
||||
"https://doh.pub/dns-query",
|
||||
}
|
||||
defaultFakeIPFilter = []string{
|
||||
// Stun Services
|
||||
// stun services
|
||||
"+.stun.*.*",
|
||||
"+.stun.*.*.*",
|
||||
"+.stun.*.*.*.*",
|
||||
"+.stun.*.*.*.*.*",
|
||||
|
||||
// Google Voices
|
||||
"lens.l.google.com",
|
||||
"stun.l.google.com",
|
||||
|
||||
// Nintendo Switch STUN
|
||||
// Nintendo Switch
|
||||
"*.n.n.srv.nintendo.net",
|
||||
|
||||
// PlayStation STUN
|
||||
"+.stun.playstation.net",
|
||||
|
||||
// XBox
|
||||
"xbox.*.*.microsoft.com",
|
||||
"*.*.xboxlive.com",
|
||||
|
||||
// Microsoft Captive Portal
|
||||
"*.msftncsi.com",
|
||||
"*.msftconnecttest.com",
|
||||
|
||||
// Bilibili CDN
|
||||
"*.mcdn.bilivideo.cn",
|
||||
|
||||
// Windows Default LAN WorkGroup
|
||||
"WORKGROUP",
|
||||
}
|
||||
defaultFakeIPRange = "28.0.0.0/8"
|
||||
localNetwork = []string{
|
||||
"0.0.0.0/8",
|
||||
"127.0.0.0/8",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -27,7 +27,7 @@ var client = &http.Client{
|
||||
DisableKeepAlives: true,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
DialContext: dialer.DialTunnelContext,
|
||||
DialContext: dialer.DefaultTunnelDialer,
|
||||
},
|
||||
Timeout: 60 * time.Second,
|
||||
}
|
||||
@@ -124,7 +124,7 @@ func FetchAndValid(
|
||||
return err
|
||||
}
|
||||
|
||||
forEachProviders(rawCfg, func(index int, total int, name string, provider map[string]any) {
|
||||
forEachProviders(rawCfg, func(index int, total int, name string, provider map[string]interface{}) {
|
||||
bytes, _ := json.Marshal(&Status{
|
||||
Action: "FetchProviders",
|
||||
Args: []string{name},
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"cfa/native/app"
|
||||
"github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
|
||||
"github.com/Dreamacro/clash/config"
|
||||
@@ -86,10 +87,18 @@ func Load(path string) error {
|
||||
}
|
||||
|
||||
func LoadDefault() {
|
||||
cfg, err := config.Parse([]byte{})
|
||||
rawConfig, _ := config.UnmarshalRawConfig([]byte{})
|
||||
|
||||
_ = patchDns(rawConfig, constant.Path.HomeDir())
|
||||
|
||||
cfg, err := config.ParseRawConfig(rawConfig)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
executor.ApplyConfig(cfg, true)
|
||||
}
|
||||
|
||||
func init() {
|
||||
LoadDefault()
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ const (
|
||||
OverrideSlotSession
|
||||
)
|
||||
|
||||
const defaultPersistOverride = `{"dns":{"enable": false}, "redir-port": 0, "tproxy-port": 0}`
|
||||
const defaultPersistOverride = `{"dns":{"enable": false}}`
|
||||
const defaultSessionOverride = `{}`
|
||||
|
||||
var sessionOverride = defaultSessionOverride
|
||||
@@ -65,4 +65,4 @@ func ClearOverride(slot OverrideSlot) {
|
||||
case OverrideSlotSession:
|
||||
sessionOverride = defaultSessionOverride
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,24 +5,29 @@ 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,
|
||||
patchTun,
|
||||
patchProxyGroup,
|
||||
validConfig,
|
||||
}
|
||||
|
||||
@@ -49,35 +54,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 = config.RawDNS{
|
||||
Enable: true,
|
||||
UseHosts: true,
|
||||
DefaultNameserver: defaultNameServers,
|
||||
NameServer: defaultNameServers,
|
||||
EnhancedMode: C.DNSFakeIP,
|
||||
FakeIPRange: defaultFakeIPRange,
|
||||
FakeIPFilter: defaultFakeIPFilter,
|
||||
}
|
||||
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.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]any) {
|
||||
forEachProviders(cfg, func(index int, total int, key string, provider map[string]interface{}) {
|
||||
if path, ok := provider["path"].(string); ok {
|
||||
provider["path"] = profileDir + "/providers/" + common.ResolveAsRoot(path)
|
||||
}
|
||||
@@ -86,6 +91,20 @@ 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`")
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
//go:build !premium
|
||||
|
||||
package config
|
||||
|
||||
import "github.com/Dreamacro/clash/config"
|
||||
|
||||
func patchTun(cfg *config.RawConfig, _ string) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
//go:build premium
|
||||
|
||||
package config
|
||||
|
||||
import "github.com/Dreamacro/clash/config"
|
||||
|
||||
func patchTun(cfg *config.RawConfig, _ string) error {
|
||||
cfg.Tun.Enable = false
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !premium
|
||||
// +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]any)) {
|
||||
func forEachProviders(rawCfg *config.RawConfig, fun func(index int, total int, key string, provider map[string]interface{})) {
|
||||
total := len(rawCfg.ProxyProvider)
|
||||
index := 0
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build premium
|
||||
// +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]any)) {
|
||||
func forEachProviders(rawCfg *config.RawConfig, fun func(index int, total int, key string, provider map[string]interface{})) {
|
||||
total := len(rawCfg.ProxyProvider) + len(rawCfg.RuleProvider)
|
||||
index := 0
|
||||
|
||||
|
||||
@@ -6,11 +6,10 @@ import (
|
||||
|
||||
"cfa/blob"
|
||||
|
||||
"github.com/Dreamacro/clash/component/process"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
|
||||
"cfa/native/app"
|
||||
"cfa/native/platform"
|
||||
"github.com/Dreamacro/clash/component/process"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
"github.com/Dreamacro/clash/component/mmdb"
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//go:build !premium
|
||||
|
||||
package main
|
||||
|
||||
//#include "bridge.h"
|
||||
@@ -25,7 +23,7 @@ func init() {
|
||||
defer log.UnSubscribe(sub)
|
||||
|
||||
for item := range sub {
|
||||
msg := item.(log.Event)
|
||||
msg := item.(*log.Event)
|
||||
|
||||
cPayload := C.CString(msg.Payload)
|
||||
|
||||
@@ -52,7 +50,7 @@ func subscribeLogcat(remote unsafe.Pointer) {
|
||||
defer log.UnSubscribe(sub)
|
||||
|
||||
for i := range sub {
|
||||
msg, ok := i.(log.Event)
|
||||
msg, ok := i.(*log.Event)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
//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())
|
||||
}
|
||||
@@ -36,7 +36,6 @@ func coreInit(home, versionName C.c_string, sdkVersion C.int) {
|
||||
func reset() {
|
||||
config.LoadDefault()
|
||||
tunnel.ResetStatistic()
|
||||
tunnel.CloseAllConnections()
|
||||
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func QuerySocketUidFromProcFs(source, _ net.Addr) int {
|
||||
|
||||
network := source.Network()
|
||||
|
||||
if strings.HasSuffix(network, "4") || strings.HasSuffix(network, "6") {
|
||||
if strings.HasSuffix(network, "4") {
|
||||
network = network[:len(network)-1]
|
||||
}
|
||||
|
||||
@@ -46,24 +46,16 @@ func QuerySocketUidFromProcFs(source, _ net.Addr) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
sIP = sIP.To16()
|
||||
if strings.HasSuffix(source.Network(), "6") {
|
||||
sIP = sIP.To16()
|
||||
} else {
|
||||
sIP = sIP.To4()
|
||||
}
|
||||
|
||||
if sIP == nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
uid := doQuery(path+"6", sIP, sPort)
|
||||
if uid == -1 {
|
||||
sIP = sIP.To4()
|
||||
if sIP == nil {
|
||||
return -1
|
||||
}
|
||||
uid = doQuery(path, sIP, sPort)
|
||||
}
|
||||
|
||||
return uid
|
||||
}
|
||||
|
||||
func doQuery(path string, sIP net.IP, sPort int) int {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return -1
|
||||
|
||||
@@ -5,8 +5,6 @@ import "C"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sync/semaphore"
|
||||
@@ -15,11 +13,7 @@ import (
|
||||
"cfa/native/tun"
|
||||
)
|
||||
|
||||
var rTunLock sync.Mutex
|
||||
var rTun *remoteTun
|
||||
|
||||
type remoteTun struct {
|
||||
closer io.Closer
|
||||
callback unsafe.Pointer
|
||||
|
||||
closed bool
|
||||
@@ -27,7 +21,7 @@ type remoteTun struct {
|
||||
}
|
||||
|
||||
func (t *remoteTun) markSocket(fd int) {
|
||||
_ = t.limit.Acquire(context.Background(), 1)
|
||||
_ = t.limit.Acquire(context.TODO(), 1)
|
||||
defer t.limit.Release(1)
|
||||
|
||||
if t.closed {
|
||||
@@ -38,7 +32,7 @@ func (t *remoteTun) markSocket(fd int) {
|
||||
}
|
||||
|
||||
func (t *remoteTun) querySocketUid(protocol int, source, target string) int {
|
||||
_ = t.limit.Acquire(context.Background(), 1)
|
||||
_ = t.limit.Acquire(context.TODO(), 1)
|
||||
defer t.limit.Release(1)
|
||||
|
||||
if t.closed {
|
||||
@@ -48,61 +42,38 @@ 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) close() {
|
||||
_ = t.limit.Acquire(context.TODO(), 4)
|
||||
func (t *remoteTun) stop() {
|
||||
_ = t.limit.Acquire(context.Background(), 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 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
|
||||
}
|
||||
|
||||
func startTun(fd, mtu C.int, gateway, dns C.c_string, callback unsafe.Pointer) C.int {
|
||||
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)
|
||||
|
||||
closer, err := tun.Start(f, g, p, d)
|
||||
if err != nil {
|
||||
remote.close()
|
||||
if tun.Start(f, m, g, d, remote.stop) != nil {
|
||||
app.ApplyTunContext(nil, nil)
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
remote.closer = closer
|
||||
|
||||
rTun = remote
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
//export stopTun
|
||||
func stopTun() {
|
||||
rTunLock.Lock()
|
||||
defer rTunLock.Unlock()
|
||||
|
||||
if rTun != nil {
|
||||
rTun.close()
|
||||
rTun = nil
|
||||
}
|
||||
tun.Stop()
|
||||
}
|
||||
|
||||
39
core/src/main/golang/native/tun/link.go
Normal file
39
core/src/main/golang/native/tun/link.go
Normal file
@@ -0,0 +1,39 @@
|
||||
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])
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
//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,
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
//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,
|
||||
}
|
||||
}
|
||||
105
core/src/main/golang/native/tun/tcp.go
Normal file
105
core/src/main/golang/native/tun/tcp.go
Normal file
@@ -0,0 +1,105 @@
|
||||
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
|
||||
}
|
||||
@@ -1,162 +1,91 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"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"
|
||||
"github.com/kr328/tun2socket-lwip"
|
||||
)
|
||||
|
||||
var _, ipv4LoopBack, _ = net.ParseCIDR("127.0.0.0/8")
|
||||
type adapter struct {
|
||||
device *os.File
|
||||
stack tun2socket.Stack
|
||||
blocking []*net.IPNet
|
||||
dns net.IP
|
||||
mtu int
|
||||
once sync.Once
|
||||
stop func()
|
||||
}
|
||||
|
||||
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)
|
||||
var lock sync.Mutex
|
||||
var instance *adapter
|
||||
|
||||
device := os.NewFile(uintptr(fd), "/dev/tun")
|
||||
func (a *adapter) close() {
|
||||
_ = a.stack.Close()
|
||||
_ = a.device.Close()
|
||||
}
|
||||
|
||||
ip, network, err := net.ParseCIDR(gateway)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
} else {
|
||||
network.IP = ip
|
||||
func Start(fd, mtu int, dns string, blocking string, stop func()) error {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
if instance != nil {
|
||||
instance.close()
|
||||
}
|
||||
|
||||
stack, err := tun2socket.StartTun2Socket(device, network, net.ParseIP(portal))
|
||||
_ = syscall.SetNonblock(fd, true)
|
||||
|
||||
device := os.NewFile(uintptr(fd), "/dev/tun")
|
||||
stack, err := tun2socket.NewStack(mtu)
|
||||
if err != nil {
|
||||
_ = device.Close()
|
||||
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
dnsAddr := net.ParseIP(dns)
|
||||
dn := net.ParseIP(dns)
|
||||
|
||||
tcp := func() {
|
||||
defer stack.TCP().Close()
|
||||
defer log.Debugln("TCP: closed")
|
||||
var blk []*net.IPNet
|
||||
|
||||
for stack.TCP().SetDeadline(time.Time{}) == nil {
|
||||
conn, err := stack.TCP().Accept()
|
||||
if err != nil {
|
||||
log.Debugln("Accept connection: %v", err)
|
||||
for _, b := range strings.Split(blocking, ";") {
|
||||
_, n, err := net.ParseCIDR(b)
|
||||
if err != nil {
|
||||
device.Close()
|
||||
|
||||
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))
|
||||
return err
|
||||
}
|
||||
|
||||
blk = append(blk, n)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
instance = &adapter{
|
||||
device: device,
|
||||
stack: stack,
|
||||
blocking: blk,
|
||||
dns: dn,
|
||||
mtu: mtu,
|
||||
once: sync.Once{},
|
||||
stop: stop,
|
||||
}
|
||||
|
||||
go tcp()
|
||||
go udp()
|
||||
go udp()
|
||||
go instance.rx()
|
||||
go instance.tx()
|
||||
go instance.tcp()
|
||||
go instance.udp()
|
||||
|
||||
return stack, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
if instance != nil {
|
||||
instance.close()
|
||||
}
|
||||
|
||||
instance = nil
|
||||
}
|
||||
|
||||
@@ -2,13 +2,21 @@ 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 {
|
||||
local *net.UDPAddr
|
||||
data []byte
|
||||
writeBack func(b []byte, addr net.Addr) (int, error)
|
||||
drop func()
|
||||
stack tun2socket.Stack
|
||||
local *net.UDPAddr
|
||||
data []byte
|
||||
}
|
||||
|
||||
func (pkt *packet) Data() []byte {
|
||||
@@ -16,13 +24,76 @@ func (pkt *packet) Data() []byte {
|
||||
}
|
||||
|
||||
func (pkt *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
||||
return pkt.writeBack(b, addr)
|
||||
return pkt.stack.UDP().WriteTo(b, pkt.local, addr)
|
||||
}
|
||||
|
||||
func (pkt *packet) Drop() {
|
||||
pkt.drop()
|
||||
pool.Put(pkt.data)
|
||||
}
|
||||
|
||||
func (pkt *packet) LocalAddr() net.Addr {
|
||||
return pkt.local
|
||||
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
|
||||
}
|
||||
|
||||
@@ -5,12 +5,6 @@ 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 {
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
//go:build !premium
|
||||
|
||||
package tunnel
|
||||
|
||||
import "net"
|
||||
|
||||
var loopback = net.ParseIP("127.0.0.1")
|
||||
@@ -1,7 +0,0 @@
|
||||
//go:build premium
|
||||
|
||||
package tunnel
|
||||
|
||||
import "net/netip"
|
||||
|
||||
var loopback = netip.MustParseAddr("127.0.0.1")
|
||||
@@ -1,8 +1,9 @@
|
||||
//go:build !premium
|
||||
// +build !premium
|
||||
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -11,6 +12,8 @@ import (
|
||||
"github.com/Dreamacro/clash/tunnel"
|
||||
)
|
||||
|
||||
var ErrInvalidType = errors.New("invalid type")
|
||||
|
||||
type Provider struct {
|
||||
Name string `json:"name"`
|
||||
VehicleType string `json:"vehicleType"`
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build premium
|
||||
// +build premium
|
||||
|
||||
package tunnel
|
||||
|
||||
@@ -49,7 +49,7 @@ func QueryProviders() []*Provider {
|
||||
for _, p := range providers {
|
||||
updatedAt := time.Time{}
|
||||
|
||||
if s, ok := p.(P.UpdatableProvider[any]); ok {
|
||||
if s, ok := p.(P.UpdatableProvider); ok {
|
||||
updatedAt = s.UpdatedAt()
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func marshalJson(obj any) *C.char {
|
||||
func marshalJson(obj interface{}) *C.char {
|
||||
res, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
@@ -16,7 +16,7 @@ func marshalJson(obj any) *C.char {
|
||||
return C.CString(string(res))
|
||||
}
|
||||
|
||||
func marshalString(obj any) *C.char {
|
||||
func marshalString(obj interface{}) *C.char {
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -64,13 +64,13 @@ object Clash {
|
||||
|
||||
fun startTun(
|
||||
fd: Int,
|
||||
gateway: String,
|
||||
portal: String,
|
||||
mtu: Int,
|
||||
dns: String,
|
||||
blocking: String,
|
||||
markSocket: (Int) -> Boolean,
|
||||
querySocketUid: (protocol: Int, source: InetSocketAddress, target: InetSocketAddress) -> Int
|
||||
) {
|
||||
Bridge.nativeStartTun(fd, gateway, portal, dns, object : TunInterface {
|
||||
Bridge.nativeStartTun(fd, mtu, dns, blocking, object : TunInterface {
|
||||
override fun markSocket(fd: Int) {
|
||||
markSocket(fd)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ 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
|
||||
|
||||
@@ -19,7 +18,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, gateway: String, portal: String, dns: String, cb: TunInterface)
|
||||
external fun nativeStartTun(fd: Int, mtu: Int, dns: String, blocking: String, cb: TunInterface)
|
||||
external fun nativeStopTun()
|
||||
external fun nativeStartHttp(listenAt: String): String?
|
||||
external fun nativeStopHttp()
|
||||
@@ -64,8 +63,6 @@ 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)
|
||||
}
|
||||
}
|
||||
@@ -49,9 +49,6 @@ data class ConfigurationOverride(
|
||||
|
||||
@SerialName("clash-for-android")
|
||||
val app: App = App(),
|
||||
|
||||
@SerialName("experimental")
|
||||
val experimental: Experimental = Experimental()
|
||||
) : Parcelable {
|
||||
@Serializable
|
||||
data class Dns(
|
||||
@@ -110,12 +107,6 @@ data class ConfigurationOverride(
|
||||
var appendSystemDns: Boolean? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Experimental(
|
||||
@SerialName("sniff-tls-sni")
|
||||
var sniffTLSSNI: Boolean? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
enum class DnsEnhancedMode {
|
||||
@SerialName("normal")
|
||||
|
||||
@@ -14,7 +14,8 @@ import kotlinx.serialization.modules.SerializersModule
|
||||
|
||||
object Parcelizer {
|
||||
private class ParcelDecoder(private val parcel: Parcel) : Decoder, CompositeDecoder {
|
||||
override val serializersModule: SerializersModule = SerializersModule {}
|
||||
@ExperimentalSerializationApi
|
||||
override val serializersModule: SerializersModule = EmptySerializersModule
|
||||
|
||||
@ExperimentalSerializationApi
|
||||
override fun decodeSequentially(): Boolean = true
|
||||
@@ -121,7 +122,8 @@ object Parcelizer {
|
||||
}
|
||||
|
||||
private class ParcelEncoder(private val parcel: Parcel) : Encoder, CompositeEncoder {
|
||||
override val serializersModule: SerializersModule = SerializersModule {}
|
||||
@ExperimentalSerializationApi
|
||||
override val serializersModule: SerializersModule = EmptySerializersModule
|
||||
|
||||
override fun encodeBooleanElement(
|
||||
descriptor: SerialDescriptor,
|
||||
|
||||
@@ -22,17 +22,17 @@ private fun trafficString(scaled: Long): String {
|
||||
scaled > 1024 * 1024 * 1024 * 100L -> {
|
||||
val data = scaled / 1024 / 1024 / 1024
|
||||
|
||||
String.format("%.2f GiB", data.toFloat() / 100)
|
||||
"${data / 100}.${data % 100} GiB"
|
||||
}
|
||||
scaled > 1024 * 1024 * 100L -> {
|
||||
val data = scaled / 1024 / 1024
|
||||
|
||||
String.format("%.2f MiB", data.toFloat() / 100)
|
||||
"${data / 100}.${data % 100} MiB"
|
||||
}
|
||||
scaled > 1024 * 100L -> {
|
||||
val data = scaled / 1024
|
||||
|
||||
String.format("%.2f KiB", data.toFloat() / 100)
|
||||
"${data / 100}.${data % 100} KiB"
|
||||
}
|
||||
else -> {
|
||||
"$scaled Bytes"
|
||||
|
||||
@@ -1,55 +1,40 @@
|
||||
module premium
|
||||
|
||||
go 1.18
|
||||
go 1.17
|
||||
|
||||
require cfa v0.0.0
|
||||
|
||||
require (
|
||||
cfa/blob v0.0.0 // indirect
|
||||
github.com/Dreamacro/clash v1.7.1 // indirect
|
||||
github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34 // indirect
|
||||
github.com/Dreamacro/clash v0.0.0 // indirect
|
||||
github.com/Dreamacro/go-shadowsocks2 v0.1.7 // indirect
|
||||
github.com/avast/apkparser v0.0.0-20210223100516-186f320f9bfc // indirect
|
||||
github.com/avast/apkverifier v0.0.0-20210916093748-2146ff7c4b7f // indirect
|
||||
github.com/cilium/ebpf v0.9.0 // indirect
|
||||
github.com/avast/apkverifier v0.0.0-20210524110121-dfe686b45d88 // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/florianl/go-tc v0.4.1 // indirect
|
||||
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
||||
github.com/gofrs/uuid v4.0.0+incompatible // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/go-cmp v0.5.7 // indirect
|
||||
github.com/google/nftables v0.0.0-20220611213346-a346d51f53b3 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f // indirect
|
||||
github.com/josharian/native v1.0.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac // indirect
|
||||
github.com/klauspost/compress v1.11.13 // indirect
|
||||
github.com/mdlayher/netlink v1.6.0 // indirect
|
||||
github.com/mdlayher/socket v0.1.1 // indirect
|
||||
github.com/miekg/dns v1.1.49 // 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.21.0 // 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/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd // indirect
|
||||
go.starlark.net v0.0.0-20210901212718-87f333178d59 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // 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-20220617184016-355a448f1bc9 // indirect
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
|
||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect
|
||||
golang.org/x/text v0.3.7 // 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
|
||||
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/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
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20220428010907-8082b77961ba // indirect
|
||||
inet.af/netaddr v0.0.0-20220617031823-097006376321 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20210904021812-0d58674c658a // indirect
|
||||
inet.af/netaddr v0.0.0-20210903134321-85fa6c94624e // indirect
|
||||
)
|
||||
|
||||
replace cfa => ../../main/golang
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,13 +9,13 @@ dependencies {
|
||||
implementation(project(":core"))
|
||||
implementation(project(":service"))
|
||||
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class LogcatDesign(
|
||||
private val binding = DesignLogcatBinding
|
||||
.inflate(context.layoutInflater, context.root, false)
|
||||
private val adapter = LogMessageAdapter(context) {
|
||||
launch {
|
||||
launch(Dispatchers.IO) {
|
||||
val data = ClipData.newPlainText("log_message", it.message)
|
||||
|
||||
context.getSystemService<ClipboardManager>()?.setPrimaryClip(data)
|
||||
|
||||
@@ -71,9 +71,9 @@ class NetworkSettingsDesign(
|
||||
)
|
||||
|
||||
switch(
|
||||
value = srvStore::allowBypass,
|
||||
title = R.string.allow_bypass,
|
||||
summary = R.string.allow_bypass_summary,
|
||||
value = srvStore::blockLoopback,
|
||||
title = R.string.block_loopback,
|
||||
summary = R.string.block_loopback_summary,
|
||||
configure = vpnDependencies::add,
|
||||
)
|
||||
|
||||
|
||||
@@ -223,15 +223,6 @@ class OverrideSettingsDesign(
|
||||
)
|
||||
}
|
||||
|
||||
if (BuildConfig.PREMIUM) {
|
||||
selectableList(
|
||||
value = configuration.experimental::sniffTLSSNI,
|
||||
values = booleanValues,
|
||||
valuesText = booleanValuesText,
|
||||
title = R.string.sniff_tls_sni,
|
||||
)
|
||||
}
|
||||
|
||||
selectableList(
|
||||
value = configuration::logLevel,
|
||||
values = arrayOf(
|
||||
|
||||
@@ -2,13 +2,12 @@ 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).foreground(),
|
||||
icon = applicationInfo.loadIcon(pm),
|
||||
label = applicationInfo.loadLabel(pm).toString(),
|
||||
installTime = firstInstallTime,
|
||||
updateDate = lastUpdateTime,
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
<?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 Logcat</string>
|
||||
<string name="clash_logcat">Clash 日誌檔採集工具</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">刪除所有日誌檔</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>
|
||||
<string name="empty_name">空白名稱</string>
|
||||
<string name="exit_without_save">退出而不儲存</string>
|
||||
<string name="exit_without_save_warning">將遺失所有變更</string>
|
||||
<string name="exit_without_save_warning">所有變更將會丟失</string>
|
||||
<string name="export">匯出</string>
|
||||
<string name="external">外部</string>
|
||||
<string name="file">檔案</string>
|
||||
<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>
|
||||
@@ -45,23 +45,23 @@
|
||||
<string name="invalid_url">無效 URL</string>
|
||||
<string name="launch_name">Clash</string>
|
||||
<string name="logcat">Logcat</string>
|
||||
<string name="logs">紀錄</string>
|
||||
<string name="logs">日誌</string>
|
||||
<string name="mode">模式</string>
|
||||
<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>
|
||||
@@ -69,27 +69,27 @@
|
||||
<string name="auto_restart">自動重新啟動</string>
|
||||
<string name="stopped">已停止</string>
|
||||
<string name="help">幫助</string>
|
||||
<string name="tap_to_start">輕觸以啟動</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="github_issues">Github Issues</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="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="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,37 +109,37 @@
|
||||
<string name="dns">DNS</string>
|
||||
<string name="http_port">HTTP 埠</string>
|
||||
<string name="socks_port">Socks 埠</string>
|
||||
<string name="mixed_port">Mixed 埠</string>
|
||||
<string name="allow_lan">允許來自區域網路的連線</string>
|
||||
<string name="mixed_port">複合埠</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">名稱伺服器</string>
|
||||
<string name="fallback">備用名稱伺服器</string>
|
||||
<string name="default_name_server">預設名稱伺服器</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="fakeip_filter">FakeIP 過濾器</string>
|
||||
<string name="geoip_fallback">GeoIP 備用</string>
|
||||
<string name="ipcidr_fallback">IPCIDR 備用</string>
|
||||
<string name="geoip_fallback">GeoIP Fallback</string>
|
||||
<string name="ipcidr_fallback">IPCIDR Fallback</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="layout">佈局</string>
|
||||
<string name="single">單欄</string>
|
||||
<string name="multiple">多欄</string>
|
||||
<string name="not_selectable">無法選擇</string>
|
||||
<string name="providers">提供者</string>
|
||||
<string name="unavailable">無法使用</string>
|
||||
<string name="not_selectable">不可選取</string>
|
||||
<string name="providers">外部資源</string>
|
||||
<string name="unavailable">不可用</string>
|
||||
<string name="_new">新增</string>
|
||||
<string name="value">值</string>
|
||||
<string name="listen">監聽</string>
|
||||
@@ -162,29 +162,29 @@
|
||||
<string name="reset">重設</string>
|
||||
<string name="use_hosts">使用 Hosts</string>
|
||||
<string name="authentication">認證</string>
|
||||
<string name="domain_fallback">備用域名</string>
|
||||
<string name="empty">空</string>
|
||||
<string name="domain_fallback">域名 Fallback</string>
|
||||
<string name="empty">置空</string>
|
||||
<string name="import_from_clipboard">從剪貼簿匯入</string>
|
||||
<string name="export_to_clipboard">匯出至剪貼簿</string>
|
||||
<string name="auto_update_minutes">自動更新 (分鐘)</string>
|
||||
<string name="profile_url">設定檔 URL</string>
|
||||
<string name="should_not_be_blank">不能為空</string>
|
||||
<string name="format_fetching_configuration">正在從 %s 下載設定檔</string>
|
||||
<string name="format_fetching_provider">正在下載額外資源 %s</string>
|
||||
<string name="format_fetching_provider">正在下載外部資源 %s</string>
|
||||
<string name="initializing">正在初始化</string>
|
||||
<string name="verifying">正在校驗</string>
|
||||
<string name="sideload_geoip">側載 GeoIP</string>
|
||||
<string name="sideload_geoip_summary">外部 GeoIP 資料庫</string>
|
||||
<string name="sideload_geoip">旁載入 GEOIP</string>
|
||||
<string name="sideload_geoip_summary">外部 GEOIP 資料庫</string>
|
||||
<string name="force_enable">強制啟用</string>
|
||||
<string name="document">文件</string>
|
||||
<string name="clash_wiki">Clash Wiki</string>
|
||||
<string name="invalid_file_name">無效的檔案名稱</string>
|
||||
<string name="reset_override_settings">重設覆寫設定</string>
|
||||
<string name="reset_override_settings_message">所有的覆寫設定將會被移除</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>
|
||||
@@ -195,26 +195,22 @@
|
||||
<string name="reverse">反轉</string>
|
||||
<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="invalid_log_file">無效的日誌檔</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="github_releases">Github Releases</string>
|
||||
<string name="unable_to_start_vpn">無法啟動 VPN 元件</string>
|
||||
<string name="request_donate_tips">如果您覺得本應用程式對您有幫助,歡迎在 [幫助] 中給予開發人員一些抖內</string>
|
||||
<string name="request_donate_tips">如果您覺得本軟體對您有幫助歡迎在 [幫助] 中給予開發者一點抖內</string>
|
||||
<string name="request_donate">抖內</string>
|
||||
<string name="version_updated">應用程式已更新</string>
|
||||
<string name="version_updated">軟體已更新</string>
|
||||
<string name="version_updated_tips">設定已被清除,舊版設定檔需要再次儲存。</string>
|
||||
<string name="active_unsaved_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="geoip_fallback_code">GeoIP 備用區域代碼</string>
|
||||
<string name="allow_bypass">允許應用程式繞過</string>
|
||||
<string name="allow_bypass_summary">允許其他程式繞過 VPN</string>
|
||||
<string name="sniff_tls_sni">嗅探 TLS 的 SNI</string>
|
||||
<string name="name_server_policy">Name Server 策略</string>
|
||||
<string name="block_loopback">阻止本地迴環</string>
|
||||
<string name="block_loopback_summary">阻止本地迴環連結</string>
|
||||
</resources>
|
||||
|
||||
@@ -214,7 +214,4 @@
|
||||
<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>
|
||||
<string name="sniff_tls_sni">嗅探 TLS 的 SNI</string>
|
||||
</resources>
|
||||
@@ -122,8 +122,6 @@
|
||||
<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>
|
||||
@@ -145,7 +143,6 @@
|
||||
<string name="bind_address">Bind Address</string>
|
||||
<string name="mode">Mode</string>
|
||||
<string name="log_level">Log Level</string>
|
||||
<string name="sniff_tls_sni">Sniff TLS SNI</string>
|
||||
<string name="ipv6">IPv6</string>
|
||||
<string name="hosts">Hosts</string>
|
||||
<string name="sideload_geoip">Sideload GEOIP</string>
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionSha256Sum=e6d864e3b5bc05cc62041842b306383fc1fefcec359e70cebb1d470a6094ca82
|
||||
distributionSha256Sum=a8da5b02437a60819cad23e10fc7e9cf32bcb57029d9cb277e26eeff76ce014b
|
||||
10
gradlew
vendored
10
gradlew
vendored
@@ -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:
|
||||
#
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
plugins {
|
||||
kotlin("android")
|
||||
kotlin("kapt")
|
||||
id("kotlinx-serialization")
|
||||
id("com.android.library")
|
||||
id("com.google.devtools.ksp")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
ksp(deps.kaidl.compiler)
|
||||
kapt(deps.androidx.room.compiler)
|
||||
|
||||
implementation(project(":core"))
|
||||
implementation(project(":common"))
|
||||
|
||||
ksp(libs.kaidl.compiler)
|
||||
ksp(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)
|
||||
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)
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
android {
|
||||
libraryVariants.forEach {
|
||||
sourceSets[it.name].kotlin.srcDir(buildDir.resolve("generated/ksp/${it.name}/kotlin"))
|
||||
sourceSets[it.name].java.srcDir(buildDir.resolve("generated/ksp/${it.name}/java"))
|
||||
sourceSets[it.name].java.srcDir(buildDir.resolve("generated/ksp/${it.name}/kotlin"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,14 +12,12 @@
|
||||
|
||||
<application>
|
||||
<service
|
||||
android:name=".ClashService"
|
||||
android:name="ClashService"
|
||||
android:exported="false"
|
||||
android:label="@string/clash_for_android"
|
||||
android:process=":background" />
|
||||
<service
|
||||
android:name=".TunService"
|
||||
android:name="TunService"
|
||||
android:exported="false"
|
||||
android:label="@string/clash_for_android"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE"
|
||||
android:process=":background">
|
||||
<intent-filter>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
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
|
||||
@@ -93,20 +95,26 @@ class ProfileWorker : BaseService() {
|
||||
}
|
||||
|
||||
private fun createChannels() {
|
||||
NotificationManagerCompat.from(this).createNotificationChannelsCompat(
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
|
||||
return
|
||||
|
||||
NotificationManagerCompat.from(this).createNotificationChannels(
|
||||
listOf(
|
||||
NotificationChannelCompat.Builder(
|
||||
NotificationChannel(
|
||||
SERVICE_CHANNEL,
|
||||
NotificationManagerCompat.IMPORTANCE_LOW
|
||||
).setName(getString(R.string.profile_service_status)).build(),
|
||||
NotificationChannelCompat.Builder(
|
||||
getString(R.string.profile_service_status),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
),
|
||||
NotificationChannel(
|
||||
STATUS_CHANNEL,
|
||||
NotificationManagerCompat.IMPORTANCE_LOW
|
||||
).setName(getString(R.string.profile_process_status)).build(),
|
||||
NotificationChannelCompat.Builder(
|
||||
getString(R.string.profile_process_status),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
),
|
||||
NotificationChannel(
|
||||
RESULT_CHANNEL,
|
||||
NotificationManagerCompat.IMPORTANCE_DEFAULT
|
||||
).setName(getString(R.string.profile_process_result)).build()
|
||||
getString(R.string.profile_process_result),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.github.kr328.clash.service
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.net.ProxyInfo
|
||||
@@ -62,9 +61,9 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
|
||||
|
||||
true
|
||||
}
|
||||
network.onEvent { n ->
|
||||
if (Build.VERSION.SDK_INT in 22..28) @TargetApi(22) {
|
||||
setUnderlyingNetworks(n?.let { arrayOf(it) })
|
||||
network.onEvent { e ->
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
setUnderlyingNetworks(e.network?.let { arrayOf(it) })
|
||||
}
|
||||
|
||||
false
|
||||
@@ -183,12 +182,12 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
|
||||
)
|
||||
|
||||
// Metered
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
setMetered(false)
|
||||
}
|
||||
|
||||
// System Proxy
|
||||
if (Build.VERSION.SDK_INT >= 29 && store.systemProxy) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && store.systemProxy) {
|
||||
listenHttp()?.let {
|
||||
setHttpProxy(
|
||||
ProxyInfo.buildDirectProxy(
|
||||
@@ -200,15 +199,16 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De
|
||||
}
|
||||
}
|
||||
|
||||
if (store.allowBypass) {
|
||||
allowBypass()
|
||||
val blocking = mutableListOf("$TUN_GATEWAY/$TUN_SUBNET_PREFIX")
|
||||
if (store.blockLoopback) {
|
||||
blocking.add(NET_SUBNET_LOOPBACK)
|
||||
}
|
||||
|
||||
TunModule.TunDevice(
|
||||
fd = establish()?.detachFd()
|
||||
?: throw NullPointerException("Establish VPN rejected by system"),
|
||||
gateway = "$TUN_GATEWAY/$TUN_SUBNET_PREFIX",
|
||||
portal = TUN_PORTAL,
|
||||
mtu = TUN_MTU,
|
||||
blocking = blocking.joinToString(";"),
|
||||
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_PORTAL = "172.19.0.2"
|
||||
private const val TUN_DNS = TUN_PORTAL
|
||||
private const val TUN_DNS = "172.19.0.2"
|
||||
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,11 +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",
|
||||
"*jd.com",
|
||||
"100ime-iat-api.xfyun.cn",
|
||||
)
|
||||
private val HTTP_PROXY_BLACK_LIST: List<String> = listOf("*zhihu.com", "*zhimg.com")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,19 +15,7 @@ class AppListCacheModule(service: Service) : Module<Unit>(service) {
|
||||
|
||||
private fun reload() {
|
||||
val packages = service.packageManager.getInstalledPackages(0)
|
||||
.groupBy { it.uniqueUidName() }
|
||||
.map { (_, v) ->
|
||||
val info = v[0]
|
||||
|
||||
if (v.size == 1) {
|
||||
// Force use package name if only one app in a single sharedUid group
|
||||
// Example: firefox
|
||||
|
||||
info.applicationInfo.uid to info.packageName
|
||||
} else {
|
||||
info.applicationInfo.uid to info.uniqueUidName()
|
||||
}
|
||||
}
|
||||
.map { it.applicationInfo.uid to it.uniqueUidName() }
|
||||
|
||||
Clash.notifyInstalledAppsChanged(packages)
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ class DynamicNotificationModule(service: Service) : Module<Unit>(service) {
|
||||
.setOnlyAlertOnce(true)
|
||||
.setShowWhen(false)
|
||||
.setContentTitle("Not Selected")
|
||||
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
|
||||
.setContentIntent(
|
||||
PendingIntent.getActivity(
|
||||
service,
|
||||
|
||||
@@ -1,128 +1,102 @@
|
||||
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.resolvePrimaryDns
|
||||
import com.github.kr328.clash.service.util.resolveDns
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.trySendBlocking
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class NetworkObserveModule(service: Service) : Module<Network?>(service) {
|
||||
private data class Action(val type: Type, val network: Network) {
|
||||
enum class Type { Available, Lost, Changed }
|
||||
}
|
||||
class NetworkObserveModule(service: Service) :
|
||||
Module<NetworkObserveModule.NetworkChanged>(service) {
|
||||
data class NetworkChanged(val network: Network?)
|
||||
|
||||
private val connectivity = service.getSystemService<ConnectivityManager>()!!
|
||||
private val actions = Channel<Action>(Channel.UNLIMITED)
|
||||
private val networks: Channel<Network?> = Channel(Channel.CONFLATED)
|
||||
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) {
|
||||
actions.trySendBlocking(Action(Action.Type.Available, 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)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLost(network: Network) {
|
||||
actions.trySendBlocking(Action(Action.Type.Lost, network))
|
||||
if (this.network == network) {
|
||||
networks.trySend(null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
|
||||
actions.trySendBlocking(Action(Action.Type.Changed, network))
|
||||
if (this.network == network) {
|
||||
networks.trySend(network)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun run() {
|
||||
try {
|
||||
connectivity.registerNetworkCallback(request, callback)
|
||||
if (Build.VERSION.SDK_INT in 24..27) @TargetApi(24) {
|
||||
connectivity.registerDefaultNetworkCallback(callback)
|
||||
} else {
|
||||
connectivity.requestNetwork(request, callback)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w("Observe network failed: $e", e)
|
||||
Log.w("Observe network changed: $e", e)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
val networks = mutableSetOf<Network>()
|
||||
|
||||
while (true) {
|
||||
val action = actions.receive()
|
||||
val network = networks.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)
|
||||
}
|
||||
val dns = connectivity.resolveDns(network)
|
||||
|
||||
Clash.notifyDnsChanged(dns)
|
||||
|
||||
Log.d("DNS: $dns")
|
||||
Log.d("Network changed, system dns = $dns")
|
||||
|
||||
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")
|
||||
}
|
||||
enqueueEvent(NetworkChanged(network))
|
||||
}
|
||||
} finally {
|
||||
withContext(NonCancellable) {
|
||||
enqueueEvent(null)
|
||||
connectivity.unregisterNetworkCallback(callback)
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
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 androidx.core.app.NotificationChannelCompat
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.github.kr328.clash.common.compat.getColorCompat
|
||||
@@ -21,7 +23,6 @@ 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,
|
||||
@@ -55,11 +56,14 @@ 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(
|
||||
NotificationChannelCompat.Builder(
|
||||
NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
NotificationManagerCompat.IMPORTANCE_LOW
|
||||
).setName(service.getText(R.string.clash_service_status_channel)).build()
|
||||
service.getText(R.string.clash_service_status_channel),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ import java.security.SecureRandom
|
||||
class TunModule(private val vpn: VpnService) : Module<Unit>(vpn) {
|
||||
data class TunDevice(
|
||||
val fd: Int,
|
||||
val gateway: String,
|
||||
val portal: String,
|
||||
val mtu: Int,
|
||||
val blocking: 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 < 29)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
|
||||
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,
|
||||
gateway = device.gateway,
|
||||
portal = device.portal,
|
||||
mtu = device.mtu,
|
||||
dns = device.dns,
|
||||
blocking = device.blocking,
|
||||
markSocket = vpn::protect,
|
||||
querySocketUid = this::queryUid
|
||||
)
|
||||
|
||||
@@ -46,8 +46,8 @@ class ServiceStore(context: Context) {
|
||||
defaultValue = true
|
||||
)
|
||||
|
||||
var allowBypass by store.boolean(
|
||||
key = "allow_bypass",
|
||||
var blockLoopback by store.boolean(
|
||||
key = "block_loopback",
|
||||
defaultValue = true
|
||||
)
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@ package com.github.kr328.clash.service.util
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
|
||||
fun ConnectivityManager.resolvePrimaryDns(network: Network?): String? {
|
||||
val properties = getLinkProperties(network) ?: return null
|
||||
|
||||
return properties.dnsServers.firstOrNull()?.asSocketAddressText(53)
|
||||
}
|
||||
fun ConnectivityManager.resolveDns(network: Network?): List<String> {
|
||||
return network?.run(this::getLinkProperties)
|
||||
?.dnsServers
|
||||
?.map { it.asSocketAddressText(53) }
|
||||
?: emptyList()
|
||||
}
|
||||
@@ -7,11 +7,6 @@
|
||||
android:tint="@color/color_clash">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
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"
|
||||
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"
|
||||
tools:ignore="VectorPath" />
|
||||
</vector>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user