mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-14 20:48:17 +08:00
🦄 Sync 2026-06-05 01:27:09
This commit is contained in:
1 parent
4c613c876b
commit
23b721b464
63 files changed
+10393
-11351
No files matched your search
@@ -1,119 +1,457 @@
|
||||
module YAML
|
||||
class << self
|
||||
alias_method :load, :unsafe_load if YAML.respond_to? :unsafe_load
|
||||
alias_method :original_dump, :dump
|
||||
alias_method :original_load_file, :load_file
|
||||
end
|
||||
class << self
|
||||
alias_method :load, :unsafe_load if YAML.respond_to? :unsafe_load
|
||||
alias_method :original_dump, :dump
|
||||
alias_method :original_load_file, :load_file
|
||||
end
|
||||
|
||||
def self.LOG(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Info] " + "#{info}"
|
||||
end
|
||||
def self.LOG(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Info] " + "#{info}"
|
||||
end
|
||||
|
||||
def self.LOG_ERROR(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Error] " + "#{info}"
|
||||
end
|
||||
def self.LOG_ERROR(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Error] " + "#{info}"
|
||||
end
|
||||
|
||||
def self.LOG_WARN(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Warning] " + "#{info}"
|
||||
end
|
||||
def self.LOG_WARN(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Warning] " + "#{info}"
|
||||
end
|
||||
|
||||
def self.LOG_TIP(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Tip] " + "#{info}"
|
||||
end
|
||||
def self.LOG_TIP(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Tip] " + "#{info}"
|
||||
end
|
||||
|
||||
# Keep `short-id` as string before YAML parsing so leading zeros are preserved.
|
||||
# This is required for REALITY short-id values like `00000000`.
|
||||
def self.load_file(filename, *args, **kwargs)
|
||||
yaml_content = File.read(filename)
|
||||
processed_content = fix_short_id_quotes(yaml_content)
|
||||
def self.load_file(filename, *args, **kwargs)
|
||||
yaml_content = File.read(filename)
|
||||
processed_content = fix_short_id_quotes(yaml_content)
|
||||
|
||||
if kwargs.empty?
|
||||
load(processed_content, *args)
|
||||
else
|
||||
load(processed_content, *args, **kwargs)
|
||||
end
|
||||
end
|
||||
load(processed_content, *args, **kwargs)
|
||||
end
|
||||
|
||||
def self.dump(obj, io = nil, **options)
|
||||
begin
|
||||
if io.nil?
|
||||
yaml_content = original_dump(obj, **options)
|
||||
fix_short_id_quotes(yaml_content)
|
||||
elsif io.respond_to?(:write)
|
||||
require 'stringio'
|
||||
temp_io = StringIO.new
|
||||
original_dump(obj, temp_io, **options)
|
||||
yaml_content = temp_io.string
|
||||
processed_content = fix_short_id_quotes(yaml_content)
|
||||
io.write(processed_content)
|
||||
io
|
||||
else
|
||||
yaml_content = original_dump(obj, io, **options)
|
||||
fix_short_id_quotes(yaml_content)
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("Write file failed:【%s】" % [e.message])
|
||||
nil
|
||||
end
|
||||
end
|
||||
def self.dump(obj, io = nil, **options)
|
||||
begin
|
||||
yaml_content = original_dump(obj, **options)
|
||||
processed = fix_short_id_quotes(yaml_content)
|
||||
if io.nil?
|
||||
processed
|
||||
elsif io.respond_to?(:write)
|
||||
io.write(processed)
|
||||
io
|
||||
else
|
||||
processed
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("Write file failed:【%s】" % [e.message])
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
SHORT_ID_REGEX = /^(\s*)short-id:\s*(.*)$/
|
||||
LIST_ITEM_REGEX = /^(\s*)-\s*(.*)$/
|
||||
KEY_REGEX = /^(\s*)([a-zA-Z0-9_-]+):\s*(.*)$/
|
||||
QUOTED_VALUE_REGEX = /^["'].*["']$/
|
||||
# fix_short_id_quotes:
|
||||
# Purpose: ensure YAML `short-id` values are emitted with the intended
|
||||
# representation when dumping or re-writing YAML files.
|
||||
# Behavior:
|
||||
# - Non-null, non-empty scalar `short-id` values (and items inside
|
||||
# `short-id` sequences) are written as double-quoted strings.
|
||||
# - Empty strings are preserved as empty quoted strings ("" remains "").
|
||||
# - Null values are preserved and may be emitted explicitly (e.g. `! "").
|
||||
# Lastly, use gsub to clean up any `! ""` tags
|
||||
# Examples:
|
||||
# Input: short-id: 00000000 -> Output: short-id: "00000000"
|
||||
# Input: short-id: "" -> Output: short-id: ""
|
||||
# Input: short-id: "abc123" -> Output: short-id: "abc123"
|
||||
# Input: short-id: "1600e237" -> Output: short-id: "1600e237"
|
||||
# Input: short-id: null -> Output: short-id: ""
|
||||
|
||||
# Inline map support, e.g. reality-opts: { ..., short-id: 00000000 }
|
||||
INLINE_SHORT_ID_REGEX = /(short-id:\s*)(?!["'\[])([^\s,"'{}\[\]\n\r]+)(?=\s*(?:[,}\]\n\r]|$))/m.freeze
|
||||
def self.fix_short_id_quotes(yaml_content)
|
||||
return yaml_content unless yaml_content.include?('short-id:')
|
||||
|
||||
def self.fix_short_id_quotes(yaml_content)
|
||||
return yaml_content unless yaml_content.include?('short-id:')
|
||||
begin
|
||||
stream = Psych.parse_stream(yaml_content)
|
||||
|
||||
begin
|
||||
# First, normalize inline-map style unquoted short-id.
|
||||
processed = yaml_content.gsub(INLINE_SHORT_ID_REGEX) do
|
||||
"#{$1}\"#{$2}\""
|
||||
end
|
||||
traverse = lambda do |node|
|
||||
case node
|
||||
when Psych::Nodes::Mapping
|
||||
children = node.children || []
|
||||
i = 0
|
||||
while i < children.length
|
||||
key = children[i]
|
||||
val = children[i + 1]
|
||||
if key.is_a?(Psych::Nodes::Scalar) && key.value == 'short-id'
|
||||
if val.is_a?(Psych::Nodes::Scalar)
|
||||
is_null_scalar = (val.tag == 'tag:yaml.org,2002:null') || (val.tag == '!!null') || (val.value =~ /^\s*(~|null|NULL|Null)\s*$/)
|
||||
unless is_null_scalar
|
||||
val.tag = nil
|
||||
val.style = defined?(Psych::Nodes::Scalar::DOUBLE_QUOTED) ? Psych::Nodes::Scalar::DOUBLE_QUOTED : 2
|
||||
end
|
||||
elsif val.is_a?(Psych::Nodes::Sequence)
|
||||
val.children.each do |child|
|
||||
if child.is_a?(Psych::Nodes::Scalar)
|
||||
is_null_child = (child.tag == 'tag:yaml.org,2002:null') || (child.tag == '!!null') || (child.value =~ /^\s*(~|null|NULL|Null)\s*$/)
|
||||
unless is_null_child
|
||||
child.tag = nil
|
||||
child.style = defined?(Psych::Nodes::Scalar::DOUBLE_QUOTED) ? Psych::Nodes::Scalar::DOUBLE_QUOTED : 2
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
traverse.call(key) if key.respond_to?(:children)
|
||||
traverse.call(val) if val.respond_to?(:children)
|
||||
end
|
||||
i += 2
|
||||
end
|
||||
when Psych::Nodes::Sequence
|
||||
(node.children || []).each { |c| traverse.call(c) }
|
||||
when Psych::Nodes::Document, Psych::Nodes::Stream
|
||||
(node.children || []).each { |c| traverse.call(c) }
|
||||
else
|
||||
if node.respond_to?(:children)
|
||||
(node.children || []).each { |c| traverse.call(c) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
lines = processed.lines
|
||||
short_id_indices = lines.each_index.select { |i| lines[i] =~ SHORT_ID_REGEX }
|
||||
short_id_indices.each do |short_id_index|
|
||||
line = lines[short_id_index]
|
||||
if line =~ SHORT_ID_REGEX
|
||||
indent = $1
|
||||
value = $2.strip
|
||||
if value.empty?
|
||||
(short_id_index + 1...lines.size).each do |i|
|
||||
line = lines[i]
|
||||
next if line.strip.empty?
|
||||
if line[/^\s*/].length <= short_id_indent_len
|
||||
break
|
||||
end
|
||||
if line =~ LIST_ITEM_REGEX
|
||||
indent = $1
|
||||
value = $2.strip
|
||||
if value =~ KEY_REGEX
|
||||
break
|
||||
end
|
||||
if value !~ QUOTED_VALUE_REGEX
|
||||
lines[i] = "#{indent}- \"#{value}\"\n"
|
||||
end
|
||||
elsif line =~ KEY_REGEX
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
if value !~ QUOTED_VALUE_REGEX
|
||||
lines[short_id_index] = "#{indent}short-id: \"#{value}\"\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
lines.join
|
||||
rescue => e
|
||||
LOG_ERROR("Fix short-id values type failed:【%s】" % [e.message])
|
||||
yaml_content
|
||||
end
|
||||
end
|
||||
end
|
||||
stream.children.each do |doc_node|
|
||||
if doc_node.is_a?(Psych::Nodes::Document)
|
||||
traverse.call(doc_node.root) if doc_node.root
|
||||
end
|
||||
end
|
||||
|
||||
if stream.respond_to?(:to_yaml)
|
||||
processed_yaml = stream.to_yaml
|
||||
processed_yaml = processed_yaml.gsub(/^([ \t]*short-id:\s*)!\s*/, "\\1")
|
||||
processed_yaml
|
||||
else
|
||||
yaml_content
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("Fix short-id values type failed:【%s】" % [e.message])
|
||||
yaml_content
|
||||
end
|
||||
end
|
||||
|
||||
def self.overwrite(base, override)
|
||||
return override if base.nil?
|
||||
return base if override.nil?
|
||||
|
||||
current_key = nil
|
||||
current_operation = nil
|
||||
|
||||
begin
|
||||
case override
|
||||
when Hash
|
||||
result = base.is_a?(Hash) ? base.dup : {}
|
||||
|
||||
override.each do |key, value|
|
||||
current_key = key
|
||||
processed_key, operation = parse_key(key)
|
||||
current_operation = operation
|
||||
|
||||
applied = apply_operation(result[processed_key], value, operation)
|
||||
if applied.equal?(DELETED_SENTINEL)
|
||||
result.delete(processed_key)
|
||||
else
|
||||
result[processed_key] = applied
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
else
|
||||
override
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("YAML overwrite failed:【key: %s, operation: %s, error: %s】" % [current_key, current_operation, e.message])
|
||||
base
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.parse_key(key)
|
||||
key_str = key.to_s
|
||||
|
||||
# +<key>
|
||||
if key_str.start_with?('+<') && key_str.include?('>')
|
||||
close_idx = key_str.index('>')
|
||||
inner_key = key_str[2...close_idx]
|
||||
return inner_key, :prepend_array
|
||||
end
|
||||
|
||||
# <key>suffix
|
||||
if key_str.start_with?('<') && key_str.include?('>')
|
||||
close_idx = key_str.index('>')
|
||||
inner_key = key_str[1...close_idx]
|
||||
suffix = key_str[(close_idx + 1)..-1]
|
||||
return inner_key, determine_operation(suffix)
|
||||
end
|
||||
|
||||
# 前缀 +key
|
||||
if key_str.start_with?('+')
|
||||
return key_str[1..-1], :prepend_array
|
||||
end
|
||||
|
||||
# 尾部(支持 +, !, *, -)
|
||||
if key_str =~ /^(.*?)([+!*\-])$/
|
||||
return Regexp.last_match(1), determine_operation(Regexp.last_match(2))
|
||||
end
|
||||
|
||||
[key_str, :merge]
|
||||
end
|
||||
|
||||
def self.determine_operation(suffix)
|
||||
case suffix
|
||||
when '+'
|
||||
:append_array
|
||||
when '-'
|
||||
:delete
|
||||
when '!'
|
||||
:force_overwrite
|
||||
when '*'
|
||||
:batch_update
|
||||
else
|
||||
:merge
|
||||
end
|
||||
end
|
||||
|
||||
def self.match_value(target, condition)
|
||||
return false if target.nil? || condition.nil?
|
||||
|
||||
begin
|
||||
if condition.is_a?(String) && condition.start_with?('/') && condition.end_with?('/')
|
||||
pattern = condition[1...-1]
|
||||
regexp = Regexp.new(pattern)
|
||||
if target.is_a?(Array)
|
||||
target.any? { |item| item.to_s =~ regexp }
|
||||
else
|
||||
target.to_s =~ regexp
|
||||
end
|
||||
elsif condition.is_a?(Array) && target.is_a?(Array)
|
||||
condition.all? { |c| target.include?(c) }
|
||||
else
|
||||
target == condition
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("YAML overwrite failed:【(match value) => target: %s, condition: %s, error: %s】" % [target, condition, e.message])
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def self.deep_dup(obj)
|
||||
case obj
|
||||
when Array
|
||||
obj.map { |x| deep_dup(x) }
|
||||
when Hash
|
||||
obj.transform_values { |v| deep_dup(v) }
|
||||
else
|
||||
obj.dup rescue obj
|
||||
end
|
||||
end
|
||||
|
||||
def self.merge_hash(base, value, prepend: false)
|
||||
if prepend
|
||||
result = {}
|
||||
|
||||
value.each do |k, v|
|
||||
if base.key?(k)
|
||||
result[k] = apply_operation(base[k], v, :merge)
|
||||
else
|
||||
result[k] = deep_dup(v)
|
||||
end
|
||||
end
|
||||
|
||||
base.each do |k, v|
|
||||
result[k] = deep_dup(v) unless result.key?(k)
|
||||
end
|
||||
|
||||
result
|
||||
else
|
||||
result = deep_dup(base)
|
||||
|
||||
value.each do |k, v|
|
||||
if result.key?(k)
|
||||
result[k] = apply_operation(result[k], v, :merge)
|
||||
else
|
||||
result[k] = deep_dup(v)
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
def self.delete_from_hash(base, value)
|
||||
result = deep_dup(base)
|
||||
|
||||
case value
|
||||
when Array
|
||||
value.each { |k| result.delete(k) }
|
||||
when Hash
|
||||
value.each do |k, v|
|
||||
if v.nil? || v == true
|
||||
result.delete(k)
|
||||
elsif result[k].is_a?(Hash) && v.is_a?(Hash)
|
||||
nested = apply_operation(result[k], v, :delete)
|
||||
if nested.equal?(DELETED_SENTINEL)
|
||||
result.delete(k)
|
||||
else
|
||||
result[k] = nested
|
||||
end
|
||||
else
|
||||
result.delete(k)
|
||||
end
|
||||
end
|
||||
else
|
||||
result.delete(value)
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
DELETED_SENTINEL = Object.new.freeze
|
||||
|
||||
def self.apply_operation(base, value, operation)
|
||||
case operation
|
||||
when :delete
|
||||
if base.is_a?(Array) && value.is_a?(Array)
|
||||
base - value
|
||||
elsif base.is_a?(Array) && !value.nil?
|
||||
base - [value]
|
||||
elsif base.is_a?(Hash)
|
||||
delete_from_hash(base, value)
|
||||
else
|
||||
DELETED_SENTINEL
|
||||
end
|
||||
when :force_overwrite
|
||||
deep_dup(value)
|
||||
when :prepend_array
|
||||
if base.is_a?(Array) && value.is_a?(Array)
|
||||
(deep_dup(value) + base).uniq
|
||||
elsif base.is_a?(Hash) && value.is_a?(Hash)
|
||||
merge_hash(base, value, prepend: true)
|
||||
else
|
||||
deep_dup(value)
|
||||
end
|
||||
when :append_array
|
||||
if base.is_a?(Array) && value.is_a?(Array)
|
||||
base_dup = base.dup
|
||||
deep_dup(value).each { |v| base_dup.delete(v) }
|
||||
base_dup + deep_dup(value)
|
||||
elsif base.is_a?(Hash) && value.is_a?(Hash)
|
||||
merge_hash(base, value, prepend: false)
|
||||
else
|
||||
deep_dup(value)
|
||||
end
|
||||
when :batch_update
|
||||
batch_update_items(base, value)
|
||||
when :merge
|
||||
if base.is_a?(Hash) && value.is_a?(Hash)
|
||||
overwrite(base, value)
|
||||
elsif value.nil?
|
||||
base
|
||||
else
|
||||
deep_dup(value)
|
||||
end
|
||||
else
|
||||
deep_dup(value)
|
||||
end
|
||||
end
|
||||
|
||||
def self.apply_set_fields(item, set_values)
|
||||
keys_to_delete = []
|
||||
|
||||
set_values.each do |k, v|
|
||||
processed_key, operation = parse_key(k)
|
||||
result = apply_operation(item[processed_key], v, operation)
|
||||
if result.equal?(DELETED_SENTINEL)
|
||||
keys_to_delete << processed_key
|
||||
else
|
||||
item[processed_key] = result
|
||||
end
|
||||
end
|
||||
|
||||
keys_to_delete.each { |k| item.delete(k) }
|
||||
end
|
||||
|
||||
def self.match_item(item, where_conditions, key = nil)
|
||||
where_conditions.all? do |k, v|
|
||||
if k == 'key' && !key.nil?
|
||||
match_value(key, v)
|
||||
elsif item.is_a?(Hash)
|
||||
match_value(item[k] || item[k.to_s], v)
|
||||
elsif item.is_a?(String) && k == 'value'
|
||||
match_value(item, v)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.batch_update_items(collection, update_spec)
|
||||
return collection unless update_spec.is_a?(Hash)
|
||||
|
||||
begin
|
||||
where_conditions = update_spec['where'] || {}
|
||||
set_values = update_spec['set'] || {}
|
||||
|
||||
if collection.is_a?(Array)
|
||||
result = collection.dup
|
||||
delete_indices = []
|
||||
|
||||
result.each_with_index do |item, index|
|
||||
match = match_item(item, where_conditions)
|
||||
|
||||
if match
|
||||
if item.is_a?(Hash)
|
||||
apply_set_fields(item, set_values)
|
||||
elsif item.is_a?(String) && set_values.key?('value')
|
||||
new_value = set_values['value']
|
||||
if new_value.nil?
|
||||
delete_indices << index
|
||||
else
|
||||
result[index] = deep_dup(new_value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
delete_indices.reverse_each { |i| result.delete_at(i) }
|
||||
result
|
||||
elsif collection.is_a?(Hash)
|
||||
if where_conditions.any? { |k, _| k != 'key' } &&
|
||||
match_item(collection, where_conditions)
|
||||
result = collection.dup
|
||||
apply_set_fields(result, set_values)
|
||||
result
|
||||
else
|
||||
result = collection.dup
|
||||
keys_to_delete = []
|
||||
|
||||
result.each do |key, value|
|
||||
next unless value.is_a?(Hash)
|
||||
match = match_item(value, where_conditions, key)
|
||||
|
||||
if match
|
||||
if set_values.key?('key-') || (set_values.key?('key') && set_values['key'].nil?)
|
||||
keys_to_delete << key
|
||||
else
|
||||
apply_set_fields(value, set_values)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
keys_to_delete.each { |k| result.delete(k) }
|
||||
result
|
||||
end
|
||||
elsif collection.nil?
|
||||
nil
|
||||
else
|
||||
collection
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("YAML overwrite failed:【(batch update) => update_spec: %s, error: %s】" % [update_spec, e.message])
|
||||
collection
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -86,17 +86,6 @@ DOWNLOAD_RESULT=$?
|
||||
|
||||
config_cus_up()
|
||||
{
|
||||
if [ -z "$CONFIG_PATH" ]; then
|
||||
for file_name in /etc/openclash/config/*
|
||||
do
|
||||
if [ -f "$file_name" ]; then
|
||||
CONFIG_PATH=$file_name
|
||||
break
|
||||
fi
|
||||
done
|
||||
uci -q set openclash.config.config_path="$CONFIG_PATH"
|
||||
uci commit openclash
|
||||
fi
|
||||
if [ -z "$subscribe_url_param" ]; then
|
||||
if [ -n "$key_match_param" ] || [ -n "$key_ex_match_param" ]; then
|
||||
LOG_OUT "Config File【$name】Start Picking Nodes..."
|
||||
@@ -192,6 +181,10 @@ config_su_check()
|
||||
mv "$CFG_FILE" "$CONFIG_FILE" 2>/dev/null
|
||||
LOG_OUT "Config File【$name】Update Successful!"
|
||||
fi
|
||||
if [ -z "$CONFIG_PATH" ]; then
|
||||
uci -q set openclash.config.config_path="$CONFIG_FILE"
|
||||
uci commit openclash
|
||||
fi
|
||||
if [ "$CONFIG_FILE" == "$CONFIG_PATH" ]; then
|
||||
restart=1
|
||||
fi
|
||||
@@ -335,13 +328,13 @@ sub_info_get()
|
||||
config_get "udp" "$section" "udp" ""
|
||||
config_get "skip_cert_verify" "$section" "skip_cert_verify" ""
|
||||
config_get "sort" "$section" "sort" ""
|
||||
config_get "convert_address" "$section" "convert_address" ""
|
||||
config_get "convert_address" "$section" "convert_address" "https://api.asailor.org/sub"
|
||||
config_get "template" "$section" "template" ""
|
||||
config_get "node_type" "$section" "node_type" ""
|
||||
config_get "rule_provider" "$section" "rule_provider" ""
|
||||
config_get "custom_template_url" "$section" "custom_template_url" ""
|
||||
config_get "de_ex_keyword" "$section" "de_ex_keyword" ""
|
||||
config_get "sub_ua" "$section" "sub_ua" "clash.meta"
|
||||
config_get "sub_ua" "$section" "sub_ua" "clash-verge/v2.4.5"
|
||||
|
||||
CONFIG_FILE="/etc/openclash/config/$name.yaml"
|
||||
CFG_FILE="/tmp/$name.yaml"
|
||||
|
||||
@@ -74,7 +74,7 @@ DOWNLOAD_FILE_CURL() {
|
||||
fi
|
||||
else
|
||||
CURL_OUTPUT=$(curl -w "\n%{http_code}" -SsL --connect-timeout 30 -m 60 --speed-time 30 --speed-limit 1 --retry 2 -H "User-Agent: ${DOWNLOAD_UA}" "$DOWNLOAD_URL" -o "$DOWNLOAD_PATH" 2>&1)
|
||||
EXIR_CODE=${PIPESTATUS[0]}
|
||||
EXIR_CODE=$?
|
||||
HTTP_CODE=$(echo "$CURL_OUTPUT" | tail -n1)
|
||||
|
||||
if [ "$EXIR_CODE" -ne 0 ] || [ "$HTTP_CODE" -ne 200 ]; then
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 888>"/tmp/lock/openclash_update_databases.lock" 2>/dev/null
|
||||
flock -x 888 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 888 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_update_databases.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
small_flash_memory=$(uci_get_config "small_flash_memory")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
restart=0
|
||||
|
||||
update_one() {
|
||||
local type="$1"
|
||||
local custom_key="$2"
|
||||
local tmpfile="$3"
|
||||
local path="$4"
|
||||
local name="$5"
|
||||
local min_size=10240
|
||||
local download_url=""
|
||||
|
||||
local custom_url=$(uci_get_config "$custom_key")
|
||||
|
||||
if [ "$small_flash_memory" != "1" ]; then
|
||||
mkdir -p /etc/openclash
|
||||
else
|
||||
mkdir -p /tmp/etc/openclash
|
||||
fi
|
||||
|
||||
case "$type" in
|
||||
geoip)
|
||||
if [ -z "$custom_url" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
download_url="${github_address_mod}gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat"
|
||||
else
|
||||
download_url="${github_address_mod}https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat"
|
||||
fi
|
||||
else
|
||||
download_url="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat"
|
||||
fi
|
||||
else
|
||||
download_url="$custom_url"
|
||||
fi
|
||||
;;
|
||||
geosite)
|
||||
if [ -z "$custom_url" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
download_url="${github_address_mod}gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat"
|
||||
else
|
||||
download_url="${github_address_mod}https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
|
||||
fi
|
||||
else
|
||||
download_url="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
|
||||
fi
|
||||
else
|
||||
download_url="$custom_url"
|
||||
fi
|
||||
;;
|
||||
geoasn)
|
||||
if [ -z "$custom_url" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
download_url="${github_address_mod}gh/xishang0128/geoip@release/GeoLite2-ASN.mmdb"
|
||||
else
|
||||
download_url="${github_address_mod}https://github.com/xishang0128/geoip/releases/latest/download/GeoLite2-ASN.mmdb"
|
||||
fi
|
||||
else
|
||||
download_url="https://github.com/xishang0128/geoip/releases/latest/download/GeoLite2-ASN.mmdb"
|
||||
fi
|
||||
else
|
||||
download_url="$custom_url"
|
||||
fi
|
||||
;;
|
||||
ipdb)
|
||||
if [ -z "$custom_url" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
download_url="${github_address_mod}gh/alecthw/mmdb_china_ip_list@release/lite/Country.mmdb"
|
||||
else
|
||||
download_url="${github_address_mod}https://raw.githubusercontent.com/alecthw/mmdb_china_ip_list/release/lite/Country.mmdb"
|
||||
fi
|
||||
else
|
||||
download_url="https://raw.githubusercontent.com/alecthw/mmdb_china_ip_list/release/lite/Country.mmdb"
|
||||
fi
|
||||
else
|
||||
download_url="$custom_url"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
LOG_OUT "【$name】Start Downloading Database..."
|
||||
|
||||
DOWNLOAD_FILE_CURL "$download_url" "/tmp/$tmpfile" "$path"
|
||||
DOWNLOAD_RESULT=$?
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "/tmp/$tmpfile" ]; then
|
||||
if head -c 512 "/tmp/$tmpfile" | grep -qiE "<!doctype|<html|<head|<body"; then
|
||||
LOG_OUT "【$name】Download Failed: HTML Response Detected, Abort Update..."
|
||||
rm -rf "/tmp/$tmpfile"
|
||||
elif [ $(du -b "/tmp/$tmpfile" 2>/dev/null | awk '{print $1}' || echo "$min_size") -lt "$min_size" ]; then
|
||||
LOG_OUT "【$name】Download Failed: File Size Too Small, Abort Update..."
|
||||
rm -rf "/tmp/$tmpfile"
|
||||
else
|
||||
LOG_OUT "【$name】Download Success, Check Updated..."
|
||||
cmp -s "/tmp/$tmpfile" "$path"
|
||||
if [ "$?" -ne 0 ]; then
|
||||
LOG_OUT "【$name】Has Been Updated, Starting To Replace The Old Version..."
|
||||
case "$type" in
|
||||
geoip)
|
||||
rm -rf "/etc/openclash/geoip.dat"
|
||||
;;
|
||||
geosite)
|
||||
rm -rf "/etc/openclash/geosite.dat"
|
||||
;;
|
||||
geoasn)
|
||||
rm -rf "/etc/openclash/GeoLite2-ASN.mmdb"
|
||||
;;
|
||||
esac
|
||||
mv "/tmp/$tmpfile" "$path" >/dev/null 2>&1
|
||||
LOG_OUT "【$name】Update Successful!"
|
||||
restart=1
|
||||
else
|
||||
LOG_OUT "【$name】No Change, Do Nothing..."
|
||||
fi
|
||||
fi
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
LOG_OUT "【$name】No Change, Do Nothing..."
|
||||
else
|
||||
LOG_OUT "【$name】Update Error, Please Try Again Later..."
|
||||
fi
|
||||
|
||||
rm -rf "/tmp/$tmpfile" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
all)
|
||||
update_one geoip "geoip_custom_url" "GeoIP.dat" "/etc/openclash/GeoIP.dat" "GeoIP.dat"
|
||||
update_one geosite "geosite_custom_url" "GeoSite.dat" "/etc/openclash/GeoSite.dat" "GeoSite.dat"
|
||||
update_one geoasn "geoasn_custom_url" "GeoLite2-ASN.mmdb" "/etc/openclash/ASN.mmdb" "ASN.mmdb"
|
||||
update_one ipdb "geo_custom_url" "Country.mmdb" "/etc/openclash/Country.mmdb" "Country.mmdb"
|
||||
;;
|
||||
geoip)
|
||||
update_one geoip "geoip_custom_url" "GeoIP.dat" "/etc/openclash/GeoIP.dat" "GeoIP.dat"
|
||||
;;
|
||||
geosite)
|
||||
update_one geosite "geosite_custom_url" "GeoSite.dat" "/etc/openclash/GeoSite.dat" "GeoSite.dat"
|
||||
;;
|
||||
geoasn)
|
||||
update_one geoasn "geoasn_custom_url" "GeoLite2-ASN.mmdb" "/etc/openclash/ASN.mmdb" "ASN.mmdb"
|
||||
;;
|
||||
ipdb)
|
||||
update_one ipdb "geo_custom_url" "Country.mmdb" "/etc/openclash/Country.mmdb" "Country.mmdb"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {all|geoip|geosite|geoasn|ipdb}"
|
||||
del_lock
|
||||
dec_job_counter_and_restart "$restart"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 874>"/tmp/lock/openclash_geoasn.lock" 2>/dev/null
|
||||
flock -x 874 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 874 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_geoasn.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
small_flash_memory=$(uci_get_config "small_flash_memory")
|
||||
GEOASN_CUSTOM_URL=$(uci_get_config "geoasn_custom_url")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
restart=0
|
||||
|
||||
if [ "$small_flash_memory" != "1" ]; then
|
||||
geoasn_path="/etc/openclash/ASN.mmdb"
|
||||
mkdir -p /etc/openclash
|
||||
else
|
||||
geoasn_path="/tmp/etc/openclash/ASN.mmdb"
|
||||
mkdir -p /tmp/etc/openclash
|
||||
fi
|
||||
LOG_OUT "Start Downloading Geo ASN Database..."
|
||||
if [ -z "$GEOASN_CUSTOM_URL" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
DOWNLOAD_URL="${github_address_mod}gh/xishang0128/geoip@release/GeoLite2-ASN.mmdb"
|
||||
else
|
||||
DOWNLOAD_URL="${github_address_mod}https://github.com/xishang0128/geoip/releases/latest/download/GeoLite2-ASN.mmdb"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL="https://github.com/xishang0128/geoip/releases/latest/download/GeoLite2-ASN.mmdb"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL=$GEOASN_CUSTOM_URL
|
||||
fi
|
||||
DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "/tmp/GeoLite2-ASN.mmdb" "$geoasn_path"
|
||||
DOWNLOAD_RESULT=$?
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "/tmp/GeoLite2-ASN.mmdb" ]; then
|
||||
LOG_OUT "Geo ASN Database Download Success, Check Updated..."
|
||||
cmp -s /tmp/GeoLite2-ASN.mmdb "$geoasn_path"
|
||||
if [ "$?" -ne "0" ]; then
|
||||
LOG_OUT "Geo ASN Database Has Been Updated, Starting To Replace The Old Version..."
|
||||
rm -rf "/etc/openclash/GeoLite2-ASN.mmdb"
|
||||
mv /tmp/GeoLite2-ASN.mmdb "$geoasn_path" >/dev/null 2>&1
|
||||
LOG_OUT "Geo ASN Database Update Successful!"
|
||||
restart=1
|
||||
else
|
||||
LOG_OUT "Updated Geo ASN Database No Change, Do Nothing..."
|
||||
fi
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
LOG_OUT "Updated Geo ASN Database No Change, Do Nothing..."
|
||||
else
|
||||
LOG_OUT "Geo ASN Database Update Error, Please Try Again Later..."
|
||||
fi
|
||||
|
||||
rm -rf /tmp/GeoLite2-ASN.mmdb >/dev/null 2>&1
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 873>"/tmp/lock/openclash_geoip.lock" 2>/dev/null
|
||||
flock -x 873 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 873 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_geoip.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
small_flash_memory=$(uci_get_config "small_flash_memory")
|
||||
GEOIP_CUSTOM_URL=$(uci_get_config "geoip_custom_url")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
restart=0
|
||||
|
||||
if [ "$small_flash_memory" != "1" ]; then
|
||||
geoip_path="/etc/openclash/GeoIP.dat"
|
||||
mkdir -p /etc/openclash
|
||||
else
|
||||
geoip_path="/tmp/etc/openclash/GeoIP.dat"
|
||||
mkdir -p /tmp/etc/openclash
|
||||
fi
|
||||
LOG_OUT "Start Downloading GeoIP Dat..."
|
||||
if [ -z "$GEOIP_CUSTOM_URL" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
DOWNLOAD_URL="${github_address_mod}gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat"
|
||||
else
|
||||
DOWNLOAD_URL="${github_address_mod}https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL=$GEOIP_CUSTOM_URL
|
||||
fi
|
||||
DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "/tmp/GeoIP.dat" "$geoip_path"
|
||||
DOWNLOAD_RESULT=$?
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "/tmp/GeoIP.dat" ]; then
|
||||
LOG_OUT "GeoIP Dat Download Success, Check Updated..."
|
||||
cmp -s /tmp/GeoIP.dat "$geoip_path"
|
||||
if [ "$?" -ne "0" ]; then
|
||||
LOG_OUT "GeoIP Dat Has Been Updated, Starting To Replace The Old Version..."
|
||||
rm -rf "/etc/openclash/geoip.dat"
|
||||
mv /tmp/GeoIP.dat "$geoip_path" >/dev/null 2>&1
|
||||
LOG_OUT "GeoIP Dat Update Successful!"
|
||||
restart=1
|
||||
else
|
||||
LOG_OUT "Updated GeoIP Dat No Change, Do Nothing..."
|
||||
fi
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
LOG_OUT "Updated GeoIP Dat No Change, Do Nothing..."
|
||||
else
|
||||
LOG_OUT "GeoIP Dat Update Error, Please Try Again Later..."
|
||||
fi
|
||||
|
||||
rm -rf /tmp/GeoIP.dat >/dev/null 2>&1
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 874>"/tmp/lock/openclash_geosite.lock" 2>/dev/null
|
||||
flock -x 874 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 874 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_geosite.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
small_flash_memory=$(uci_get_config "small_flash_memory")
|
||||
GEOSITE_CUSTOM_URL=$(uci_get_config "geosite_custom_url")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
restart=0
|
||||
|
||||
if [ "$small_flash_memory" != "1" ]; then
|
||||
geosite_path="/etc/openclash/GeoSite.dat"
|
||||
mkdir -p /etc/openclash
|
||||
else
|
||||
geosite_path="/tmp/etc/openclash/GeoSite.dat"
|
||||
mkdir -p /tmp/etc/openclash
|
||||
fi
|
||||
LOG_OUT "Start Downloading GeoSite Database..."
|
||||
if [ -z "$GEOSITE_CUSTOM_URL" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
DOWNLOAD_URL="${github_address_mod}gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat"
|
||||
else
|
||||
DOWNLOAD_URL="${github_address_mod}https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL=$GEOSITE_CUSTOM_URL
|
||||
fi
|
||||
DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "/tmp/GeoSite.dat" "$geosite_path"
|
||||
DOWNLOAD_RESULT=$?
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "/tmp/GeoSite.dat" ]; then
|
||||
LOG_OUT "GeoSite Database Download Success, Check Updated..."
|
||||
cmp -s /tmp/GeoSite.dat "$geosite_path"
|
||||
if [ "$?" -ne "0" ]; then
|
||||
LOG_OUT "GeoSite Database Has Been Updated, Starting To Replace The Old Version..."
|
||||
rm -rf "/etc/openclash/geosite.dat"
|
||||
mv /tmp/GeoSite.dat "$geosite_path" >/dev/null 2>&1
|
||||
LOG_OUT "GeoSite Database Update Successful!"
|
||||
restart=1
|
||||
else
|
||||
LOG_OUT "Updated GeoSite Database No Change, Do Nothing..."
|
||||
fi
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
LOG_OUT "Updated GeoSite Database No Change, Do Nothing..."
|
||||
else
|
||||
LOG_OUT "GeoSite Database Update Error, Please Try Again Later..."
|
||||
fi
|
||||
|
||||
rm -rf /tmp/GeoSite.dat >/dev/null 2>&1
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -1,69 +0,0 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 880>"/tmp/lock/openclash_ipdb.lock" 2>/dev/null
|
||||
flock -x 880 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 880 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_ipdb.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
small_flash_memory=$(uci_get_config "small_flash_memory")
|
||||
GEOIP_CUSTOM_URL=$(uci_get_config "geo_custom_url")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
restart=0
|
||||
|
||||
if [ "$small_flash_memory" != "1" ]; then
|
||||
geoip_path="/etc/openclash/Country.mmdb"
|
||||
mkdir -p /etc/openclash
|
||||
else
|
||||
geoip_path="/tmp/etc/openclash/Country.mmdb"
|
||||
mkdir -p /tmp/etc/openclash
|
||||
fi
|
||||
LOG_OUT "Start Downloading Geoip Database..."
|
||||
if [ -z "$GEOIP_CUSTOM_URL" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
DOWNLOAD_URL="${github_address_mod}gh/alecthw/mmdb_china_ip_list@release/lite/Country.mmdb"
|
||||
else
|
||||
DOWNLOAD_URL="${github_address_mod}https://raw.githubusercontent.com/alecthw/mmdb_china_ip_list/release/lite/Country.mmdb"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL="https://raw.githubusercontent.com/alecthw/mmdb_china_ip_list/release/lite/Country.mmdb"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL=$GEOIP_CUSTOM_URL
|
||||
fi
|
||||
DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "/tmp/Country.mmdb" "$geoip_path"
|
||||
DOWNLOAD_RESULT=$?
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "/tmp/Country.mmdb" ]; then
|
||||
LOG_OUT "Geoip Database Download Success, Check Updated..."
|
||||
cmp -s /tmp/Country.mmdb "$geoip_path"
|
||||
if [ "$?" -ne 0 ]; then
|
||||
LOG_OUT "Geoip Database Has Been Updated, Starting To Replace The Old Version..."
|
||||
mv /tmp/Country.mmdb "$geoip_path" >/dev/null 2>&1
|
||||
LOG_OUT "Geoip Database Update Successful!"
|
||||
restart=1
|
||||
else
|
||||
LOG_OUT "Updated Geoip Database No Change, Do Nothing..."
|
||||
fi
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
LOG_OUT "Updated Geoip Database No Change, Do Nothing..."
|
||||
else
|
||||
LOG_OUT "Geoip Database Update Error, Please Try Again Later..."
|
||||
fi
|
||||
|
||||
rm -rf /tmp/Country.mmdb >/dev/null 2>&1
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -46,7 +46,7 @@ function unlock_auto_select()
|
||||
local no_old_region_unlock = {}
|
||||
local full_support_list = {}
|
||||
local fallback_select = {}
|
||||
local gorup_i18 = "Group:"
|
||||
local gorup_i18 = "【"..type.."】Group:"
|
||||
local no_group_find = "failed to search based on keywords and automatically obtain the group, please confirm the validity of the regex!"
|
||||
local full_support_no_area = "full support"
|
||||
local full_support = "full support, area:"
|
||||
@@ -119,6 +119,10 @@ function unlock_auto_select()
|
||||
key_group = FS.uci_get_config("config", "stream_auto_select_group_key_google_not_cn") or "google|谷歌"
|
||||
elseif type == "OpenAI" then
|
||||
key_group = FS.uci_get_config("config", "stream_auto_select_group_key_openai") or "OpenAI|ChatGPT"
|
||||
elseif type == "Claude" then
|
||||
key_group = FS.uci_get_config("config", "stream_auto_select_group_key_claude") or "Claude"
|
||||
elseif type == "Gemini" then
|
||||
key_group = FS.uci_get_config("config", "stream_auto_select_group_key_gemini") or "Gemini"
|
||||
end
|
||||
if not key_group then key_group = type end
|
||||
else
|
||||
@@ -148,9 +152,9 @@ function unlock_auto_select()
|
||||
--test now proxy
|
||||
region = proxy_unlock_test()
|
||||
if table_include(groups, now_name) then
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.."】"
|
||||
else
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.." ➟ "..now_name.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.." ➟ "..now_name.."】"
|
||||
end
|
||||
if status ~= 2 and status ~= 4 then
|
||||
region = proxy_unlock_test()
|
||||
@@ -244,7 +248,7 @@ function unlock_auto_select()
|
||||
end
|
||||
end
|
||||
if #(value.all) == 0 then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..no_nodes_filter)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..no_nodes_filter)
|
||||
break
|
||||
end
|
||||
--loop proxy test
|
||||
@@ -274,16 +278,16 @@ function unlock_auto_select()
|
||||
end
|
||||
end
|
||||
if #(proxies) == 0 then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.."】"..no_nodes_filter)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.."】"..no_nodes_filter)
|
||||
break
|
||||
end
|
||||
for p = 1, #(proxies) do
|
||||
proxy = proxies[p]
|
||||
if table_include(groups, proxy) then
|
||||
group_now = get_group_now(info, proxy)
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.." ➟ "..group_now.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.." ➟ "..group_now.."】"
|
||||
else
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.." ➟ "..proxy.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.." ➟ "..proxy.."】"
|
||||
end
|
||||
--skip tested proxy
|
||||
while true do
|
||||
@@ -303,7 +307,7 @@ function unlock_auto_select()
|
||||
table.insert(full_support_list, {value.all[i], group_name, proxy, region})
|
||||
if not all_test then
|
||||
print(now..full_support.."【"..region.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..proxy.."】"..area_i18.."【"..region.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..proxy.."】"..area_i18.."【"..region.."】")
|
||||
else
|
||||
print(now..full_support.."【"..region.."】")
|
||||
end
|
||||
@@ -312,7 +316,7 @@ function unlock_auto_select()
|
||||
table.insert(full_support_list, {value.all[i], group_name, proxy})
|
||||
if not all_test then
|
||||
print(now..full_support_no_area)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..proxy.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..proxy.."】")
|
||||
else
|
||||
print(now..full_support_no_area)
|
||||
end
|
||||
@@ -372,16 +376,16 @@ function unlock_auto_select()
|
||||
end
|
||||
region = proxy_unlock_test()
|
||||
if table_include(groups, now_name) then
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.."】"
|
||||
else
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.." ➟ "..now_name.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.." ➟ "..now_name.."】"
|
||||
end
|
||||
if status == 2 then
|
||||
if region ~= "" then
|
||||
table.insert(full_support_list, {value.all[i], group_name, value.all[i], region})
|
||||
if not all_test then
|
||||
print(now..full_support.."【"..region.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, now_name).."】"..area_i18.."【"..region.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, now_name).."】"..area_i18.."【"..region.."】")
|
||||
else
|
||||
print(now..full_support.."【"..region.."】")
|
||||
end
|
||||
@@ -390,7 +394,7 @@ function unlock_auto_select()
|
||||
table.insert(full_support_list, {value.all[i], group_name, value.all[i]})
|
||||
if not all_test then
|
||||
print(now..full_support_no_area)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, now_name).."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, now_name).."】")
|
||||
else
|
||||
print(now..full_support_no_area)
|
||||
end
|
||||
@@ -469,24 +473,24 @@ function unlock_auto_select()
|
||||
group_now = group_now .. area_i18 .. "【"..v[4].."】"
|
||||
end
|
||||
if #full_support_list > 0 then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_all_full_support..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_all_full_support..group_now)
|
||||
elseif #no_old_region_unlock > 0 then
|
||||
if not all_test then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success_no_old_region..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success_no_old_region..group_now)
|
||||
else
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_all_no_old_region..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_all_no_old_region..group_now)
|
||||
end
|
||||
elseif #other_region_unlock > 0 then
|
||||
if not all_test then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_faild_other_region..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_faild_other_region..group_now)
|
||||
else
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_all_other_region..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_all_other_region..group_now)
|
||||
end
|
||||
else
|
||||
if not all_test then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_faild..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_faild..group_now)
|
||||
else
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_all_faild..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_all_faild..group_now)
|
||||
end
|
||||
end
|
||||
close_connections()
|
||||
@@ -499,7 +503,7 @@ function unlock_auto_select()
|
||||
else
|
||||
group_now = value.name.." ➟ "..proxy_default
|
||||
end
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_faild.."【"..group_now.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_faild.."【"..group_now.."】")
|
||||
end
|
||||
end
|
||||
elseif #nodes_filter(get_group_now(info, value.name), info) ~= 0 then
|
||||
@@ -509,12 +513,12 @@ function unlock_auto_select()
|
||||
if not all_test then
|
||||
print(now..full_support.."【"..region.."】")
|
||||
end
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, value.name).."】"..area_i18.."【"..region.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, value.name).."】"..area_i18.."【"..region.."】")
|
||||
else
|
||||
if not all_test then
|
||||
print(now..full_support_no_area)
|
||||
end
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, value.name).."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, value.name).."】")
|
||||
end
|
||||
if not all_test then
|
||||
break
|
||||
@@ -548,7 +552,7 @@ function unlock_auto_select()
|
||||
if status == 2 and not all_test then break end
|
||||
end
|
||||
if not group_match and not auto_get_group then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..key_group.."】"..no_group_find)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..key_group.."】"..no_group_find)
|
||||
end
|
||||
--write cache
|
||||
FS.writefile(unlock_cache_file, JSON.stringify(unlock_cache_info))
|
||||
@@ -817,6 +821,10 @@ function nodes_filter(t, info)
|
||||
regex = FS.uci_get_config("config", "stream_auto_select_node_key_google_not_cn") or ""
|
||||
elseif type == "OpenAI" then
|
||||
regex = FS.uci_get_config("config", "stream_auto_select_node_key_openai") or ""
|
||||
elseif type == "Claude" then
|
||||
regex = FS.uci_get_config("config", "stream_auto_select_node_key_claude") or ""
|
||||
elseif type == "Gemini" then
|
||||
regex = FS.uci_get_config("config", "stream_auto_select_node_key_gemini") or ""
|
||||
end
|
||||
|
||||
if class_type(t) == "table" then
|
||||
@@ -877,6 +885,10 @@ function proxy_unlock_test()
|
||||
region = google_not_cn_test()
|
||||
elseif type == "OpenAI" then
|
||||
region = openai_unlock_test()
|
||||
elseif type == "Claude" then
|
||||
region = claude_unlock_test()
|
||||
elseif type == "Gemini" then
|
||||
region = gemini_unlock_test()
|
||||
end
|
||||
return region
|
||||
end
|
||||
@@ -908,6 +920,10 @@ function auto_get_policy_group(passwd, ip, port)
|
||||
SYS.call('curl -sL -m 5 --limit-rate 1k -o /dev/null https://timeline.google.com &')
|
||||
elseif type == "OpenAI" then
|
||||
SYS.call('curl -sL -m 5 --limit-rate 1k -o /dev/null https://chatgpt.com/ &')
|
||||
elseif type == "Claude" then
|
||||
SYS.call('curl -sL -m 5 --limit-rate 1k -o /dev/null https://claude.ai/ &')
|
||||
elseif type == "Gemini" then
|
||||
SYS.call('curl -sL -m 5 --limit-rate 1k -o /dev/null https://gemini.google.com/ &')
|
||||
end
|
||||
os.execute("sleep 1")
|
||||
con = SYS.exec(string.format('curl -sL -m 5 --retry 2 -H "Content-Type: application/json" -H "Authorization: Bearer %s" -XGET http://%s:%s/connections', passwd, ip, port))
|
||||
@@ -976,6 +992,16 @@ function auto_get_policy_group(passwd, ip, port)
|
||||
auto_get_group = con.connections[i].chains[#(con.connections[i].chains)]
|
||||
break
|
||||
end
|
||||
elseif type == "Claude" then
|
||||
if string.match(con.connections[i].metadata.host, "claude%.ai") then
|
||||
auto_get_group = con.connections[i].chains[#(con.connections[i].chains)]
|
||||
break
|
||||
end
|
||||
elseif type == "Gemini" then
|
||||
if string.match(con.connections[i].metadata.host, "gemini%.google%.com") then
|
||||
auto_get_group = con.connections[i].chains[#(con.connections[i].chains)]
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1571,6 +1597,82 @@ function openai_unlock_test()
|
||||
return region
|
||||
end
|
||||
|
||||
function claude_unlock_test()
|
||||
status = 0
|
||||
local url = "https://claude.ai/"
|
||||
local region_url = "https://claude.ai/cdn-cgi/trace"
|
||||
local regex = FS.uci_get_config("config", "stream_auto_select_region_key_claude") or ""
|
||||
local region = ""
|
||||
local old_region = get_old_region()
|
||||
local old_regex = get_old_regex()
|
||||
local data = SYS.exec(string.format("curl -sIL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' '%s'", UA, url))
|
||||
if data then
|
||||
if string.find(data, "App unavailable in region") then
|
||||
status = 1
|
||||
else
|
||||
status = 2
|
||||
local region_data = SYS.exec(string.format("curl -sL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' '%s'", UA, region_url))
|
||||
if region_data and string.match(region_data, "loc=%a+") then
|
||||
region = string.upper(string.sub(string.match(region_data, "loc=%a+"), 5, -1))
|
||||
if not datamatch(region, regex) then
|
||||
status = 3
|
||||
elseif old_regex ~= regex and not all_test then
|
||||
status = 2
|
||||
elseif old_region ~= "" and region ~= old_region and not all_test then
|
||||
status = 4
|
||||
end
|
||||
if status == 2 and not all_test and region ~= old_region then
|
||||
write_cache(type, "old_region", region)
|
||||
end
|
||||
if status == 2 and not all_test and regex ~= old_regex then
|
||||
write_cache(type, "old_regex", regex)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return region
|
||||
end
|
||||
|
||||
function gemini_unlock_test()
|
||||
status = 0
|
||||
local url = "https://gemini.google.com/"
|
||||
local regex = FS.uci_get_config("config", "stream_auto_select_region_key_gemini") or ""
|
||||
local region = ""
|
||||
local old_region = get_old_region()
|
||||
local old_regex = get_old_regex()
|
||||
local data = SYS.exec(string.format("curl -sL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' '%s'", UA, url))
|
||||
if not data or string.sub(data, 1, 4) == "curl" then
|
||||
status = 1
|
||||
return region
|
||||
end
|
||||
|
||||
if string.find(data, "45631641,null,true", 1, true) then
|
||||
local cc = string.match(data, ',2,1,200,"([A-Z][A-Z][A-Z])"')
|
||||
if cc and cc ~= "" then
|
||||
region = cc
|
||||
end
|
||||
status = 2
|
||||
if region ~= "" then
|
||||
if not datamatch(region, regex) then
|
||||
status = 3
|
||||
elseif old_regex ~= regex and not all_test then
|
||||
status = 2
|
||||
elseif old_region ~= "" and region ~= old_region and not all_test then
|
||||
status = 4
|
||||
end
|
||||
if status == 2 and not all_test and region ~= old_region then
|
||||
write_cache(type, "old_region", region)
|
||||
end
|
||||
if status == 2 and not all_test and regex ~= old_regex then
|
||||
write_cache(type, "old_regex", regex)
|
||||
end
|
||||
end
|
||||
else
|
||||
status = 1
|
||||
end
|
||||
return region
|
||||
end
|
||||
|
||||
function network_test()
|
||||
local test_url1 = "https://www.gstatic.com/generate_204"
|
||||
local test_url2 = "https://cp.cloudflare.com/generate_204"
|
||||
|
||||
@@ -16,7 +16,6 @@ del_lock() {
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
restart=0
|
||||
|
||||
if [ -n "$1" ] && [ "$1" != "one_key_update" ]; then
|
||||
/usr/share/openclash/openclash_version.sh "$1" 2>/dev/null
|
||||
@@ -29,7 +28,7 @@ fi
|
||||
if [ ! -f "/tmp/openclash_last_version" ]; then
|
||||
LOG_ERROR "Failed to get version information, please try again later..."
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
dec_job_counter_and_restart "0"
|
||||
del_lock
|
||||
exit 0
|
||||
fi
|
||||
@@ -57,7 +56,7 @@ LAST_VER=$(sed -n 1p "$LAST_OPVER" 2>/dev/null |sed "s/^v//g" |tr -d "\n")
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
OP_CV=$(rm -f /var/lock/opkg.lock && opkg status luci-app-openclash 2>/dev/null |grep 'Version' |awk -F 'Version: ' '{print $2}' 2>/dev/null)
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
OP_CV=$(apk list luci-app-openclash 2>/dev/null|grep 'installed' | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null)
|
||||
OP_CV=$(apk list luci-app-openclash 2>/dev/null|grep "installed" | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null)
|
||||
fi
|
||||
OP_LV=$(sed -n 1p "$LAST_OPVER" 2>/dev/null |sed "s/^v//g" |tr -d "\n")
|
||||
RELEASE_BRANCH=$(uci_get_config "release_branch" || echo "master")
|
||||
@@ -69,14 +68,12 @@ if [ "$1" = "one_key_update" ]; then
|
||||
LOG_TIP "If the download fails, try setting the CDN in Overwrite Settings - General Settings - Github Address Modify Options"
|
||||
fi
|
||||
if [ -n "$2" ]; then
|
||||
/usr/share/openclash/openclash_core.sh "Meta" "$1" "$2" >/dev/null 2>&1 &
|
||||
/usr/share/openclash/openclash_core.sh "Meta" "$1" "$2" >/dev/null 2>&1
|
||||
github_address_mod="$2"
|
||||
else
|
||||
/usr/share/openclash/openclash_core.sh "Meta" "$1" >/dev/null 2>&1 &
|
||||
/usr/share/openclash/openclash_core.sh "Meta" "$1" >/dev/null 2>&1
|
||||
github_address_mod=0
|
||||
fi
|
||||
|
||||
wait
|
||||
else
|
||||
if [ "$github_address_mod" = "0" ]; then
|
||||
LOG_TIP "If the download fails, try setting the CDN in Overwrite Settings - General Settings - Github Address Modify Options"
|
||||
@@ -175,9 +172,8 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
LOG_ERROR "【OpenClash - v$LAST_VER】Pre update test failed after 3 attempts, the file is saved in /tmp/openclash.apk, please try to update manually with【apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk】"
|
||||
fi
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
dec_job_counter_and_restart "0"
|
||||
del_lock
|
||||
exit 0
|
||||
fi
|
||||
@@ -191,8 +187,8 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
LOG_ERROR "【OpenClash - v$LAST_VER】Download Failed after 3 attempts, please check the network or try again later!"
|
||||
rm -rf /tmp/openclash.ipk >/dev/null 2>&1
|
||||
rm -rf /tmp/openclash.apk >/dev/null 2>&1
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
exit 0
|
||||
fi
|
||||
@@ -200,9 +196,8 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
done
|
||||
cat > /tmp/openclash_update.sh <<"EOF"
|
||||
#!/bin/sh
|
||||
START_LOG="/tmp/openclash_start.log"
|
||||
LOG_FILE="/tmp/openclash.log"
|
||||
LOGTIME=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
|
||||
UPDATE_LOCK="/tmp/lock/openclash_update_install.lock"
|
||||
mkdir -p /tmp/lock
|
||||
@@ -224,27 +219,6 @@ fi
|
||||
|
||||
trap 'del_update_lock; exit' INT TERM EXIT
|
||||
|
||||
LOG_ERROR()
|
||||
{
|
||||
if [ -n "${1}" ]; then
|
||||
echo -e "${1}" > $START_LOG
|
||||
echo -e "${LOGTIME} [Error] ${1}" >> $LOG_FILE
|
||||
fi
|
||||
}
|
||||
|
||||
LOG_TIP()
|
||||
{
|
||||
if [ -n "${1}" ]; then
|
||||
echo -e "${1}" > $START_LOG
|
||||
echo -e "${LOGTIME} [Tip] ${1}" >> $LOG_FILE
|
||||
fi
|
||||
}
|
||||
|
||||
SLOG_CLEAN()
|
||||
{
|
||||
echo "" > $START_LOG
|
||||
}
|
||||
|
||||
check_install_success()
|
||||
{
|
||||
local target_version="$1"
|
||||
@@ -253,7 +227,7 @@ check_install_success()
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
current_version=$(rm -f /var/lock/opkg.lock && opkg status luci-app-openclash 2>/dev/null |grep 'Version' |awk -F 'Version: ' '{print $2}' 2>/dev/null)
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
current_version=$(apk list luci-app-openclash 2>/dev/null|grep 'installed' | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null)
|
||||
current_version=$(apk list luci-app-openclash 2>/dev/null |grep "installed" | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [ -n "$current_version" ] && [ "$current_version" = "$target_version" ]; then
|
||||
@@ -266,41 +240,39 @@ check_install_success()
|
||||
install_missing_packages() {
|
||||
local installed_before="$1"
|
||||
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
if [ -n "$installed_before" ]; then
|
||||
for pkg in $installed_before; do
|
||||
if ! opkg status "$pkg" >/dev/null 2>&1; then
|
||||
local retry_count=0
|
||||
local max_retries=3
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
retry_count=$((retry_count + 1))
|
||||
local retry_count=0
|
||||
local max_retries=3
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
if opkg status "$pkg" >/dev/null 2>&1; then
|
||||
continue
|
||||
fi
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
if apk list "$pkg" |grep "installed" >/dev/null 2>&1; then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
LOG_TIP "【$pkg】depended package reinstalling..."
|
||||
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
retry_count=$((retry_count + 1))
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
opkg install "$pkg"
|
||||
if [ $? -eq 0 ]; then
|
||||
break
|
||||
else
|
||||
if [ $retry_count -lt $max_retries ]; then
|
||||
sleep 2
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
for pkg in $installed_before; do
|
||||
if ! apk info "$pkg" >/dev/null 2>&1; then
|
||||
local retry_count=0
|
||||
local max_retries=3
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
retry_count=$((retry_count + 1))
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
apk add "$pkg"
|
||||
if [ $? -eq 0 ]; then
|
||||
break
|
||||
fi
|
||||
if [ $? -eq 0 ]; then
|
||||
break
|
||||
else
|
||||
if [ $retry_count -lt $max_retries ]; then
|
||||
sleep 2
|
||||
else
|
||||
if [ $retry_count -lt $max_retries ]; then
|
||||
sleep 2
|
||||
fi
|
||||
LOG_ERROR "【$pkg】failed to install, please try to install it manually..."
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
fi
|
||||
}
|
||||
@@ -324,7 +296,7 @@ while [ $install_retry_count -lt $max_install_retries ]; do
|
||||
opkg install /tmp/openclash.ipk
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
for pkg in $packages_to_check; do
|
||||
if apk info "$pkg" >/dev/null 2>&1; then
|
||||
if apk list "$pkg" |grep "installed" >/dev/null 2>&1; then
|
||||
installed_before="$installed_before $pkg"
|
||||
fi
|
||||
done
|
||||
@@ -357,9 +329,9 @@ else
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
LOG_ERROR "OpenClash update failed after 3 attempts, the file is saved in /tmp/openclash.apk, please try to update manually with【apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk】"
|
||||
fi
|
||||
SLOG_CLEAN
|
||||
fi
|
||||
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
del_update_lock
|
||||
EOF
|
||||
chmod 4755 /tmp/openclash_update.sh
|
||||
@@ -367,6 +339,8 @@ EOF
|
||||
if [ ! -f "/tmp/openclash_update.sh" ] || [ ! -s "/tmp/openclash_update.sh" ] || [ ! -x "/tmp/openclash_update.sh" ]; then
|
||||
LOG_ERROR "Failed to create update script!"
|
||||
rm -rf /tmp/openclash_update.sh
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
del_lock
|
||||
exit 1
|
||||
fi
|
||||
@@ -405,8 +379,8 @@ else
|
||||
else
|
||||
LOG_TIP "OpenClash has not been updated, stop continuing!"
|
||||
fi
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
fi
|
||||
|
||||
del_lock
|
||||
@@ -5,20 +5,10 @@
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
LOG_FILE="/tmp/openclash.log"
|
||||
CONFIG_FILE="/etc/openclash/$(uci_get_config "config_path" |awk -F '/' '{print $5}' 2>/dev/null)"
|
||||
ipv6_enable=$(uci_get_config "ipv6_enable" || echo 0)
|
||||
enable_redirect_dns=$(uci_get_config "enable_redirect_dns")
|
||||
dns_port=$(uci_get_config "dns_port")
|
||||
disable_masq_cache=$(uci_get_config "disable_masq_cache")
|
||||
cfg_update_interval=$(uci_get_config "config_update_interval" || echo 60)
|
||||
log_size=$(uci_get_config "log_size" || echo 1024)
|
||||
router_self_proxy=$(uci_get_config "router_self_proxy" || echo 1)
|
||||
stream_auto_select_interval=$(uci_get_config "stream_auto_select_interval" || echo 30)
|
||||
skip_proxy_address=$(uci_get_config "skip_proxy_address" || echo 0)
|
||||
CFG_UPDATE_INT=1
|
||||
CFG_UPDATE_INT=0
|
||||
SKIP_PROXY_ADDRESS=1
|
||||
SKIP_PROXY_ADDRESS_INTERVAL=30
|
||||
STREAM_AUTO_SELECT=1
|
||||
STREAM_AUTO_SELECT=0
|
||||
FIREWALL_RELOAD=0
|
||||
MAX_FIREWALL_RELOAD=3
|
||||
FW4=$(command -v fw4)
|
||||
@@ -155,11 +145,20 @@ end" 2>/dev/null >> $LOG_FILE
|
||||
|
||||
while :;
|
||||
do
|
||||
CONFIG_FILE="/etc/openclash/$(uci_get_config "config_path" |awk -F '/' '{print $5}' 2>/dev/null)"
|
||||
ipv6_enable=$(uci_get_config "ipv6_enable" || echo 0)
|
||||
enable_redirect_dns=$(uci_get_config "enable_redirect_dns")
|
||||
dns_port=$(uci_get_config "dns_port")
|
||||
disable_masq_cache=$(uci_get_config "disable_masq_cache")
|
||||
log_size=$(uci_get_config "log_size" || echo 1024)
|
||||
router_self_proxy=$(uci_get_config "router_self_proxy" || echo 1)
|
||||
skip_proxy_address=$(uci_get_config "skip_proxy_address" || echo 0)
|
||||
|
||||
cfg_update=$(uci_get_config "auto_update")
|
||||
cfg_update_mode=$(uci_get_config "config_auto_update_mode")
|
||||
cfg_update_interval_now=$(uci_get_config "config_update_interval" || echo 60)
|
||||
cfg_update_interval=$(uci_get_config "config_update_interval" || echo 60)
|
||||
stream_auto_select=$(uci_get_config "stream_auto_select" || echo 0)
|
||||
stream_auto_select_interval_now=$(uci_get_config "stream_auto_select_interval" || echo 30)
|
||||
stream_auto_select_interval=$(uci_get_config "stream_auto_select_interval" || echo 30)
|
||||
stream_auto_select_netflix=$(uci_get_config "stream_auto_select_netflix" || echo 0)
|
||||
stream_auto_select_disney=$(uci_get_config "stream_auto_select_disney" || echo 0)
|
||||
stream_auto_select_hbo_max=$(uci_get_config "stream_auto_select_hbo_max" || echo 0)
|
||||
@@ -172,6 +171,8 @@ do
|
||||
stream_auto_select_bilibili=$(uci_get_config "stream_auto_select_bilibili" || echo 0)
|
||||
stream_auto_select_google_not_cn=$(uci_get_config "stream_auto_select_google_not_cn" || echo 0)
|
||||
stream_auto_select_openai=$(uci_get_config "stream_auto_select_openai" || echo 0)
|
||||
stream_auto_select_claude=$(uci_get_config "stream_auto_select_claude" || echo 0)
|
||||
stream_auto_select_gemini=$(uci_get_config "stream_auto_select_gemini" || echo 0)
|
||||
upnp_lease_file=$(uci -q get upnpd.config.upnp_lease_file)
|
||||
|
||||
#wait for core start complete
|
||||
@@ -362,66 +363,72 @@ fi
|
||||
|
||||
## 配置文件循环更新
|
||||
if [ "$cfg_update" -eq 1 ] && [ "$cfg_update_mode" -eq 1 ]; then
|
||||
[ "$cfg_update_interval" -ne "$cfg_update_interval_now" ] && CFG_UPDATE_INT=0 && cfg_update_interval="$cfg_update_interval_now"
|
||||
if [ "$CFG_UPDATE_INT" -ne 0 ]; then
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$cfg_update_interval_now")" -eq 0 ] && /usr/share/openclash/openclash.sh
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$cfg_update_interval")" -eq 0 ] && /usr/share/openclash/openclash.sh
|
||||
fi
|
||||
CFG_UPDATE_INT=$(expr "$CFG_UPDATE_INT" + 1)
|
||||
fi
|
||||
|
||||
##STREAMING_UNLOCK_CHECK
|
||||
if [ "$stream_auto_select" -eq 1 ] && [ "$router_self_proxy" -eq 1 ]; then
|
||||
[ "$stream_auto_select_interval" -ne "$stream_auto_select_interval_now" ] && STREAM_AUTO_SELECT=1 && stream_auto_select_interval="$stream_auto_select_interval_now"
|
||||
if [ "$STREAM_AUTO_SELECT" -ne 0 ]; then
|
||||
if [ "$(expr "$STREAM_AUTO_SELECT" % "$stream_auto_select_interval_now")" -eq 0 ] || [ "$STREAM_AUTO_SELECT" -eq 1 ]; then
|
||||
if [ "$(expr "$STREAM_AUTO_SELECT" % "$stream_auto_select_interval")" -eq 0 ] || [ "$STREAM_AUTO_SELECT" -eq 1 ]; then
|
||||
if [ "$stream_auto_select_netflix" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Netflix Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Netflix】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Netflix" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_disney" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Disney Plus Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Disney Plus】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Disney Plus" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_google_not_cn" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Google Not CN Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Google Not CN】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Google" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_ytb" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For YouTube Premium Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【YouTube Premium】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "YouTube Premium" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_prime_video" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Amazon Prime Video Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Amazon Prime Video】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Amazon Prime Video" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_hbo_max" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For HBO Max Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【HBO Max】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "HBO Max" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_tvb_anywhere" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For TVB Anywhere+ Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【TVB Anywhere+】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "TVB Anywhere+" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_dazn" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For DAZN Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【DAZN】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "DAZN" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_paramount_plus" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Paramount Plus Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Paramount Plus】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Paramount Plus" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_discovery_plus" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Discovery Plus Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Discovery Plus】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Discovery Plus" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_bilibili" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Bilibili Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Bilibili】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Bilibili" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_openai" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For OpenAI Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【OpenAI】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "OpenAI" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_claude" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Claude】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Claude" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_gemini" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Gemini】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Gemini" >> $LOG_FILE
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
STREAM_AUTO_SELECT=$(expr "$STREAM_AUTO_SELECT" + 1)
|
||||
|
||||
@@ -672,6 +672,7 @@ proxies: # socks5
|
||||
grpc-opts:
|
||||
grpc-service-name: "example"
|
||||
# grpc-user-agent: "grpc-go/1.36.0"
|
||||
# ping-interval: 0 # 默认关闭,单位为秒
|
||||
# ip-version: ipv4
|
||||
|
||||
# vless
|
||||
@@ -762,6 +763,7 @@ proxies: # socks5
|
||||
grpc-opts:
|
||||
grpc-service-name: "grpc"
|
||||
# grpc-user-agent: "grpc-go/1.36.0"
|
||||
# ping-interval: 0 # 默认关闭,单位为秒
|
||||
|
||||
reality-opts:
|
||||
public-key: CrrQSjAG_YkHLwvM2M-7XkKJilgL5upBKCp0od0tLhE
|
||||
@@ -790,6 +792,69 @@ proxies: # socks5
|
||||
# v2ray-http-upgrade: false
|
||||
# v2ray-http-upgrade-fast-open: false
|
||||
|
||||
- name: "vless-xhttp"
|
||||
type: vless
|
||||
server: server
|
||||
port: 443
|
||||
uuid: uuid
|
||||
udp: true
|
||||
tls: true
|
||||
network: xhttp
|
||||
alpn:
|
||||
- h2
|
||||
# ech-opts: ...
|
||||
# reality-opts: ...
|
||||
# skip-cert-verify: false
|
||||
# fingerprint: ...
|
||||
# certificate: ...
|
||||
# private-key: ...
|
||||
servername: xxx.com
|
||||
client-fingerprint: chrome
|
||||
encryption: ""
|
||||
xhttp-opts:
|
||||
path: "/"
|
||||
host: xxx.com
|
||||
# mode: "stream-one" # Available: "stream-one", "stream-up" or "packet-up"
|
||||
# headers:
|
||||
# X-Forwarded-For: ""
|
||||
# no-grpc-header: false
|
||||
# x-padding-bytes: "100-1000"
|
||||
# reuse-settings: # aka XMUX
|
||||
# max-connections: "16-32"
|
||||
# max-concurrency: "0"
|
||||
# c-max-reuse-times: "0"
|
||||
# h-max-request-times: "600-900"
|
||||
# h-max-reusable-secs: "1800-3000"
|
||||
# download-settings:
|
||||
# ## xhttp part
|
||||
# path: "/"
|
||||
# host: xxx.com
|
||||
# headers:
|
||||
# X-Forwarded-For: ""
|
||||
# no-grpc-header: false
|
||||
# x-padding-bytes: "100-1000"
|
||||
# reuse-settings: # aka XMUX
|
||||
# max-connections: "16-32"
|
||||
# max-concurrency: "0"
|
||||
# c-max-reuse-times: "0"
|
||||
# h-max-request-times: "600-900"
|
||||
# h-max-reusable-secs: "1800-3000"
|
||||
# ## proxy part
|
||||
# server: server
|
||||
# port: 443
|
||||
# tls: true
|
||||
# alpn:
|
||||
# - h2
|
||||
# ech-opts: ...
|
||||
# reality-opts: ...
|
||||
# skip-cert-verify: false
|
||||
# fingerprint: ...
|
||||
# certificate: ...
|
||||
# private-key: ...
|
||||
# servername: xxx.com
|
||||
# client-fingerprint: chrome
|
||||
|
||||
|
||||
# Trojan
|
||||
- name: "trojan"
|
||||
type: trojan
|
||||
@@ -833,6 +898,7 @@ proxies: # socks5
|
||||
grpc-opts:
|
||||
grpc-service-name: "example"
|
||||
# grpc-user-agent: "grpc-go/1.36.0"
|
||||
# ping-interval: 0 # 默认关闭,单位为秒
|
||||
|
||||
- name: trojan-ws
|
||||
server: server
|
||||
@@ -1080,6 +1146,8 @@ proxies: # socks5
|
||||
# multiplexing: MULTIPLEXING_LOW
|
||||
# 如果想开启 0-RTT 握手,请设置为 HANDSHAKE_NO_WAIT,否则请设置为 HANDSHAKE_STANDARD。默认值为 HANDSHAKE_STANDARD
|
||||
# handshake-mode: HANDSHAKE_STANDARD
|
||||
# 一个 base64 字符串用于微调网络行为
|
||||
# traffic-pattern: ""
|
||||
|
||||
# sudoku
|
||||
- name: sudoku
|
||||
@@ -1090,15 +1158,17 @@ proxies: # socks5
|
||||
aead-method: chacha20-poly1305 # 可选:chacha20-poly1305、aes-128-gcm、none(不建议;且 enable-pure-downlink=false 时不可用)
|
||||
padding-min: 2 # 最小填充率(0-100)
|
||||
padding-max: 7 # 最大填充率(0-100,必须 >= padding-min)
|
||||
table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy 前者全ascii映射,后者保证熵值(汉明1)低于3
|
||||
# custom-table: xpxvvpvv # 可选,自定义字节布局,必须包含2个x、2个p、4个v,可随意组合。启用此处则需配置`table-type`为`prefer_entropy`
|
||||
# custom-tables: ["xpxvvpvv", "vxpvxvvp"] # 可选,自定义字节布局列表(x/v/p),用于 xvp 模式轮换;非空时覆盖 custom-table
|
||||
http-mask: true # 是否启用http掩码
|
||||
# http-mask-mode: legacy # 可选:legacy(默认)、stream(split-stream)、poll、auto(先 stream 再 poll);stream/poll/auto 支持走 CDN/反代
|
||||
# http-mask-tls: true # 可选:仅在 http-mask-mode 为 stream/poll/auto 时生效;true 强制 https;false 强制 http(不会根据端口自动推断)
|
||||
# http-mask-host: "" # 可选:覆盖 Host/SNI(支持 example.com 或 example.com:443);仅在 http-mask-mode 为 stream/poll/auto 时生效
|
||||
# path-root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload
|
||||
# http-mask-multiplex: off # 可选:off(默认)、auto(复用底层 HTTP 连接,减少建链 RTT)、on(Sudoku mux 单隧道多目标;仅在 http-mask-mode=stream/poll/auto 生效)
|
||||
table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy、up_ascii_down_entropy、up_entropy_down_ascii
|
||||
# custom-table: xpxvvpvv # 可选,自定义字节布局,必须包含2个x、2个p、4个v,可随意组合;只对 entropy 方向生效
|
||||
# custom-tables: ["xpxvvpvv", "vxpvxvvp"] # 可选,自定义字节布局列表(x/v/p),非空时覆盖 custom-table
|
||||
# 推荐:使用 httpmask 对象统一管理 HTTPMask 相关字段:
|
||||
httpmask:
|
||||
disable: false # true 禁用所有 HTTP 伪装/隧道
|
||||
mode: legacy # 可选:legacy(默认)、stream(split-stream)、poll、auto(先 stream 再 poll)、ws(WebSocket 隧道)
|
||||
# tls: true # 可选:按需开启 HTTPS/WSS
|
||||
# host: "" # 可选:覆盖 Host/SNI(支持 example.com 或 example.com:443);仅在 mode 为 stream/poll/auto/ws 时生效
|
||||
# path-root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload、/aabbcc/ws
|
||||
# multiplex: "off" # 可选字符串:off(默认)、auto(复用底层 HTTP 连接,减少建链 RTT)、on(Sudoku mux 单隧道多目标;仅在 mode=stream/poll/auto 生效;ws 强制 off)
|
||||
enable-pure-downlink: false # 可选:false=带宽优化下行(更快,要求 aead-method != none);true=纯 Sudoku 下行
|
||||
|
||||
# anytls
|
||||
@@ -1118,6 +1188,23 @@ proxies: # socks5
|
||||
# - http/1.1
|
||||
# skip-cert-verify: true
|
||||
|
||||
# trusttunnel
|
||||
- name: trusttunnel
|
||||
type: trusttunnel
|
||||
server: 1.2.3.4
|
||||
port: 443
|
||||
username: username
|
||||
password: password
|
||||
# client-fingerprint: chrome
|
||||
health-check: true
|
||||
udp: true
|
||||
# sni: "example.com"
|
||||
# alpn:
|
||||
# - h2
|
||||
# skip-cert-verify: true
|
||||
# quic: true # 默认为false
|
||||
# congestion-controller: bbr
|
||||
|
||||
# dns 出站会将请求劫持到内部 dns 模块,所有请求均在内部处理
|
||||
- name: "dns-out"
|
||||
type: dns
|
||||
@@ -1555,6 +1642,12 @@ listeners:
|
||||
flow: xtls-rprx-vision
|
||||
# ws-path: "/" # 如果不为空则开启 websocket 传输层
|
||||
# grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层
|
||||
# xhttp-config: # 如果不为空则开启 xhttp 传输层
|
||||
# path: "/"
|
||||
# host: ""
|
||||
# mode: auto # Available: "stream-one", "stream-up" or "packet-up"
|
||||
# no-sse-header: false
|
||||
# sc-stream-up-server-secs: "20-80"
|
||||
# -------------------------
|
||||
# vless encryption服务端配置:
|
||||
# (原生外观 / 只 XOR 公钥 / 全随机数。1-RTT 每次下发随机 300 到 600 秒的 ticket 以便 0-RTT 复用 / 只允许 1-RTT)
|
||||
@@ -1631,6 +1724,8 @@ listeners:
|
||||
users:
|
||||
username1: password1
|
||||
username2: password2
|
||||
# 一个 base64 字符串用于微调网络行为
|
||||
# traffic-pattern: ""
|
||||
|
||||
- name: sudoku-in-1
|
||||
type: sudoku
|
||||
@@ -1640,14 +1735,18 @@ listeners:
|
||||
aead-method: chacha20-poly1305 # 可选:chacha20-poly1305、aes-128-gcm、none(不建议;且 enable-pure-downlink=false 时不可用)
|
||||
padding-min: 1 # 最小填充率(0-100)
|
||||
padding-max: 15 # 最大填充率(0-100,必须 >= padding-min)
|
||||
table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy 前者全ascii映射,后者保证熵值(汉明1)低于3
|
||||
# custom-table: xpxvvpvv # 可选,自定义字节布局,必须包含2个x、2个p、4个v,可随意组合。启用此处则需配置`table-type`为`prefer_entropy`
|
||||
# custom-tables: ["xpxvvpvv", "vxpvxvvp"] # 可选,自定义字节布局列表(x/v/p),用于 xvp 模式轮换;非空时覆盖 custom-table
|
||||
table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy、up_ascii_down_entropy、up_entropy_down_ascii
|
||||
# custom-table: xpxvvpvv # 可选,自定义字节布局,必须包含2个x、2个p、4个v,可随意组合;只对 entropy 方向生效
|
||||
# custom-tables: ["xpxvvpvv", "vxpvxvvp"] # 可选,自定义字节布局列表(x/v/p),用于多表轮换;非空时覆盖 custom-table
|
||||
handshake-timeout: 5 # 可选(秒)
|
||||
enable-pure-downlink: false # 可选:false=带宽优化下行(更快,要求 aead-method != none);true=纯 Sudoku 下行
|
||||
disable-http-mask: false # 可选:禁用 http 掩码/隧道(默认为 false)
|
||||
# http-mask-mode: legacy # 可选:legacy(默认)、stream(split-stream)、poll、auto(先 stream 再 poll);stream/poll/auto 支持走 CDN/反代
|
||||
# path-root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload
|
||||
# 推荐:使用 httpmask 对象统一管理 HTTPMask 相关字段:
|
||||
httpmask:
|
||||
disable: false # true 禁用所有 HTTP 伪装/隧道
|
||||
mode: legacy # 可选:legacy(默认)、stream(split-stream)、poll、auto(先 stream 再 poll)、ws(WebSocket 隧道)
|
||||
# path-root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload、/aabbcc/ws
|
||||
#
|
||||
# fallback: "127.0.0.1:80" # 可选:用于可连接请求的回落转发,可与其他服务共端口
|
||||
|
||||
|
||||
|
||||
@@ -1734,6 +1833,30 @@ listeners:
|
||||
# masquerade: http://127.0.0.1:8080 #作为反向代理
|
||||
# masquerade: https://127.0.0.1:8080 #作为反向代理
|
||||
|
||||
- name: trusttunnel-in-1
|
||||
type: trusttunnel
|
||||
port: 10821 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
|
||||
listen: 0.0.0.0
|
||||
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
|
||||
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
|
||||
users:
|
||||
- username: 1
|
||||
password: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68
|
||||
certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
|
||||
private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
network: ["tcp", "udp"] # http2+http3
|
||||
congestion-controller: bbr
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
|
||||
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
|
||||
# dC5jb20AAA==
|
||||
# -----END ECH KEYS-----
|
||||
|
||||
# 注意,listeners中的tun仅提供给高级用户使用,普通用户应使用顶层配置中的tun
|
||||
- name: tun-in-1
|
||||
type: tun
|
||||
|
||||
@@ -41,7 +41,7 @@ if [ "$1" = "fake-ip" ] && [ "$enable_redirect_dns" != "2" ]; then
|
||||
awk -v mode="$fake_ip_filter_mode" '
|
||||
!/^$/ && !/^#/ {
|
||||
# 跳过IPv4和IPv6地址
|
||||
if ($0 ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/ || $0 ~ /:/) {
|
||||
if ($0 ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(\/[0-9]+)?$/ || $0 ~ /:/) {
|
||||
next
|
||||
}
|
||||
if (mode == "blacklist") {
|
||||
@@ -185,7 +185,7 @@ set_disable_qtype()
|
||||
yml_dns_get()
|
||||
{
|
||||
local section="$1" regex='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$'
|
||||
local enabled port type ip group dns_type dns_address interface specific_group node_resolve http3 ecs_subnet ecs_override disable_qtype_param
|
||||
local enabled port type ip group dns_type dns_address interface specific_group node_resolve direct_nameserver http3 skip_cert_verify ecs_subnet ecs_override disable_qtype_param disable_qtype disable_ipv4 disable_ipv6 disable_reuse
|
||||
|
||||
config_get_bool "enabled" "$section" "enabled" "1"
|
||||
[ "$enabled" = "0" ] && return
|
||||
@@ -378,6 +378,8 @@ begin
|
||||
smart_collect = '${44}' == '1'
|
||||
smart_collect_size = '${45}'
|
||||
fake_ip_range6 = '${46}'
|
||||
fake_ip_range6_enable = '${47}' == '1'
|
||||
global_ua = '${48}'
|
||||
default_dashboard = '$default_dashboard'
|
||||
yacd_type = '$yacd_type'
|
||||
dashboard_type = '$dashboard_type'
|
||||
@@ -408,6 +410,7 @@ begin
|
||||
Value['external-controller'] = '0.0.0.0:' + controller_port
|
||||
Value['secret'] = secret
|
||||
Value['bind-address'] = '*'
|
||||
Value['global-ua'] = global_ua if global_ua != '0'
|
||||
Value['external-ui'] = '/usr/share/openclash/ui'
|
||||
Value['external-ui-name'] = default_dashboard
|
||||
case default_dashboard
|
||||
@@ -480,7 +483,7 @@ begin
|
||||
else
|
||||
Value['dns']['enhanced-mode'] = 'fake-ip'
|
||||
Value['dns']['fake-ip-range'] = fake_ip_range
|
||||
if Value['dns']['ipv6']
|
||||
if Value['dns']['ipv6'] and fake_ip_range6_enable
|
||||
Value['dns']['fake-ip-range6'] = fake_ip_range6
|
||||
end
|
||||
end
|
||||
@@ -657,14 +660,13 @@ begin
|
||||
end
|
||||
if fake_ip_mode == 'fake-ip' && (china_ip_route || china_ip6_route)
|
||||
filter_mode = Value.dig('dns', 'fake-ip-filter-mode')
|
||||
filters = Value.dig('dns', 'fake-ip-filter') || []
|
||||
deleted_filters = filters.select { |f| f =~ /(geosite:?|rule-set:?).*(@cn|:cn|,cn|:china)/i }
|
||||
if filter_mode == 'blacklist' || filter_mode.nil?
|
||||
if !deleted_filters.any?
|
||||
(Value['dns']['fake-ip-filter'] ||= []) << 'geosite:cn'
|
||||
YAML.LOG_TIP('Because Need Ensure Bypassing IP Option Work, Added The Fake-IP-Filter Rule【geosite:cn】...')
|
||||
end
|
||||
else
|
||||
filter_rule = 'rule-set:oc-cn-domain'
|
||||
(Value['dns']['fake-ip-filter'] ||= []) << filter_rule
|
||||
end
|
||||
if filter_mode == 'whitelist'
|
||||
filters = Value.dig('dns', 'fake-ip-filter') || []
|
||||
deleted_filters = filters.select { |f| f =~ /(geosite:?|rule-set:?).*(@cn|:cn|,cn|:china)/i }
|
||||
if deleted_filters.any?
|
||||
Value['dns']['fake-ip-filter'] -= deleted_filters
|
||||
deleted_filters.each do |f|
|
||||
@@ -673,8 +675,14 @@ begin
|
||||
end
|
||||
end
|
||||
if filter_mode == 'rule'
|
||||
(Value['dns']['fake-ip-filter'] ||= []).unshift('GEOSITE,cn,real-ip')
|
||||
YAML.LOG_TIP('Because Need Ensure Bypassing IP Option Work, Added The Fake-IP-Filter Rule【GEOSITE,cn,real-ip】...')
|
||||
filter_rule = 'RULE-SET,oc-cn-domain,real-ip'
|
||||
(Value['dns']['fake-ip-filter'] ||= []).unshift(filter_rule)
|
||||
end
|
||||
Value['dns']['fake-ip-filter'].uniq!
|
||||
if filter_mode != 'whitelist'
|
||||
rule_set_hash = {'rule-providers+'=>{'oc-cn-domain'=>{'type'=>'http', 'interval'=>43200, 'behavior'=>'domain', 'format'=>'mrs', 'url'=>'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/cn.mrs', 'path'=> './rule_provider/oc-cn-domain.mrs'}}}
|
||||
Value = YAML.overwrite(Value, rule_set_hash)
|
||||
YAML.LOG_TIP('Because Need Ensure Bypassing IP Option Work, Added The Fake-IP-Filter Rule【%s】...' % [filter_rule])
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
|
||||
@@ -592,7 +592,7 @@ ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
};
|
||||
end;
|
||||
|
||||
#Mieru
|
||||
#Mieru
|
||||
if x['type'] == 'mieru' then
|
||||
threads << Thread.new{
|
||||
#port-range
|
||||
@@ -1138,6 +1138,19 @@ ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
uci_commands << uci_set + 'reality_short_id=\"' + x['reality-opts']['short-id'].to_s + '\"'
|
||||
end
|
||||
end
|
||||
if x.key?('encryption') then
|
||||
uci_commands << uci_set + 'vless_encryption=\"' + x['encryption'].to_s + '\"'
|
||||
end
|
||||
elsif x['network'].to_s == 'xhttp'
|
||||
uci_commands << uci_set + 'obfs_vless=xhttp'
|
||||
if x.key?('xhttp-opts') then
|
||||
if x['xhttp-opts'].key?('path') then
|
||||
uci_commands << uci_set + 'xhttp_opts_path=\"' + x['xhttp-opts']['path'].to_s + '\"'
|
||||
end
|
||||
if x['xhttp-opts'].key?('host') then
|
||||
uci_commands << uci_set + 'xhttp_opts_host=\"' + x['xhttp-opts']['host'].to_s + '\"'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
};
|
||||
@@ -1424,6 +1437,132 @@ ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
};
|
||||
end;
|
||||
|
||||
if x['type'] == 'masque' then
|
||||
threads << Thread.new{
|
||||
#private-key
|
||||
if x.key?('private-key') then
|
||||
uci_commands << uci_set + 'masque_private_key=\"' + x['private-key'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#public-key
|
||||
if x.key?('public-key') then
|
||||
uci_commands << uci_set + 'masque_public_key=\"' + x['public-key'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#ip
|
||||
if x.key?('ip') then
|
||||
uci_commands << uci_set + 'masque_ip=\"' + x['ip'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#ipv6
|
||||
if x.key?('ipv6') then
|
||||
uci_commands << uci_set + 'masque_ipv6=\"' + x['ipv6'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#mtu
|
||||
if x.key?('mtu') then
|
||||
uci_commands << uci_set + 'masque_mtu=\"' + x['mtu'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#remote-dns-resolve
|
||||
if x.key?('remote-dns-resolve') then
|
||||
uci_commands << uci_set + 'masque_remote_dns_resolve=\"' + x['remote-dns-resolve'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#dns
|
||||
if x.key?('dns') then
|
||||
dns = uci_del + 'dns >/dev/null 2>&1'
|
||||
system(dns)
|
||||
x['dns'].each{
|
||||
|x|
|
||||
uci_commands << uci_add + 'masque_dns=\"' + x.to_s + '\"'
|
||||
}
|
||||
end
|
||||
};
|
||||
end;
|
||||
|
||||
if x['type'] == 'trusttunnel' then
|
||||
threads << Thread.new{
|
||||
#username
|
||||
if x.key?('username') then
|
||||
uci_commands << uci_set + 'trusttunnel_username=\"' + x['username'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#password
|
||||
if x.key?('password') then
|
||||
uci_commands << uci_set + 'trusttunnel_password=\"' + x['password'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#health-check
|
||||
if x.key?('health-check') then
|
||||
uci_commands << uci_set + 'trusttunnel_health_check=\"' + x['health-check'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#quic
|
||||
if x.key?('quic') then
|
||||
uci_commands << uci_set + 'trusttunnel_quic=\"' + x['quic'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#congestion-controller
|
||||
if x.key?('congestion-controller') then
|
||||
uci_commands << uci_set + 'trusttunnel_congestion_controller=\"' + x['congestion-controller'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
#alpn
|
||||
threads << Thread.new{
|
||||
if x.key?('alpn') then
|
||||
alpn = uci_del + 'alpn >/dev/null 2>&1'
|
||||
system(alpn)
|
||||
x['alpn'].each{
|
||||
|x|
|
||||
uci_commands << uci_add + 'alpn=\"' + x.to_s + '\"'
|
||||
}
|
||||
end
|
||||
};
|
||||
|
||||
#sni
|
||||
threads << Thread.new{
|
||||
if x.key?('sni') then
|
||||
uci_commands << uci_set + 'sni=\"' + x['sni'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
#skip-cert-verify
|
||||
threads << Thread.new{
|
||||
if x.key?('skip-cert-verify') then
|
||||
uci_commands << uci_set + 'skip_cert_verify=\"' + x['skip-cert-verify'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
#client_fingerprint
|
||||
threads << Thread.new{
|
||||
if x.key?('client-fingerprint') then
|
||||
uci_commands << uci_set + 'client_fingerprint=\"' + x['client-fingerprint'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
end;
|
||||
|
||||
#加入策略组
|
||||
threads << Thread.new{
|
||||
#加入策略组
|
||||
|
||||
@@ -186,135 +186,6 @@ yml_servers_set()
|
||||
config_get "name" "$section" "name" ""
|
||||
config_get "server" "$section" "server" ""
|
||||
config_get "port" "$section" "port" ""
|
||||
config_get "dialer_proxy" "$section" "dialer_proxy" ""
|
||||
config_get "cipher" "$section" "cipher" ""
|
||||
config_get "cipher_ssr" "$section" "cipher_ssr" ""
|
||||
config_get "password" "$section" "password" ""
|
||||
config_get "securitys" "$section" "securitys" ""
|
||||
config_get "udp" "$section" "udp" ""
|
||||
config_get "obfs" "$section" "obfs" ""
|
||||
config_get "obfs_ssr" "$section" "obfs_ssr" ""
|
||||
config_get "obfs_param" "$section" "obfs_param" ""
|
||||
config_get "obfs_vmess" "$section" "obfs_vmess" ""
|
||||
config_get "obfs_trojan" "$section" "obfs_trojan" ""
|
||||
config_get "protocol" "$section" "protocol" ""
|
||||
config_get "protocol_param" "$section" "protocol_param" ""
|
||||
config_get "host" "$section" "host" ""
|
||||
config_get "mux" "$section" "mux" ""
|
||||
config_get "custom" "$section" "custom" ""
|
||||
config_get "tls" "$section" "tls" ""
|
||||
config_get "skip_cert_verify" "$section" "skip_cert_verify" ""
|
||||
config_get "path" "$section" "path" ""
|
||||
config_get "alterId" "$section" "alterId" ""
|
||||
config_get "uuid" "$section" "uuid" ""
|
||||
config_get "auth_name" "$section" "auth_name" ""
|
||||
config_get "auth_pass" "$section" "auth_pass" ""
|
||||
config_get "psk" "$section" "psk" ""
|
||||
config_get "obfs_snell" "$section" "obfs_snell" ""
|
||||
config_get "snell_version" "$section" "snell_version" ""
|
||||
config_get "sni" "$section" "sni" ""
|
||||
config_get "alpn" "$section" "alpn" ""
|
||||
config_get "http_path" "$section" "http_path" ""
|
||||
config_get "keep_alive" "$section" "keep_alive" ""
|
||||
config_get "servername" "$section" "servername" ""
|
||||
config_get "h2_path" "$section" "h2_path" ""
|
||||
config_get "h2_host" "$section" "h2_host" ""
|
||||
config_get "grpc_service_name" "$section" "grpc_service_name" ""
|
||||
config_get "ws_opts_path" "$section" "ws_opts_path" ""
|
||||
config_get "ws_opts_headers" "$section" "ws_opts_headers" ""
|
||||
config_get "max_early_data" "$section" "max_early_data" ""
|
||||
config_get "early_data_header_name" "$section" "early_data_header_name" ""
|
||||
config_get "trojan_ws_path" "$section" "trojan_ws_path" ""
|
||||
config_get "trojan_ws_headers" "$section" "trojan_ws_headers" ""
|
||||
config_get "interface_name" "$section" "interface_name" ""
|
||||
config_get "routing_mark" "$section" "routing_mark" ""
|
||||
config_get "obfs_vless" "$section" "obfs_vless" ""
|
||||
config_get "vless_flow" "$section" "vless_flow" ""
|
||||
config_get "http_headers" "$section" "http_headers" ""
|
||||
config_get "hysteria_protocol" "$section" "hysteria_protocol" ""
|
||||
config_get "hysteria2_protocol" "$section" "hysteria2_protocol" ""
|
||||
config_get "hysteria_up" "$section" "hysteria_up" ""
|
||||
config_get "hysteria_down" "$section" "hysteria_down" ""
|
||||
config_get "hysteria_alpn" "$section" "hysteria_alpn" ""
|
||||
config_get "hysteria_obfs" "$section" "hysteria_obfs" ""
|
||||
config_get "hysteria_auth" "$section" "hysteria_auth" ""
|
||||
config_get "hysteria_auth_str" "$section" "hysteria_auth_str" ""
|
||||
config_get "hysteria_ca" "$section" "hysteria_ca" ""
|
||||
config_get "hysteria_ca_str" "$section" "hysteria_ca_str" ""
|
||||
config_get "recv_window_conn" "$section" "recv_window_conn" ""
|
||||
config_get "recv_window" "$section" "recv_window" ""
|
||||
config_get "disable_mtu_discovery" "$section" "disable_mtu_discovery" ""
|
||||
config_get "initial_stream_receive_window" "$section" "initial_stream_receive_window" ""
|
||||
config_get "max_stream_receive_window" "$section" "max_stream_receive_window" ""
|
||||
config_get "initial_connection_receive_window" "$section" "initial_connection_receive_window" ""
|
||||
config_get "max_connection_receive_window" "$section" "max_connection_receive_window" ""
|
||||
config_get "xudp" "$section" "xudp" ""
|
||||
config_get "packet_encoding" "$section" "packet_encoding" ""
|
||||
config_get "global_padding" "$section" "global_padding" ""
|
||||
config_get "authenticated_length" "$section" "authenticated_length" ""
|
||||
config_get "wg_ip" "$section" "wg_ip" ""
|
||||
config_get "wg_ipv6" "$section" "wg_ipv6" ""
|
||||
config_get "private_key" "$section" "private_key" ""
|
||||
config_get "public_key" "$section" "public_key" ""
|
||||
config_get "preshared_key" "$section" "preshared_key" ""
|
||||
config_get "wg_dns" "$section" "wg_dns" ""
|
||||
config_get "public_key" "$section" "public_key" ""
|
||||
config_get "preshared_key" "$section" "preshared_key" ""
|
||||
config_get "wg_mtu" "$section" "wg_mtu" ""
|
||||
config_get "tc_ip" "$section" "tc_ip" ""
|
||||
config_get "tc_token" "$section" "tc_token" ""
|
||||
config_get "tc_uuid" "$section" "tc_uuid" ""
|
||||
config_get "tc_password" "$section" "tc_password" ""
|
||||
config_get "udp_relay_mode" "$section" "udp_relay_mode" ""
|
||||
config_get "congestion_controller" "$section" "congestion_controller" ""
|
||||
config_get "tc_alpn" "$section" "tc_alpn" ""
|
||||
config_get "disable_sni" "$section" "disable_sni" ""
|
||||
config_get "reduce_rtt" "$section" "reduce_rtt" ""
|
||||
config_get "heartbeat_interval" "$section" "heartbeat_interval" ""
|
||||
config_get "request_timeout" "$section" "request_timeout" ""
|
||||
config_get "max_udp_relay_packet_size" "$section" "max_udp_relay_packet_size" ""
|
||||
config_get "fast_open" "$section" "fast_open" ""
|
||||
config_get "fingerprint" "$section" "fingerprint" ""
|
||||
config_get "ports" "$section" "ports" ""
|
||||
config_get "hop_interval" "$section" "hop_interval" ""
|
||||
config_get "max_open_streams" "$section" "max_open_streams" ""
|
||||
config_get "obfs_password" "$section" "obfs_password" ""
|
||||
config_get "packet_addr" "$section" "packet_addr" ""
|
||||
config_get "client_fingerprint" "$section" "client_fingerprint" ""
|
||||
config_get "ip_version" "$section" "ip_version" ""
|
||||
config_get "tfo" "$section" "tfo" ""
|
||||
config_get "udp_over_tcp" "$section" "udp_over_tcp" ""
|
||||
config_get "reality_public_key" "$section" "reality_public_key" ""
|
||||
config_get "reality_short_id" "$section" "reality_short_id" ""
|
||||
config_get "obfs_version_hint" "$section" "obfs_version_hint" ""
|
||||
config_get "obfs_restls_script" "$section" "obfs_restls_script" ""
|
||||
config_get "multiplex" "$section" "multiplex" ""
|
||||
config_get "multiplex_protocol" "$section" "multiplex_protocol" ""
|
||||
config_get "multiplex_max_connections" "$section" "multiplex_max_connections" ""
|
||||
config_get "multiplex_min_streams" "$section" "multiplex_min_streams" ""
|
||||
config_get "multiplex_max_streams" "$section" "multiplex_max_streams" ""
|
||||
config_get "multiplex_padding" "$section" "multiplex_padding" ""
|
||||
config_get "multiplex_statistic" "$section" "multiplex_statistic" ""
|
||||
config_get "multiplex_only_tcp" "$section" "multiplex_only_tcp" ""
|
||||
config_get "other_parameters" "$section" "other_parameters" ""
|
||||
config_get "hysteria_obfs_password" "$section" "hysteria_obfs_password" ""
|
||||
config_get "port_range" "$section" "port_range" ""
|
||||
config_get "username" "$section" "username" ""
|
||||
config_get "transport" "$section" "transport" "TCP"
|
||||
config_get "multiplexing" "$section" "multiplexing" "MULTIPLEXING_LOW"
|
||||
config_get "private_key" "$section" "private_key" ""
|
||||
config_get "private_key_passphrase" "$section" "private_key_passphrase" ""
|
||||
config_get "host_key" "$section" "host_key" ""
|
||||
config_get "host_key_algorithms" "$section" "host_key_algorithms" ""
|
||||
config_get "idle_session_check_interval" "$section" "idle_session_check_interval" ""
|
||||
config_get "idle_session_timeout" "$section" "idle_session_timeout" ""
|
||||
config_get "min_idle_session" "$section" "min_idle_session" ""
|
||||
config_get "sudoku_key" "$section" "sudoku_key" ""
|
||||
config_get "aead_method" "$section" "aead_method" "none"
|
||||
config_get "padding_min" "$section" "padding_min" ""
|
||||
config_get "padding_max" "$section" "padding_max" ""
|
||||
config_get "table_type" "$section" "table_type" "prefer_ascii"
|
||||
config_get "http_mask" "$section" "http_mask" "true"
|
||||
|
||||
if [ "$enabled" = "0" ]; then
|
||||
return
|
||||
@@ -336,11 +207,12 @@ yml_servers_set()
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$password" ]; then
|
||||
if [ "$type" = "ss" ] || [ "$type" = "trojan" ] || [ "$type" = "ssr" ]; then
|
||||
return
|
||||
fi
|
||||
fi
|
||||
if [ "$type" = "ss" ] || [ "$type" = "trojan" ] || [ "$type" = "ssr" ]; then
|
||||
config_get "password" "$section" "password" ""
|
||||
if [ -z "$password" ]; then
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -z "$config" ] && [ "$config" != "$CONFIG_NAME" ] && [ "$config" != "all" ]; then
|
||||
return
|
||||
@@ -364,59 +236,27 @@ yml_servers_set()
|
||||
fi
|
||||
LOG_OUT "Start Writing【$CONFIG_NAME - $type - $name】Proxy To Config File..."
|
||||
|
||||
if [ "$obfs" != "none" ] && [ -n "$obfs" ]; then
|
||||
if [ "$obfs" = "websocket" ]; then
|
||||
obfss="plugin: v2ray-plugin"
|
||||
elif [ "$obfs" = "shadow-tls" ]; then
|
||||
obfss="plugin: shadow-tls"
|
||||
elif [ "$obfs" = "restls" ]; then
|
||||
obfss="plugin: restls"
|
||||
else
|
||||
obfss="plugin: obfs"
|
||||
fi
|
||||
else
|
||||
obfss=""
|
||||
fi
|
||||
|
||||
if [ "$obfs_vless" = "ws" ]; then
|
||||
obfs_vless="network: ws"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vless" = "grpc" ]; then
|
||||
obfs_vless="network: grpc"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vless" = "tcp" ]; then
|
||||
obfs_vless="network: tcp"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vmess" = "websocket" ]; then
|
||||
obfs_vmess="network: ws"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vmess" = "http" ]; then
|
||||
obfs_vmess="network: http"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vmess" = "h2" ]; then
|
||||
obfs_vmess="network: h2"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vmess" = "grpc" ]; then
|
||||
obfs_vmess="network: grpc"
|
||||
fi
|
||||
|
||||
if [ ! -z "$custom" ] && [ "$type" = "vmess" ]; then
|
||||
custom="Host: \"$custom\""
|
||||
fi
|
||||
|
||||
if [ ! -z "$path" ]; then
|
||||
if [ "$type" != "vmess" ]; then
|
||||
path="path: \"$path\""
|
||||
elif [ "$obfs_vmess" = "network: ws" ]; then
|
||||
path="ws-path: \"$path\""
|
||||
fi
|
||||
fi
|
||||
config_get "dialer_proxy" "$section" "dialer_proxy" ""
|
||||
config_get "udp" "$section" "udp" ""
|
||||
config_get "skip_cert_verify" "$section" "skip_cert_verify" ""
|
||||
config_get "tls" "$section" "tls" ""
|
||||
config_get "sni" "$section" "sni" ""
|
||||
config_get "alpn" "$section" "alpn" ""
|
||||
config_get "fingerprint" "$section" "fingerprint" ""
|
||||
config_get "client_fingerprint" "$section" "client_fingerprint" ""
|
||||
config_get "ip_version" "$section" "ip_version" ""
|
||||
config_get "tfo" "$section" "tfo" ""
|
||||
config_get "multiplex" "$section" "multiplex" ""
|
||||
config_get "multiplex_protocol" "$section" "multiplex_protocol" ""
|
||||
config_get "multiplex_max_connections" "$section" "multiplex_max_connections" ""
|
||||
config_get "multiplex_min_streams" "$section" "multiplex_min_streams" ""
|
||||
config_get "multiplex_max_streams" "$section" "multiplex_max_streams" ""
|
||||
config_get "multiplex_padding" "$section" "multiplex_padding" ""
|
||||
config_get "multiplex_statistic" "$section" "multiplex_statistic" ""
|
||||
config_get "multiplex_only_tcp" "$section" "multiplex_only_tcp" ""
|
||||
config_get "interface_name" "$section" "interface_name" ""
|
||||
config_get "routing_mark" "$section" "routing_mark" ""
|
||||
config_get "other_parameters" "$section" "other_parameters" ""
|
||||
|
||||
if [ "$client_fingerprint" = "none" ]; then
|
||||
client_fingerprint=""
|
||||
@@ -428,6 +268,35 @@ yml_servers_set()
|
||||
|
||||
#ss
|
||||
if [ "$type" = "ss" ]; then
|
||||
config_get "cipher" "$section" "cipher" ""
|
||||
config_get "obfs" "$section" "obfs" ""
|
||||
config_get "host" "$section" "host" ""
|
||||
config_get "mux" "$section" "mux" ""
|
||||
config_get "custom" "$section" "custom" ""
|
||||
config_get "path" "$section" "path" ""
|
||||
config_get "obfs_password" "$section" "obfs_password" ""
|
||||
config_get "obfs_version_hint" "$section" "obfs_version_hint" ""
|
||||
config_get "obfs_restls_script" "$section" "obfs_restls_script" ""
|
||||
config_get "udp_over_tcp" "$section" "udp_over_tcp" ""
|
||||
|
||||
if [ "$obfs" != "none" ] && [ -n "$obfs" ]; then
|
||||
if [ "$obfs" = "websocket" ]; then
|
||||
obfss="plugin: v2ray-plugin"
|
||||
elif [ "$obfs" = "shadow-tls" ]; then
|
||||
obfss="plugin: shadow-tls"
|
||||
elif [ "$obfs" = "restls" ]; then
|
||||
obfss="plugin: restls"
|
||||
else
|
||||
obfss="plugin: obfs"
|
||||
fi
|
||||
else
|
||||
obfss=""
|
||||
fi
|
||||
|
||||
if [ ! -z "$path" ]; then
|
||||
path="path: \"$path\""
|
||||
fi
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -528,6 +397,12 @@ fi
|
||||
|
||||
#ssr
|
||||
if [ "$type" = "ssr" ]; then
|
||||
config_get "cipher_ssr" "$section" "cipher_ssr" ""
|
||||
config_get "obfs_ssr" "$section" "obfs_ssr" ""
|
||||
config_get "protocol" "$section" "protocol" ""
|
||||
config_get "obfs_param" "$section" "obfs_param" ""
|
||||
config_get "protocol_param" "$section" "protocol_param" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -557,6 +432,48 @@ fi
|
||||
|
||||
#vmess
|
||||
if [ "$type" = "vmess" ]; then
|
||||
config_get "uuid" "$section" "uuid" ""
|
||||
config_get "alterId" "$section" "alterId" ""
|
||||
config_get "securitys" "$section" "securitys" ""
|
||||
config_get "xudp" "$section" "xudp" ""
|
||||
config_get "packet_encoding" "$section" "packet_encoding" ""
|
||||
config_get "global_padding" "$section" "global_padding" ""
|
||||
config_get "authenticated_length" "$section" "authenticated_length" ""
|
||||
config_get "servername" "$section" "servername" ""
|
||||
config_get "obfs_vmess" "$section" "obfs_vmess" ""
|
||||
config_get "custom" "$section" "custom" ""
|
||||
config_get "path" "$section" "path" ""
|
||||
config_get "ws_opts_path" "$section" "ws_opts_path" ""
|
||||
config_get "ws_opts_headers" "$section" "ws_opts_headers" ""
|
||||
config_get "max_early_data" "$section" "max_early_data" ""
|
||||
config_get "early_data_header_name" "$section" "early_data_header_name" ""
|
||||
config_get "http_path" "$section" "http_path" ""
|
||||
config_get "keep_alive" "$section" "keep_alive" ""
|
||||
config_get "h2_path" "$section" "h2_path" ""
|
||||
config_get "h2_host" "$section" "h2_host" ""
|
||||
config_get "grpc_service_name" "$section" "grpc_service_name" ""
|
||||
|
||||
if [ "$obfs_vmess" = "websocket" ]; then
|
||||
obfs_vmess="network: ws"
|
||||
fi
|
||||
if [ "$obfs_vmess" = "http" ]; then
|
||||
obfs_vmess="network: http"
|
||||
fi
|
||||
if [ "$obfs_vmess" = "h2" ]; then
|
||||
obfs_vmess="network: h2"
|
||||
fi
|
||||
if [ "$obfs_vmess" = "grpc" ]; then
|
||||
obfs_vmess="network: grpc"
|
||||
fi
|
||||
|
||||
if [ ! -z "$custom" ]; then
|
||||
custom="Host: \"$custom\""
|
||||
fi
|
||||
|
||||
if [ ! -z "$path" ] && [ "$obfs_vmess" = "network: ws" ]; then
|
||||
path="ws-path: \"$path\""
|
||||
fi
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -702,6 +619,11 @@ fi
|
||||
|
||||
#anytls
|
||||
if [ "$type" = "anytls" ]; then
|
||||
config_get "password" "$section" "password" ""
|
||||
config_get "idle_session_check_interval" "$section" "idle_session_check_interval" ""
|
||||
config_get "idle_session_timeout" "$section" "idle_session_timeout" ""
|
||||
config_get "min_idle_session" "$section" "min_idle_session" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -758,6 +680,11 @@ fi
|
||||
|
||||
#Mieru
|
||||
if [ "$type" = "mieru" ]; then
|
||||
config_get "port_range" "$section" "port_range" ""
|
||||
config_get "username" "$section" "username" ""
|
||||
config_get "transport" "$section" "transport" "TCP"
|
||||
config_get "multiplexing" "$section" "multiplexing" "MULTIPLEXING_LOW"
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -788,6 +715,21 @@ fi
|
||||
|
||||
#Tuic
|
||||
if [ "$type" = "tuic" ]; then
|
||||
config_get "tc_ip" "$section" "tc_ip" ""
|
||||
config_get "tc_token" "$section" "tc_token" ""
|
||||
config_get "tc_uuid" "$section" "tc_uuid" ""
|
||||
config_get "tc_password" "$section" "tc_password" ""
|
||||
config_get "udp_relay_mode" "$section" "udp_relay_mode" ""
|
||||
config_get "congestion_controller" "$section" "congestion_controller" ""
|
||||
config_get "tc_alpn" "$section" "tc_alpn" ""
|
||||
config_get "disable_sni" "$section" "disable_sni" ""
|
||||
config_get "reduce_rtt" "$section" "reduce_rtt" ""
|
||||
config_get "fast_open" "$section" "fast_open" ""
|
||||
config_get "heartbeat_interval" "$section" "heartbeat_interval" ""
|
||||
config_get "request_timeout" "$section" "request_timeout" ""
|
||||
config_get "max_udp_relay_packet_size" "$section" "max_udp_relay_packet_size" ""
|
||||
config_get "max_open_streams" "$section" "max_open_streams" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -874,6 +816,14 @@ fi
|
||||
|
||||
#WireGuard
|
||||
if [ "$type" = "wireguard" ]; then
|
||||
config_get "wg_ip" "$section" "wg_ip" ""
|
||||
config_get "wg_ipv6" "$section" "wg_ipv6" ""
|
||||
config_get "private_key" "$section" "private_key" ""
|
||||
config_get "public_key" "$section" "public_key" ""
|
||||
config_get "preshared_key" "$section" "preshared_key" ""
|
||||
config_get "wg_dns" "$section" "wg_dns" ""
|
||||
config_get "wg_mtu" "$section" "wg_mtu" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -905,7 +855,7 @@ cat >> "$SERVER_FILE" <<-EOF
|
||||
preshared-key: "$preshared_key"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$preshared_key" ]; then
|
||||
if [ -n "$wg_dns" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
dns:
|
||||
EOF
|
||||
@@ -925,6 +875,22 @@ fi
|
||||
|
||||
#hysteria
|
||||
if [ "$type" = "hysteria" ]; then
|
||||
config_get "hysteria_protocol" "$section" "hysteria_protocol" ""
|
||||
config_get "hysteria_up" "$section" "hysteria_up" ""
|
||||
config_get "hysteria_down" "$section" "hysteria_down" ""
|
||||
config_get "hysteria_alpn" "$section" "hysteria_alpn" ""
|
||||
config_get "hysteria_obfs" "$section" "hysteria_obfs" ""
|
||||
config_get "hysteria_auth" "$section" "hysteria_auth" ""
|
||||
config_get "hysteria_auth_str" "$section" "hysteria_auth_str" ""
|
||||
config_get "hysteria_ca" "$section" "hysteria_ca" ""
|
||||
config_get "hysteria_ca_str" "$section" "hysteria_ca_str" ""
|
||||
config_get "recv_window_conn" "$section" "recv_window_conn" ""
|
||||
config_get "recv_window" "$section" "recv_window" ""
|
||||
config_get "disable_mtu_discovery" "$section" "disable_mtu_discovery" ""
|
||||
config_get "fast_open" "$section" "fast_open" ""
|
||||
config_get "ports" "$section" "ports" ""
|
||||
config_get "hop_interval" "$section" "hop_interval" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1029,6 +995,22 @@ fi
|
||||
|
||||
#hysteria2
|
||||
if [ "$type" = "hysteria2" ]; then
|
||||
config_get "password" "$section" "password" ""
|
||||
config_get "hysteria_up" "$section" "hysteria_up" ""
|
||||
config_get "hysteria_down" "$section" "hysteria_down" ""
|
||||
config_get "hysteria_alpn" "$section" "hysteria_alpn" ""
|
||||
config_get "hysteria_obfs" "$section" "hysteria_obfs" ""
|
||||
config_get "hysteria_obfs_password" "$section" "hysteria_obfs_password" ""
|
||||
config_get "hysteria_ca" "$section" "hysteria_ca" ""
|
||||
config_get "hysteria_ca_str" "$section" "hysteria_ca_str" ""
|
||||
config_get "initial_stream_receive_window" "$section" "initial_stream_receive_window" ""
|
||||
config_get "max_stream_receive_window" "$section" "max_stream_receive_window" ""
|
||||
config_get "initial_connection_receive_window" "$section" "initial_connection_receive_window" ""
|
||||
config_get "max_connection_receive_window" "$section" "max_connection_receive_window" ""
|
||||
config_get "ports" "$section" "ports" ""
|
||||
config_get "hysteria2_protocol" "$section" "hysteria2_protocol" ""
|
||||
config_get "hop_interval" "$section" "hop_interval" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1096,7 +1078,7 @@ EOF
|
||||
fi
|
||||
if [ -n "$max_stream_receive_window" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
max_stream_receive_window: "$max_stream_receive_window"
|
||||
max-stream-receive-window: "$max_stream_receive_window"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$initial_connection_receive_window" ]; then
|
||||
@@ -1133,6 +1115,35 @@ fi
|
||||
|
||||
#vless
|
||||
if [ "$type" = "vless" ]; then
|
||||
config_get "uuid" "$section" "uuid" ""
|
||||
config_get "xudp" "$section" "xudp" ""
|
||||
config_get "packet_addr" "$section" "packet_addr" ""
|
||||
config_get "packet_encoding" "$section" "packet_encoding" ""
|
||||
config_get "servername" "$section" "servername" ""
|
||||
config_get "obfs_vless" "$section" "obfs_vless" ""
|
||||
config_get "ws_opts_path" "$section" "ws_opts_path" ""
|
||||
config_get "ws_opts_headers" "$section" "ws_opts_headers" ""
|
||||
config_get "grpc_service_name" "$section" "grpc_service_name" ""
|
||||
config_get "reality_public_key" "$section" "reality_public_key" ""
|
||||
config_get "reality_short_id" "$section" "reality_short_id" ""
|
||||
config_get "vless_flow" "$section" "vless_flow" ""
|
||||
config_get "xhttp_opts_path" "$section" "xhttp_opts_path" ""
|
||||
config_get "xhttp_opts_host" "$section" "xhttp_opts_host" ""
|
||||
config_get "vless_encryption" "$section" "vless_encryption" ""
|
||||
|
||||
if [ "$obfs_vless" = "ws" ]; then
|
||||
obfs_vless="network: ws"
|
||||
fi
|
||||
if [ "$obfs_vless" = "grpc" ]; then
|
||||
obfs_vless="network: grpc"
|
||||
fi
|
||||
if [ "$obfs_vless" = "tcp" ]; then
|
||||
obfs_vless="network: tcp"
|
||||
fi
|
||||
if [ "$obfs_vless" = "xhttp" ]; then
|
||||
obfs_vless="network: xhttp"
|
||||
fi
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1232,6 +1243,11 @@ EOF
|
||||
if [ ! -z "$vless_flow" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
flow: "$vless_flow"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$vless_encryption" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
encryption: "$vless_encryption"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$reality_public_key" ] || [ -n "$reality_short_id" ]; then
|
||||
@@ -1247,6 +1263,21 @@ EOF
|
||||
if [ -n "$reality_short_id" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
short-id: "$reality_short_id"
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
if [ "$obfs_vless" = "network: xhttp" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
xhttp-opts:
|
||||
EOF
|
||||
if [ -n "$xhttp_opts_path" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
path: "$xhttp_opts_path"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$xhttp_opts_host" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
host: "$xhttp_opts_host"
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
@@ -1276,6 +1307,13 @@ fi
|
||||
|
||||
#ssh
|
||||
if [ "$type" = "ssh" ]; then
|
||||
config_get "auth_name" "$section" "auth_name" ""
|
||||
config_get "auth_pass" "$section" "auth_pass" ""
|
||||
config_get "private_key" "$section" "private_key" ""
|
||||
config_get "private_key_passphrase" "$section" "private_key_passphrase" ""
|
||||
config_get "host_key" "$section" "host_key" ""
|
||||
config_get "host_key_algorithms" "$section" "host_key_algorithms" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1318,6 +1356,9 @@ fi
|
||||
|
||||
#socks5
|
||||
if [ "$type" = "socks5" ]; then
|
||||
config_get "auth_name" "$section" "auth_name" ""
|
||||
config_get "auth_pass" "$section" "auth_pass" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1358,6 +1399,10 @@ fi
|
||||
|
||||
#http
|
||||
if [ "$type" = "http" ]; then
|
||||
config_get "auth_name" "$section" "auth_name" ""
|
||||
config_get "auth_pass" "$section" "auth_pass" ""
|
||||
config_get "http_headers" "$section" "http_headers" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1399,6 +1444,11 @@ fi
|
||||
|
||||
#trojan
|
||||
if [ "$type" = "trojan" ]; then
|
||||
config_get "grpc_service_name" "$section" "grpc_service_name" ""
|
||||
config_get "obfs_trojan" "$section" "obfs_trojan" ""
|
||||
config_get "trojan_ws_path" "$section" "trojan_ws_path" ""
|
||||
config_get "trojan_ws_headers" "$section" "trojan_ws_headers" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1467,6 +1517,11 @@ fi
|
||||
|
||||
#snell
|
||||
if [ "$type" = "snell" ]; then
|
||||
config_get "psk" "$section" "psk" ""
|
||||
config_get "snell_version" "$section" "snell_version" ""
|
||||
config_get "obfs_snell" "$section" "obfs_snell" ""
|
||||
config_get "host" "$section" "host" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1490,6 +1545,13 @@ fi
|
||||
|
||||
#Sudoku
|
||||
if [ "$type" = "sudoku" ]; then
|
||||
config_get "sudoku_key" "$section" "sudoku_key" ""
|
||||
config_get "aead_method" "$section" "aead_method" "none"
|
||||
config_get "padding_min" "$section" "padding_min" ""
|
||||
config_get "padding_max" "$section" "padding_max" ""
|
||||
config_get "table_type" "$section" "table_type" "prefer_ascii"
|
||||
config_get "http_mask" "$section" "http_mask" "true"
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1528,6 +1590,132 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
#MASQUE
|
||||
if [ "$type" = "masque" ]; then
|
||||
config_get "masque_private_key" "$section" "masque_private_key" ""
|
||||
config_get "masque_public_key" "$section" "masque_public_key" ""
|
||||
config_get "masque_ip" "$section" "masque_ip" ""
|
||||
config_get "masque_ipv6" "$section" "masque_ipv6" ""
|
||||
config_get "masque_mtu" "$section" "masque_mtu" ""
|
||||
config_get "masque_remote_dns_resolve" "$section" "masque_remote_dns_resolve" ""
|
||||
config_get "masque_dns" "$section" "masque_dns" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
server: "$server"
|
||||
port: $port
|
||||
EOF
|
||||
if [ -n "$masque_private_key" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
private-key: "$masque_private_key"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$masque_public_key" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
public-key: "$masque_public_key"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$masque_ip" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
ip: "$masque_ip"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$masque_ipv6" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
ipv6: "$masque_ipv6"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$masque_mtu" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
mtu: $masque_mtu
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$masque_remote_dns_resolve" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
remote-dns-resolve: $masque_remote_dns_resolve
|
||||
EOF
|
||||
fi
|
||||
if [ ! -z "$udp" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
udp: $udp
|
||||
EOF
|
||||
fi
|
||||
if [ ! -z "$masque_dns" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
dns:
|
||||
EOF
|
||||
config_list_foreach "$section" "masque_dns" set_alpn
|
||||
fi
|
||||
fi
|
||||
|
||||
#TrustTunnel
|
||||
if [ "$type" = "trusttunnel" ]; then
|
||||
config_get "trusttunnel_username" "$section" "trusttunnel_username" ""
|
||||
config_get "trusttunnel_password" "$section" "trusttunnel_password" ""
|
||||
config_get "trusttunnel_health_check" "$section" "trusttunnel_health_check" ""
|
||||
config_get "trusttunnel_quic" "$section" "trusttunnel_quic" ""
|
||||
config_get "trusttunnel_congestion_controller" "$section" "trusttunnel_congestion_controller" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
server: "$server"
|
||||
port: $port
|
||||
EOF
|
||||
if [ -n "$trusttunnel_username" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
username: "$trusttunnel_username"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$trusttunnel_password" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
password: "$trusttunnel_password"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$trusttunnel_health_check" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
health-check: $trusttunnel_health_check
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$trusttunnel_quic" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
quic: $trusttunnel_quic
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$trusttunnel_congestion_controller" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
congestion-controller: "$trusttunnel_congestion_controller"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$client_fingerprint" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
client-fingerprint: "$client_fingerprint"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$udp" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
udp: $udp
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$sni" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
sni: "$sni"
|
||||
EOF
|
||||
fi
|
||||
if [ ! -z "$alpn" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
alpn:
|
||||
EOF
|
||||
config_list_foreach "$section" "alpn" set_alpn
|
||||
fi
|
||||
if [ ! -z "$skip_cert_verify" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
skip-cert-verify: $skip_cert_verify
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
#ip_version
|
||||
if [ ! -z "$ip_version" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
|
||||
@@ -21,6 +21,9 @@ yml_other_set()
|
||||
|
||||
begin
|
||||
thread_pool = [];
|
||||
# GEOIP replace
|
||||
geoip_pattern = /GEOIP,([A-Za-z]{2}),([^,]+)(,.*)?/;
|
||||
match_pattern = /(^MATCH.*|^FINAL.*)/;
|
||||
thread_pool << Thread.new{
|
||||
#BT/P2P DIRECT Rules
|
||||
begin
|
||||
@@ -102,10 +105,6 @@ yml_other_set()
|
||||
end;
|
||||
end;
|
||||
|
||||
# GEOIP replace
|
||||
geoip_pattern = /GEOIP,([A-Za-z]{2}),([^,]+)(,.*)?/;
|
||||
match_pattern = /(^MATCH.*|^FINAL.*)/;
|
||||
|
||||
Value['rules'].to_a.collect!{|x|
|
||||
x.to_s.gsub(geoip_pattern, 'GEOIP,\1,DIRECT\3').gsub(match_pattern, 'MATCH,DIRECT')
|
||||
};
|
||||
@@ -136,6 +135,18 @@ yml_other_set()
|
||||
{ file: '/etc/openclash/custom/openclash_custom_rules_2.list', position: 'bottom' }
|
||||
];
|
||||
|
||||
# 在开始对 custom_files 进行插入之前,记录当前 rules 中 GEOIP、MATCH、DST-PORT,80 的原始规则文本(锚点)
|
||||
anchors_orig = {}
|
||||
if Value.has_key?('rules') and not Value['rules'].to_a.empty? then
|
||||
anchors_orig[:dst80_rule] = Value['rules'].grep(/DST-PORT,80/).last
|
||||
anchors_orig[:match_rule] = Value['rules'].grep(match_pattern).first
|
||||
anchors_orig[:geo_rule] = Value['rules'].grep(geoip_pattern).first
|
||||
else
|
||||
anchors_orig[:dst80_rule] = nil
|
||||
anchors_orig[:match_rule] = nil
|
||||
anchors_orig[:geo_rule] = nil
|
||||
end;
|
||||
|
||||
custom_files.each{|file_info|
|
||||
if File::exist?(file_info[:file]) then
|
||||
custom_data = YAML.load_file(file_info[:file]);
|
||||
@@ -150,6 +161,13 @@ yml_other_set()
|
||||
[]
|
||||
end;
|
||||
|
||||
rule_providers_array = case custom_data.class.to_s
|
||||
when 'Hash'
|
||||
custom_data['rule-providers'].to_a if custom_data['rule-providers'].class.to_s == 'Hash'
|
||||
else
|
||||
[]
|
||||
end;
|
||||
|
||||
next unless rules_array;
|
||||
|
||||
ipv4_regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
@@ -157,9 +175,10 @@ yml_other_set()
|
||||
cidr_regex = /\/\d+$/;
|
||||
rule_suffix_regex = /^no-resolve$|^src$/;
|
||||
|
||||
ip_rule_types = ['IP-CIDR', 'IP-CIDR6', 'SRC-IP-CIDR', 'SRC-IP-CIDR6', 'IP-SUFFIX', 'SRC-IP-SUFFIX'];
|
||||
transformed_rules = rules_array.map{|x|
|
||||
parts = x.split(',');
|
||||
if parts.length >= 2 then
|
||||
if parts.length >= 2 && ip_rule_types.include?(parts[0].strip.upcase) then
|
||||
ip_part = parts[1].strip;
|
||||
if ip_part !~ cidr_regex then
|
||||
# IPv4
|
||||
@@ -194,11 +213,15 @@ yml_other_set()
|
||||
if file_info[:position] == 'top' then
|
||||
valid_rules.reverse.each{|x| Value['rules'].insert(0,x)};
|
||||
else
|
||||
if Value['rules'].grep(/GEOIP/)[0].nil? or Value['rules'].grep(/GEOIP/)[0].empty? then
|
||||
ruby_add_index = Value['rules'].index(Value['rules'].grep(/DST-PORT,80/).last);
|
||||
ruby_add_index ||= Value['rules'].index(Value['rules'].grep(/(MATCH|FINAL)/).first);
|
||||
else
|
||||
ruby_add_index = Value['rules'].index(Value['rules'].grep(/GEOIP/).first);
|
||||
ruby_add_index = nil;
|
||||
if anchors_orig[:dst80_rule]
|
||||
ruby_add_index = Value['rules'].rindex(anchors_orig[:dst80_rule])
|
||||
end;
|
||||
if ruby_add_index.nil? and anchors_orig[:match_rule]
|
||||
ruby_add_index = Value['rules'].rindex(anchors_orig[:match_rule])
|
||||
end;
|
||||
if ruby_add_index.nil? and anchors_orig[:geo_rule]
|
||||
ruby_add_index = Value['rules'].rindex(anchors_orig[:geo_rule])
|
||||
end;
|
||||
ruby_add_index ||= -1;
|
||||
|
||||
@@ -209,6 +232,11 @@ yml_other_set()
|
||||
else
|
||||
Value['rules'] = valid_rules.uniq;
|
||||
end;
|
||||
|
||||
if rule_providers_array and not rule_providers_array.empty? then
|
||||
Value['rule-providers'] ||= {};
|
||||
Value['rule-providers'] = Value['rule-providers'].merge!(custom_data['rule-providers']);
|
||||
end;
|
||||
end;
|
||||
};
|
||||
|
||||
@@ -256,19 +284,13 @@ yml_other_set()
|
||||
thread_pool << Thread.new{
|
||||
threads = [];
|
||||
|
||||
#provider path
|
||||
#provider CDN
|
||||
begin
|
||||
provider_configs = {'proxy-providers' => 'proxy_provider', 'rule-providers' => 'rule_provider'};
|
||||
provider_configs.each do |provider_type, path_prefix|
|
||||
if Value.key?(provider_type) then
|
||||
if Value.key?(provider_type) && Value[provider_type].is_a?(Hash) then
|
||||
Value[provider_type].each{|name, config|
|
||||
threads << Thread.new {
|
||||
if config['path'] and not config['path'] =~ /.\/#{path_prefix}\/*/ then
|
||||
config['path'] = './'+path_prefix+'/'+File.basename(config['path']);
|
||||
elsif not config['path'] and config['type'] == 'http' then
|
||||
config['path'] = './'+path_prefix+'/'+name;
|
||||
end;
|
||||
|
||||
# CDN
|
||||
if '$github_address_mod' != '0' and config['url'] then
|
||||
if config['url'] =~ /^https:\/\/raw.githubusercontent.com/ then
|
||||
@@ -293,12 +315,12 @@ yml_other_set()
|
||||
end;
|
||||
end;
|
||||
rescue Exception => e
|
||||
YAML.LOG_ERROR('Edit Provider Path Failed,【' + e.message + '】');
|
||||
YAML.LOG_ERROR('Edit Provider CDN Failed,【' + e.message + '】');
|
||||
end;
|
||||
|
||||
# tolerance
|
||||
begin
|
||||
if '$tolerance' != '0' and Value.key?('proxy-groups') then
|
||||
if '$tolerance' != '0' and Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then
|
||||
Value['proxy-groups'].each{|group|
|
||||
threads << Thread.new {
|
||||
if group['type'] == 'url-test' then
|
||||
@@ -314,7 +336,7 @@ yml_other_set()
|
||||
# URL-Test interval
|
||||
begin
|
||||
if '$urltest_interval_mod' != '0' then
|
||||
if Value.key?('proxy-groups') then
|
||||
if Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then
|
||||
Value['proxy-groups'].each{|group|
|
||||
threads << Thread.new {
|
||||
if ['url-test', 'fallback', 'load-balance', 'smart'].include?(group['type']) then
|
||||
@@ -349,7 +371,7 @@ yml_other_set()
|
||||
};
|
||||
};
|
||||
end;
|
||||
if Value.key?('proxy-groups') then
|
||||
if Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then
|
||||
Value['proxy-groups'].each{|group|
|
||||
threads << Thread.new {
|
||||
if ['url-test', 'fallback', 'load-balance', 'smart'].include?(group['type']) then
|
||||
@@ -365,7 +387,7 @@ yml_other_set()
|
||||
|
||||
# smart auto switch
|
||||
begin
|
||||
if ('${8}' == '1' or '${9}' == '1' or '${11}' != '0' or '${12}' != '0' or '${12}' == '1' or '${13}' == '1') and Value.key?('proxy-groups') then
|
||||
if ('${8}' == '1' or '${9}' == '1' or '${11}' != '0' or '${12}' != '0' or '${12}' == '1' or '${13}' == '1') and Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then
|
||||
Value['proxy-groups'].each{|group|
|
||||
threads << Thread.new {
|
||||
if '${8}' == '1' and ['url-test', 'load-balance'].include?(group['type']) then
|
||||
|
||||
Reference in new issue
Block a user