Compare commits

..

1 Commits

Author SHA1 Message Date
Kr328
c4c070cb97 Chore: bump version 2021-09-24 11:15:54 +08:00
101 changed files with 1952 additions and 1600 deletions

View 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>
```

View File

@@ -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."

View 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.

View File

@@ -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.

View 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
# 在此粘贴
```
**日志**
粘贴日志以帮助侦测错误
```
<在此粘贴>
```

View File

@@ -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: "可选"

View File

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

View File

@@ -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: |
与此功能相关的其他附加信息。

View File

@@ -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
View File

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

View File

@@ -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.
**Childrens 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.

View File

@@ -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/`

View File

@@ -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) {

View 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
}
}

View File

@@ -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)
}
}
}
}

View File

@@ -234,12 +234,12 @@ abstract class BaseActivity<D : Design<*>> :
window.statusBarColor = resolveThemedColor(android.R.attr.statusBarColor)
window.navigationBarColor = resolveThemedColor(android.R.attr.navigationBarColor)
if (Build.VERSION.SDK_INT >= 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)
}

View File

@@ -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
)

View File

@@ -67,7 +67,7 @@ class LogcatActivity : BaseActivity<LogcatDesign>() {
}
LogcatDesign.Request.Export -> {
val output = startActivityForResult(
ActivityResultContracts.CreateDocument("text/plain"),
ActivityResultContracts.CreateDocument(),
file.fileName
)

View File

@@ -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()

View File

@@ -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")

View File

@@ -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()

View File

@@ -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>

View 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"))
)
}
}
}
}

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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? {

View File

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

View File

@@ -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
}

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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

View File

@@ -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=

View File

@@ -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) {

View File

@@ -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*

View File

@@ -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

View File

@@ -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

View File

@@ -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=

View File

@@ -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 {

View File

@@ -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",
}
)

View File

@@ -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},

View File

@@ -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()
}

View File

@@ -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
}
}
}

View File

@@ -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`")

View File

@@ -1,9 +0,0 @@
//go:build !premium
package config
import "github.com/Dreamacro/clash/config"
func patchTun(cfg *config.RawConfig, _ string) error {
return nil
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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
}

View File

@@ -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())
}

View File

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

View File

@@ -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

View File

@@ -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()
}

View 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])
}
}

View File

@@ -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,
}
}

View File

@@ -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,
}
}

View 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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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
}
}

View File

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

View File

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

View File

@@ -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"`

View File

@@ -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()
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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)
}
}

View File

@@ -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")

View File

@@ -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,

View File

@@ -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"

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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,
)

View File

@@ -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(

View File

@@ -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,

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.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
View File

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

View File

@@ -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"))
}
}
}

View File

@@ -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>

View File

@@ -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
)
)
)
}

View File

@@ -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")
}
}

View File

@@ -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)

View File

@@ -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,

View File

@@ -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()
}
}

View File

@@ -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
)
)
}

View File

@@ -15,8 +15,8 @@ import java.security.SecureRandom
class TunModule(private val vpn: VpnService) : Module<Unit>(vpn) {
data class TunDevice(
val fd: Int,
val 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
)

View File

@@ -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
)

View File

@@ -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()
}

View File

@@ -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