2023-11-17 01:44:01 -05:00
|
|
|
<?php
|
|
|
|
namespace App\Protocols;
|
|
|
|
|
|
|
|
use App\Utils\Helper;
|
|
|
|
|
|
|
|
class SingBox
|
|
|
|
{
|
2023-11-23 11:02:33 -05:00
|
|
|
public $flag = 'sing-box,Hiddify';
|
2023-11-17 01:44:01 -05:00
|
|
|
private $servers;
|
|
|
|
private $user;
|
|
|
|
|
|
|
|
public function __construct($user, $servers, array $options = null)
|
|
|
|
{
|
|
|
|
$this->user = $user;
|
|
|
|
$this->servers = $servers;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function handle()
|
|
|
|
{
|
|
|
|
$appName = config('app_name', 'V2Board');
|
|
|
|
$config = $this->loadConfig();
|
|
|
|
$outbounds = $this->buildOutbounds();
|
|
|
|
$config['outbounds'] = $outbounds;
|
|
|
|
|
|
|
|
return json_encode($config);
|
|
|
|
//return response($config, 200);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function loadConfig()
|
|
|
|
{
|
|
|
|
$defaultConfig = base_path('resources/rules/default.sing-box.json');
|
|
|
|
$customConfig = base_path('resources/rules/custom.sing-box.json');
|
|
|
|
$jsonData = file_exists($customConfig) ? file_get_contents($customConfig) : file_get_contents($defaultConfig);
|
|
|
|
|
|
|
|
return json_decode($jsonData, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function buildOutbounds()
|
|
|
|
{
|
|
|
|
$outbounds = [];
|
|
|
|
|
|
|
|
$selector = [
|
|
|
|
"tag" => "节点选择",
|
|
|
|
"type" => "selector",
|
|
|
|
"default" => "自动选择",
|
|
|
|
"outbounds" => ["自动选择"]
|
|
|
|
];
|
|
|
|
|
|
|
|
$urltest = [
|
|
|
|
"tag" => "自动选择",
|
|
|
|
"type" => "urltest",
|
|
|
|
"outbounds" => []
|
|
|
|
];
|
|
|
|
|
|
|
|
$outbounds[] = &$selector;
|
|
|
|
|
|
|
|
foreach ($this->servers as $item) {
|
|
|
|
if ($item['type'] === 'shadowsocks') {
|
|
|
|
$ssConfig = $this->buildShadowsocks($this->user['uuid'], $item);
|
|
|
|
$outbounds[] = $ssConfig;
|
|
|
|
$selector['outbounds'][] = $item['name'];
|
|
|
|
$urltest['outbounds'][] = $item['name'];
|
|
|
|
}
|
|
|
|
if ($item['type'] === 'trojan') {
|
|
|
|
$trojanConfig = $this->buildTrojan($this->user['uuid'], $item);
|
|
|
|
$outbounds[] = $trojanConfig;
|
|
|
|
$selector['outbounds'][] = $item['name'];
|
|
|
|
$urltest['outbounds'][] = $item['name'];
|
|
|
|
}
|
|
|
|
if ($item['type'] === 'vmess') {
|
|
|
|
$vmessConfig = $this->buildVmess($this->user['uuid'], $item);
|
|
|
|
$outbounds[] = $vmessConfig;
|
|
|
|
$selector['outbounds'][] = $item['name'];
|
|
|
|
$urltest['outbounds'][] = $item['name'];
|
|
|
|
}
|
|
|
|
if ($item['type'] === 'vless') {
|
|
|
|
$vlessConfig = $this->buildVless($this->user['uuid'], $item);
|
|
|
|
$outbounds[] = $vlessConfig;
|
|
|
|
$selector['outbounds'][] = $item['name'];
|
|
|
|
$urltest['outbounds'][] = $item['name'];
|
|
|
|
}
|
|
|
|
if ($item['type'] === 'hysteria') {
|
|
|
|
$hysteriaConfig = $this->buildHysteria($this->user['uuid'], $item, $this->user);
|
|
|
|
$outbounds[] = $hysteriaConfig;
|
|
|
|
$selector['outbounds'][] = $item['name'];
|
|
|
|
$urltest['outbounds'][] = $item['name'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$outbounds[] = [ "tag" => "direct", "type" => "direct" ];
|
|
|
|
$outbounds[] = [ "tag" => "block", "type" => "block" ];
|
|
|
|
$outbounds[] = [ "tag" => "dns-out", "type" => "dns" ];
|
|
|
|
$outbounds[] = $urltest;
|
|
|
|
|
|
|
|
return $outbounds;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function buildShadowsocks($password, $server)
|
|
|
|
{
|
|
|
|
if ($server['cipher'] === '2022-blake3-aes-128-gcm') {
|
|
|
|
$serverKey = Helper::getServerKey($server['created_at'], 16);
|
|
|
|
$userKey = Helper::uuidToBase64($password, 16);
|
|
|
|
$password = "{$serverKey}:{$userKey}";
|
|
|
|
}
|
|
|
|
if ($server['cipher'] === '2022-blake3-aes-256-gcm') {
|
|
|
|
$serverKey = Helper::getServerKey($server['created_at'], 32);
|
|
|
|
$userKey = Helper::uuidToBase64($password, 32);
|
|
|
|
$password = "{$serverKey}:{$userKey}";
|
|
|
|
}
|
|
|
|
$array = [];
|
|
|
|
$array['tag'] = $server['name'];
|
|
|
|
$array['type'] = 'shadowsocks';
|
|
|
|
$array['server'] = $server['host'];
|
|
|
|
$array['server_port'] = $server['port'];
|
|
|
|
$array['method'] = $server['cipher'];
|
|
|
|
$array['password'] = $password;
|
|
|
|
|
|
|
|
return $array;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected function buildVmess($uuid, $server)
|
|
|
|
{
|
|
|
|
$array = [];
|
|
|
|
$array['tag'] = $server['name'];
|
|
|
|
$array['type'] = 'vmess';
|
|
|
|
$array['server'] = $server['host'];
|
|
|
|
$array['server_port'] = $server['port'];
|
|
|
|
$array['uuid'] = $uuid;
|
|
|
|
$array['security'] = 'auto';
|
|
|
|
$array['alter_id'] = 0;
|
|
|
|
$array['transport']= [];
|
|
|
|
|
|
|
|
if ($server['tls']) {
|
|
|
|
$tlsConfig = [];
|
|
|
|
$tlsConfig['enabled'] = true;
|
|
|
|
if ($server['tlsSettings']) {
|
|
|
|
$tlsSettings = $server['tlsSettings'] ?? [];
|
|
|
|
$tlsConfig['insecure'] = $tlsSettings['allowInsecure'] ? true : false;
|
|
|
|
$tlsConfig['server_name'] = $tlsSettings['serverName'] ?? null;
|
|
|
|
}
|
|
|
|
$array['tls'] = $tlsConfig;
|
|
|
|
}
|
|
|
|
if ($server['network'] === 'tcp') {
|
|
|
|
$tcpSettings = $server['networkSettings'];
|
|
|
|
if (isset($tcpSettings['header']['type']) && $tcpSettings['header']['type'] == 'http') $array['transport']['type'] = $tcpSettings['header']['type'];
|
|
|
|
if (isset($tcpSettings['header']['request']['path'])) $array['transport']['path'] = $tcpSettings['header']['request']['path'];
|
|
|
|
}
|
|
|
|
if ($server['network'] === 'ws') {
|
|
|
|
$array['transport']['type'] ='ws';
|
|
|
|
if ($server['networkSettings']) {
|
|
|
|
$wsSettings = $server['networkSettings'];
|
|
|
|
if (isset($wsSettings['path']) && !empty($wsSettings['path'])) $array['transport']['path'] = $wsSettings['path'];
|
|
|
|
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host'])) $array['transport']['headers'] = ['Host' => array($wsSettings['headers']['Host'])];
|
|
|
|
$array['transport']['max_early_data'] = 2048;
|
|
|
|
$array['transport']['early_data_header_name'] = 'Sec-WebSocket-Protocol';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($server['network'] === 'grpc') {
|
|
|
|
$array['transport']['type'] ='grpc';
|
|
|
|
if ($server['networkSettings']) {
|
|
|
|
$grpcSettings = $server['networkSettings'];
|
|
|
|
if (isset($grpcSettings['serviceName'])) $array['transport']['service_name'] = $grpcSettings['serviceName'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $array;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function buildVless($password, $server)
|
|
|
|
{
|
|
|
|
$array = [
|
|
|
|
"type" => "vless",
|
|
|
|
"tag" => $server['name'],
|
|
|
|
"server" => $server['host'],
|
|
|
|
"server_port" => $server['port'],
|
|
|
|
"uuid" => $password,
|
|
|
|
"packet_encoding" => "xudp"
|
|
|
|
];
|
|
|
|
|
|
|
|
$tlsSettings = $server['tls_settings'] ?? [];
|
|
|
|
|
|
|
|
if ($server['tls']) {
|
|
|
|
$tlsConfig = [];
|
|
|
|
$tlsConfig['enabled'] = true;
|
|
|
|
$array['flow'] = !empty($server['flow']) ? $server['flow'] : "";
|
|
|
|
$tlsSettings = $server['tls_settings'] ?? [];
|
|
|
|
if ($server['tls_settings']) {
|
|
|
|
$tlsConfig['insecure'] = isset($tlsSettings['allow_insecure']) && $tlsSettings['allow_insecure'] == 1 ? true : false;
|
|
|
|
$tlsConfig['server_name'] = $tlsSettings['server_name'] ?? null;
|
|
|
|
if ($server['tls'] == 2) {
|
|
|
|
$tlsConfig['reality'] = [
|
|
|
|
'enabled' => true,
|
|
|
|
'public_key' => $tlsSettings['public_key'],
|
|
|
|
'short_id' => $tlsSettings['short_id']
|
|
|
|
];
|
|
|
|
}
|
|
|
|
$fingerprints = ['chrome', 'firefox', 'safari', 'ios', 'edge', 'qq'];
|
|
|
|
$tlsConfig['utls'] = [
|
|
|
|
"enabled" => true,
|
|
|
|
"fingerprint" => $fingerprints[array_rand($fingerprints)]
|
|
|
|
];
|
|
|
|
}
|
|
|
|
$array['tls'] = $tlsConfig;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($server['network'] === 'tcp') {
|
|
|
|
$tcpSettings = $server['network_settings'];
|
|
|
|
if (isset($tcpSettings['header']['type']) && $tcpSettings['header']['type'] == 'http') $array['transport']['type'] = $tcpSettings['header']['type'];
|
|
|
|
if (isset($tcpSettings['header']['request']['path'])) $array['transport']['path'] = $tcpSettings['header']['request']['path'];
|
|
|
|
}
|
|
|
|
if ($server['network'] === 'ws') {
|
|
|
|
$array['transport']['type'] ='ws';
|
|
|
|
if ($server['network_settings']) {
|
|
|
|
$wsSettings = $server['network_settings'];
|
|
|
|
if (isset($wsSettings['path']) && !empty($wsSettings['path'])) $array['transport']['path'] = $wsSettings['path'];
|
|
|
|
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host'])) $array['transport']['headers'] = ['Host' => array($wsSettings['headers']['Host'])];
|
|
|
|
$array['transport']['max_early_data'] = 2048;
|
|
|
|
$array['transport']['early_data_header_name'] = 'Sec-WebSocket-Protocol';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($server['network'] === 'grpc') {
|
|
|
|
$array['transport']['type'] ='grpc';
|
|
|
|
if ($server['network_settings']) {
|
|
|
|
$grpcSettings = $server['network_settings'];
|
|
|
|
if (isset($grpcSettings['serviceName'])) $array['transport']['service_name'] = $grpcSettings['serviceName'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($server['network'] === 'h2') {
|
|
|
|
$array['transport']['type'] = 'http';
|
|
|
|
if ($server['network_settings']) {
|
|
|
|
$h2Settings = $server['network_settings'];
|
|
|
|
if (isset($h2Settings['host'])) $array['transport']['host'] = array($h2Settings['host']);
|
|
|
|
if (isset($h2Settings['path'])) $array['transport']['path'] = $h2Settings['path'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $array;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function buildTrojan($password, $server)
|
|
|
|
{
|
|
|
|
$array = [];
|
|
|
|
$array['tag'] = $server['name'];
|
|
|
|
$array['type'] = 'trojan';
|
|
|
|
$array['server'] = $server['host'];
|
|
|
|
$array['server_port'] = $server['port'];
|
|
|
|
$array['password'] = $password;
|
|
|
|
|
|
|
|
$array['tls'] = [
|
|
|
|
'enabled' => true,
|
|
|
|
'insecure' => $server['allow_insecure'] ? true : false,
|
|
|
|
'server_name' => $server['server_name']
|
|
|
|
];
|
|
|
|
|
|
|
|
if(isset($server['network']) && in_array($server['network'], ["grpc", "ws"])){
|
|
|
|
$array['transport']['type'] = $server['network'];
|
|
|
|
// grpc配置
|
|
|
|
if($server['network'] === "grpc" && isset($server['network_settings']['serviceName'])) {
|
|
|
|
$array['transport']['service_name'] = $server['network_settings']['serviceName'];
|
|
|
|
}
|
|
|
|
// ws配置
|
|
|
|
if($server['network'] === "ws") {
|
|
|
|
if(isset($server['network_settings']['path'])) {
|
|
|
|
$array['transport']['path'] = $server['network_settings']['path'];
|
|
|
|
}
|
|
|
|
if(isset($server['network_settings']['headers']['Host'])){
|
|
|
|
$array['transport']['headers'] = ['Host' => array($server['network_settings']['headers']['Host'])];
|
|
|
|
}
|
|
|
|
$array['transport']['max_early_data'] = 2048;
|
|
|
|
$array['transport']['early_data_header_name'] = 'Sec-WebSocket-Protocol';
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return $array;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function buildHysteria($password, $server, $user)
|
|
|
|
{
|
|
|
|
$array = [
|
|
|
|
'server' => $server['host'],
|
|
|
|
'server_port' => $server['port'],
|
|
|
|
'tls' => [
|
|
|
|
'enabled' => true,
|
|
|
|
'insecure' => $server['insecure'] ? true : false,
|
|
|
|
'server_name' => $server['server_name']
|
|
|
|
]
|
|
|
|
];
|
|
|
|
|
|
|
|
if (is_null($server['version']) || $server['version'] == 1) {
|
|
|
|
$array['auth_str'] = $password;
|
|
|
|
$array['tag'] = $server['name'];
|
|
|
|
$array['type'] = 'hysteria';
|
|
|
|
$array['up_mbps'] = $user->speed_limit ? min($server['down_mbps'], $user->speed_limit) : $server['down_mbps'];
|
|
|
|
$array['down_mbps'] = $user->speed_limit ? min($server['up_mbps'], $user->speed_limit) : $server['up_mbps'];
|
|
|
|
if (isset($server['obfs']) && isset($server['obfs_password'])) {
|
|
|
|
$array['obfs'] = $server['obfs_password'];
|
|
|
|
}
|
|
|
|
|
|
|
|
$array['disable_mtu_discovery'] = true;
|
|
|
|
|
|
|
|
} elseif ($server['version'] == 2) {
|
|
|
|
$array['password'] = $password;
|
|
|
|
$array['tag'] = $server['name'];
|
|
|
|
$array['type'] = 'hysteria2';
|
|
|
|
$array['password'] = $password;
|
|
|
|
|
|
|
|
if (isset($server['obfs'])) {
|
|
|
|
$array['obfs']['type'] = $server['obfs'];
|
|
|
|
$array['obfs']['password'] = $server['obfs_password'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $array;
|
|
|
|
}
|
|
|
|
}
|