Skip to content
This repository has been archived by the owner on Jan 4, 2024. It is now read-only.

Commit

Permalink
Add brook support
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed May 22, 2021
1 parent d4b7f5f commit 7771636
Show file tree
Hide file tree
Showing 29 changed files with 332 additions and 75 deletions.
5 changes: 5 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<activity android:name="io.nekohasekai.sagernet.ui.profile.NaiveSettingsActivity" />
<activity android:name="io.nekohasekai.sagernet.ui.profile.PingTunnelSettingsActivity" />
<activity android:name="io.nekohasekai.sagernet.ui.profile.RelayBatonSettingsActivity" />
<activity android:name="io.nekohasekai.sagernet.ui.profile.BrookSettingsActivity" />
<activity android:name="io.nekohasekai.sagernet.ui.profile.ChainSettingsActivity" />
<activity android:name="io.nekohasekai.sagernet.ui.RouteSettingsActivity" />

Expand Down
37 changes: 37 additions & 0 deletions app/src/main/java/io/nekohasekai/sagernet/bg/ProxyInstance.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.ProxyEntity
import io.nekohasekai.sagernet.database.SagerDatabase
import io.nekohasekai.sagernet.fmt.V2rayBuildResult
import io.nekohasekai.sagernet.fmt.brook.BrookBean
import io.nekohasekai.sagernet.fmt.buildV2RayConfig
import io.nekohasekai.sagernet.fmt.buildXrayConfig
import io.nekohasekai.sagernet.fmt.gson.gson
Expand Down Expand Up @@ -147,6 +148,9 @@ class ProxyInstance(val profile: ProxyEntity) {
Logs.d(it)
}
}
bean is BrookBean -> {
initPlugin("brook-plugin")
}
}
}
}
Expand Down Expand Up @@ -342,6 +346,39 @@ class ProxyInstance(val profile: ProxyEntity) {
"client", "--config", configFile.absolutePath
)

base.data.processes!!.start(commands)
}
bean is BrookBean -> {
if (needChain) error("brook is incompatible with chain")

val commands = mutableListOf(initPlugin("brook-plugin").path)

when (bean.protocol) {
"ws" -> {
commands.add("wsclient")
commands.add("--wsserver")
commands.add("ws://${bean.serverAddress}:${bean.serverPort}")
}
"wss" -> {
commands.add("wssclient")
commands.add("--wssserver")
commands.add("wss://${bean.serverAddress}:${bean.serverPort}")
}
else -> {
commands.add("client")
commands.add("--server")
commands.add("${bean.serverAddress}:${bean.serverPort}")
}
}

if (bean.password.isNotBlank()) {
commands.add("--password")
commands.add(bean.password)
}

commands.add("--socks5")
commands.add("127.0.0.1:$port")

base.data.processes!!.start(commands)
}
}
Expand Down
14 changes: 14 additions & 0 deletions app/src/main/java/io/nekohasekai/sagernet/database/ProxyEntity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.aidl.TrafficStats
import io.nekohasekai.sagernet.fmt.AbstractBean
import io.nekohasekai.sagernet.fmt.KryoConverters
import io.nekohasekai.sagernet.fmt.brook.BrookBean
import io.nekohasekai.sagernet.fmt.brook.toUri
import io.nekohasekai.sagernet.fmt.chain.ChainBean
import io.nekohasekai.sagernet.fmt.http.HttpBean
import io.nekohasekai.sagernet.fmt.http.toUri
Expand Down Expand Up @@ -83,6 +85,7 @@ data class ProxyEntity(
var naiveBean: NaiveBean? = null,
var ptBean: PingTunnelBean? = null,
var rbBean: RelayBatonBean? = null,
var brookBean: BrookBean? = null,
var chainBean: ChainBean? = null,
) : Parcelable {

Expand All @@ -98,6 +101,7 @@ data class ProxyEntity(
const val TYPE_NAIVE = 9
const val TYPE_PING_TUNNEL = 10
const val TYPE_RELAY_BATON = 11
const val TYPE_BROOK = 12

const val TYPE_CHAIN = 8

Expand Down Expand Up @@ -146,6 +150,7 @@ data class ProxyEntity(
TYPE_NAIVE -> naiveBean = KryoConverters.naiveDeserialize(byteArray)
TYPE_PING_TUNNEL -> ptBean = KryoConverters.pingTunnelDeserialize(byteArray)
TYPE_RELAY_BATON -> rbBean = KryoConverters.relayBatonDeserialize(byteArray)
TYPE_BROOK -> brookBean = KryoConverters.brookDeserialize(byteArray)

TYPE_CHAIN -> chainBean = KryoConverters.chainDeserialize(byteArray)
}
Expand Down Expand Up @@ -177,6 +182,7 @@ data class ProxyEntity(
TYPE_NAIVE -> "Naïve"
TYPE_PING_TUNNEL -> "PingTunnel"
TYPE_RELAY_BATON -> "relaybaton"
TYPE_BROOK -> "Brook"
TYPE_CHAIN -> chainName
else -> "Undefined type $type"
}
Expand Down Expand Up @@ -216,6 +222,7 @@ data class ProxyEntity(
TYPE_NAIVE -> naiveBean
TYPE_PING_TUNNEL -> ptBean
TYPE_RELAY_BATON -> rbBean
TYPE_BROOK -> brookBean

TYPE_CHAIN -> chainBean
else -> error("Undefined type $type")
Expand All @@ -235,6 +242,7 @@ data class ProxyEntity(
is NaiveBean -> toUri()
is PingTunnelBean -> toUri()
is RelayBatonBean -> toUri()
is BrookBean -> toUri()
else -> null
}
}
Expand All @@ -253,6 +261,7 @@ data class ProxyEntity(
TYPE_CHAIN -> false
TYPE_PING_TUNNEL -> true
TYPE_RELAY_BATON -> true
TYPE_BROOK -> true
else -> error("Undefined type $type")
}
}
Expand Down Expand Up @@ -349,6 +358,10 @@ data class ProxyEntity(
type = TYPE_RELAY_BATON
rbBean = bean
}
is BrookBean -> {
type = TYPE_BROOK
brookBean = bean
}
is ChainBean -> {
type = TYPE_CHAIN
chainBean = bean
Expand All @@ -371,6 +384,7 @@ data class ProxyEntity(
TYPE_NAIVE -> NaiveSettingsActivity::class.java
TYPE_PING_TUNNEL -> PingTunnelSettingsActivity::class.java
TYPE_RELAY_BATON -> RelayBatonSettingsActivity::class.java
TYPE_BROOK -> BrookSettingsActivity::class.java
TYPE_CHAIN -> ChainSettingsActivity::class.java
else -> throw IllegalArgumentException()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import kotlinx.coroutines.launch

@Database(
entities = [ProxyGroup::class, ProxyEntity::class, RuleEntity::class, KeyValuePair::class],
version = 4
version = 5
)
@TypeConverters(value = [KryoConverters::class, GsonConverters::class])
@GenerateRoomMigrations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import io.nekohasekai.sagernet.fmt.brook.BrookBean;
import io.nekohasekai.sagernet.fmt.chain.ChainBean;
import io.nekohasekai.sagernet.fmt.http.HttpBean;
import io.nekohasekai.sagernet.fmt.naive.NaiveBean;
Expand Down Expand Up @@ -158,4 +159,10 @@ public static RelayBatonBean relayBatonDeserialize(byte[] bytes) {
return deserialize(new RelayBatonBean(), bytes);
}

@TypeConverter
public static BrookBean brookDeserialize(byte[] bytes) {
if (ArrayUtil.isEmpty(bytes)) return null;
return deserialize(new BrookBean(), bytes);
}

}
65 changes: 65 additions & 0 deletions app/src/main/java/io/nekohasekai/sagernet/fmt/brook/BrookBean.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/******************************************************************************
* *
* Copyright (C) 2021 by nekohasekai <sekai@neko.services> *
* Copyright (C) 2021 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2021 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
******************************************************************************/

package io.nekohasekai.sagernet.fmt.brook;

import androidx.annotation.NonNull;

import com.esotericsoftware.kryo.io.ByteBufferInput;
import com.esotericsoftware.kryo.io.ByteBufferOutput;

import io.nekohasekai.sagernet.fmt.AbstractBean;
import io.nekohasekai.sagernet.fmt.KryoConverters;

public class BrookBean extends AbstractBean {

public String protocol;
public String password;

@Override
public void initDefaultValues() {
super.initDefaultValues();
if (protocol == null) protocol = "";
if (password == null) password = "";
}

@Override
public void serialize(ByteBufferOutput output) {
output.writeInt(0);
super.serialize(output);
output.writeString(protocol);
output.writeString(password);
}

@Override
public void deserialize(ByteBufferInput input) {
int version = input.readInt();
super.deserialize(input);
protocol = input.readString();
password = input.readString();
}

@NonNull
@Override
public BrookBean clone() {
return KryoConverters.deserialize(new BrookBean(), KryoConverters.serialize(this));
}
}
77 changes: 77 additions & 0 deletions app/src/main/java/io/nekohasekai/sagernet/fmt/brook/BrookFmt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/******************************************************************************
* *
* Copyright (C) 2021 by nekohasekai <sekai@neko.services> *
* Copyright (C) 2021 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2021 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
******************************************************************************/

package io.nekohasekai.sagernet.fmt.brook

import io.nekohasekai.sagernet.fmt.AbstractBean
import io.nekohasekai.sagernet.fmt.socks.SOCKSBean
import io.nekohasekai.sagernet.ktx.applyDefaultValues
import io.nekohasekai.sagernet.ktx.unUrlSafe
import io.nekohasekai.sagernet.ktx.urlSafe

// https://txthinking.github.io/brook/#/brook-link
fun parseBrook(text: String): AbstractBean {
var server = text.substringAfter("brook://").unUrlSafe()
if (server.startsWith("socks5://")) {
server = server.substringAfter("://")
val bean = SOCKSBean()
bean.serverAddress = server.substringBefore(":")
bean.serverPort = server.substringAfter(":").substringBefore(" ").toInt()
server = server.substringAfter(":").substringAfter(" ")
if (server.contains(" ")) {
bean.username = server.substringBefore(" ")
bean.password = server.substringAfter(" ")
}
return bean.applyDefaultValues()
}

val bean = BrookBean()

if (server.startsWith("ws://")) {
bean.protocol = "ws"
server = server.substringAfter("://")
} else if (server.startsWith("wss://")) {
bean.protocol = "wss"
server = server.substringAfter("://")
} else {
bean.protocol = ""
}

bean.serverAddress = server.substringBefore(":")
bean.serverPort = server.substringAfter(":").substringBefore(" ").toInt()
server = server.substringAfter(":")
if (server.contains(" ")) {
bean.password = server.substringAfter(" ")
}
return bean.applyDefaultValues()
}

fun BrookBean.toUri(): String {
var server = when (protocol) {
"ws" -> "ws://$serverAddress:$serverPort"
"wss" -> "wss://$serverAddress:$serverPort"
else -> "$serverAddress:$serverPort"
}
if (password.isNotBlank()) {
server = "$server $password"
}
return "brook://" + server.urlSafe()
}
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ class ConfigurationFragment @JvmOverloads constructor(
R.id.action_new_relay_baton -> {
startActivity(Intent(requireActivity(), RelayBatonSettingsActivity::class.java))
}
R.id.action_new_brook -> {
startActivity(Intent(requireActivity(), BrookSettingsActivity::class.java))
}
R.id.action_new_chain -> {
startActivity(Intent(requireActivity(), ChainSettingsActivity::class.java))
}
Expand Down
Loading

0 comments on commit 7771636

Please sign in to comment.