Repository: HMBSbige/ShadowsocksR-Windows Branch: master Commit: a8a088458c59 Files: 223 Total size: 1.3 MB Directory structure: gitextract_jyjjkvlh/ ├── .editorconfig ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── config.yml │ │ ├── feature_request.md │ │ └── other-issue.md │ ├── renovate.json │ └── workflows/ │ └── CI.yml ├── .gitignore ├── Build/ │ └── DotNetDllPathPatcher.ps1 ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── UnitTest/ │ ├── DnsTest.cs │ ├── EncryptionTest.cs │ ├── IPSubnet.cs │ ├── ServerTest.cs │ ├── SubscribeTest.cs │ ├── UnitTest.cs │ └── UnitTest.csproj ├── build.ps1 ├── shadowsocks-csharp/ │ ├── Controller/ │ │ ├── AutoStartup.cs │ │ ├── FileManager.cs │ │ ├── HttpRequest/ │ │ │ ├── GfwListUpdater.cs │ │ │ ├── HttpRequest.cs │ │ │ ├── UpdateChecker.cs │ │ │ └── UpdateNode.cs │ │ ├── Logging.cs │ │ ├── MainController.cs │ │ ├── MenuViewController.cs │ │ ├── Service/ │ │ │ ├── HostDaemon.cs │ │ │ ├── HostMap.cs │ │ │ ├── HttpPortForwarder.cs │ │ │ ├── HttpProxyRunner.cs │ │ │ ├── Listener.cs │ │ │ ├── Local.cs │ │ │ ├── PACDaemon.cs │ │ │ ├── PACServer.cs │ │ │ ├── ProtocolResponseDetector.cs │ │ │ ├── Socks5Forwarder.cs │ │ │ ├── SpeedTest.cs │ │ │ └── UpdateSubscribeManager.cs │ │ └── SystemProxy.cs │ ├── Data/ │ │ ├── abp.js │ │ ├── chn_ip.txt │ │ ├── proxy.pac.txt │ │ └── user-rule.txt │ ├── Encryption/ │ │ ├── CircularBuffer/ │ │ │ └── ByteCircularBuffer.cs │ │ ├── CryptoUtils.cs │ │ ├── EncryptorBase.cs │ │ ├── EncryptorFactory.cs │ │ ├── EncryptorInfo.cs │ │ ├── Exception/ │ │ │ └── CryptoException.cs │ │ ├── IEncryptor.cs │ │ ├── OpenSSL.cs │ │ ├── Sodium.cs │ │ └── Stream/ │ │ ├── NoneEncryptor.cs │ │ ├── StreamEncryptor.cs │ │ ├── StreamOpenSSLEncryptor.cs │ │ └── StreamSodiumEncryptor.cs │ ├── Enums/ │ │ ├── BalanceType.cs │ │ ├── DnsType.cs │ │ ├── HttpRequestProxyType.cs │ │ ├── LogLevel.cs │ │ ├── PacType.cs │ │ ├── PortMapType.cs │ │ ├── ProxyMode.cs │ │ ├── ProxyRuleMode.cs │ │ ├── ProxyType.cs │ │ └── ServerTreeViewType.cs │ ├── I18N/ │ │ ├── App.en-US.xaml │ │ ├── App.zh-CN.xaml │ │ ├── App.zh-TW.xaml │ │ ├── ConfigWindow.en-US.xaml │ │ ├── ConfigWindow.zh-CN.xaml │ │ ├── ConfigWindow.zh-TW.xaml │ │ ├── DnsSettingWindow.en-US.xaml │ │ ├── DnsSettingWindow.zh-CN.xaml │ │ ├── DnsSettingWindow.zh-TW.xaml │ │ ├── LogWindow.en-US.xaml │ │ ├── LogWindow.zh-CN.xaml │ │ ├── LogWindow.zh-TW.xaml │ │ ├── PortSettingsWindow.en-US.xaml │ │ ├── PortSettingsWindow.zh-CN.xaml │ │ ├── PortSettingsWindow.zh-TW.xaml │ │ ├── ServerLogWindow.en-US.xaml │ │ ├── ServerLogWindow.zh-CN.xaml │ │ ├── ServerLogWindow.zh-TW.xaml │ │ ├── SettingsWindow.en-US.xaml │ │ ├── SettingsWindow.zh-CN.xaml │ │ ├── SettingsWindow.zh-TW.xaml │ │ ├── SubscribeWindow.en-US.xaml │ │ ├── SubscribeWindow.zh-CN.xaml │ │ └── SubscribeWindow.zh-TW.xaml │ ├── Model/ │ │ ├── Configuration.cs │ │ ├── ConfigurationException.cs │ │ ├── Connections.cs │ │ ├── DnsBuffer.cs │ │ ├── DnsClient.cs │ │ ├── ErrorLog.cs │ │ ├── Global.cs │ │ ├── HostNode.cs │ │ ├── IPRangeSet.cs │ │ ├── IPSegment.cs │ │ ├── LRUCache.cs │ │ ├── MinSearchTree.cs │ │ ├── PortMapConfig.cs │ │ ├── PortMapConfigCache.cs │ │ ├── Rule.cs │ │ ├── Server.cs │ │ ├── ServerSelectStrategy.cs │ │ ├── ServerSubscribe.cs │ │ ├── ServerTreeViewModel.cs │ │ ├── Transfer/ │ │ │ ├── ServerSpeedLog.cs │ │ │ ├── ServerTrans.cs │ │ │ ├── ServerTransferTotal.cs │ │ │ └── TransLog.cs │ │ ├── UriVisitTime.cs │ │ └── WindowStatus.cs │ ├── Obfs/ │ │ ├── AuthAES128SHA1.cs │ │ ├── AuthAkarin.cs │ │ ├── AuthAkarin_spec_a.cs │ │ ├── AuthChain_a.cs │ │ ├── AuthChain_b.cs │ │ ├── AuthChain_c.cs │ │ ├── AuthChain_d.cs │ │ ├── AuthChain_e.cs │ │ ├── AuthChain_f.cs │ │ ├── AuthData.cs │ │ ├── AuthSHA1.cs │ │ ├── AuthSHA1V2.cs │ │ ├── AuthSHA1V4.cs │ │ ├── HttpSimpleObfs.cs │ │ ├── IObfs.cs │ │ ├── ObfsBase.cs │ │ ├── ObfsException.cs │ │ ├── ObfsFactory.cs │ │ ├── Plain.cs │ │ ├── ProtocolException.cs │ │ ├── ServerInfo.cs │ │ ├── TlsAuthData.cs │ │ ├── TlsTicketAuthObfs.cs │ │ ├── VerifyData.cs │ │ ├── VerifyDeflateObfs.cs │ │ ├── VerifySimpleBase.cs │ │ └── xorshift128plus.cs │ ├── Program.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── Proxy/ │ │ ├── CallbackState.cs │ │ ├── CallbackStatus.cs │ │ ├── Handler.cs │ │ ├── HandlerConfig.cs │ │ ├── HttpParser.cs │ │ ├── IHandler.cs │ │ ├── ProxyAuthHandler.cs │ │ ├── ProxyEncryptSocket.cs │ │ ├── ProxySocketTun.cs │ │ └── ProxySocketTunLocal.cs │ ├── SyncfusionLicenseRegister.bat │ ├── Util/ │ │ ├── Base64.cs │ │ ├── CRC.cs │ │ ├── ColorConvert.cs │ │ ├── Constants.cs │ │ ├── I18NUtil.cs │ │ ├── JsonUtils.cs │ │ ├── NetUtils/ │ │ │ ├── DnsUtil.cs │ │ │ ├── IPSubnet.cs │ │ │ ├── SocketUtil.cs │ │ │ └── WrappedSocket.cs │ │ ├── QrCodeUtils.cs │ │ ├── RNG.cs │ │ ├── Reg.cs │ │ ├── Utils.cs │ │ └── ViewUtils.cs │ ├── View/ │ │ ├── Controls/ │ │ │ ├── BindablePasswordBox.cs │ │ │ ├── GridColumnSizerExt.cs │ │ │ ├── MaskedTextBox.xaml │ │ │ ├── MaskedTextBox.xaml.cs │ │ │ ├── NumberUpDown.xaml │ │ │ └── NumberUpDown.xaml.cs │ │ ├── DnsSettingWindow.xaml │ │ ├── DnsSettingWindow.xaml.cs │ │ ├── LogWindow.xaml │ │ ├── LogWindow.xaml.cs │ │ ├── NotifyIconResources.xaml │ │ ├── PortSettingsWindow.xaml │ │ ├── PortSettingsWindow.xaml.cs │ │ ├── QRCodeSplashWindow.xaml │ │ ├── QRCodeSplashWindow.xaml.cs │ │ ├── ServerConfigWindow.xaml │ │ ├── ServerConfigWindow.xaml.cs │ │ ├── ServerLogWindow.xaml │ │ ├── ServerLogWindow.xaml.cs │ │ ├── SettingsWindow.xaml │ │ ├── SettingsWindow.xaml.cs │ │ ├── ShowTextWindow.xaml │ │ ├── ShowTextWindow.xaml.cs │ │ ├── SubscribeWindow.xaml │ │ ├── SubscribeWindow.xaml.cs │ │ └── ValueConverter/ │ │ ├── BalanceTypeEnumConverter.cs │ │ ├── BooleanToEnabledConverter.cs │ │ ├── ConnectEmptyToBrushConverter.cs │ │ ├── ConnectErrorToBrushConverter.cs │ │ ├── ConnectNumberToBrushConverter.cs │ │ ├── ErrorPercentToBrushConverter.cs │ │ ├── LatencyToBrushConverter.cs │ │ ├── ProxyTypeConverter.cs │ │ ├── ProxyTypeEnumConverter.cs │ │ ├── ServerTreeTypeToFontConverter.cs │ │ ├── SpeedToBrushConverter.cs │ │ ├── TotalDownloadBackgroundBrushConvert.cs │ │ ├── TotalDownloadRawBackgroundBrushConvert.cs │ │ ├── TotalUploadBackgroundBrushConvert.cs │ │ └── UnixSecondsToString.cs │ ├── ViewModel/ │ │ ├── DnsSettingViewModel.cs │ │ ├── ServerConfigViewModel.cs │ │ ├── ServerLogViewModel.cs │ │ ├── SettingViewModel.cs │ │ ├── SubscribeWindowViewModel.cs │ │ └── ViewModelBase.cs │ └── shadowsocksr.csproj └── shadowsocks-csharp.sln ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ # 如果要从更高级别的目录继承 .editorconfig 设置,请删除以下行 root = true [*] # 字符集 charset = utf-8 # 缩进和间距 indent_style = space indent_size = 4 # 新行首选项 end_of_line = crlf insert_final_newline = true [*.bat] indent_style = tab [*.csproj] indent_size = 2 # c# 文件 [*.cs] # 缩进和间距 indent_style = space #### .NET 编码约定 #### # 组织 Using dotnet_separate_import_directive_groups = false dotnet_sort_system_directives_first = false file_header_template = unset # this. 和 Me. 首选项 dotnet_style_qualification_for_event = false:warning dotnet_style_qualification_for_field = false:warning dotnet_style_qualification_for_method = false:warning dotnet_style_qualification_for_property = false:warning # 语言关键字与 bcl 类型首选项 dotnet_style_predefined_type_for_locals_parameters_members = true:warning dotnet_style_predefined_type_for_member_access = true:warning # 括号首选项 dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:silent dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:silent dotnet_style_parentheses_in_other_operators = never_if_unnecessary:warning dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:silent # 修饰符首选项 dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning # 表达式级首选项 dotnet_style_coalesce_expression = true:warning dotnet_style_collection_initializer = true:warning dotnet_style_explicit_tuple_names = true:warning dotnet_style_null_propagation = true:warning dotnet_style_object_initializer = true:warning dotnet_style_operator_placement_when_wrapping = beginning_of_line dotnet_style_prefer_auto_properties = true:warning dotnet_style_prefer_compound_assignment = true:warning dotnet_style_prefer_conditional_expression_over_assignment = true:silent dotnet_style_prefer_conditional_expression_over_return = true:silent dotnet_style_prefer_inferred_anonymous_type_member_names = true:silent dotnet_style_prefer_inferred_tuple_names = true:silent dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning dotnet_style_prefer_simplified_boolean_expressions = true:warning dotnet_style_prefer_simplified_interpolation = true:suggestion # 字段首选项 dotnet_style_readonly_field = true:suggestion # 参数首选项 dotnet_code_quality_unused_parameters = all:warning # 禁止显示首选项 dotnet_remove_unnecessary_suppression_exclusions = none #### c# 编码约定 #### # var 首选项 csharp_style_var_elsewhere = true:silent csharp_style_var_for_built_in_types = true:warning csharp_style_var_when_type_is_apparent = true:warning # Expression-bodied 成员 csharp_style_expression_bodied_accessors = when_on_single_line:warning csharp_style_expression_bodied_constructors = false:suggestion csharp_style_expression_bodied_indexers = when_on_single_line:warning csharp_style_expression_bodied_lambdas = when_on_single_line:suggestion csharp_style_expression_bodied_local_functions = false:suggestion csharp_style_expression_bodied_methods = false:suggestion csharp_style_expression_bodied_operators = false:suggestion csharp_style_expression_bodied_properties = when_on_single_line:warning # 模式匹配首选项 csharp_style_pattern_matching_over_as_with_null_check = true:warning csharp_style_pattern_matching_over_is_with_cast_check = true:warning csharp_style_prefer_not_pattern = true:warning csharp_style_prefer_pattern_matching = true:warning csharp_style_prefer_switch_expression = true:warning # Null 检查首选项 csharp_style_conditional_delegate_call = true:warning # 修饰符首选项 csharp_prefer_static_local_function = true:suggestion csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion # 代码块首选项 csharp_prefer_braces = true:warning csharp_prefer_simple_using_statement = true:suggestion # 表达式级首选项 csharp_prefer_simple_default_expression = true:warning csharp_style_deconstructed_variable_declaration = true:suggestion csharp_style_inlined_variable_declaration = true:warning csharp_style_pattern_local_over_anonymous_function = true:suggestion csharp_style_prefer_index_operator = true:warning csharp_style_prefer_range_operator = true:suggestion csharp_style_throw_expression = true:suggestion csharp_style_unused_value_assignment_preference = discard_variable:silent csharp_style_unused_value_expression_statement_preference = discard_variable:silent # "using" 指令首选项 csharp_using_directive_placement = outside_namespace:warning #### C# 格式规则 #### # 新行首选项 csharp_new_line_before_catch = true csharp_new_line_before_else = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_open_brace = all csharp_new_line_between_query_expression_clauses = true # 缩进首选项 csharp_indent_block_contents = true csharp_indent_braces = false csharp_indent_case_contents = true csharp_indent_case_contents_when_block = false csharp_indent_labels = flush_left csharp_indent_switch_labels = true # 空格键首选项 csharp_space_after_cast = false csharp_space_after_colon_in_inheritance_clause = true csharp_space_after_comma = true csharp_space_after_dot = false csharp_space_after_keywords_in_control_flow_statements = true csharp_space_after_semicolon_in_for_statement = true csharp_space_around_binary_operators = before_and_after csharp_space_around_declaration_statements = false csharp_space_before_colon_in_inheritance_clause = true csharp_space_before_comma = false csharp_space_before_dot = false csharp_space_before_open_square_brackets = false csharp_space_before_semicolon_in_for_statement = false csharp_space_between_empty_square_brackets = false csharp_space_between_method_call_empty_parameter_list_parentheses = false csharp_space_between_method_call_name_and_opening_parenthesis = false csharp_space_between_method_call_parameter_list_parentheses = false csharp_space_between_method_declaration_empty_parameter_list_parentheses = false csharp_space_between_method_declaration_name_and_open_parenthesis = false csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_space_between_square_brackets = false # 包装首选项 csharp_preserve_single_line_blocks = true csharp_preserve_single_line_statements = false #### 命名样式 #### # 命名规则 dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion dotnet_naming_rule.types_should_be_pascal_case.symbols = types dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case # 符号规范 dotnet_naming_symbols.interface.applicable_kinds = interface dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal dotnet_naming_symbols.interface.required_modifiers = dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal dotnet_naming_symbols.types.required_modifiers = dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal dotnet_naming_symbols.non_field_members.required_modifiers = # 命名样式 dotnet_naming_style.pascal_case.required_prefix = dotnet_naming_style.pascal_case.required_suffix = dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case dotnet_naming_style.begins_with_i.required_prefix = I dotnet_naming_style.begins_with_i.required_suffix = dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: "[BUG]" labels: Bug assignees: '' --- **描述 bug** 简要描述所遇到的bug **如何复现** 说明您在进行了怎样的操作后出现了bug: 1. 2. 3. **预期行为** 简要描述进行以上操作后预期的脚本行为 **截图** 如果可以,请添加屏幕截图以帮助解释您的问题 **环境** - 系统:[如 Windows 10 1809] - 浏览器:[如 Chrome 74.0.3729.157,无关则删除] - 程序版本:[如 5.0.0.0 .Net Core SelfContained x64] **其它内容** 在此添加有关此问题的任何其它内容。 最好能贴上相关的日志 ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: Telegram Channel url: https://t.me/ShadowsocksR_Windows about: Telegram Channel ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: Enhancement assignees: '' --- **您的功能请求是否与 BUG 有关? 请描述一下。** 简明扼要地描述了问题所在 **描述您想要的解决方案** 简明扼要地描述您想要发生的事情 **描述您考虑过的替代方案** 对您考虑的任何替代解决方案或功能的简明扼要描述 **其它内容** 在此处添加有关功能请求的任何其它内容或屏幕截图 ================================================ FILE: .github/ISSUE_TEMPLATE/other-issue.md ================================================ --- name: Other issue about: Other issue title: '' labels: '' assignees: '' --- 之所以写中文,本issue是写给打算写给乱发中文问题的人看的 1. 不欢迎小白,不回答诸如软件如何使用,如何搭建,如何配置,使用速度不快,如何提速等等和软件问题无关的问题,或把开发者当成客服的问题 2. 这里用于反馈软件可能的Bug,软件潜在的问题,和软件功能需求及讨论 3. 同一个issue不得在不同repo重复发,除非你发现发错地方(这种情况下你自行删除错误的issue),否则直接关闭且不回答问题,严重者拉黑名单 4. 建议你把问题事先在其它社区或和其它使用者讨论过,以确认不是密码错误,协议或插件错误,或服务器防火墙没关诸如此类本来应该自己解决的问题 5. 在你确认你需要发问题时,请尽可能提供详细的信息,包括服务端客户端具体版本,及相应log,及相应服务端客户端协议混淆等等的配置。如信息明显过少,则直接close不理踩 确认你读完以上内容后,请删除以上所有内容,然后写下你的问题 Please remove all above then write down your issue ================================================ FILE: .github/renovate.json ================================================ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "assignees": [ "HMBSbige" ], "commitMessagePrefix": "dep:", "dependencyDashboard": false, "extends": [ "config:base", ":automergeBranch", ":automergeDigest", ":automergeMinor", ":disableRateLimiting" ], "packageRules": [ { "matchPackagePrefixes": [ "Syncfusion" ], "groupName": "Syncfusion" } ], "labels": [ "Automatic" ] } ================================================ FILE: .github/workflows/CI.yml ================================================ name: CI on: [push, pull_request, workflow_dispatch] env: ProjectName: ShadowsocksR jobs: build: name: Build runs-on: windows-latest env: SyncfusionLicenseKey: ${{ secrets.SyncfusionLicenseKey }} NET_TFM: net7.0-windows Configuration: Release steps: - name: Checkout code uses: actions/checkout@v4 with: submodules: true - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: 7.0.x - name: Setup NuGet Private Sources shell: pwsh run: dotnet nuget add source https://nuget.pkg.github.com/HMBSbige/index.json -n GitHub-HMBSbige -u HMBSbige -p ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text - name: Build .NET App shell: pwsh run: .\build.ps1 app - name: Build x64 shell: pwsh run: .\build.ps1 x64 - name: Build x86 shell: pwsh run: .\build.ps1 x86 - name: Upload .NET App continue-on-error: true if: ${{ !startsWith(github.ref, 'refs/tags/') }} uses: actions/upload-artifact@v4 with: name: ${{ env.ProjectName }} path: shadowsocks-csharp\bin\${{ env.Configuration }}\${{ env.NET_TFM }}\publish\ - name: Upload x64 continue-on-error: true if: ${{ !startsWith(github.ref, 'refs/tags/') }} uses: actions/upload-artifact@v4 with: name: ${{ env.ProjectName }}-Win64 path: shadowsocks-csharp\bin\${{ env.Configuration }}\${{ env.NET_TFM }}\win-x64\publish\ - name: Upload x86 continue-on-error: true if: ${{ !startsWith(github.ref, 'refs/tags/') }} uses: actions/upload-artifact@v4 with: name: ${{ env.ProjectName }}-Win32 path: shadowsocks-csharp\bin\${{ env.Configuration }}\${{ env.NET_TFM }}\win-x86\publish\ - name: Get tag if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }} id: tag uses: dawidd6/action-get-tag@v1 - name: Package .NET App if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }} shell: pwsh run: | New-Item -ItemType Directory -Path C:\builtfiles -Force > $null $zip_path = "C:\builtfiles\$env:ProjectName-${{ steps.tag.outputs.tag }}.7z" 7z a -mx9 "$zip_path" ".\shadowsocks-csharp\bin\$env:Configuration\$env:NET_TFM\publish\" 7z rn "$zip_path" publish $env:ProjectName echo "NET_SHA256=$((Get-FileHash $zip_path -Algorithm SHA256).Hash)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Package x64 if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }} shell: pwsh run: | New-Item -ItemType Directory -Path C:\builtfiles -Force > $null $zip_path = "C:\builtfiles\$env:ProjectName-Win64-${{ steps.tag.outputs.tag }}.7z" 7z a -mx9 "$zip_path" ".\shadowsocks-csharp\bin\$env:Configuration\$env:NET_TFM\win-x64\publish\" 7z rn "$zip_path" publish $env:ProjectName echo "NET64_SHA256=$((Get-FileHash $zip_path -Algorithm SHA256).Hash)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Package x86 if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }} shell: pwsh run: | New-Item -ItemType Directory -Path C:\builtfiles -Force > $null $zip_path = "C:\builtfiles\$env:ProjectName-Win32-${{ steps.tag.outputs.tag }}.7z" 7z a -mx9 "$zip_path" ".\shadowsocks-csharp\bin\$env:Configuration\$env:NET_TFM\win-x86\publish\" 7z rn "$zip_path" publish $env:ProjectName echo "NET86_SHA256=$((Get-FileHash $zip_path -Algorithm SHA256).Hash)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Create a new GitHub release if a new tag is pushed uses: ncipollo/release-action@v1 if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }} with: token: ${{ secrets.GITHUB_TOKEN }} name: v${{ steps.tag.outputs.tag }} prerelease: true draft: false artifacts: C:\builtfiles\* body: | [![](https://img.shields.io/badge/Channel-blue?label=Telegram&logo=telegram)](https://t.me/ShadowsocksR_Windows) [![](https://img.shields.io/badge/Group-green?label=Telegram&logo=telegram)](https://t.me/joinchat/Gn-Aa0-j4HcpdBaW-Iv8Sw) ## 更新日志: * 这是 GitHub Action 自动化部署,更新日志应该很快会手动更新 ## 文件校验 | 文件名 | SHA256 | | :- | :- | | ${{ env.ProjectName }}-${{ steps.tag.outputs.tag }}.7z | ${{ env.NET_SHA256 }} | | ${{ env.ProjectName }}-Win64-${{ steps.tag.outputs.tag }}.7z | ${{ env.NET64_SHA256 }} | | ${{ env.ProjectName }}-Win32-${{ steps.tag.outputs.tag }}.7z | ${{ env.NET86_SHA256 }} | ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Mono auto generated files mono_crash.* # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # NuGet Symbol Packages *.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx *.appxbundle *.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- [Bb]ackup.rdl *- [Bb]ackup ([0-9]).rdl *- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ ================================================ FILE: Build/DotNetDllPathPatcher.ps1 ================================================ using namespace System.IO using namespace System.Text param([string]$exe_path, [string]$target_path = 'bin') $ErrorActionPreference = 'Stop' #$DebugPreference = 'Continue' $exe_path = (Resolve-Path -Path $exe_path).Path Write-Host "Origin path: `"$exe_path`"" Write-Host "Target dll path: $target_path" $separator = '\' $max_path_length = 1024 $exe_name = [Path]::GetFileName($exe_path) $dll_name = [Path]::ChangeExtension($exe_name, '.dll') Write-Debug "exe: $exe_name" Write-Debug "dll: $dll_name" function Update-Exe { $old_bytes = [Encoding]::UTF8.GetBytes("$dll_name`0") if ($old_bytes.Count -gt $max_path_length) { throw [PathTooLongException] 'old dll path is too long' } $new_dll_path = "$target_path$separator$dll_name" $new_bytes = [Encoding]::UTF8.GetBytes("$new_dll_path`0") Write-Host "Dll path Change to `"$new_dll_path`"" if ($new_bytes.Count -gt $max_path_length) { throw [PathTooLongException] 'new dll path is too long' } $bytes = [File]::ReadAllBytes($exe_path) $index = (Get-Content $exe_path -Raw -Encoding 28591).IndexOf("$dll_name`0") if ($index -lt 0) { throw [InvalidDataException] 'Could not find old dll path' } Write-Debug "Position: $index" $end_postion = $index + $($new_bytes.Count) $end_length = $bytes.Count - $end_postion if ($end_postion -gt $bytes.Count) { throw [PathTooLongException] 'new dll path is too long' } Write-Debug "End Position: $end_postion" Write-Debug "End Length: $end_length" $fs = [File]::OpenWrite($exe_path) try { $fs.Write($bytes, 0, $index) $fs.Write($new_bytes) $fs.Write($bytes, $end_postion, $end_length) } finally { $fs.Dispose(); } } function Move-Dll { $tmpbin = 'tmpbin' $dir = [Path]::GetDirectoryName($exe_path); $root = [Path]::GetDirectoryName($dir); Write-Debug "root path: $root" Write-Debug "dir path: $dir" Rename-Item $dir $tmpbin New-Item -ItemType Directory $dir > $null Move-Item $root\$tmpbin $dir Rename-Item $dir\$tmpbin $target_path Move-Item $dir\$target_path\$exe_name $dir } Update-Exe Move-Dll ================================================ FILE: CONTRIBUTING.md ================================================ How to Contribute ================= Pull Requests ------------- 1. Pull requests are welcome. 2. Make sure to pass the unit tests. Write unit tests for new modules if needed. ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: README.md ================================================ ShadowsocksR for Windows ======================= [![](https://img.shields.io/badge/Channel-blue?label=Telegram&logo=telegram)](https://t.me/ShadowsocksR_Windows) [![](https://img.shields.io/badge/Group-green?label=Telegram&logo=telegram)](https://t.me/joinchat/Gn-Aa0-j4HcpdBaW-Iv8Sw) ## Build [![](https://github.com/HMBSbige/ShadowsocksR-Windows/workflows/CI/badge.svg)](https://github.com/HMBSbige/ShadowsocksR-Windows/actions) ## [Wiki](https://github.com/HMBSbige/ShadowsocksR-Windows/wiki) ## Download * [latest release] ## Develop Visual Studio Community 2022 is recommended. ## License GPLv3 Copyright © 2019 - 2022 HMBSbige. Forked from ShadowsocksR by BreakWa11 [latest release]: https://github.com/HMBSbige/ShadowsocksR-Windows/releases ================================================ FILE: UnitTest/DnsTest.cs ================================================ using Microsoft.VisualStudio.TestTools.UnitTesting; using Shadowsocks.Enums; using Shadowsocks.Util.NetUtils; using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; namespace UnitTest; [TestClass] public class DnsTest { [TestMethod] public async Task DefaultTest() { var ip1 = await DnsUtil.QueryDefaultAsync(@"dns.google"); Assert.IsTrue(Equals(ip1, IPAddress.Parse(@"8.8.8.8")) || Equals(ip1, IPAddress.Parse(@"8.8.4.4"))); var ip2 = await DnsUtil.QueryDefaultAsync(@"dns.google", true); Assert.IsTrue(Equals(ip2, IPAddress.Parse(@"2001:4860:4860::8888")) || Equals(ip2, IPAddress.Parse(@"2001:4860:4860::8844"))); } [TestMethod] public async Task Test() { var client = new Shadowsocks.Model.DnsClient(DnsType.Default) { DnsServer = @"101.6.6.6", Port = 5353, IsTcpEnabled = true, IsUdpEnabled = false }; var ip = await client.QueryIpAddressAsync(@"www.google.com", default); Assert.IsNotNull(ip); Console.WriteLine(ip); } [TestMethod] public async Task DnsOverTlsTest() { var client = new Shadowsocks.Model.DnsClient(DnsType.DnsOverTls); var ip = await client.QueryIpAddressAsync(@"www.google.com", default); Assert.IsNotNull(ip); Console.WriteLine(ip); } [TestMethod] public async Task TestTwoDnsAsync() { const string host = @"www.google.com"; var clients = new List { new(DnsType.Default) { DnsServer = @"101.6.6.6", Port = 5353, IsTcpEnabled = true, IsUdpEnabled = false }, new(DnsType.DnsOverTls) }; var res = await DnsUtil.QueryAsync(host, clients); Assert.IsNotNull(res); Console.WriteLine(res); } [TestMethod] public async Task TestIpv6FallbackAsync() { const string host = @"speed.neu6.edu.cn"; var resDefault = await DnsUtil.QueryDefaultAsync(host); Assert.IsNotNull(resDefault); Console.WriteLine(resDefault); var clients = new List { new(DnsType.DnsOverTls) { DnsServer = @"dns.alidns.com" }, new(DnsType.Default) { DnsServer = @"114.114.114.114", Port = 53, IsTcpEnabled = true, IsUdpEnabled = false } }; var res = await DnsUtil.QueryAsync(host, clients); Assert.IsNotNull(res); Console.WriteLine(res); } [TestMethod] public async Task TestIpv6FirstAsync() { const string host = @"speed.neu.edu.cn"; var clients = new List { new(DnsType.Default) { DnsServer = @"114.114.114.114", Port = 53, IsTcpEnabled = true, IsUdpEnabled = false, Ipv6First = true } }; var res = await DnsUtil.QueryAsync(host, clients); Assert.IsNotNull(res); Assert.AreEqual(AddressFamily.InterNetworkV6, res.AddressFamily); Console.WriteLine(res); } } ================================================ FILE: UnitTest/EncryptionTest.cs ================================================ using Microsoft.VisualStudio.TestTools.UnitTesting; using Shadowsocks.Encryption; using Shadowsocks.Encryption.Stream; using Shadowsocks.Util; using System; using System.Collections.Generic; using System.Threading.Tasks; namespace UnitTest { [TestClass] public class EncryptionTest { private void RunEncryptionRound(IEncryptor encryptor, IEncryptor decryptor) { var plain = new byte[16384]; var cipher = new byte[plain.Length + 16]; var plain2 = new byte[plain.Length + 16]; Rng.RandBytes(plain); encryptor.Encrypt(plain, plain.Length, cipher, out var outLen); decryptor.Decrypt(cipher, outLen, plain2, out var outLen2); Assert.AreEqual(plain.Length, outLen2); for (var j = 0; j < plain.Length; j++) { Assert.AreEqual(plain[j], plain2[j]); } encryptor.Encrypt(plain, 1000, cipher, out outLen); decryptor.Decrypt(cipher, outLen, plain2, out outLen2); Assert.AreEqual(1000, outLen2); for (var j = 0; j < outLen2; j++) { Assert.AreEqual(plain[j], plain2[j]); } encryptor.Encrypt(plain, 12333, cipher, out outLen); decryptor.Decrypt(cipher, outLen, plain2, out outLen2); Assert.AreEqual(12333, outLen2); for (var j = 0; j < outLen2; j++) { Assert.AreEqual(plain[j], plain2[j]); } } [TestMethod] public void TestStreamOpenSSLEncryption() { var failed = false; // run it once before the multi-threading test to initialize global tables RunSingleStreamOpenSSLEncryptionThread(); var tasks = new List(); foreach (var cipher in StreamOpenSSLEncryptor.SupportedCiphers()) { if (cipher.EndsWith(@"-cbc")) { continue; } var t = new Task(() => { try { RunSingleStreamOpenSSLEncryptionThread(cipher); } catch (Exception e) { Console.WriteLine($@"{cipher}:{e.Message}"); failed = true; throw; } }); tasks.Add(t); t.Start(); } Task.WaitAll(tasks.ToArray()); Assert.IsFalse(failed); } private void RunSingleStreamOpenSSLEncryptionThread(string methodName = @"aes-256-cfb8", string password = @"barfoo!") { for (var i = 0; i < 100; i++) { IEncryptor encryptor = new StreamOpenSSLEncryptor(methodName, password); IEncryptor decryptor = new StreamOpenSSLEncryptor(methodName, password); RunEncryptionRound(encryptor, decryptor); } } [TestMethod] public void TestStreamSodiumEncryption() { var failed = false; // run it once before the multi-threading test to initialize global tables RunSingleStreamSodiumEncryptionThread(); var tasks = new List(); foreach (var cipher in StreamSodiumEncryptor.SupportedCiphers()) { if (cipher.StartsWith(@"x")) { continue; } var t = new Task(() => { try { RunSingleStreamSodiumEncryptionThread(cipher); } catch (Exception e) { Console.WriteLine($@"{cipher}:{e.Message}"); failed = true; throw; } }); tasks.Add(t); t.Start(); } Task.WaitAll(tasks.ToArray()); Assert.IsFalse(failed); } private void RunSingleStreamSodiumEncryptionThread(string methodName = @"salsa20", string password = @"barfoo!") { for (var i = 0; i < 100; i++) { IEncryptor encryptor = new StreamSodiumEncryptor(methodName, password); IEncryptor decryptor = new StreamSodiumEncryptor(methodName, password); RunEncryptionRound(encryptor, decryptor); } } } } ================================================ FILE: UnitTest/IPSubnet.cs ================================================ using Microsoft.VisualStudio.TestTools.UnitTesting; using Shadowsocks.Util.NetUtils; using System.Net; namespace UnitTest { [TestClass] public class IPSubnetTest { [TestMethod] public void IsLoopBackTest() { Assert.IsTrue(IPSubnet.IsLoopBack(IPAddress.Loopback)); Assert.IsTrue(IPSubnet.IsLoopBack(IPAddress.IPv6Loopback)); Assert.IsTrue(IPSubnet.IsLoopBack(IPAddress.Parse(@"127.0.0.255"))); Assert.IsTrue(IPSubnet.IsLoopBack(IPAddress.Parse(@"127.255.255.255"))); Assert.IsFalse(IPSubnet.IsLoopBack(IPAddress.Parse(@"192.168.1.1"))); Assert.IsFalse(IPSubnet.IsLoopBack(IPAddress.Parse(@"2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFFF"))); } [TestMethod] public void IsInSubnetTest() { Assert.IsTrue(IPAddress.Parse(@"192.168.5.1").IsInSubnet(@"192.168.5.85/24")); Assert.IsTrue(IPAddress.Parse(@"192.168.5.254").IsInSubnet(@"192.168.5.85/24")); Assert.IsTrue(IPAddress.Parse(@"10.128.240.48").IsInSubnet(@"10.128.240.50/30")); Assert.IsTrue(IPAddress.Parse(@"10.128.240.49").IsInSubnet(@"10.128.240.50/30")); Assert.IsTrue(IPAddress.Parse(@"10.128.240.50").IsInSubnet(@"10.128.240.50/30")); Assert.IsTrue(IPAddress.Parse(@"10.128.240.51").IsInSubnet(@"10.128.240.50/30")); Assert.IsFalse(IPAddress.Parse(@"192.168.4.254").IsInSubnet(@"192.168.5.85/24")); Assert.IsFalse(IPAddress.Parse(@"191.168.5.254").IsInSubnet(@"192.168.5.85/24")); Assert.IsFalse(IPAddress.Parse(@"10.128.240.47").IsInSubnet(@"10.128.240.50/30")); Assert.IsFalse(IPAddress.Parse(@"10.128.240.52").IsInSubnet(@"10.128.240.50/30")); Assert.IsFalse(IPAddress.Parse(@"10.128.239.50").IsInSubnet(@"10.128.240.50/30")); Assert.IsFalse(IPAddress.Parse(@"10.127.240.51").IsInSubnet(@"10.128.240.50/30")); Assert.IsTrue(IPAddress.Parse(@"2001:0DB8:ABCD:0012:0000:0000:0000:0000").IsInSubnet(@"2001:db8:abcd:0012::0/64")); Assert.IsTrue(IPAddress.Parse(@"2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFFF").IsInSubnet(@"2001:db8:abcd:0012::0/64")); Assert.IsTrue(IPAddress.Parse(@"2001:0DB8:ABCD:0012:0001:0000:0000:0000").IsInSubnet(@"2001:db8:abcd:0012::0/64")); Assert.IsTrue(IPAddress.Parse(@"2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFF0").IsInSubnet(@"2001:db8:abcd:0012::0/64")); Assert.IsTrue(IPAddress.Parse(@"2001:0DB8:ABCD:0012:0000:0000:0000:0000").IsInSubnet(@"2001:db8:abcd:0012::0/128")); Assert.IsFalse(IPAddress.Parse(@"2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFFF").IsInSubnet(@"2001:db8:abcd:0012::0/64")); Assert.IsFalse(IPAddress.Parse(@"2001:0DB8:ABCD:0013:0000:0000:0000:0000").IsInSubnet(@"2001:db8:abcd:0012::0/64")); Assert.IsFalse(IPAddress.Parse(@"2001:0DB8:ABCD:0013:0001:0000:0000:0000").IsInSubnet(@"2001:db8:abcd:0012::0/64")); Assert.IsFalse(IPAddress.Parse(@"2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFF0").IsInSubnet(@"2001:db8:abcd:0012::0/64")); Assert.IsFalse(IPAddress.Parse(@"2001:0DB8:ABCD:0012:0000:0000:0000:0001").IsInSubnet(@"2001:db8:abcd:0012::0/128")); } } } ================================================ FILE: UnitTest/ServerTest.cs ================================================ using Microsoft.VisualStudio.TestTools.UnitTesting; using Shadowsocks.Model; using System; namespace UnitTest { [TestClass] public class ServerTest { [TestMethod] public void TestServerFromSSR() { var server = new Server(); var nornameCase = "ssr://MTI3LjAuMC4xOjEyMzQ6YXV0aF9hZXMxMjhfbWQ1OmFlcy0xMjgtY2ZiOnRsczEuMl90aWNrZXRfYXV0aDpZV0ZoWW1KaS8_b2Jmc3BhcmFtPVluSmxZV3QzWVRFeExtMXZaUQ"; server.ServerFromSsr(nornameCase, ""); Assert.AreEqual(server.server, "127.0.0.1"); Assert.AreEqual(server.Server_Port, (ushort)1234); Assert.AreEqual(server.Protocol, "auth_aes128_md5"); Assert.AreEqual(server.Method, "aes-128-cfb"); Assert.AreEqual(server.obfs, "tls1.2_ticket_auth"); Assert.AreEqual(server.ObfsParam, "breakwa11.moe"); Assert.AreEqual(server.Password, "aaabbb"); server = new Server(); const string normalCaseWithRemark = "ssr://MTI3LjAuMC4xOjEyMzQ6YXV0aF9hZXMxMjhfbWQ1OmFlcy0xMjgtY2ZiOnRsczEuMl90aWNrZXRfYXV0aDpZV0ZoWW1KaS8_b2Jmc3BhcmFtPVluSmxZV3QzWVRFeExtMXZaUSZyZW1hcmtzPTVyV0w2Sy1WNUxpdDVwYUg"; server.ServerFromSsr(normalCaseWithRemark, "firewallAirport"); Assert.AreEqual(server.server, "127.0.0.1"); Assert.AreEqual(server.Server_Port, 1234); Assert.AreEqual(server.Protocol, "auth_aes128_md5"); Assert.AreEqual(server.Method, "aes-128-cfb"); Assert.AreEqual(server.obfs, "tls1.2_ticket_auth"); Assert.AreEqual(server.ObfsParam, "breakwa11.moe"); Assert.AreEqual(server.Password, "aaabbb"); Assert.AreEqual(server.Remarks, "测试中文"); Assert.AreEqual(server.Group, string.Empty); Assert.AreEqual(server.SubTag, "firewallAirport"); } [TestMethod] public void TestBadPortNumber() { var server = new Server(); const string link = "ssr://MTI3LjAuMC4xOjgwOmF1dGhfc2hhMV92NDpjaGFjaGEyMDpodHRwX3NpbXBsZTplaWZnYmVpd3ViZ3IvP29iZnNwYXJhbT0mcHJvdG9wYXJhbT0mcmVtYXJrcz0mZ3JvdXA9JnVkcHBvcnQ9NDY0MzgxMzYmdW90PTQ2MDA3MTI4"; try { server.ServerFromSsr(link, ""); } catch (OverflowException e) { Console.Write(e.ToString()); } } } } ================================================ FILE: UnitTest/SubscribeTest.cs ================================================ using Microsoft.VisualStudio.TestTools.UnitTesting; using Shadowsocks.Controller.HttpRequest; using Shadowsocks.Util; using System; using System.Text.RegularExpressions; namespace UnitTest { [TestClass] public class SubscribeTest { [TestMethod] public void ParseTest() { var url = @"sub://aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0hNQlNiaWdlL1RleHRfVHJhbnNsYXRpb24vbWFzdGVyL1NoYWRvd3NvY2tzUi9mcmVlbm9kZXBsYWluLnR4dA"; var sub = Regex.Match(url, "sub://([A-Za-z0-9_-]+)", RegexOptions.IgnoreCase); if (!sub.Success) { throw new FormatException(); } var res = Base64.DecodeUrlSafeBase64(sub.Groups[1].Value); Assert.AreEqual(res, UpdateNode.DefaultUpdateUrl); } } } ================================================ FILE: UnitTest/UnitTest.cs ================================================ using Microsoft.VisualStudio.TestTools.UnitTesting; using Shadowsocks.Encryption; using Shadowsocks.Util; using System.Linq; using System.Security.Cryptography; using System.Text; namespace UnitTest { [TestClass] public class UnitTest { [TestMethod] public void TestMd5() { var buff = Encoding.UTF8.GetBytes(@"密码"); var md5Sum = CryptoUtils.MD5(buff); var md5Hash = MD5.Create().ComputeHash(buff); Assert.IsTrue(md5Hash.SequenceEqual(md5Sum)); } [TestMethod] public void EncryptStringTest() { var largeBytes = new byte[ushort.MaxValue * 100]; Rng.RandBytes(largeBytes); var largeStr = Encoding.UTF8.GetString(largeBytes); using var encryptor = EncryptorFactory.GetEncryptor(@"aes-256-cfb", @"密码"); var encodeStr = Utils.EncryptLargeBytesToBase64String(encryptor, largeBytes); var decodeStr = Encoding.UTF8.GetString(Utils.DecryptLargeBase64StringToBytes(encryptor, encodeStr)); Assert.AreEqual(largeStr, decodeStr); } } } ================================================ FILE: UnitTest/UnitTest.csproj ================================================ net7.0-windows latest false ================================================ FILE: build.ps1 ================================================ param([string]$buildtfm = 'all') $ErrorActionPreference = 'Stop' Write-Host 'dotnet SDK info' dotnet --info $exe = 'ShadowsocksR.exe' $net_tfm = 'net7.0-windows' $configuration = 'Release' $output_dir = "$PSScriptRoot\shadowsocks-csharp\bin\$configuration" $proj_path = "$PSScriptRoot\shadowsocks-csharp\shadowsocksr.csproj" $build = $buildtfm -eq 'all' -or $buildtfm -eq 'app' $buildX86 = $buildtfm -eq 'all' -or $buildtfm -eq 'x86' $buildX64 = $buildtfm -eq 'all' -or $buildtfm -eq 'x64' function Build-App { Write-Host 'Building .NET App' $outdir = "$output_dir\$net_tfm" $publishDir = "$outdir\publish" Remove-Item $publishDir -Recurse -Force -Confirm:$false -ErrorAction Ignore dotnet publish -c $configuration -f $net_tfm $proj_path if ($LASTEXITCODE) { exit $LASTEXITCODE } & "$PSScriptRoot\Build\DotNetDllPathPatcher.ps1" $publishDir\$exe bin if ($LASTEXITCODE) { exit $LASTEXITCODE } } function Build-SelfContained { param([string]$rid) Write-Host "Building .NET App SelfContained $rid" $outdir = "$output_dir\$net_tfm\$rid" $publishDir = "$outdir\publish" Remove-Item $publishDir -Recurse -Force -Confirm:$false -ErrorAction Ignore dotnet publish -c $configuration -f $net_tfm -r $rid --self-contained true $proj_path if ($LASTEXITCODE) { exit $LASTEXITCODE } & "$PSScriptRoot\Build\DotNetDllPathPatcher.ps1" $publishDir\$exe bin if ($LASTEXITCODE) { exit $LASTEXITCODE } } if ($build) { Build-App } if ($buildX64) { Build-SelfContained win-x64 } if ($buildX86) { Build-SelfContained win-x86 } ================================================ FILE: shadowsocks-csharp/Controller/AutoStartup.cs ================================================ using CryptoBase; using RunAtStartup; using System; using System.IO; using Utils = Shadowsocks.Util.Utils; namespace Shadowsocks.Controller { internal static class AutoStartup { private static readonly string Key = $@"ShadowsocksR_{Directory.GetCurrentDirectory().GetClassicHashCode()}"; public static bool Set(bool enabled) { try { var path = $@"""{Utils.GetExecutablePath()}"""; var service = new StartupService(Key); if (enabled) { service.Set(path); } else { service.Delete(); } return true; } catch (Exception e) { Logging.LogUsefulException(e); return false; } } public static bool Check() { try { var path = $@"""{Utils.GetExecutablePath()}"""; var service = new StartupService(Key); return service.Check(path); } catch (Exception e) { Logging.LogUsefulException(e); return false; } } } } ================================================ FILE: shadowsocks-csharp/Controller/FileManager.cs ================================================ using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.IO.Compression; using System.Text; using System.Threading.Tasks; namespace Shadowsocks.Controller { public static class FileManager { public static bool ByteArrayToFile(string fileName, byte[] content) { try { var fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write); fileStream.Write(content, 0, content.Length); fileStream.Close(); return true; } catch (Exception ex) { Console.WriteLine($@"Exception caught in process: {ex}"); } return false; } public static void DecompressFile(string fileName, byte[] content) { var destinationFile = File.Create(fileName); // Because the uncompressed size of the file is unknown, // we are using an arbitrary buffer size. var buffer = new byte[4096]; using (var input = new GZipStream(new MemoryStream(content), CompressionMode.Decompress, false)) { while (true) { var n = input.Read(buffer, 0, buffer.Length); if (n == 0) { break; } destinationFile.Write(buffer, 0, n); } } destinationFile.Close(); } public static byte[] DeflateCompress(byte[] content, int index, int count, out int size) { size = 0; try { var memStream = new MemoryStream(); using (var ds = new DeflateStream(memStream, CompressionMode.Compress)) { ds.Write(content, index, count); } var buffer = memStream.ToArray(); size = buffer.Length; return buffer; } catch (Exception ex) { Console.WriteLine($@"Exception caught in process: {ex}"); } return null; } public static byte[] DeflateDecompress(byte[] content, int index, int count, out int size) { size = 0; try { var buffer = new byte[16384]; var ds = new DeflateStream(new MemoryStream(content, index, count), CompressionMode.Decompress); while (true) { var readSize = ds.Read(buffer, size, buffer.Length - size); if (readSize == 0) { break; } size += readSize; var newBuffer = new byte[buffer.Length * 2]; buffer.CopyTo(newBuffer, 0); buffer = newBuffer; } return buffer; } catch (Exception ex) { Console.WriteLine($@"Exception caught in process: {ex}"); } return null; } [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] public static async Task ZipCompressToFile(string path) { try { var filename = Path.GetFileName(path); var zipFilePath = $@"{Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path))}.zip"; using (var zipFileToOpen = new FileStream(zipFilePath, FileMode.Create)) { using var archive = new ZipArchive(zipFileToOpen, ZipArchiveMode.Create); var readMeEntry = archive.CreateEntry(filename); using var zipStream = readMeEntry.Open(); using var stream = File.Open(path, FileMode.Open); var bytes = new byte[(int)stream.Length]; var totalBytesRead = 0; while (totalBytesRead < bytes.Length) { totalBytesRead += await stream.ReadAsync(bytes, totalBytesRead, bytes.Length - totalBytesRead); } await zipStream.WriteAsync(bytes, 0, bytes.Length); } return true; } catch { return false; } } public static string NonExclusiveReadAllText(string path) { return NonExclusiveReadAllText(path, Encoding.UTF8); } public static string NonExclusiveReadAllText(string path, Encoding encoding) { try { using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using var sr = new StreamReader(fs, encoding); return sr.ReadToEnd(); } catch (Exception ex) { Logging.Error(ex); throw; } } } } ================================================ FILE: shadowsocks-csharp/Controller/HttpRequest/GfwListUpdater.cs ================================================ using Shadowsocks.Controller.Service; using Shadowsocks.Enums; using Shadowsocks.Model; using Shadowsocks.Properties; using Shadowsocks.Util; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace Shadowsocks.Controller.HttpRequest { public class GfwListUpdater : HttpRequest { private const string GfwlistUrl = @"https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt"; #region event public event EventHandler UpdateCompleted; public event ErrorEventHandler Error; public class ResultEventArgs : EventArgs { public readonly bool Success; public readonly PacType PacType; public ResultEventArgs(bool success, PacType pacType) { Success = success; PacType = pacType; } } #endregion #region GfwList public async void UpdatePacFromGfwList(Configuration config) { Logging.Info($@"Checking GFWList from {GfwlistUrl}"); try { var userAgent = config.ProxyUserAgent; var proxy = CreateProxy(config); var content = await AutoGetAsync(GfwlistUrl, proxy, userAgent, config.ConnectTimeout * 1000, TimeSpan.FromMinutes(1).TotalMilliseconds); File.WriteAllText(Utils.GetTempPath(PACServer.gfwlist_FILE), content, Encoding.UTF8); var pacFileChanged = MergeAndWritePacFile(content); UpdateCompleted?.Invoke(this, new ResultEventArgs(pacFileChanged, PacType.GfwList)); } catch (Exception ex) { Error?.Invoke(this, new ErrorEventArgs(ex)); } } public static bool MergeAndWritePacFile(string gfwListResult) { var abpContent = MergePacFile(gfwListResult); if (File.Exists(PACDaemon.PAC_FILE)) { var original = FileManager.NonExclusiveReadAllText(PACDaemon.PAC_FILE, Encoding.UTF8); if (original == abpContent) { return false; } } File.WriteAllText(PACDaemon.PAC_FILE, abpContent, Encoding.UTF8); return true; } private static string MergePacFile(string gfwListResult) { var abpContent = File.Exists(PACDaemon.USER_ABP_FILE) ? FileManager.NonExclusiveReadAllText(PACDaemon.USER_ABP_FILE) : Resources.abp; var userRuleLines = new List(); if (File.Exists(PACDaemon.USER_RULE_FILE)) { var userRulesString = FileManager.NonExclusiveReadAllText(PACDaemon.USER_RULE_FILE); userRuleLines = ParseToValidList(userRulesString); } var gfwLines = ParseBase64ToValidList(gfwListResult); abpContent = abpContent.Replace(@"__USERRULES__", JsonUtils.Serialize(userRuleLines, false)) .Replace(@"__RULES__", JsonUtils.Serialize(gfwLines, false)); return abpContent; } private static List ParseBase64ToValidList(string response) { var bytes = Convert.FromBase64String(response); var content = Encoding.ASCII.GetString(bytes); return ParseToValidList(content); } private static List ParseToValidList(string content) { var lines = content.GetLines().ToArray(); var validLines = new List(lines.Length); validLines.AddRange(lines.Where(line => !line.StartsWith(@"!") && !line.StartsWith(@"["))); return validLines; } #endregion #region OnlinePAC public async void UpdateOnlinePac(Configuration config, string url) { try { var userAgent = config.ProxyUserAgent; var proxy = CreateProxy(config); var content = await AutoGetAsync(url, proxy, userAgent, config.ConnectTimeout * 1000, TimeSpan.FromMinutes(1).TotalMilliseconds); if (File.Exists(PACDaemon.PAC_FILE)) { var original = FileManager.NonExclusiveReadAllText(PACDaemon.PAC_FILE); if (original == content) { UpdateCompleted?.Invoke(this, new ResultEventArgs(false, PacType.Online)); return; } } File.WriteAllText(PACDaemon.PAC_FILE, content); UpdateCompleted?.Invoke(this, new ResultEventArgs(true, PacType.Online)); } catch (Exception ex) { Error?.Invoke(this, new ErrorEventArgs(ex)); } } #endregion } } ================================================ FILE: shadowsocks-csharp/Controller/HttpRequest/HttpRequest.cs ================================================ using Shadowsocks.Model; using System; using System.Net; using System.Net.Http; using System.Threading.Tasks; namespace Shadowsocks.Controller.HttpRequest { public abstract class HttpRequest { private const string DefaultUserAgent = @"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36"; private const int DefaultGetTimeout = 30000; private const int DefaultHeadTimeout = 4000; public static HttpClient CreateClient(bool useProxy, IWebProxy proxy, string userAgent, double timeout) { var httpClientHandler = new SocketsHttpHandler { Proxy = proxy, UseProxy = useProxy }; var client = new HttpClient(httpClientHandler) { Timeout = TimeSpan.FromMilliseconds(timeout), DefaultRequestVersion = HttpVersion.Version20 }; client.DefaultRequestHeaders.Add(@"User-Agent", string.IsNullOrWhiteSpace(userAgent) ? DefaultUserAgent : userAgent); return client; } private static async Task GetAsync(string url, IWebProxy proxy, string userAgent = DefaultUserAgent, double timeout = DefaultGetTimeout, bool useProxy = true) { using var client = CreateClient(useProxy, proxy, userAgent, timeout); using var response = await client.GetAsync(url); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); } private static async Task HeadAsync(string url, IWebProxy proxy, double timeout = DefaultHeadTimeout) { using var client = CreateClient(proxy != null, proxy, DefaultUserAgent, timeout); try { using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); return true; } catch { return false; } } protected static async Task AutoGetAsync(string url, IWebProxy proxy, string userAgent = @"", double headTimeout = DefaultHeadTimeout, double getTimeout = DefaultGetTimeout) { string res = null; if (await HeadAsync(url, proxy, headTimeout)) { try { res = await ProxyGetAsync(url, proxy, userAgent, getTimeout); } catch { res = null; } } if (res != null) { return res; } res = await DirectGetAsync(url, userAgent, getTimeout); return res; } protected static async Task DirectGetAsync(string url, string userAgent = DefaultUserAgent, double getTimeout = DefaultGetTimeout) { Logging.Info($@"GET request directly: {url}"); return await GetAsync(url, null, userAgent, getTimeout, false); } protected static async Task ProxyGetAsync(string url, IWebProxy proxy, string userAgent = DefaultUserAgent, double timeout = DefaultGetTimeout) { Logging.Info($@"GET request by proxy: {url}"); return await GetAsync(url, proxy, userAgent, timeout); } protected static async Task DefaultGetAsync(string url, string userAgent = DefaultUserAgent, double getTimeout = DefaultGetTimeout) { Logging.Info($@"GET request by default: {url}"); return await GetAsync(url, null, userAgent, getTimeout); } protected static IWebProxy CreateProxy(Configuration config) { var proxy = new WebProxy(Global.LocalHost, config.LocalPort); if (!string.IsNullOrEmpty(config.AuthPass)) { proxy.Credentials = new NetworkCredential(config.AuthUser, config.AuthPass); } return proxy; } } } ================================================ FILE: shadowsocks-csharp/Controller/HttpRequest/UpdateChecker.cs ================================================ using Shadowsocks.Model; using System; using UpdateChecker; namespace Shadowsocks.Controller.HttpRequest { public class UpdateChecker : HttpRequest { private const string Owner = @"HMBSbige"; private const string Repo = @"ShadowsocksR-Windows"; public string LatestVersionNumber; public string LatestVersionUrl; public bool Found; public event EventHandler NewVersionFound; public event EventHandler NewVersionFoundFailed; public event EventHandler NewVersionNotFound; public const string Name = @"ShadowsocksR"; public const string Copyright = @"Copyright © 2019 - 2022 HMBSbige. Forked from ShadowsocksR by BreakWa11"; public const string Version = @"6.1.0"; public const string FullVersion = Version + #if SelfContained #if Is64Bit @" x64" + #else @" x86" + #endif #endif #if DEBUG @" Debug"; #else @""; #endif public async void Check(Configuration config, bool notifyNoFound) { try { var updater = new GitHubReleasesUpdateChecker( Owner, Repo, config.IsPreRelease, Version); var userAgent = config.ProxyUserAgent; var proxy = CreateProxy(config); using var client = CreateClient(true, proxy, userAgent, config.ConnectTimeout * 1000); var res = await updater.CheckAsync(client, default); LatestVersionNumber = updater.LatestVersion; Found = res; if (Found) { LatestVersionUrl = updater.LatestVersionUrl; NewVersionFound?.Invoke(this, EventArgs.Empty); } else { if (notifyNoFound) { NewVersionNotFound?.Invoke(this, EventArgs.Empty); } } } catch (Exception e) { Logging.LogUsefulException(e); if (notifyNoFound) { NewVersionFoundFailed?.Invoke(this, EventArgs.Empty); } } } } } ================================================ FILE: shadowsocks-csharp/Controller/HttpRequest/UpdateNode.cs ================================================ using Shadowsocks.Enums; using Shadowsocks.Model; using System; using System.Net; namespace Shadowsocks.Controller.HttpRequest { public class UpdateNode : HttpRequest { public const string DefaultUpdateUrl = @"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/freenodeplain.txt"; public event EventHandler NewFreeNodeFound; public string FreeNodeResult; public ServerSubscribe SubscribeTask; public bool Notify; public void CheckUpdate(Configuration config, ServerSubscribe subscribeTask, bool notify) { FreeNodeResult = null; Notify = notify; try { var proxy = CreateProxy(config); SubscribeTask = subscribeTask; var url = subscribeTask.Url ?? DefaultUpdateUrl; Update(subscribeTask.ProxyType, proxy, config.ConnectTimeout * 1000, url, config.ProxyUserAgent); } catch (Exception e) { Logging.LogUsefulException(e); } } private async void Update(HttpRequestProxyType proxyType, IWebProxy proxy, int timeout, string url, string userAgent) { try { FreeNodeResult = proxyType switch { HttpRequestProxyType.Auto => await AutoGetAsync(url, proxy, userAgent, timeout), HttpRequestProxyType.Direct => await DirectGetAsync(url, userAgent, timeout), HttpRequestProxyType.Proxy => await ProxyGetAsync(url, proxy, userAgent, timeout), HttpRequestProxyType.SystemSetting => await DefaultGetAsync(url, userAgent, timeout), _ => await AutoGetAsync(url, proxy, userAgent, timeout) }; } catch (Exception ex) { Logging.Debug(ex.ToString()); } NewFreeNodeFound?.Invoke(this, EventArgs.Empty); } } } ================================================ FILE: shadowsocks-csharp/Controller/Logging.cs ================================================ using Shadowsocks.Enums; using Shadowsocks.Obfs; using Shadowsocks.Util; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Sockets; using System.Text; namespace Shadowsocks.Controller { public static class Logging { public static string LogFile; public static string LogFileName; private static string _date; private static FileStream _logFileStream; private static StreamWriterWithTimestamp _logStreamWriter; private static readonly object Lock = new(); public static bool SaveToFile = true; public static TextWriter DefaultOut; public static TextWriter DefaultError; public static bool OpenLogFile() { try { CloseLogFile(); if (SaveToFile) { var newDate = DateTime.Now.ToString("yyyy-MM"); LogFileName = $@"shadowsocks_{newDate}.log"; LogFile = Utils.GetTempPath(LogFileName); _logFileStream = new FileStream(LogFile, FileMode.Append); _logStreamWriter = new StreamWriterWithTimestamp(_logFileStream) { AutoFlush = true }; Console.SetOut(_logStreamWriter); Console.SetError(_logStreamWriter); _date = newDate; CompressOldLogFile(); } else { Console.SetOut(DefaultOut); Console.SetError(DefaultError); } return true; } catch (IOException e) { Console.WriteLine(e.ToString()); return false; } } private static void CloseLogFile() { _logStreamWriter?.Close(); _logStreamWriter?.Dispose(); _logFileStream?.Close(); _logFileStream?.Dispose(); _logStreamWriter = null; _logFileStream = null; } public static void Clear() { CloseLogFile(); if (LogFile != null) { File.Delete(LogFile); } OpenLogFile(); } public static void Error(object o) { Log(LogLevel.Error, o); System.Diagnostics.Debug.WriteLine($@"[{DateTime.Now}] ERROR {o}"); } public static void Info(object o) { Log(LogLevel.Info, o); System.Diagnostics.Debug.WriteLine($@"[{DateTime.Now}] INFO {o}"); } [Conditional("DEBUG")] public static void Debug(object o) { Log(LogLevel.Debug, o); System.Diagnostics.Debug.WriteLine($@"[{DateTime.Now}] DEBUG {o}"); } private static string ToString(IEnumerable stacks) { return stacks.Aggregate(string.Empty, (current, stack) => current + $@"{stack.GetMethod()}{Environment.NewLine}"); } private static void CompressOldLogFile() { var list = Directory.GetFiles(Utils.TempPath, @"shadowsocks_*.log", SearchOption.TopDirectoryOnly); foreach (var file in list) { if (file != LogFile) { FileManager.ZipCompressToFile(file).ContinueWith(task => { if (task.Result) { File.Delete(file); } }); } } } private static void UpdateLogFile() { if (DateTime.Now.ToString("yyyy-MM") != _date) { lock (Lock) { if (DateTime.Now.ToString("yyyy-MM") != _date) { OpenLogFile(); } } } } public static void LogUsefulException(Exception e) { UpdateLogFile(); // just log useful exceptions, not all of them if (e is SocketException se) { switch (se.SocketErrorCode) { case SocketError.ConnectionAborted: // closed by browser when sending // normally happens when download is canceled or a tab is closed before page is loaded break; case SocketError.ConnectionReset: // received rst break; case SocketError.NotConnected: // close when not connected break; case SocketError.Shutdown: // ignore break; case SocketError.Interrupted: // ignore break; default: { if ((uint)se.SocketErrorCode == 0x80004005) { // already closed } else { Error(e); Debug(ToString(new StackTrace().GetFrames())); } break; } } } else { Error(e); Debug(ToString(new StackTrace().GetFrames())); } } public static bool LogSocketException(string remarks, string server, Exception e) { UpdateLogFile(); switch (e) { // just log useful exceptions, not all of them case ObfsException oe: Error($@"Proxy server [{remarks}({server})] {oe.Message}"); return true; case NullReferenceException _: case ObjectDisposedException _: return true; case SocketException se when se.ErrorCode == 11004: Log(LogLevel.Warn, $@"Proxy server [{remarks}({server})] DNS lookup failed"); return true; case SocketException se when (uint)se.SocketErrorCode == 0x80004005: // already closed return true; case SocketException se: switch (se.SocketErrorCode) { case SocketError.HostNotFound: Log(LogLevel.Warn, $@"Proxy server [{remarks}({server})] Host not found"); return true; case SocketError.ConnectionRefused: Log(LogLevel.Warn, $@"Proxy server [{remarks}({server})] connection refused"); return true; case SocketError.NetworkUnreachable: Log(LogLevel.Warn, $@"Proxy server [{remarks}({server})] network unreachable"); return true; case SocketError.TimedOut: case SocketError.Shutdown: return true; } Log(LogLevel.Info, $@"Proxy server [{remarks}({server})] {Convert.ToString(se.SocketErrorCode)}:{se.Message}"); Debug(ToString(new StackTrace().GetFrames())); return true; default: return false; } } public static void Log(LogLevel level, object s) { UpdateLogFile(); Console.WriteLine($@"[{level}] {s}"); } [Conditional("DEBUG")] public static void LogBin(LogLevel level, string info, byte[] data, int length) { var s = new StringBuilder(); for (var i = 0; i < length; ++i) { var fs = $@"0{Convert.ToString(data[i], 16)}"; s.Append($@" {fs.Substring(fs.Length - 2, 2)}"); } Log(level, $@"{info}{s}"); } } // Simply extended System.IO.StreamWriter for adding timestamp workaround public class StreamWriterWithTimestamp : StreamWriter { public StreamWriterWithTimestamp(Stream stream) : base(stream) { } private static string GetTimestamp() { return $@"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] "; } public override void WriteLine(string value) { try { base.WriteLine(GetTimestamp() + value); } catch (ObjectDisposedException) { } } public override void Write(string value) { try { base.Write(GetTimestamp() + value); } catch (ObjectDisposedException) { } } } } ================================================ FILE: shadowsocks-csharp/Controller/MainController.cs ================================================ using Shadowsocks.Controller.HttpRequest; using Shadowsocks.Controller.Service; using Shadowsocks.Enums; using Shadowsocks.Model; using Shadowsocks.Model.Transfer; using Shadowsocks.Util; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Sockets; using System.Text.RegularExpressions; using System.Windows; namespace Shadowsocks.Controller { public class MainController { // controller: // handle user actions // manipulates UI // interacts with low level logic private Listener _listener; private List _portMapListener; private PACDaemon _pacDaemon; private PACServer _pacServer; private readonly ServerTransferTotal _transfer; private HostDaemon _hostDaemon; private IPRangeSet _chnRangeSet; private HttpProxyRunner _httpProxyRunner; private GfwListUpdater _gfwListUpdater; private bool _stopped; public class PathEventArgs : EventArgs { public string Path; } #region Event public event EventHandler ConfigChanged; public event EventHandler ShowConfigFormEvent; public event EventHandler ShowSubscribeWindowEvent; // when user clicked Edit PAC, and PAC file has already created public event EventHandler PACFileReadyToOpen; public event EventHandler UserRuleFileReadyToOpen; public event EventHandler UpdatePACFromGFWListCompleted; public event ErrorEventHandler UpdatePACFromGFWListError; public event ErrorEventHandler Errored; #endregion public MainController() { _transfer = ServerTransferTotal.Load(); foreach (var server in Global.GuiConfig.Configs) { if (_transfer.Servers.TryGetValue(server.Id, out var st)) { var log = new ServerSpeedLog(st.TotalUploadBytes, st.TotalDownloadBytes); server.SpeedLog = log; } } } private void ReportError(Exception e) { Errored?.Invoke(this, new ErrorEventArgs(e)); } private static int FindFirstMatchServer(Server server, IReadOnlyList servers) { for (var i = 0; i < servers.Count; ++i) { if (server.IsMatchServer(servers[i])) { return i; } } return -1; } private static void AppendConfiguration(Configuration mergeConfig, IReadOnlyList servers) { if (servers != null) { Application.Current.Dispatcher?.InvokeAsync(() => { foreach (var server in servers) { if (FindFirstMatchServer(server, mergeConfig.Configs) == -1) { mergeConfig.Configs.Add(server); } } }); } } private static IEnumerable MergeConfiguration(Configuration mergeConfig, IReadOnlyList servers) { if (servers != null) { foreach (var server in servers) { var i = FindFirstMatchServer(server, mergeConfig.Configs); if (i != -1) { var enable = server.Enable; server.CopyServer(mergeConfig.Configs[i]); server.Enable = enable; } } } return from t in mergeConfig.Configs let j = FindFirstMatchServer(t, servers) where j == -1 select t; } private static Configuration MergeGetConfiguration(Configuration mergeConfig) { var ret = Global.Load(); if (mergeConfig != null) { MergeConfiguration(mergeConfig, ret.Configs); } return ret; } /// /// 从配置文件导入服务器 /// /// public void MergeConfiguration(Configuration mergeConfig) { AppendConfiguration(Global.GuiConfig, mergeConfig.Configs); SaveAndReload(); } public void SaveServersConfig(Configuration config, bool reload) { var missingServers = MergeConfiguration(Global.GuiConfig, config.Configs); Global.GuiConfig.CopyFrom(config); foreach (var s in missingServers) { s.Connections.CloseAll(); } if (reload) { SaveAndReload(); } else { SaveAndNotifyChanged(); } } public void SaveServersPortMap(Configuration config) { StopPortMap(); Global.GuiConfig.PortMap = config.PortMap; Global.GuiConfig.FlushPortMapCache(); LoadPortMap(); SaveAndNotifyChanged(); } /// /// 选择指定服务器 /// public void SelectServerIndex(int index) { Global.GuiConfig.Index = index; SaveAndNotifyChanged(); } /// /// 导入服务器链接 /// public bool AddServerBySsUrl(string ssUrLs, string force_group = null, bool toLast = false) { try { var urls = ssUrLs.GetLines().Reverse(); var i = 0; foreach (var url in urls.Select(url => url.Trim('/')).Where(url => url.StartsWith(@"ss://", StringComparison.OrdinalIgnoreCase) || url.StartsWith(@"ssr://", StringComparison.OrdinalIgnoreCase))) { ++i; var server = new Server(url, force_group); if (toLast) { Global.GuiConfig.Configs.Add(server); } else { var index = Global.GuiConfig.Index + 1; if (index < 0 || index > Global.GuiConfig.Configs.Count) { index = Global.GuiConfig.Configs.Count; } Global.GuiConfig.Configs.Insert(index, server); } } if (i > 0) { SaveAndReload(); return true; } } catch (Exception e) { Logging.LogUsefulException(e); return false; } return false; } /// /// 导入订阅链接 /// public bool AddSubscribeUrl(string str) { try { var urls = str.GetLines(); var newSubscribes = new List(); var existSubscribes = new List(); foreach (var url in urls.Where(url => url.StartsWith(@"sub://", StringComparison.OrdinalIgnoreCase))) { var sub = Regex.Match(url, "sub://([A-Za-z0-9_-]+)", RegexOptions.IgnoreCase); if (sub.Success) { var res = Base64.DecodeUrlSafeBase64(sub.Groups[1].Value); if (Global.GuiConfig.ServerSubscribes.All(serverSubscribe => serverSubscribe.Url != res)) { var newSub = new ServerSubscribe { Url = res }; newSubscribes.Add(newSub); Global.GuiConfig.ServerSubscribes.Add(newSub); } else { existSubscribes.Add(Global.GuiConfig.ServerSubscribes.Find(serverSubscribe => serverSubscribe.Url == res)); } } } if (newSubscribes.Count > 0) { SaveAndNotifyChanged(); Global.UpdateSubscribeManager.CreateTask(Global.GuiConfig, Global.UpdateNodeChecker, true, newSubscribes); return true; } if (existSubscribes.Count > 0) { Global.UpdateSubscribeManager.CreateTask(Global.GuiConfig, Global.UpdateNodeChecker, true, existSubscribes); return false; } } catch (Exception e) { Logging.LogUsefulException(e); return false; } return false; } /// /// 切换系统代理模式 /// public void ToggleMode(ProxyMode mode) { ProxyMode oldMode = Global.GuiConfig.SysProxyMode; Global.GuiConfig.SysProxyMode = mode; ReloadPacServer(); if (oldMode is not ProxyMode.NoModify && mode is ProxyMode.NoModify) { SystemProxy.Restore(); } else { UpdateSystemProxy(); } SaveAndNotifyChanged(); } /// /// 切换代理规则 /// /// public void ToggleRuleMode(ProxyRuleMode mode) { Global.GuiConfig.ProxyRuleMode = mode; SaveAndNotifyChanged(); } public void ToggleSelectRandom(bool enabled) { Global.GuiConfig.Random = enabled; if (!enabled) { DisconnectAllConnections(true); } SaveAndNotifyChanged(); } public void ToggleSameHostForSameTargetRandom(bool enabled) { Global.GuiConfig.SameHostForSameTarget = enabled; SaveAndNotifyChanged(); } public void ToggleSelectAutoCheckUpdate(bool enabled) { Global.GuiConfig.AutoCheckUpdate = enabled; Global.SaveConfig(); } public void ToggleSelectAllowPreRelease(bool enabled) { Global.GuiConfig.IsPreRelease = enabled; Global.SaveConfig(); } /// /// 保存配置文件并通知配置改变 /// public void SaveAndNotifyChanged() { Global.SaveConfig(); Application.Current.Dispatcher?.InvokeAsync(() => { ConfigChanged?.Invoke(this, EventArgs.Empty); }); } /// /// 保存配置文件并重载 /// private void SaveAndReload() { Global.SaveConfig(); Reload(); } private void StopPortMap() { if (_portMapListener != null) { foreach (var l in _portMapListener) { l.Stop(); } _portMapListener = null; } } private void LoadPortMap() { _portMapListener = new List(); foreach (var pair in Global.GuiConfig.PortMapCache) { try { var local = new Local(Global.GuiConfig, _transfer, _chnRangeSet); var services = new List { local }; var listener = new Listener(services); listener.Start(Global.GuiConfig, pair.Key); _portMapListener.Add(listener); } catch (Exception e) { ThrowSocketException(ref e); Logging.LogUsefulException(e); ReportError(e); } } } public void Stop() { if (_stopped) { return; } _stopped = true; StopPortMap(); _listener?.Stop(); _httpProxyRunner?.Stop(); if (Global.GuiConfig.SysProxyMode is not ProxyMode.NoModify) { SystemProxy.Restore(); } ServerTransferTotal.Save(_transfer, Global.GuiConfig.Configs); } public void ClearTransferTotal(string serverId) { _transfer.Clear(serverId); var server = Global.GuiConfig.Configs.Find(s => s.Id == serverId); server?.SpeedLog.ClearTrans(); } public void TouchPACFile() { PACFileReadyToOpen?.Invoke(this, new PathEventArgs { Path = _pacDaemon.TouchPACFile() }); } public void TouchUserRuleFile() { UserRuleFileReadyToOpen?.Invoke(this, new PathEventArgs { Path = _pacDaemon.TouchUserRuleFile() }); } public void UpdatePACFromGFWList() { _gfwListUpdater?.UpdatePacFromGfwList(Global.GuiConfig); } public void UpdatePACFromOnlinePac(string url) { _gfwListUpdater?.UpdateOnlinePac(Global.GuiConfig, url); } private void ReloadPacServer() { if (_pacDaemon == null) { _pacDaemon = new PACDaemon(); _pacDaemon.PACFileChanged += (o, args) => { _pacServer?.UpdatePacUrl(Global.GuiConfig); UpdateSystemProxy(); }; _pacDaemon.UserRuleFileChanged += PacDaemon_UserRuleFileChanged; } if (_pacServer == null) { _pacServer = new PACServer(_pacDaemon); } _pacServer.UpdatePacUrl(Global.GuiConfig); } private void ReloadIPRange() { _chnRangeSet = new IPRangeSet(); _chnRangeSet.LoadChn(); } private void ReloadProxyRule() { if (_hostDaemon == null) { _hostDaemon = new HostDaemon(); _hostDaemon.ChnIpChanged += (o, args) => ReloadIPRange(); _hostDaemon.UserRuleChanged += (o, args) => HostMap.Reload(); } ReloadIPRange(); HostMap.Reload(); } public void Reload() { StopPortMap(); // some logic in configuration updated the config when saving, we need to read it again Global.GuiConfig = MergeGetConfiguration(Global.GuiConfig); Global.GuiConfig.FlushPortMapCache(); Logging.SaveToFile = Global.GuiConfig.LogEnable; Logging.OpenLogFile(); ReloadProxyRule(); _httpProxyRunner ??= new HttpProxyRunner(); ReloadPacServer(); if (_gfwListUpdater == null) { _gfwListUpdater = new GfwListUpdater(); _gfwListUpdater.UpdateCompleted += (o, args) => UpdatePACFromGFWListCompleted?.Invoke(o, args); _gfwListUpdater.Error += (o, args) => UpdatePACFromGFWListError?.Invoke(o, args); } _listener?.Stop(); _httpProxyRunner.Stop(); try { _httpProxyRunner.Start(Global.GuiConfig); var local = new Local(Global.GuiConfig, _transfer, _chnRangeSet); var services = new List { local, _pacServer, new HttpPortForwarder(_httpProxyRunner.RunningPort, Global.GuiConfig) }; _listener = new Listener(services); _listener.Start(Global.GuiConfig, 0); } catch (Exception e) { ThrowSocketException(ref e); Logging.LogUsefulException(e); ReportError(e); } LoadPortMap(); Application.Current.Dispatcher?.InvokeAsync(() => { ConfigChanged?.Invoke(this, EventArgs.Empty); }); UpdateSystemProxy(); } private static void ThrowSocketException(ref Exception e) { // TODO:translate Microsoft language into human language // i.e. An attempt was made to access a socket in a way forbidden by its access permissions => Port already in use // https://docs.microsoft.com/zh-cn/dotnet/api/system.net.sockets.socketerror if (e is not SocketException se) { return; } switch (se.SocketErrorCode) { case SocketError.AddressAlreadyInUse: { e = new Exception(string.Format(I18NUtil.GetAppStringValue(@"PortInUse"), Global.GuiConfig.LocalPort), se); break; } case SocketError.AccessDenied: { e = new Exception(string.Format(I18NUtil.GetAppStringValue(@"PortReserved"), Global.GuiConfig.LocalPort), se); break; } } } private void UpdateSystemProxy() { SystemProxy.Update(Global.GuiConfig, _pacServer); } private void PacDaemon_UserRuleFileChanged(object sender, EventArgs e) { if (!Utils.IsGFWListPAC(PACDaemon.PAC_FILE)) { return; } if (!File.Exists(Utils.GetTempPath(PACServer.gfwlist_FILE))) { UpdatePACFromGFWList(); } else { GfwListUpdater.MergeAndWritePacFile(FileManager.NonExclusiveReadAllText(Utils.GetTempPath(PACServer.gfwlist_FILE))); } UpdateSystemProxy(); } public void ShowConfigForm(int? index = null) { ShowConfigFormEvent?.Invoke(index, EventArgs.Empty); } public void ShowSubscribeWindow() { ShowSubscribeWindowEvent?.Invoke(default, EventArgs.Empty); } /// /// Disconnect all connections from the remote host. /// public void DisconnectAllConnections(bool checkSwitchAutoCloseAll = false) { var config = Global.GuiConfig; if (checkSwitchAutoCloseAll && !config.CheckSwitchAutoCloseAll) { Console.WriteLine(@"config.checkSwitchAutoCloseAll:False"); return; } foreach (var server in config.Configs) { server.Connections.CloseAll(); } } public void CopyPacUrl() { Clipboard.SetDataObject(_pacServer.PacUrl); } } } ================================================ FILE: shadowsocks-csharp/Controller/MenuViewController.cs ================================================ using Hardcodet.Wpf.TaskbarNotification; using Microsoft.Win32; using Shadowsocks.Controller.HttpRequest; using Shadowsocks.Controller.Service; using Shadowsocks.Enums; using Shadowsocks.Model; using Shadowsocks.Properties; using Shadowsocks.Util; using Shadowsocks.View; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Shapes; using Brushes = System.Windows.Media.Brushes; using Rectangle = System.Drawing.Rectangle; namespace Shadowsocks.Controller { public class MenuViewController { private class EventParams { public readonly object sender; public readonly EventArgs e; public EventParams(object sender, EventArgs e) { this.sender = sender; this.e = e; } } // yes this is just a menu view controller // when config form is closed, it moves away from RAM // and it should just do anything related to the config form private readonly MainController controller; private readonly HttpRequest.UpdateChecker updateChecker; private readonly TaskbarIcon _notifyIcon; private ContextMenu _contextMenu; private MenuItem noModifyItem; private MenuItem enableItem; private MenuItem PACModeItem; private MenuItem globalModeItem; private MenuItem ruleBypassLan; private MenuItem ruleBypassChina; private MenuItem ruleBypassNotChina; private MenuItem ruleUser; private MenuItem ruleDisableBypass; private Separator SeparatorItem; private MenuItem ServersItem; private MenuItem SelectRandomItem; private MenuItem sameHostForSameTargetItem; private MenuItem _moreMenu; private MenuItem _updateMenu; private MenuItem UpdateItem; private MenuItem AutoCheckUpdateItem; private MenuItem AllowPreReleaseItem; private ServerConfigWindow _serverConfigWindow; private SettingsWindow _settingsWindow; private DnsSettingWindow _dnsSettingsWindow; #region ServerLogWindow private ServerLogWindow _serverLogWindow; private WindowStatus _serverLogWindowStatus; #endregion private PortSettingsWindow _portMapWindow; private SubscribeWindow _subScribeWindow; private LogWindow _logWindow; private string _urlToOpen; private System.Timers.Timer timerDelayCheckUpdate; private bool configFrom_open; private readonly List eventList = new(); public MenuViewController(MainController controller) { this.controller = controller; LoadMenu(); controller.ConfigChanged += controller_ConfigChanged; controller.PACFileReadyToOpen += controller_FileReadyToOpen; controller.UserRuleFileReadyToOpen += controller_FileReadyToOpen; controller.Errored += ControllerError; controller.UpdatePACFromGFWListCompleted += controller_UpdatePACFromGFWListCompleted; controller.UpdatePACFromGFWListError += controller_UpdatePACFromGFWListError; controller.ShowConfigFormEvent += Config_Click; controller.ShowSubscribeWindowEvent += Controller_ShowSubscribeWindowEvent; _notifyIcon = new TaskbarIcon(); UpdateTrayIcon(); _notifyIcon.Visibility = Visibility.Visible; _notifyIcon.ContextMenu = _contextMenu; _notifyIcon.TrayLeftMouseUp += notifyIcon_TrayLeftMouseUp; _notifyIcon.TrayMiddleMouseUp += notifyIcon_TrayMiddleMouseUp; _notifyIcon.TrayBalloonTipClicked += notifyIcon_TrayBalloonTipClicked; updateChecker = new HttpRequest.UpdateChecker(); updateChecker.NewVersionFound += updateChecker_NewVersionFound; updateChecker.NewVersionNotFound += updateChecker_NewVersionNotFound; updateChecker.NewVersionFoundFailed += UpdateChecker_NewVersionFoundFailed; Global.UpdateNodeChecker = new UpdateNode(); Global.UpdateNodeChecker.NewFreeNodeFound += UpdateNodeCheckerNewNodeFound; Global.UpdateSubscribeManager = new UpdateSubscribeManager(); LoadCurrentConfiguration(); timerDelayCheckUpdate = new System.Timers.Timer(1000.0 * 10); timerDelayCheckUpdate.Elapsed += timer_Elapsed; timerDelayCheckUpdate.Start(); } private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { timerDelayCheckUpdate.Interval = 1000.0 * 60 * 60 * 1;// 1 hour var cfg = Global.GuiConfig; if (cfg.AutoCheckUpdate) { updateChecker.Check(cfg, false); } Global.UpdateSubscribeManager.CreateTask(cfg, Global.UpdateNodeChecker, false); } private static void ControllerError(object sender, ErrorEventArgs e) { MessageBox.Show(e.GetException().ToString(), string.Format(I18NUtil.GetAppStringValue(@"ControllerError"), e.GetException().Message)); } private void UpdateTrayIcon() { var config = Global.GuiConfig; var enabled = config.SysProxyMode is not ProxyMode.NoModify and not ProxyMode.Direct; var global = config.SysProxyMode == ProxyMode.Global; var random = config.Random; var colorMask = ViewUtils.SelectColorMask(enabled, global); var icon = ViewUtils.ChangeBitmapColor(Resources.ss128, colorMask, random); var size = ViewUtils.GetIconSize(); var newIcon = Icon.FromHandle(ViewUtils.ResizeBitmap(icon, size.Width, size.Height).GetHicon()); if (_notifyIcon.Icon != null) { ViewUtils.DestroyIcon(_notifyIcon.Icon.Handle); } _notifyIcon.Icon = newIcon; string strServer = null; var line3 = string.Empty; var line4 = string.Empty; if (random) { strServer = $@"{I18NUtil.GetAppStringValue(@"LoadBalance")}{I18NUtil.GetAppStringValue(@"Colon")}{I18NUtil.GetAppStringValue(config.BalanceType.ToString())}"; if (config.RandomInGroup) { line3 = $@"{I18NUtil.GetAppStringValue(@"BalanceInGroup")}{Environment.NewLine}"; } if (config.AutoBan) { line4 = $@"{I18NUtil.GetAppStringValue(@"AutoBan")}{Environment.NewLine}"; } } else { if (config.Index >= 0 && config.Index < config.Configs.Count) { var groupName = config.Configs[config.Index].Group; var serverName = config.Configs[config.Index].Remarks; if (string.IsNullOrWhiteSpace(groupName)) { strServer = string.IsNullOrWhiteSpace(serverName) ? null : serverName; } else if (string.IsNullOrWhiteSpace(serverName)) { strServer = $@"{groupName}"; } else { strServer = $@"{groupName}{I18NUtil.GetAppStringValue(@"Colon")}{serverName}"; } } } string line1; switch (config.SysProxyMode) { case ProxyMode.NoModify: { line1 = $@"{I18NUtil.GetAppStringValue(@"NoProxy")}{Environment.NewLine}"; break; } case ProxyMode.Direct: { line1 = $@"{I18NUtil.GetAppStringValue(@"DisableProxy")}{Environment.NewLine}"; break; } case ProxyMode.Pac: { line1 = $@"{I18NUtil.GetAppStringValue(@"PacProxy")}{Environment.NewLine}"; break; } case ProxyMode.Global: { line1 = $@"{I18NUtil.GetAppStringValue(@"GlobalProxy")}{Environment.NewLine}"; break; } default: { line1 = null; break; } } var line2 = string.IsNullOrWhiteSpace(strServer) ? null : $@"{strServer}{Environment.NewLine}"; var line5 = string.Format(I18NUtil.GetAppStringValue(@"RunningPort"), config.LocalPort); // this feedback is very important because they need to know Shadowsocks is running var text = $@"{line1}{line2}{line3}{line4}{line5}"; _notifyIcon.ToolTipText = text; } private void LoadMenu() { if (Application.Current.FindResource(@"SysTrayMenu") is ContextMenu menu) { _contextMenu = menu; } I18NUtil.SetLanguage(_contextMenu); foreach (var obj in _contextMenu.Items) { if (obj is MenuItem menuItem) { switch (menuItem.Name) { case @"Mode": { enableItem = (MenuItem)menuItem.Items[0]; PACModeItem = (MenuItem)menuItem.Items[1]; globalModeItem = (MenuItem)menuItem.Items[2]; noModifyItem = (MenuItem)menuItem.Items[4]; enableItem.Click += EnableItem_Click; PACModeItem.Click += PACModeItem_Click; globalModeItem.Click += GlobalModeItem_Click; noModifyItem.Click += NoModifyItem_Click; break; } case @"ProxySetting": { var pacMenuItem = (MenuItem)menuItem.Items[0]; var proxyMenuItem = (MenuItem)menuItem.Items[1]; ((MenuItem)menuItem.Items[3]).Click += CopyPacUrlItem_Click; ((MenuItem)menuItem.Items[4]).Click += EditPACFileItem_Click; ((MenuItem)menuItem.Items[5]).Click += EditUserRuleFileForGFWListItem_Click; ((MenuItem)pacMenuItem.Items[0]).Click += UpdatePACFromLanIPListItem_Click; ((MenuItem)pacMenuItem.Items[2]).Click += UpdatePACFromCNWhiteListItem_Click; ((MenuItem)pacMenuItem.Items[3]).Click += UpdatePACFromCnWhiteListIpItem_Click; ((MenuItem)pacMenuItem.Items[4]).Click += UpdatePACFromChnIpItem_Click; ((MenuItem)pacMenuItem.Items[5]).Click += UpdatePACFromGFWListItem_Click; ((MenuItem)pacMenuItem.Items[7]).Click += UpdatePACFromCNOnlyListItem_Click; ruleBypassLan = (MenuItem)proxyMenuItem.Items[0]; ruleBypassChina = (MenuItem)proxyMenuItem.Items[1]; ruleBypassNotChina = (MenuItem)proxyMenuItem.Items[2]; ruleUser = (MenuItem)proxyMenuItem.Items[3]; ruleDisableBypass = (MenuItem)proxyMenuItem.Items[5]; ruleBypassLan.Click += RuleBypassLanItem_Click; ruleBypassChina.Click += RuleBypassChinaItem_Click; ruleBypassNotChina.Click += RuleBypassNotChinaItem_Click; ruleUser.Click += RuleUserItem_Click; ruleDisableBypass.Click += RuleBypassDisableItem_Click; break; } case @"Servers": { ServersItem = menuItem; SeparatorItem = (Separator)menuItem.Items[0]; SelectRandomItem = (MenuItem)menuItem.Items[7]; sameHostForSameTargetItem = (MenuItem)menuItem.Items[8]; ((MenuItem)menuItem.Items[1]).Click += Config_Click; ((MenuItem)menuItem.Items[3]).Click += ScanQRCodeItem_Click; ((MenuItem)menuItem.Items[4]).Click += ImportAddressFromClipboard_Click; ((MenuItem)menuItem.Items[5]).Click += Import_Click; SelectRandomItem.Click += SelectRandomItem_Click; sameHostForSameTargetItem.Click += SelectSameHostForSameTargetItem_Click; ((MenuItem)menuItem.Items[10]).Click += ShowServerLogItem_Click; ((MenuItem)menuItem.Items[11]).Click += DisconnectCurrent_Click; break; } case @"ServersSubscribe": { ((MenuItem)menuItem.Items[0]).Click += SubscribeSetting_Click; ((MenuItem)menuItem.Items[1]).Click += CheckNodeUpdate_Click; break; } case @"ShowLogs": { menuItem.Click += ShowLogItem_Click; break; } case @"More": { _moreMenu = menuItem; ((MenuItem)_moreMenu.Items[0]).Click += Setting_Click; ((MenuItem)_moreMenu.Items[1]).Click += DnsSetting_Click; ((MenuItem)_moreMenu.Items[2]).Click += ShowPortMapItem_Click; ((MenuItem)_moreMenu.Items[3]).Click += ShowUrlFromQrCode; ((MenuItem)_moreMenu.Items[5]).Click += OpenWiki_Click; ((MenuItem)_moreMenu.Items[6]).Click += FeedbackItem_Click; _updateMenu = (MenuItem)_moreMenu.Items[8]; ((MenuItem)_updateMenu.Items[0]).Click += CheckUpdate_Click; UpdateItem = (MenuItem)_updateMenu.Items[1]; AutoCheckUpdateItem = (MenuItem)_updateMenu.Items[3]; AllowPreReleaseItem = (MenuItem)_updateMenu.Items[4]; UpdateItem.Click += UpdateItem_Clicked; AutoCheckUpdateItem.Click += AutoCheckUpdateItem_Click; AllowPreReleaseItem.Click += AllowPreRelease_Click; break; } case @"Quit": { menuItem.Click += Quit_Click; break; } } } } } private void controller_ConfigChanged(object sender, EventArgs e) { LoadCurrentConfiguration(); UpdateTrayIcon(); } private void controller_FileReadyToOpen(object sender, MainController.PathEventArgs e) { Utils.OpenURL(e.Path); } private void controller_UpdatePACFromGFWListError(object sender, ErrorEventArgs e) { _notifyIcon.ShowBalloonTip(I18NUtil.GetAppStringValue(@"UpdatePacFailed"), e.GetException().Message, BalloonIcon.Error); Logging.LogUsefulException(e.GetException()); } private void controller_UpdatePACFromGFWListCompleted(object sender, GfwListUpdater.ResultEventArgs e) { var result = e.Success ? e.PacType == PacType.GfwList ? I18NUtil.GetAppStringValue(@"GfwListPacUpdated") : I18NUtil.GetAppStringValue(@"PacUpdated") : I18NUtil.GetAppStringValue(@"GfwListPacNotFound"); _notifyIcon.ShowBalloonTip(HttpRequest.UpdateChecker.Name, result, BalloonIcon.Info); } private void UpdateNodeCheckerNewNodeFound(object sender, EventArgs e) { if (configFrom_open) { eventList.Add(new EventParams(sender, e)); return; } string lastGroup = null; var count = 0; if (!string.IsNullOrWhiteSpace(Global.UpdateNodeChecker.FreeNodeResult)) { Global.UpdateNodeChecker.FreeNodeResult = Global.UpdateNodeChecker.FreeNodeResult.TrimEnd('\r', '\n', ' '); var config = Global.GuiConfig; var selectedServer = config.Configs.ElementAtOrDefault(config.Index); try { Global.UpdateNodeChecker.FreeNodeResult = Base64.DecodeBase64(Global.UpdateNodeChecker.FreeNodeResult); } catch { Global.UpdateNodeChecker.FreeNodeResult = string.Empty; } var urls = Global.UpdateNodeChecker.FreeNodeResult.GetLines().ToList(); urls.RemoveAll(url => !url.StartsWith(@"ssr://")); if (urls.Count > 0) { lastGroup = Global.UpdateSubscribeManager.CurrentServerSubscribe.OriginTag; if (string.IsNullOrEmpty(lastGroup)) { foreach (var url in urls) { try // try get group name { var server = new Server(url, null); if (!string.IsNullOrEmpty(server.Group)) { if (config.ServerSubscribes.Any(subscribe => subscribe.Tag == server.Group)) { continue; } var serverSubscribe = config.ServerSubscribes.Find(sub => sub.Url == Global.UpdateSubscribeManager.CurrentServerSubscribe.Url && string.IsNullOrEmpty(sub.OriginTag)); if (serverSubscribe != null) { lastGroup = serverSubscribe.Tag = server.Group; } break; } } catch { // ignored } } } if (string.IsNullOrEmpty(lastGroup)) { lastGroup = Global.UpdateSubscribeManager.CurrentServerSubscribe.UrlMd5; } //Find old servers var firstInsertIndex = config.Configs.Count; var oldServers = config.Configs.FindAll(server => server.SubTag == lastGroup); var index = config.Configs.FindIndex(server => server.SubTag == lastGroup); if (index >= 0) { firstInsertIndex = index; } //Find new servers var newServers = new List(); foreach (var url in urls) { try { var server = new Server(url, lastGroup) { Index = firstInsertIndex++ }; newServers.Add(server); } catch { // ignored } } //Group name is not empty foreach (var newServer in newServers.Where(newServer => string.IsNullOrEmpty(newServer.Group))) { newServer.Group = lastGroup; } count = newServers.Count; var removeServers = oldServers.Except(newServers); var addServers = newServers.Except(oldServers); //Remove servers foreach (var server in removeServers) { server.Connections.CloseAll(); config.Configs.Remove(server); } //Add servers foreach (var server in addServers) { if (server.Index > config.Configs.Count) { server.Index = config.Configs.Count; } config.Configs.Insert(server.Index, server); } //Set SelectedServer var selectedIndex = -1; if (selectedServer is not null) { selectedIndex = config.Configs.FindIndex(server => server.Id == selectedServer.Id); if (selectedIndex < 0) { selectedIndex = config.Configs.FindIndex(server => server.SubTag == selectedServer.SubTag && server.IsMatchServer(selectedServer) ); } if (selectedIndex < 0) { selectedIndex = config.Configs.FindIndex(server => server.SubTag == selectedServer.SubTag && server.Group == selectedServer.Group && server.Remarks == selectedServer.Remarks ); } if (selectedIndex < 0) { selectedIndex = config.Configs.FindIndex(server => server.SubTag == selectedServer.SubTag && server.Group == selectedServer.Group ); } if (selectedIndex < 0) { selectedIndex = config.Configs.FindIndex(server => server.SubTag == selectedServer.SubTag); } } config.Index = selectedIndex < 0 ? default : selectedIndex; //If Update Success if (count > 0) { foreach (var serverSubscribe in config.ServerSubscribes.Where(serverSubscribe => serverSubscribe.Url == Global.UpdateNodeChecker.SubscribeTask.Url)) { serverSubscribe.LastUpdateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); } var defaultServer = new Server(); config.Configs.RemoveAll(server => server.IsMatchServer(defaultServer)); } controller.SaveServersConfig(config, true); } } if (count > 0) { if (Global.UpdateNodeChecker.Notify) { _notifyIcon.ShowBalloonTip(I18NUtil.GetAppStringValue(@"Success"), string.Format(I18NUtil.GetAppStringValue(@"UpdateSubscribeSuccess"), lastGroup), BalloonIcon.Info); } } else { if (string.IsNullOrEmpty(lastGroup)) { lastGroup = Global.UpdateNodeChecker.SubscribeTask.Tag; } if (Global.UpdateNodeChecker.Notify) { _notifyIcon.ShowBalloonTip(I18NUtil.GetAppStringValue(@"Error"), string.Format(I18NUtil.GetAppStringValue(@"UpdateSubscribeFailure"), lastGroup), BalloonIcon.Info); } } Global.UpdateSubscribeManager.Next(); } private void updateChecker_NewVersionFound(object sender, EventArgs e) { Application.Current.Dispatcher?.InvokeAsync(() => { if (updateChecker.Found) { if (UpdateItem.Visibility != Visibility.Visible) { _notifyIcon.ShowBalloonTip( string.Format(I18NUtil.GetAppStringValue(@"NewVersionFound"), HttpRequest.UpdateChecker.Name, updateChecker.LatestVersionNumber), I18NUtil.GetAppStringValue(@"ClickMenuToDownload"), BalloonIcon.Info); } _moreMenu.Icon = CreateSelectedIcon(); _updateMenu.Icon = CreateSelectedIcon(); UpdateItem.Visibility = Visibility.Visible; UpdateItem.Header = string.Format(I18NUtil.GetAppStringValue(@"NewVersionAvailable"), HttpRequest.UpdateChecker.Name, updateChecker.LatestVersionNumber); } }); } private void updateChecker_NewVersionNotFound(object sender, EventArgs e) { _notifyIcon.ShowBalloonTip($@"{HttpRequest.UpdateChecker.Name} {HttpRequest.UpdateChecker.FullVersion}", $@"{I18NUtil.GetAppStringValue(@"NewVersionNotFound")}{Environment.NewLine}{HttpRequest.UpdateChecker.Version}≥{updateChecker.LatestVersionNumber}", BalloonIcon.Info); } private void UpdateChecker_NewVersionFoundFailed(object sender, EventArgs e) { _notifyIcon.ShowBalloonTip($@"{HttpRequest.UpdateChecker.Name} {HttpRequest.UpdateChecker.FullVersion}", I18NUtil.GetAppStringValue(@"NewVersionFoundFailed"), BalloonIcon.Info); } private void UpdateItem_Clicked(object sender, RoutedEventArgs e) { Utils.OpenURL(updateChecker.LatestVersionUrl); _moreMenu.Icon = null; _updateMenu.Icon = null; UpdateItem.Visibility = Visibility.Collapsed; updateChecker.Found = false; } private void notifyIcon_TrayBalloonTipClicked(object sender, RoutedEventArgs e) { var url = updateChecker.LatestVersionUrl; if (!string.IsNullOrWhiteSpace(url)) { Utils.OpenURL(url); } } private void UpdateSysProxyMode(Configuration config) { noModifyItem.IsChecked = config.SysProxyMode == ProxyMode.NoModify; enableItem.IsChecked = config.SysProxyMode == ProxyMode.Direct; PACModeItem.IsChecked = config.SysProxyMode == ProxyMode.Pac; globalModeItem.IsChecked = config.SysProxyMode == ProxyMode.Global; } private void UpdateProxyRule(Configuration config) { ruleDisableBypass.IsChecked = config.ProxyRuleMode == ProxyRuleMode.Disable; ruleBypassLan.IsChecked = config.ProxyRuleMode == ProxyRuleMode.BypassLan; ruleBypassChina.IsChecked = config.ProxyRuleMode == ProxyRuleMode.BypassLanAndChina; ruleBypassNotChina.IsChecked = config.ProxyRuleMode == ProxyRuleMode.BypassLanAndNotChina; ruleUser.IsChecked = config.ProxyRuleMode == ProxyRuleMode.UserCustom; } private void LoadCurrentConfiguration() { var config = Global.GuiConfig; UpdateServersMenu(); UpdateSysProxyMode(config); UpdateProxyRule(config); SelectRandomItem.IsChecked = config.Random; sameHostForSameTargetItem.IsChecked = config.SameHostForSameTarget; AutoCheckUpdateItem.IsChecked = config.AutoCheckUpdate; AllowPreReleaseItem.IsChecked = config.IsPreRelease; } private static Grid CreateSelectedIcon() { var icon = new Grid(); icon.Children.Add(new Ellipse { Width = 8, Height = 8, Fill = Brushes.Black }); return icon; } private void UpdateServersMenu() { var items = ServersItem.Items; while (!Equals(items[0], SeparatorItem)) { items.RemoveAt(0); } var configuration = Global.GuiConfig; for (var i = 0; i < configuration.Configs.Count;) { configuration.Configs[i].Index = ++i; } var sub = new List(); var subTags = new HashSet(configuration.Configs.Select(server => server.SubTag)); foreach (var subTag in subTags) { var isSelected = false; var subItem = new MenuItem { Header = string.IsNullOrEmpty(subTag) ? I18NUtil.GetAppStringValue(@"EmptySubtag") : subTag }; var servers = configuration.Configs.Where(server => server.SubTag == subTag).ToArray(); var groups = new HashSet(servers.Select(server => server.Group)); foreach (var group in groups) { var groupItem = new MenuItem { Header = string.IsNullOrEmpty(group) ? I18NUtil.GetAppStringValue(@"EmptyGroup") : group }; var subServers = servers.Where(server => server.Group == group); foreach (var server in subServers) { var item = new MenuItem { Header = server.FriendlyName, Tag = server.Index - 1 }; item.Click += AServerItem_Click; if (configuration.Index == Convert.ToInt32(item.Tag)) { item.IsChecked = true; isSelected = true; } groupItem.Items.Add(item); } if (groups.Count > 1) { subItem.Items.Add(groupItem); if (isSelected) { groupItem.Icon = CreateSelectedIcon(); subItem.Icon = CreateSelectedIcon(); isSelected = false; } } else { groupItem.Header = subItem.Header; sub.Add(groupItem); if (isSelected) { groupItem.Icon = CreateSelectedIcon(); } } } if (groups.Count > 1) { sub.Add(subItem); } } var index = 0; foreach (var menuItem in sub) { items.Insert(index++, menuItem); } } private void ShowConfigForm(bool addNode) { if (_serverConfigWindow != null) { _serverConfigWindow.Activate(); _serverConfigWindow.UpdateLayout(); if (_serverConfigWindow.WindowState == WindowState.Minimized) { _serverConfigWindow.WindowState = WindowState.Normal; } if (addNode) { var cfg = Global.GuiConfig; _serverConfigWindow.MoveToSelectedItem(cfg.Index + 1); } } else { configFrom_open = true; _serverConfigWindow = new ServerConfigWindow(controller, addNode ? -1 : -2); _serverConfigWindow.Show(); _serverConfigWindow.Activate(); _serverConfigWindow.BringToFront(); _serverConfigWindow.Closed += ServerConfigWindowClosed; } } private void ServerConfigWindowClosed(object sender, EventArgs e) { _serverConfigWindow = null; configFrom_open = false; if (eventList.Count > 0) { foreach (var p in eventList) { UpdateNodeCheckerNewNodeFound(p.sender, p.e); } eventList.Clear(); } } private void ShowConfigForm(int index) { if (_serverConfigWindow != null) { _serverConfigWindow.Activate(); _serverConfigWindow.UpdateLayout(); if (_serverConfigWindow.WindowState == WindowState.Minimized) { _serverConfigWindow.WindowState = WindowState.Normal; } _serverConfigWindow.Topmost = true; _serverConfigWindow.MoveToSelectedItem(index); } else { configFrom_open = true; _serverConfigWindow = new ServerConfigWindow(controller, index); _serverConfigWindow.Show(); _serverConfigWindow.Activate(); _serverConfigWindow.Topmost = true; _serverConfigWindow.Closed += ServerConfigWindowClosed; } } private void ShowSettingForm() { if (_settingsWindow != null) { _settingsWindow.Activate(); } else { _settingsWindow = new SettingsWindow(controller); _settingsWindow.Show(); _settingsWindow.Activate(); _settingsWindow.BringToFront(); _settingsWindow.Closed += (_, _) => { _settingsWindow = null; }; } } private void ShowDnsSettingWindow() { if (_dnsSettingsWindow != null) { _dnsSettingsWindow.Activate(); } else { _dnsSettingsWindow = new DnsSettingWindow(); _dnsSettingsWindow.Show(); _dnsSettingsWindow.Activate(); _dnsSettingsWindow.BringToFront(); _dnsSettingsWindow.Closed += (o, args) => { _dnsSettingsWindow = null; }; } } private void ShowPortMapForm() { if (_portMapWindow != null) { _portMapWindow.Activate(); _portMapWindow.UpdateLayout(); if (_portMapWindow.WindowState == WindowState.Minimized) { _portMapWindow.WindowState = WindowState.Normal; } } else { _portMapWindow = new PortSettingsWindow(controller); _portMapWindow.Show(); _portMapWindow.Activate(); _portMapWindow.BringToFront(); _portMapWindow.Closed += (o, e) => { _portMapWindow = null; }; } } private void ShowServerLogForm() { if (_serverLogWindow != null) { _serverLogWindow.Activate(); _serverLogWindow.UpdateLayout(); if (_serverLogWindow.WindowState == WindowState.Minimized) { _serverLogWindow.WindowState = WindowState.Normal; } } else { _serverLogWindow = new ServerLogWindow(controller, _serverLogWindowStatus); _serverLogWindow.Show(); _serverLogWindow.Activate(); _serverLogWindow.BringToFront(); _serverLogWindow.Closed += (o, e) => { _serverLogWindowStatus = new WindowStatus(_serverLogWindow); _serverLogWindow = null; }; } } private void ShowGlobalLogWindow() { if (_logWindow != null) { _logWindow.Activate(); _logWindow.UpdateLayout(); if (_logWindow.WindowState == WindowState.Minimized) { _logWindow.WindowState = WindowState.Normal; } } else { _logWindow = new LogWindow(); _logWindow.Show(); _logWindow.Activate(); _logWindow.BringToFront(); _logWindow.Closed += (sender, args) => { _logWindow = null; }; } } private void ShowSubscribeSettingForm() { if (_subScribeWindow != null) { _subScribeWindow.Activate(); _subScribeWindow.UpdateLayout(); if (_subScribeWindow.WindowState == WindowState.Minimized) { _subScribeWindow.WindowState = WindowState.Normal; } } else { _subScribeWindow = new SubscribeWindow(controller); _subScribeWindow.Show(); _subScribeWindow.Activate(); _subScribeWindow.BringToFront(); _subScribeWindow.Closed += (sender, args) => { _subScribeWindow = null; }; } } private void Config_Click(object sender, EventArgs e) { if (sender is int i) { ShowConfigForm(i); } else { ShowConfigForm(false); } } private void Controller_ShowSubscribeWindowEvent(object sender, EventArgs e) { ShowSubscribeSettingForm(); } private void Import_Click(object sender, RoutedEventArgs e) { Task.Run(() => { var dlg = new OpenFileDialog { InitialDirectory = Directory.GetCurrentDirectory() }; if (dlg.ShowDialog() == true) { var name = dlg.FileName; var cfg = Global.LoadFile(name); if (cfg.IsDefaultConfig()) { MessageBox.Show(I18NUtil.GetAppStringValue(@"ImportConfigFailed"), HttpRequest.UpdateChecker.Name); } else { controller.MergeConfiguration(cfg); } } }); } private void Setting_Click(object sender, RoutedEventArgs e) { ShowSettingForm(); } private void DnsSetting_Click(object sender, RoutedEventArgs e) { ShowDnsSettingWindow(); } public void Quit_Click(object sender, EventArgs e) { controller.Stop(); if (_serverConfigWindow != null) { _serverConfigWindow.Close(); _serverConfigWindow = null; } if (_serverLogWindow != null) { _serverLogWindow.Close(); _serverLogWindow = null; } if (timerDelayCheckUpdate != null) { timerDelayCheckUpdate.Elapsed -= timer_Elapsed; timerDelayCheckUpdate.Stop(); timerDelayCheckUpdate = null; } if (_notifyIcon.Icon != null) { ViewUtils.DestroyIcon(_notifyIcon.Icon.Handle); } _notifyIcon.Dispose(); Application.Current.Shutdown(); } private static void OpenWiki_Click(object sender, RoutedEventArgs e) { Utils.OpenURL(@"https://github.com/HMBSbige/ShadowsocksR-Windows/wiki"); } private static void FeedbackItem_Click(object sender, RoutedEventArgs e) { Utils.OpenURL(@"https://github.com/HMBSbige/ShadowsocksR-Windows/issues/new/choose"); } private void notifyIcon_TrayLeftMouseUp(object sender, RoutedEventArgs e) { var key = Keyboard.IsKeyDown(Key.LeftShift) ? 1 : 0; key |= Keyboard.IsKeyDown(Key.RightShift) ? 1 : 0; key |= Keyboard.IsKeyDown(Key.LeftCtrl) ? 2 : 0; key |= Keyboard.IsKeyDown(Key.RightCtrl) ? 2 : 0; key |= Keyboard.IsKeyDown(Key.LeftAlt) ? 4 : 0; switch (key) { case 1: ShowSettingForm(); break; case 2: ShowServerLogForm(); break; case 3: ShowSubscribeSettingForm(); break; case 4: ShowPortMapForm(); break; case 6: ShowDnsSettingWindow(); break; default: ShowConfigForm(false); break; } } private void notifyIcon_TrayMiddleMouseUp(object sender, RoutedEventArgs e) { ShowServerLogForm(); } private void NoModifyItem_Click(object sender, RoutedEventArgs e) { Task.Run(() => { controller.ToggleMode(ProxyMode.NoModify); }); } private void EnableItem_Click(object sender, RoutedEventArgs e) { Task.Run(() => { controller.ToggleMode(ProxyMode.Direct); }); } private void GlobalModeItem_Click(object sender, RoutedEventArgs e) { Task.Run(() => { controller.ToggleMode(ProxyMode.Global); }); } private void PACModeItem_Click(object sender, RoutedEventArgs e) { Task.Run(() => { controller.ToggleMode(ProxyMode.Pac); }); } private void RuleBypassLanItem_Click(object sender, RoutedEventArgs e) { Task.Run(() => { controller.ToggleRuleMode(ProxyRuleMode.BypassLan); }); } private void RuleBypassChinaItem_Click(object sender, RoutedEventArgs e) { Task.Run(() => { controller.ToggleRuleMode(ProxyRuleMode.BypassLanAndChina); }); } private void RuleBypassNotChinaItem_Click(object sender, RoutedEventArgs e) { Task.Run(() => { controller.ToggleRuleMode(ProxyRuleMode.BypassLanAndNotChina); }); } private void RuleUserItem_Click(object sender, RoutedEventArgs e) { Task.Run(() => { controller.ToggleRuleMode(ProxyRuleMode.UserCustom); }); } private void RuleBypassDisableItem_Click(object sender, RoutedEventArgs e) { Task.Run(() => { controller.ToggleRuleMode(ProxyRuleMode.Disable); }); } private void SelectRandomItem_Click(object sender, RoutedEventArgs e) { SelectRandomItem.IsChecked = !SelectRandomItem.IsChecked; if (SelectRandomItem.IsChecked) { Task.Run(() => { controller.ToggleSelectRandom(true); }); } else { Task.Run(() => { controller.ToggleSelectRandom(false); }); } } private void AutoCheckUpdateItem_Click(object sender, RoutedEventArgs e) { AutoCheckUpdateItem.IsChecked = !AutoCheckUpdateItem.IsChecked; controller.ToggleSelectAutoCheckUpdate(AutoCheckUpdateItem.IsChecked); } private void AllowPreRelease_Click(object sender, RoutedEventArgs e) { AllowPreReleaseItem.IsChecked = !AllowPreReleaseItem.IsChecked; controller.ToggleSelectAllowPreRelease(AllowPreReleaseItem.IsChecked); } private void SelectSameHostForSameTargetItem_Click(object sender, RoutedEventArgs e) { sameHostForSameTargetItem.IsChecked = !sameHostForSameTargetItem.IsChecked; if (sameHostForSameTargetItem.IsChecked) { Task.Run(() => { controller.ToggleSameHostForSameTargetRandom(true); }); } else { Task.Run(() => { controller.ToggleSameHostForSameTargetRandom(false); }); } } private void CopyPacUrlItem_Click(object sender, RoutedEventArgs e) { controller.CopyPacUrl(); } private void EditPACFileItem_Click(object sender, RoutedEventArgs e) { controller.TouchPACFile(); } private void UpdatePACFromGFWListItem_Click(object sender, RoutedEventArgs e) { controller.UpdatePACFromGFWList(); } private void UpdatePACFromLanIPListItem_Click(object sender, RoutedEventArgs e) { controller.UpdatePACFromOnlinePac(@"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_lanip.pac"); } private void UpdatePACFromCNWhiteListItem_Click(object sender, RoutedEventArgs e) { //域名白名单 controller.UpdatePACFromOnlinePac(@"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_white.pac"); } private void UpdatePACFromCNOnlyListItem_Click(object sender, RoutedEventArgs e) { //回国 controller.UpdatePACFromOnlinePac(@"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_white_r.pac"); } private void UpdatePACFromCnWhiteListIpItem_Click(object sender, RoutedEventArgs e) { //域名白名单+国内IP controller.UpdatePACFromOnlinePac(@"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_cnall.pac"); } private void UpdatePACFromChnIpItem_Click(object sender, RoutedEventArgs e) { //国内IP controller.UpdatePACFromOnlinePac(@"https://raw.githubusercontent.com/HMBSbige/Text_Translation/master/ShadowsocksR/ss_cnip.pac"); } private void EditUserRuleFileForGFWListItem_Click(object sender, RoutedEventArgs e) { controller.TouchUserRuleFile(); } private void AServerItem_Click(object sender, EventArgs e) { var item = (MenuItem)sender; var index = (int)item.Tag; Task.Run(() => { controller.DisconnectAllConnections(true); controller.SelectServerIndex(index); }); } private void CheckUpdate_Click(object sender, RoutedEventArgs e) { updateChecker.Check(Global.GuiConfig, true); } private void CheckNodeUpdate_Click(object sender, RoutedEventArgs e) { Global.UpdateSubscribeManager.CreateTask(Global.GuiConfig, Global.UpdateNodeChecker, true); } private void ShowLogItem_Click(object sender, RoutedEventArgs e) { ShowGlobalLogWindow(); } private void ShowPortMapItem_Click(object sender, RoutedEventArgs e) { ShowPortMapForm(); } private void ShowServerLogItem_Click(object sender, RoutedEventArgs e) { ShowServerLogForm(); } private void SubscribeSetting_Click(object sender, RoutedEventArgs e) { ShowSubscribeSettingForm(); } private void DisconnectCurrent_Click(object sender, RoutedEventArgs e) { Task.Run(() => { controller.DisconnectAllConnections(); }); } public void ImportAddress(string text) { ImportSsrUrl(text); ImportSubUrl(text); } private void ImportSsrUrl(string text) { if (controller.AddServerBySsUrl(text)) { ShowConfigForm(true); } } private void ImportSubUrl(string text) { if (controller.AddSubscribeUrl(text)) { ShowSubscribeSettingForm(); } } private void ImportAddressFromClipboard_Click(object sender, RoutedEventArgs e) { try { var iData = Clipboard.GetDataObject(); if (iData != null && iData.GetDataPresent(DataFormats.Text)) { ImportAddress((string)iData.GetData(DataFormats.Text)); } } catch { // ignored } } #region QRCode private void ScanQRCodeItem_Click(object sender, RoutedEventArgs e) { Task.Run(() => { var w = (int)SystemParameters.VirtualScreenWidth; var h = (int)SystemParameters.VirtualScreenHeight; var x = (int)SystemParameters.VirtualScreenLeft; var y = (int)SystemParameters.VirtualScreenTop; var fullImage = new Bitmap(w, h); using (var g = Graphics.FromImage(fullImage)) { g.CopyFromScreen(x, y, 0, 0, fullImage.Size, CopyPixelOperation.SourceCopy); } const int maxTry = 10; for (var i = 0; i < maxTry; i++) { var marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry); var marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry); var cropRect = new Rectangle(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2); var target = new Bitmap(w, h); var imageScale = w / (double)cropRect.Width; using (var g = Graphics.FromImage(target)) { g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel); } var result = QrCodeUtils.ScanBitmap(target); if (result != null) { var success = controller.AddServerBySsUrl(result.Text); var successSub = controller.AddSubscribeUrl(result.Text); Application.Current.Dispatcher?.InvokeAsync(() => { var splash = new QRCodeSplashWindow(); if (successSub) { splash.Closed += Splash_Closed0; } if (success) { splash.Closed += Splash_Closed; } if (!(successSub || success)) { _urlToOpen = result.Text; splash.Closed += Splash_Closed2; } double minX = int.MaxValue, minY = int.MaxValue, maxX = 0, maxY = 0; foreach (var point in result.ResultPoints) { minX = Math.Min(minX, point.X); minY = Math.Min(minY, point.Y); maxX = Math.Max(maxX, point.X); maxY = Math.Max(maxY, point.Y); } minX /= imageScale; minY /= imageScale; maxX /= imageScale; maxY /= imageScale; // make it 20% larger var margin = (maxX - minX) * 0.20f; minX += -margin + marginLeft; maxX += margin + marginLeft; minY += -margin + marginTop; maxY += margin + marginTop; splash.Left = x; splash.Top = y; splash.TargetRect = new Rectangle((int)minX, (int)minY, (int)maxX - (int)minX, (int)maxY - (int)minY); splash.Width = fullImage.Width; splash.Height = fullImage.Height; fullImage.Dispose(); splash.Show(); }); return; } } MessageBox.Show(I18NUtil.GetAppStringValue(@"QrCodeNotFound")); }); } private void Splash_Closed(object sender, EventArgs e) { ShowConfigForm(true); } private void Splash_Closed0(object sender, EventArgs e) { ShowSubscribeSettingForm(); } private void ShowUrlFromQrCode() { var dlg = new ShowTextWindow(_urlToOpen); dlg.Show(); dlg.Activate(); dlg.BringToFront(); } private void Splash_Closed2(object sender, EventArgs e) { ShowUrlFromQrCode(); } private void ShowUrlFromQrCode(object sender, RoutedEventArgs e) { ShowUrlFromQrCode(); } #endregion } } ================================================ FILE: shadowsocks-csharp/Controller/Service/HostDaemon.cs ================================================ using Shadowsocks.Model; using System; using System.IO; using System.Threading.Tasks; namespace Shadowsocks.Controller.Service { public class HostDaemon { private FileSystemWatcher _userRuleWatcher; private FileSystemWatcher _chnIpWatcher; public event EventHandler UserRuleChanged; public event EventHandler ChnIpChanged; public HostDaemon() { WatchChnIp(); WatchUserRule(); } private void WatchChnIp() { _chnIpWatcher?.Dispose(); _chnIpWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory()) { NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName, Filter = IPRangeSet.ChnFilename }; _chnIpWatcher.Changed += ChnIpWatcher_Changed; _chnIpWatcher.Created += ChnIpWatcher_Changed; _chnIpWatcher.Deleted += ChnIpWatcher_Changed; _chnIpWatcher.Renamed += ChnIpWatcher_Changed; _chnIpWatcher.EnableRaisingEvents = true; } private void WatchUserRule() { _userRuleWatcher?.Dispose(); _userRuleWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory()) { NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName, Filter = HostMap.UserRule }; _userRuleWatcher.Changed += UserRuleWatcher_Changed; _userRuleWatcher.Created += UserRuleWatcher_Changed; _userRuleWatcher.Deleted += UserRuleWatcher_Changed; _userRuleWatcher.Renamed += UserRuleWatcher_Changed; _userRuleWatcher.EnableRaisingEvents = true; } private void UserRuleWatcher_Changed(object sender, FileSystemEventArgs e) { if (UserRuleChanged == null) { return; } try { ((FileSystemWatcher)sender).EnableRaisingEvents = false; Logging.Info($@"Detected: user rule file '{e.Name}' was {e.ChangeType.ToString().ToLower()}."); Task.Delay(10).ContinueWith(task => UserRuleChanged(this, EventArgs.Empty)); } finally { ((FileSystemWatcher)sender).EnableRaisingEvents = true; } } private void ChnIpWatcher_Changed(object sender, FileSystemEventArgs e) { if (ChnIpChanged == null) { return; } try { ((FileSystemWatcher)sender).EnableRaisingEvents = false; Logging.Info($@"Detected: '{e.Name}' was {e.ChangeType.ToString().ToLower()}."); Task.Delay(10).ContinueWith(task => ChnIpChanged(this, EventArgs.Empty)); } finally { ((FileSystemWatcher)sender).EnableRaisingEvents = true; } } } } ================================================ FILE: shadowsocks-csharp/Controller/Service/HostMap.cs ================================================ using Shadowsocks.Model; using System; using System.Collections.Generic; using System.IO; using System.Net; namespace Shadowsocks.Controller.Service { public static class HostMap { private static readonly Dictionary Root = new(); private static IPSegment _ips; public const string UserRule = @"user.rule"; static HostMap() { Clear(); } private static void Clear() { Root.Clear(); _ips = new IPSegment(@"remoteproxy"); } public static void Reload() { Clear(); LoadHostFile(); } private static void AddHost(string host, string addr) { if (IPAddress.TryParse(host, out _)) { var addr_parts = addr.Split(new[] { ' ', '\t' }, 2, StringSplitOptions.RemoveEmptyEntries); if (addr_parts.Length >= 2) { _ips.insert(new IPAddressCmp(host), new IPAddressCmp(addr_parts[0]), addr_parts[1]); return; } } var parts = host.Split('.'); var node = Root; var include_sub = false; var end = 0; if (parts[0].Length == 0) { end = 1; include_sub = true; } for (var i = parts.Length - 1; i > end; --i) { if (!node.ContainsKey(parts[i])) { node[parts[i]] = new HostNode(); } if (node[parts[i]].SubNode == null) { node[parts[i]].SubNode = new Dictionary(); } node = node[parts[i]].SubNode; } node[parts[end]] = new HostNode(include_sub, addr); } public static bool GetHost(string host, out string addr) { var parts = host.Split('.'); var node = Root; addr = null; for (var i = parts.Length - 1; i >= 0; --i) { if (!node.ContainsKey(parts[i])) { return false; } if (node[parts[i]].Addr.Length > 0 || node[parts[i]].IncludeSub) { addr = node[parts[i]].Addr; return true; } if (node.ContainsKey("*")) { addr = node["*"].Addr; return true; } if (node[parts[i]].SubNode == null) { return false; } node = node[parts[i]].SubNode; } return false; } public static bool GetIP(IPAddress ip, out string addr) { var host = ip.ToString(); addr = _ips.Get(new IPAddressCmp(host)) as string; return addr != null; } private static void LoadHostFile() { if (File.Exists(UserRule)) { try { foreach (var line in File.ReadLines(UserRule)) { if (line.Length > 0 && line.StartsWith(@"#")) { continue; } var parts = line.Split(new[] { ' ', '\t' }, 2, StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 2) { continue; } AddHost(parts[0], parts[1]); } } catch { // ignored } } } } } ================================================ FILE: shadowsocks-csharp/Controller/Service/HttpPortForwarder.cs ================================================ using Shadowsocks.Model; using Shadowsocks.Proxy; using Shadowsocks.Util.NetUtils; using System; using System.Net; using System.Net.Sockets; namespace Shadowsocks.Controller.Service { internal class HttpPortForwarder : Listener.Service { private readonly int _targetPort; private readonly Configuration _config; public HttpPortForwarder(int targetPort, Configuration config) { _targetPort = targetPort; _config = config; } public override bool Handle(byte[] firstPacket, int length, Socket socket) { if (socket.ProtocolType != ProtocolType.Tcp) { return false; } new Handler().Start(_config, firstPacket, length, socket, _targetPort); return true; } private class Handler { private byte[] _firstPacket; private int _firstPacketLength; private int _targetPort; private Socket _local; private WrappedSocket _remote; private bool _closed; private bool _localShutdown; private bool _remoteShutdown; private Configuration _config; private HttpParser _httpProxyState; private const int RecvSize = 4096; // remote receive buffer private readonly byte[] _remoteRecvBuffer = new byte[RecvSize]; // connection receive buffer private readonly byte[] _connetionRecvBuffer = new byte[RecvSize]; public void Start(Configuration config, byte[] firstPacket, int length, Socket socket, int targetPort) { _config = config; _firstPacket = firstPacket; _firstPacketLength = length; _local = socket; _targetPort = targetPort; if ((_config.AuthUser ?? string.Empty).Length == 0 || IPSubnet.IsLoopBack(((IPEndPoint)_local.RemoteEndPoint).Address)) { Connect(); } else { RspHttpHandshakeReceive(); } } private void RspHttpHandshakeReceive() { if (_httpProxyState == null) { _httpProxyState = new HttpParser(true); } _httpProxyState.httpAuthUser = _config.AuthUser; _httpProxyState.httpAuthPass = _config.AuthPass; var err = _httpProxyState.HandshakeReceive(_firstPacket, _firstPacketLength, out _); if (err == 1) { _local.BeginReceive(_connetionRecvBuffer, 0, _firstPacket.Length, 0, HttpHandshakeRecv, null); } else if (err == 2) { var dataSend = HttpParser.Http407(); var httpData = System.Text.Encoding.UTF8.GetBytes(dataSend); _local.BeginSend(httpData, 0, httpData.Length, 0, HttpHandshakeAuthEndSend, null); } else if (err == 3) { Connect(); } else if (err == 4) { Connect(); } else if (err == 0) { var dataSend = HttpParser.Http200(); var httpData = System.Text.Encoding.UTF8.GetBytes(dataSend); _local.BeginSend(httpData, 0, httpData.Length, 0, StartConnect, null); } else if (err == 500) { var dataSend = HttpParser.Http500(); var httpData = System.Text.Encoding.UTF8.GetBytes(dataSend); _local.BeginSend(httpData, 0, httpData.Length, 0, HttpHandshakeAuthEndSend, null); } } private void HttpHandshakeRecv(IAsyncResult ar) { if (_closed) { return; } try { var bytesRead = _local.EndReceive(ar); if (bytesRead > 0) { Array.Copy(_connetionRecvBuffer, _firstPacket, bytesRead); _firstPacketLength = bytesRead; RspHttpHandshakeReceive(); } else { Console.WriteLine(@"failed to recv data in HttpHandshakeRecv"); Close(); } } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void HttpHandshakeAuthEndSend(IAsyncResult ar) { if (_closed) { return; } try { _local.EndSend(ar); _local.BeginReceive(_connetionRecvBuffer, 0, _firstPacket.Length, 0, HttpHandshakeRecv, null); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void StartConnect(IAsyncResult ar) { try { _local.EndSend(ar); Connect(); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void Connect() { try { var ipAddress = Global.OSSupportsLocalIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback; var remoteEp = new IPEndPoint(ipAddress, _targetPort); _remote = new WrappedSocket(); // Connect to the remote endpoint. _remote.BeginConnect(remoteEp, ConnectCallback, null); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void ConnectCallback(IAsyncResult ar) { if (_closed) { return; } try { _remote.EndConnect(ar); _remote.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); HandshakeReceive(); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void HandshakeReceive() { if (_closed) { return; } try { _remote.BeginSend(_firstPacket, 0, _firstPacketLength, SocketFlags.None, StartPipe, null); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void StartPipe(IAsyncResult ar) { if (_closed) { return; } try { _remote.EndSend(ar); _remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, SocketFlags.None, PipeRemoteReceiveCallback, null); _local.BeginReceive(_connetionRecvBuffer, 0, RecvSize, SocketFlags.None, PipeConnectionReceiveCallback, null); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void PipeRemoteReceiveCallback(IAsyncResult ar) { if (_closed) { return; } try { var bytesRead = _remote.EndReceive(ar); if (bytesRead > 0) { _local.BeginSend(_remoteRecvBuffer, 0, bytesRead, 0, PipeConnectionSendCallback, null); } else { _local.Shutdown(SocketShutdown.Send); _localShutdown = true; CheckClose(); } } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void PipeConnectionReceiveCallback(IAsyncResult ar) { if (_closed) { return; } try { var bytesRead = _local.EndReceive(ar); if (bytesRead > 0) { _remote.BeginSend(_connetionRecvBuffer, 0, bytesRead, SocketFlags.None, PipeRemoteSendCallback, null); } else { _remote.Shutdown(SocketShutdown.Send); _remoteShutdown = true; CheckClose(); } } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void PipeRemoteSendCallback(IAsyncResult ar) { if (_closed) { return; } try { _remote.EndSend(ar); _local.BeginReceive(_connetionRecvBuffer, 0, RecvSize, 0, PipeConnectionReceiveCallback, null); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void PipeConnectionSendCallback(IAsyncResult ar) { if (_closed) { return; } try { _local.EndSend(ar); _remote.BeginReceive(_remoteRecvBuffer, 0, RecvSize, 0, PipeRemoteReceiveCallback, null); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void CheckClose() { if (_localShutdown && _remoteShutdown) { Close(); } } private void Close() { lock (this) { if (_closed) { return; } _closed = true; } if (_local != null) { try { _local.Shutdown(SocketShutdown.Both); _local.Close(); } catch (Exception e) { Logging.LogUsefulException(e); } } if (_remote != null) { try { _remote.Shutdown(SocketShutdown.Both); _remote.Dispose(); } catch (SocketException e) { Logging.LogUsefulException(e); } } } } } } ================================================ FILE: shadowsocks-csharp/Controller/Service/HttpProxyRunner.cs ================================================ using HttpProxy; using Microsoft.VisualStudio.Threading; using Shadowsocks.Model; using Socks5.Models; using System.Net; #nullable enable namespace Shadowsocks.Controller.Service { public class HttpProxyRunner { private HttpSocks5Service? _service; public int RunningPort { get; private set; } public void Start(Configuration configuration) { if (_service is not null) { return; } var ip = configuration.ShareOverLan ? Global.IpAny : Global.IpLocal; var ipe = new IPEndPoint(ip, 0); var option = new Socks5CreateOption { Address = Global.IpLocal, Port = (ushort)configuration.LocalPort, UsernamePassword = new UsernamePassword { UserName = configuration.AuthUser, Password = configuration.AuthPass } }; _service = new HttpSocks5Service(ipe, new HttpToSocks5(), option); _service.StartAsync().Forget(); RunningPort = ((IPEndPoint)_service.TcpListener.LocalEndpoint).Port; } public void Stop() { if (_service is null) { return; } _service.Stop(); _service = null; } } } ================================================ FILE: shadowsocks-csharp/Controller/Service/Listener.cs ================================================ using Shadowsocks.Enums; using Shadowsocks.Model; using Shadowsocks.Util; using Shadowsocks.Util.NetUtils; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; namespace Shadowsocks.Controller.Service { public class Listener { public interface IService { bool Handle(byte[] firstPacket, int length, Socket socket); void Stop(); } public abstract class Service : IService { public abstract bool Handle(byte[] firstPacket, int length, Socket socket); public virtual void Stop() { } } private Configuration _config; private bool _shareOverLan; private string _authUser; private Socket _socket; private Socket _socketV6; private bool _stop; private readonly List _services; public Listener(List services) { _services = services; _stop = false; } private static bool CheckIfPortInUse(int port) { var ipProperties = IPGlobalProperties.GetIPGlobalProperties(); return ipProperties.GetActiveTcpListeners().Any(endPoint => endPoint.Port == port); } public void Start(Configuration config, int port) { _config = config; _shareOverLan = config.ShareOverLan; _authUser = config.AuthUser; var localPort = port == 0 ? _config.LocalPort : port; if (CheckIfPortInUse(localPort)) { throw new Exception(string.Format(I18NUtil.GetAppStringValue(@"PortInUse"), localPort)); } try { //TODO:UDP socket // Create a TCP/IP socket. _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); var localEndPoint = new IPEndPoint(_shareOverLan ? IPAddress.Any : IPAddress.Loopback, localPort); // Bind the socket to the local endpoint and listen for incoming connections. _socket.Bind(localEndPoint); _socket.Listen(1024); // IPv6 if (Global.OSSupportsLocalIPv6) { try { _socketV6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); _socketV6.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); } catch { _socketV6 = null; } var localEndPointV6 = new IPEndPoint(_shareOverLan ? IPAddress.IPv6Any : IPAddress.IPv6Loopback, localPort); if (_socketV6 != null) { _socketV6.Bind(localEndPointV6); _socketV6.Listen(1024); } } else { _socketV6 = null; } // Start an asynchronous socket to listen for connections. Console.WriteLine($@"ShadowsocksR started on port {localPort}"); _socket.BeginAccept(AcceptCallback, _socket); _socketV6?.BeginAccept(AcceptCallback, _socketV6); } catch (SocketException e) { Logging.LogUsefulException(e); if (_socket != null) { _socket.Close(); _socket = null; } if (_socketV6 != null) { _socketV6.Close(); _socketV6 = null; } throw; } } public void Stop() { _stop = true; if (_socket != null) { _socket.Close(); _socket = null; } if (_socketV6 != null) { _socketV6.Close(); _socketV6 = null; } _services.ForEach(s => s.Stop()); } private void AcceptCallback(IAsyncResult ar) { if (_stop) { return; } var listener = (Socket)ar.AsyncState; try { var conn = listener.EndAccept(ar); var localPort = ((IPEndPoint)conn.LocalEndPoint).Port; if ((_authUser ?? string.Empty).Length == 0 && !IPSubnet.IsLan(conn) && !(_config.PortMapCache.ContainsKey(localPort) || _config.PortMapCache[localPort].type == PortMapType.Forward)) { conn.Shutdown(SocketShutdown.Both); conn.Close(); } else { var buf = new byte[4096]; object[] state = { conn, buf }; if (_config.PortMapCache.TryGetValue(localPort, out var portMap) && portMap.type == PortMapType.Forward) { if (_services.Any(service => service.Handle(buf, 0, conn))) { return; } // no service found for this // shouldn't happen conn.Shutdown(SocketShutdown.Both); conn.Close(); } else { conn.BeginReceive(buf, 0, buf.Length, 0, ReceiveCallback, state); } } } catch (ObjectDisposedException) { } catch (Exception e) { Console.WriteLine(e); } finally { try { listener.BeginAccept(AcceptCallback, listener); } catch (ObjectDisposedException) { // do nothing } catch (Exception e) { Logging.LogUsefulException(e); } } } private void ReceiveCallback(IAsyncResult ar) { var state = (object[])ar.AsyncState; var conn = (Socket)state[0]; var buf = (byte[])state[1]; try { var bytesRead = conn.EndReceive(ar); if (bytesRead > 0 && _services.Any(service => service.Handle(buf, bytesRead, conn))) { return; } // no service found for this // shouldn't happen conn.Shutdown(SocketShutdown.Both); conn.Close(); } catch (Exception e) { Console.WriteLine(e); conn.Shutdown(SocketShutdown.Both); conn.Close(); } } } } ================================================ FILE: shadowsocks-csharp/Controller/Service/Local.cs ================================================ using Shadowsocks.Model; using Shadowsocks.Model.Transfer; using Shadowsocks.Proxy; using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; namespace Shadowsocks.Controller.Service { public class Local : Listener.Service { private readonly Configuration _config; private readonly ServerTransferTotal _transfer; private readonly IPRangeSet _ipRange; public Local(Configuration config, ServerTransferTotal transfer, IPRangeSet IPRange) { _config = config; _transfer = transfer; _ipRange = IPRange; } private static bool Accept(byte[] firstPacket, int length) { if (length < 2) { return false; } if (firstPacket[0] is 5 or 4) { return true; } Debug.WriteLine(System.Text.Encoding.UTF8.GetString(firstPacket)); if (length > 8 && firstPacket[0] == 'C' && firstPacket[1] == 'O' && firstPacket[2] == 'N' && firstPacket[3] == 'N' && firstPacket[4] == 'E' && firstPacket[5] == 'C' && firstPacket[6] == 'T' && firstPacket[7] == ' ') { return true; } return false; } public override bool Handle(byte[] firstPacket, int length, Socket socket) { if (!_config.PortMapCache.ContainsKey(((IPEndPoint)socket.LocalEndPoint).Port) && !Accept(firstPacket, length)) { return false; } Task.Run(() => { var unused = new ProxyAuthHandler(_config, _transfer, _ipRange, firstPacket, length, socket); }); return true; } } } ================================================ FILE: shadowsocks-csharp/Controller/Service/PACDaemon.cs ================================================ using Shadowsocks.Properties; using System; using System.IO; using System.Text; using System.Threading.Tasks; namespace Shadowsocks.Controller.Service { /// /// Processing the PAC file content /// public class PACDaemon { public const string PAC_FILE = @"pac.txt"; public const string USER_RULE_FILE = @"user-rule.txt"; public const string USER_ABP_FILE = @"abp.txt"; FileSystemWatcher PACFileWatcher; FileSystemWatcher UserRuleFileWatcher; public event EventHandler PACFileChanged; public event EventHandler UserRuleFileChanged; public PACDaemon() { TouchPACFile(); TouchUserRuleFile(); WatchPacFile(); WatchUserRuleFile(); } public string TouchPACFile() { if (!File.Exists(PAC_FILE)) { File.WriteAllText(PAC_FILE, Resources.proxy_pac); } return PAC_FILE; } internal string TouchUserRuleFile() { if (!File.Exists(USER_RULE_FILE)) { File.WriteAllText(USER_RULE_FILE, Resources.user_rule); } return USER_RULE_FILE; } internal string GetPACContent() { if (File.Exists(PAC_FILE)) { return File.ReadAllText(PAC_FILE, Encoding.UTF8); } return Resources.proxy_pac; } private void WatchPacFile() { PACFileWatcher?.Dispose(); PACFileWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory()) { NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName, Filter = PAC_FILE }; PACFileWatcher.Changed += PACFileWatcher_Changed; PACFileWatcher.Created += PACFileWatcher_Changed; PACFileWatcher.Deleted += PACFileWatcher_Changed; PACFileWatcher.Renamed += PACFileWatcher_Changed; PACFileWatcher.EnableRaisingEvents = true; } private void WatchUserRuleFile() { UserRuleFileWatcher?.Dispose(); UserRuleFileWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory()) { NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName, Filter = USER_RULE_FILE }; UserRuleFileWatcher.Changed += UserRuleFileWatcher_Changed; UserRuleFileWatcher.Created += UserRuleFileWatcher_Changed; UserRuleFileWatcher.Deleted += UserRuleFileWatcher_Changed; UserRuleFileWatcher.Renamed += UserRuleFileWatcher_Changed; UserRuleFileWatcher.EnableRaisingEvents = true; } #region FileSystemWatcher.OnChanged() // FileSystemWatcher Changed event is raised twice // http://stackoverflow.com/questions/1764809/filesystemwatcher-changed-event-is-raised-twice // Add a short delay to avoid raise event twice in a short period private void PACFileWatcher_Changed(object sender, FileSystemEventArgs e) { if (PACFileChanged == null) { return; } try { ((FileSystemWatcher)sender).EnableRaisingEvents = false; Logging.Info($@"Detected: PAC file '{e.Name}' was {e.ChangeType.ToString().ToLower()}."); Task.Delay(10).ContinueWith(task => { PACFileChanged(this, EventArgs.Empty); }); } finally { ((FileSystemWatcher)sender).EnableRaisingEvents = true; } } private void UserRuleFileWatcher_Changed(object sender, FileSystemEventArgs e) { if (UserRuleFileChanged == null) { return; } try { ((FileSystemWatcher)sender).EnableRaisingEvents = false; Logging.Info($@"Detected: User Rule file '{e.Name}' was {e.ChangeType.ToString().ToLower()}."); Task.Delay(10).ContinueWith(task => { UserRuleFileChanged(this, EventArgs.Empty); }); } finally { ((FileSystemWatcher)sender).EnableRaisingEvents = true; } } #endregion } } ================================================ FILE: shadowsocks-csharp/Controller/Service/PACServer.cs ================================================ using Shadowsocks.Enums; using Shadowsocks.Model; using Shadowsocks.Util; using System; using System.Net; using System.Net.Sockets; using System.Text; namespace Shadowsocks.Controller.Service { public class PACServer : Listener.Service { private const string ResourceName = @"pac"; public static string gfwlist_FILE = @"gfwlist.txt"; public static string WHITELIST_FILE = @"whitelist.txt"; public static string USER_WHITELIST_TEMPLATE_FILE = @"user_whitelist_temp.txt"; public string PacUrl { get; private set; } = string.Empty; private Configuration _config; private readonly PACDaemon _pacDaemon; public PACServer(PACDaemon pacDaemon) { _pacDaemon = pacDaemon; } public void UpdatePacUrl(Configuration config) { _config = config; //Lots of software do not support ipv6 pac url yet PacUrl = $@"http://{IPAddress.Loopback}:{config.LocalPort}/{ResourceName}?t={DateTime.Now:yyyyMMddHHmmssffff}"; } public override bool Handle(byte[] firstPacket, int length, Socket socket) { if (socket.ProtocolType != ProtocolType.Tcp) { return false; } try { var request = Encoding.UTF8.GetString(firstPacket, 0, length); var lines = request.GetLines(); bool hostMatch = false, pathMatch = false; var socksType = 0; string proxy = null; foreach (var line in lines) { var kv = line.Split(new[] { ':' }, 2); switch (kv.Length) { case 2: { if (kv[0] == @"Host") { if (kv[1].Trim() == ((IPEndPoint)socket.LocalEndPoint).ToString()) { hostMatch = true; } } break; } case 1: { if (line.IndexOf($" /{ResourceName}?", StringComparison.Ordinal) > 0 && line.IndexOf(@"GET", StringComparison.Ordinal) == 0) { var url = line.Substring(line.IndexOf(" ", StringComparison.Ordinal) + 1); url = url.Substring(0, url.IndexOf(" ", StringComparison.Ordinal)); pathMatch = true; var portPos = url.IndexOf("port=", StringComparison.Ordinal); if (portPos > 0) { var port = url.Substring(portPos + 5); if (port.IndexOf("&", StringComparison.Ordinal) >= 0) { port = port.Substring(0, port.IndexOf("&", StringComparison.Ordinal)); } var ipPos = url.IndexOf("ip=", StringComparison.Ordinal); if (ipPos > 0) { proxy = url.Substring(ipPos + 3); if (proxy.IndexOf("&", StringComparison.Ordinal) >= 0) { proxy = proxy.Substring(0, proxy.IndexOf("&", StringComparison.Ordinal)); } proxy += $@":{port};"; } else { proxy = $@"127.0.0.1:{port};"; } } if (url.IndexOf("type=socks4", StringComparison.Ordinal) > 0 || url.IndexOf("type=s4", StringComparison.Ordinal) > 0) { socksType = 4; } if (url.IndexOf("type=socks5", StringComparison.Ordinal) > 0 || url.IndexOf("type=s5", StringComparison.Ordinal) > 0) { socksType = 5; } } break; } } } if (hostMatch && pathMatch) { SendResponse(socket, socksType, proxy); return true; } return false; } catch (ArgumentException) { return false; } } private void SendResponse(Socket socket, int socksType, string setProxy) { try { var pac = _pacDaemon.GetPACContent(); var localEndPoint = (IPEndPoint)socket.LocalEndPoint; var proxy = setProxy == null ? GetPACAddress(localEndPoint, socksType) : socksType == 5 ? $@"SOCKS5 {setProxy}" : socksType == 4 ? $@"SOCKS {setProxy}" : $@"PROXY {setProxy}"; if (_config.PacDirectGoProxy && _config.ProxyEnable) { if (_config.ProxyType == ProxyType.Socks5) { pac = pac.Replace(@"__DIRECT__", $@"SOCKS5 {_config.ProxyHost}:{_config.ProxyPort};DIRECT;"); } else if (_config.ProxyType == ProxyType.Http) { pac = pac.Replace(@"__DIRECT__", $@"PROXY {_config.ProxyHost}:{_config.ProxyPort};DIRECT;"); } } else { pac = pac.Replace(@"__DIRECT__", @"DIRECT;"); } pac = pac.Replace(@"__PROXY__", $@"{proxy}DIRECT;"); var text = $@"HTTP/1.1 200 OK Server: {HttpRequest.UpdateChecker.Name}/{HttpRequest.UpdateChecker.Version} Content-Type: application/x-ns-proxy-autoconfig Content-Length: {Encoding.UTF8.GetBytes(pac).Length} Connection: Close {pac}"; var response = Encoding.UTF8.GetBytes(text); socket.BeginSend(response, 0, response.Length, 0, SendCallback, socket); } catch (Exception e) { Logging.LogUsefulException(e); socket.Shutdown(SocketShutdown.Both); socket.Close(); } } private static void SendCallback(IAsyncResult ar) { var conn = (Socket)ar.AsyncState; try { conn.Shutdown(SocketShutdown.Both); conn.Close(); } catch { // ignored } } private string GetPACAddress(IPEndPoint localEndPoint, int socksType) { var localhost = localEndPoint.AddressFamily == AddressFamily.InterNetworkV6 ? $@"[{localEndPoint.Address}]" : $@"{localEndPoint.Address}"; return socksType switch { 5 => $@"SOCKS5 {localhost}:{_config.LocalPort};", 4 => $@"SOCKS {localhost}:{_config.LocalPort};", _ => $@"PROXY {localhost}:{_config.LocalPort};" }; } } } ================================================ FILE: shadowsocks-csharp/Controller/Service/ProtocolResponseDetector.cs ================================================ using System; namespace Shadowsocks.Controller.Service { internal class ProtocolResponseDetector { protected enum Protocol { Unknown = -1, NotBegin = 0, HTTP = 1, TLS = 2, SOCKS4 = 4, SOCKS5 = 5 } protected Protocol protocol = Protocol.NotBegin; private byte[] _sendBuffer = new byte[0]; private byte[] _recvBuffer = new byte[0]; public bool Pass { get; set; } public ProtocolResponseDetector() { Pass = false; } public void OnSend(byte[] sendData, int length) { if (protocol != Protocol.NotBegin) { return; } Array.Resize(ref _sendBuffer, _sendBuffer.Length + length); Array.Copy(sendData, 0, _sendBuffer, _sendBuffer.Length - length, length); if (_sendBuffer.Length < 2) { return; } var head_size = Obfs.ObfsBase.GetHeadSize(_sendBuffer, _sendBuffer.Length); if (_sendBuffer.Length - head_size < 0) { return; } var data = new byte[_sendBuffer.Length - head_size]; Array.Copy(_sendBuffer, head_size, data, 0, data.Length); if (data.Length < 2) { return; } if (data.Length > 8) { if (data[0] == 22 && data[1] == 3 && data[2] <= 3) { protocol = Protocol.TLS; return; } if (data[0] == 'G' && data[1] == 'E' && data[2] == 'T' && data[3] == ' ' || data[0] == 'P' && data[1] == 'U' && data[2] == 'T' && data[3] == ' ' || data[0] == 'H' && data[1] == 'E' && data[2] == 'A' && data[3] == 'D' && data[4] == ' ' || data[0] == 'P' && data[1] == 'O' && data[2] == 'S' && data[3] == 'T' && data[4] == ' ' || data[0] == 'C' && data[1] == 'O' && data[2] == 'N' && data[3] == 'N' && data[4] == 'E' && data[5] == 'C' && data[6] == 'T' && data[7] == ' ' ) { protocol = Protocol.HTTP; } } else { protocol = Protocol.Unknown; } } public int OnRecv(byte[] recv_data, int length) { if (protocol is Protocol.Unknown or Protocol.NotBegin) { return 0; } Array.Resize(ref _recvBuffer, _recvBuffer.Length + length); Array.Copy(recv_data, 0, _recvBuffer, _recvBuffer.Length - length, length); if (_recvBuffer.Length < 2) { return 0; } if (protocol == Protocol.HTTP && _recvBuffer.Length > 4) { if (_recvBuffer[0] == 'H' && _recvBuffer[1] == 'T' && _recvBuffer[2] == 'T' && _recvBuffer[3] == 'P') { Finish(); return 0; } protocol = Protocol.Unknown; return 1; //throw new ProtocolException("Wrong http response"); } if (protocol == Protocol.TLS && _recvBuffer.Length > 4) { if (_recvBuffer[0] == 22 && _recvBuffer[1] == 3) { Finish(); return 0; } protocol = Protocol.Unknown; return 2; //throw new ProtocolException("Wrong tls response"); } return 0; } private void Finish() { _sendBuffer = null; _recvBuffer = null; protocol = Protocol.Unknown; Pass = true; } } } ================================================ FILE: shadowsocks-csharp/Controller/Service/Socks5Forwarder.cs ================================================ using Shadowsocks.Enums; using Shadowsocks.Model; using Shadowsocks.Proxy; using Shadowsocks.Util.NetUtils; using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Timers; namespace Shadowsocks.Controller.Service { class Socks5Forwarder : Listener.Service { private Configuration _config; private IPRangeSet _IPRange; const int CONNECT_DIRECT = 1; const int CONNECT_LOCALPROXY = 2; const int CONNECT_REMOTEPROXY = 0; public Socks5Forwarder(Configuration config, IPRangeSet IPRange) { _config = config; _IPRange = IPRange; } public override bool Handle(byte[] firstPacket, int length, Socket socket) { return Handle(firstPacket, length, socket, null); } public bool Handle(byte[] firstPacket, int length, Socket socket, string local_sendback_protocol) { var handle = IsHandle(firstPacket, length); if (handle > 0) { if (_config.ProxyEnable) { new Handler().Start(_config, firstPacket, socket, local_sendback_protocol, handle == 2); } else { new Handler().Start(_config, firstPacket, socket, local_sendback_protocol, false); } return true; } return false; } private int IsHandle(byte[] firstPacket, int length) { if (length >= 7 && _config.ProxyRuleMode != ProxyRuleMode.Disable) { IPAddress ipAddress = null; if (firstPacket[0] == 1) { var addr = new byte[4]; Array.Copy(firstPacket, 1, addr, 0, addr.Length); ipAddress = new IPAddress(addr); } else if (firstPacket[0] == 3) { int len = firstPacket[1]; var addr = new byte[len]; if (length >= len + 2) { Array.Copy(firstPacket, 2, addr, 0, addr.Length); var host = Encoding.UTF8.GetString(firstPacket, 2, len); if (IPAddress.TryParse(host, out ipAddress)) { //pass } else { if ((_config.ProxyRuleMode == ProxyRuleMode.BypassLanAndChina || _config.ProxyRuleMode == ProxyRuleMode.BypassLanAndNotChina) && _IPRange != null || _config.ProxyRuleMode == ProxyRuleMode.UserCustom) { if (!IPAddress.TryParse(host, out ipAddress)) { if (_config.ProxyRuleMode == ProxyRuleMode.UserCustom) { if (HostMap.GetHost(host, out var host_addr)) { if (!string.IsNullOrEmpty(host_addr)) { var lower_host_addr = host_addr.ToLower(); if (lower_host_addr.StartsWith("reject") || lower_host_addr.StartsWith("direct") ) { return CONNECT_DIRECT; } if (lower_host_addr.StartsWith("localproxy")) { return CONNECT_LOCALPROXY; } if (lower_host_addr.StartsWith("remoteproxy")) { return CONNECT_REMOTEPROXY; } if (lower_host_addr.IndexOf('.') >= 0 || lower_host_addr.IndexOf(':') >= 0) { if (!IPAddress.TryParse(lower_host_addr, out ipAddress)) { // } } } } } if (ipAddress == null) { ipAddress = DnsUtil.DnsBuffer.Get(host); } } if (ipAddress == null) { ipAddress = DnsUtil.QueryDns(host); if (ipAddress != null) { DnsUtil.DnsBuffer.Set(host, new IPAddress(ipAddress.GetAddressBytes())); if (host.IndexOf('.') >= 0 && IPSubnet.IsLan(ipAddress)) { // assume that it is pollution if return LAN address return CONNECT_REMOTEPROXY; } } else { Logging.Log(LogLevel.Debug, "DNS query fail: " + host); } } } } } } else if (firstPacket[0] == 4) { var addr = new byte[16]; Array.Copy(firstPacket, 1, addr, 0, addr.Length); ipAddress = new IPAddress(addr); } if (ipAddress != null) { if (_config.ProxyRuleMode == ProxyRuleMode.UserCustom) { if (HostMap.GetIP(ipAddress, out var host_addr)) { var lower_host_addr = host_addr.ToLower(); if (lower_host_addr.StartsWith("reject") || lower_host_addr.StartsWith("direct") ) { return CONNECT_DIRECT; } if (lower_host_addr.StartsWith("localproxy")) { return CONNECT_LOCALPROXY; } if (lower_host_addr.StartsWith("remoteproxy")) { return CONNECT_REMOTEPROXY; } } } else { if (IPSubnet.IsLan(ipAddress)) { return CONNECT_DIRECT; } if (_config.ProxyRuleMode is ProxyRuleMode.BypassLanAndChina or ProxyRuleMode.BypassLanAndNotChina && _IPRange is not null) { if (_IPRange.IsInIPRange(ipAddress)) { return CONNECT_LOCALPROXY; } DnsUtil.DnsBuffer.Sweep(); } } } } return CONNECT_REMOTEPROXY; } private class Handler : IHandler { private Configuration _config; private byte[] _firstPacket; private ProxySocketTunLocal _local; private ProxySocketTun _remote; private bool _closed; private bool _local_proxy; private string _remote_host; private int _remote_port; public const int RecvSize = 1460 * 8; // remote receive buffer private byte[] remoteRecvBuffer = new byte[RecvSize]; // connection receive buffer private byte[] connetionRecvBuffer = new byte[RecvSize]; private int _totalRecvSize; protected int TTL = 600; protected System.Timers.Timer timer; protected object timerLock = new(); protected DateTime lastTimerSetTime; public void Start(Configuration config, byte[] firstPacket, Socket socket, string local_sendback_protocol, bool proxy) { _firstPacket = firstPacket; _local = new ProxySocketTunLocal(socket) { local_sendback_protocol = local_sendback_protocol }; _config = config; _local_proxy = proxy; Connect(); } private void Connect() { try { IPAddress ipAddress = null; var _targetPort = 0; { if (_firstPacket[0] == 1) { var addr = new byte[4]; Array.Copy(_firstPacket, 1, addr, 0, addr.Length); ipAddress = new IPAddress(addr); _targetPort = (_firstPacket[5] << 8) | _firstPacket[6]; _remote_host = ipAddress.ToString(); Logging.Info((_local_proxy ? "Local proxy" : "Direct") + " connect " + _remote_host + ":" + _targetPort); } else if (_firstPacket[0] == 4) { var addr = new byte[16]; Array.Copy(_firstPacket, 1, addr, 0, addr.Length); ipAddress = new IPAddress(addr); _targetPort = (_firstPacket[17] << 8) | _firstPacket[18]; _remote_host = ipAddress.ToString(); Logging.Info((_local_proxy ? "Local proxy" : "Direct") + " connect " + _remote_host + ":" + _targetPort); } else if (_firstPacket[0] == 3) { int len = _firstPacket[1]; var addr = new byte[len]; Array.Copy(_firstPacket, 2, addr, 0, addr.Length); _remote_host = Encoding.UTF8.GetString(_firstPacket, 2, len); _targetPort = (_firstPacket[len + 2] << 8) | _firstPacket[len + 3]; Logging.Info((_local_proxy ? "Local proxy" : "Direct") + " connect " + _remote_host + ":" + _targetPort); //if (!_local_proxy) { if (!IPAddress.TryParse(_remote_host, out ipAddress)) { if (_config.ProxyRuleMode == ProxyRuleMode.UserCustom) { if (HostMap.GetHost(_remote_host, out var host_addr)) { if (!string.IsNullOrEmpty(host_addr)) { var lower_host_addr = host_addr.ToLower(); if (lower_host_addr.StartsWith("reject")) { Close(); return; } if (lower_host_addr.IndexOf('.') >= 0 || lower_host_addr.IndexOf(':') >= 0) { if (!IPAddress.TryParse(lower_host_addr, out ipAddress)) { // } } } } } if (ipAddress == null) { ipAddress = DnsUtil.DnsBuffer.Get(_remote_host); } } if (ipAddress == null) { ipAddress = DnsUtil.QueryDns(_remote_host); } if (ipAddress != null) { DnsUtil.DnsBuffer.Set(_remote_host, new IPAddress(ipAddress.GetAddressBytes())); DnsUtil.DnsBuffer.Sweep(); } else { if (!_local_proxy) { throw new SocketException((int)SocketError.HostNotFound); } } } } _remote_port = _targetPort; } if (ipAddress != null && _config.ProxyRuleMode == ProxyRuleMode.UserCustom) { if (HostMap.GetIP(ipAddress, out var host_addr)) { var lower_host_addr = host_addr.ToLower(); if (lower_host_addr.StartsWith("reject") ) { Close(); return; } } } if (_local_proxy) { IPAddress.TryParse(_config.ProxyHost, out ipAddress); _targetPort = _config.ProxyPort; } // ProxyAuth recv only socks5 head, so don't need to save anything else var remoteEP = new IPEndPoint(ipAddress ?? throw new InvalidOperationException(), _targetPort); _remote = new ProxySocketTun(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _remote.GetSocket().NoDelay = true; // Connect to the remote endpoint. _remote.BeginConnect(remoteEP, ConnectCallback, null); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private bool ConnectProxyServer(string strRemoteHost, int iRemotePort) { if (_config.ProxyType == ProxyType.Socks5) { var ret = _remote.ConnectSocks5ProxyServer(strRemoteHost, iRemotePort, false, _config.ProxyAuthUser, _config.ProxyAuthPass); return ret; } if (_config.ProxyType == ProxyType.Http) { var ret = _remote.ConnectHttpProxyServer(strRemoteHost, iRemotePort, _config.ProxyAuthUser, _config.ProxyAuthPass, _config.ProxyUserAgent); return ret; } return true; } private void ConnectCallback(IAsyncResult ar) { if (_closed) { return; } try { _remote.EndConnect(ar); if (_local_proxy) { if (!ConnectProxyServer(_remote_host, _remote_port)) { throw new SocketException((int)SocketError.ConnectionReset); } } StartPipe(); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void ResetTimeout(double time) { if (time <= 0 && timer == null) { return; } if (time <= 0) { if (timer != null) { lock (timerLock) { if (timer != null) { timer.Enabled = false; timer.Elapsed -= timer_Elapsed; timer.Dispose(); timer = null; } } } } else { if ((DateTime.Now - lastTimerSetTime).TotalMilliseconds > 500) { lock (timerLock) { if (timer == null) { timer = new System.Timers.Timer(time * 1000.0); timer.Elapsed += timer_Elapsed; } else { timer.Interval = time * 1000.0; timer.Stop(); } timer.Start(); lastTimerSetTime = DateTime.Now; } } } } private void timer_Elapsed(object sender, ElapsedEventArgs e) { if (_closed) { return; } Close(); } private void StartPipe() { if (_closed) { return; } try { Server.ForwardServer.Connections.AddRef(this); _remote.BeginReceive(remoteRecvBuffer, RecvSize, SocketFlags.None, PipeRemoteReceiveCallback, null); _local.BeginReceive(connetionRecvBuffer, RecvSize, SocketFlags.None, PipeConnectionReceiveCallback, null); _local.Send(connetionRecvBuffer, 0, SocketFlags.None); ResetTimeout(TTL); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void PipeRemoteReceiveCallback(IAsyncResult ar) { if (_closed) { return; } try { var bytesRead = _remote.EndReceive(ar); if (bytesRead > 0) { ResetTimeout(TTL); //_local.BeginSend(remoteRecvBuffer, bytesRead, 0, new AsyncCallback(PipeConnectionSendCallback), null); _local.Send(remoteRecvBuffer, bytesRead, SocketFlags.None); _totalRecvSize += bytesRead; if (_totalRecvSize <= 1024 * 1024 * 2) { _remote.BeginReceive(remoteRecvBuffer, RecvSize, SocketFlags.None, PipeRemoteReceiveCallback, null); } else { PipeRemoteReceiveLoop(); } } else { Close(); } } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void PipeRemoteReceiveLoop() { var final_close = false; var recv_buffer = new byte[RecvSize]; var beforeReceive = DateTime.Now; while (!_closed) { try { var bytesRead = _remote.Receive(recv_buffer, RecvSize, SocketFlags.None); var now = DateTime.Now; if (_remote != null && _remote.IsClose) { final_close = true; break; } if (_closed) { break; } ResetTimeout(TTL); if (bytesRead > 0) { _local.Send(recv_buffer, bytesRead, SocketFlags.None); if ((now - beforeReceive).TotalSeconds > 5) { _totalRecvSize = 0; _remote.BeginReceive(remoteRecvBuffer, RecvSize, SocketFlags.None, PipeRemoteReceiveCallback, null); return; } beforeReceive = now; } else { Close(); } } catch (Exception e) { Logging.LogUsefulException(e); final_close = true; break; } } if (final_close) { Close(); } } private void PipeConnectionReceiveCallback(IAsyncResult ar) { if (_closed) { return; } try { var bytesRead = _local.EndReceive(ar); if (bytesRead > 0) { ResetTimeout(TTL); //_remote.BeginSend(connetionRecvBuffer, bytesRead, 0, new AsyncCallback(PipeRemoteSendCallback), null); _remote.Send(connetionRecvBuffer, bytesRead, SocketFlags.None); _local.BeginReceive(connetionRecvBuffer, RecvSize, SocketFlags.None, PipeConnectionReceiveCallback, null); } else { Close(); } } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void CloseSocket(ProxySocketTun sock) { lock (this) { if (sock != null) { var s = sock; try { s.Shutdown(SocketShutdown.Both); } catch { // ignored } try { s.Close(); } catch { // ignored } } } } public void Close() { lock (this) { if (_closed) { return; } _closed = true; } ResetTimeout(0); Thread.Sleep(100); CloseSocket(_remote); CloseSocket(_local); Server.ForwardServer.Connections.DecRef(this); } public override void Shutdown() { Task.Run(Close); } } } } ================================================ FILE: shadowsocks-csharp/Controller/Service/SpeedTest.cs ================================================ using System; using Shadowsocks.Model.Transfer; #if DEBUG using System.Collections.Generic; #endif namespace Shadowsocks.Controller.Service { internal class SpeedTester { #if DEBUG private struct TransLog { public int Dir; public int Size; } #endif public DateTime TimeConnectBegin; public DateTime TimeConnectEnd; public DateTime TimeBeginUpload; public DateTime TimeBeginDownload; public long SizeUpload; public long SizeDownload; public long SizeProtocolRecv; public long SizeRecv; #if DEBUG private readonly List _sizeTransfer = new(); #endif public string ServerId; public ServerTransferTotal Transfer; private int _uploadCnt; private int _downloadCnt; public void BeginConnect() { TimeConnectBegin = DateTime.Now; } public void EndConnect() { TimeConnectEnd = DateTime.Now; } public void BeginUpload() { TimeBeginUpload = DateTime.Now; } public bool BeginDownload() { if (TimeBeginDownload == new DateTime()) { TimeBeginDownload = DateTime.Now; return true; } return false; } public bool AddDownloadSize(int size) { SizeDownload += size; if (Transfer != null && ServerId != null) { Transfer.AddDownload(ServerId, size); } _uploadCnt = 0; _downloadCnt += 1; #if DEBUG if (_sizeTransfer.Count < 1024 * 128) { lock (_sizeTransfer) { _sizeTransfer.Add(new TransLog { Dir = 1, Size = size }); } } #endif return _downloadCnt > 30; } public void AddProtocolRecvSize(int size) { SizeProtocolRecv += size; } public void AddRecvSize(int size) { SizeRecv += size; } public bool AddUploadSize(int size) { SizeUpload += size; if (Transfer != null && ServerId != null) { Transfer.AddUpload(ServerId, size); } _uploadCnt += 1; _downloadCnt = 0; #if DEBUG if (_sizeTransfer.Count < 1024 * 128) { lock (_sizeTransfer) { _sizeTransfer.Add(new TransLog { Dir = 0, Size = size }); } } #endif return _uploadCnt > 30; } public string TransferLog() { var ret = string.Empty; #if DEBUG var lastDir = -1; foreach (var t in _sizeTransfer) { if (t.Dir != lastDir) { lastDir = t.Dir; ret += t.Dir == 0 ? " u" : " d"; } ret += $" {t.Size}"; } #endif return ret; } } } ================================================ FILE: shadowsocks-csharp/Controller/Service/UpdateSubscribeManager.cs ================================================ using Shadowsocks.Controller.HttpRequest; using Shadowsocks.Model; using System.Collections.Generic; using System.Linq; namespace Shadowsocks.Controller.Service { public class UpdateSubscribeManager { private Configuration _config; private Queue _serverSubscribes; private UpdateNode _updater; private bool _notify; public void CreateTask(Configuration config, UpdateNode updater, bool updateManually, List serverSubscribe = null) { if (_config != null) { return; } _config = config; _updater = updater; _notify = updateManually; if (serverSubscribe?.Count > 0) { _serverSubscribes = new Queue(serverSubscribe); } else { _serverSubscribes = new Queue(); if (updateManually) { config.ServerSubscribes.ForEach(sub => _serverSubscribes.Enqueue(sub)); } else { foreach (var server in config.ServerSubscribes.Where(server => server.AutoCheckUpdate)) { _serverSubscribes.Enqueue(server); } } } Next(); } public void Next() { if (_serverSubscribes.Count == 0) { _config = null; return; } CurrentServerSubscribe = _serverSubscribes.Dequeue(); _updater.CheckUpdate(_config, CurrentServerSubscribe, _notify); } public ServerSubscribe CurrentServerSubscribe { get; private set; } } } ================================================ FILE: shadowsocks-csharp/Controller/SystemProxy.cs ================================================ using Shadowsocks.Controller.Service; using Shadowsocks.Enums; using Shadowsocks.Model; using System; using WindowsProxy; namespace Shadowsocks.Controller; public static class SystemProxy { private static readonly ProxyStatus Old; static SystemProxy() { try { using var proxy = new ProxyService(); Old = proxy.Query(); } catch (Exception e) { Logging.LogUsefulException(e); } } public static void Restore() { try { using var proxy = new ProxyService(); proxy.Set(Old); } catch (Exception e) { Logging.LogUsefulException(e); } } public static void Update(Configuration config, PACServer pacSrv) { var sysProxyMode = config.SysProxyMode; try { using var proxy = new ProxyService(); switch (sysProxyMode) { case ProxyMode.Direct: { proxy.Direct(); break; } case ProxyMode.Pac: { proxy.AutoConfigUrl = pacSrv.PacUrl; proxy.Pac(); break; } case ProxyMode.Global: { proxy.Server = $@"localhost:{config.LocalPort}"; proxy.Bypass = string.Join(';', ProxyService.LanIp); proxy.Global(); break; } } } catch (Exception e) { Logging.LogUsefulException(e); } } } ================================================ FILE: shadowsocks-csharp/Data/abp.js ================================================ var direct = "__DIRECT__"; if (direct == "__DIR" + "ECT__") direct = "DIRECT;"; var wall_proxy = function(){ return "__PROXY__"; }; var wall_v6_proxy = function(){ return "__PROXY__"; }; var nowall_proxy = function(){ return direct; }; var ip_proxy = function(){ return nowall_proxy(); }; var ipv6_proxy = function(){ return nowall_proxy(); }; var userrules = __USERRULES__; var rules = __RULES__; /* * This file is part of Adblock Plus , * Copyright (C) 2006-2014 Eyeo GmbH * * Adblock Plus is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * Adblock Plus is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Adblock Plus. If not, see . */ function createDict() { var result = {}; result.__proto__ = null; return result; } function getOwnPropertyDescriptor(obj, key) { if (obj.hasOwnProperty(key)) { return obj[key]; } return null; } function extend(subclass, superclass, definition) { if (Object.__proto__) { definition.__proto__ = superclass.prototype; subclass.prototype = definition; } else { var tmpclass = function(){}, ret; tmpclass.prototype = superclass.prototype; subclass.prototype = new tmpclass(); subclass.prototype.constructor = superclass; for (var i in definition) { if (definition.hasOwnProperty(i)) { subclass.prototype[i] = definition[i]; } } } } function Filter(text) { this.text = text; this.subscriptions = []; } Filter.prototype = { text: null, subscriptions: null, toString: function() { return this.text; } }; Filter.knownFilters = createDict(); Filter.elemhideRegExp = /^([^\/\*\|\@"!]*?)#(\@)?(?:([\w\-]+|\*)((?:\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\))*)|#([^{}]+))$/; Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)?$/; Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/; Filter.fromText = function(text) { if (text in Filter.knownFilters) { return Filter.knownFilters[text]; } var ret; if (text.charAt(0) == "!") { ret = new CommentFilter(text); } else { ret = RegExpFilter.fromText(text); } Filter.knownFilters[ret.text] = ret; return ret; }; function InvalidFilter(text, reason) { Filter.call(this, text); this.reason = reason; } extend(InvalidFilter, Filter, { reason: null }); function CommentFilter(text) { Filter.call(this, text); } extend(CommentFilter, Filter, { }); function ActiveFilter(text, domains) { Filter.call(this, text); this.domainSource = domains; } extend(ActiveFilter, Filter, { domainSource: null, domainSeparator: null, ignoreTrailingDot: true, domainSourceIsUpperCase: false, getDomains: function() { var prop = getOwnPropertyDescriptor(this, "domains"); if (prop) { return prop; } var domains = null; if (this.domainSource) { var source = this.domainSource; if (!this.domainSourceIsUpperCase) { source = source.toUpperCase(); } var list = source.split(this.domainSeparator); if (list.length == 1 && (list[0]).charAt(0) != "~") { domains = createDict(); domains[""] = false; if (this.ignoreTrailingDot) { list[0] = list[0].replace(/\.+$/, ""); } domains[list[0]] = true; } else { var hasIncludes = false; for (var i = 0; i < list.length; i++) { var domain = list[i]; if (this.ignoreTrailingDot) { domain = domain.replace(/\.+$/, ""); } if (domain == "") { continue; } var include; if (domain.charAt(0) == "~") { include = false; domain = domain.substr(1); } else { include = true; hasIncludes = true; } if (!domains) { domains = createDict(); } domains[domain] = include; } domains[""] = !hasIncludes; } this.domainSource = null; } return this.domains; }, sitekeys: null, isActiveOnDomain: function(docDomain, sitekey) { if (this.getSitekeys() && (!sitekey || this.getSitekeys().indexOf(sitekey.toUpperCase()) < 0)) { return false; } if (!this.getDomains()) { return true; } if (!docDomain) { return this.getDomains()[""]; } if (this.ignoreTrailingDot) { docDomain = docDomain.replace(/\.+$/, ""); } docDomain = docDomain.toUpperCase(); while (true) { if (docDomain in this.getDomains()) { return this.domains[docDomain]; } var nextDot = docDomain.indexOf("."); if (nextDot < 0) { break; } docDomain = docDomain.substr(nextDot + 1); } return this.domains[""]; }, isActiveOnlyOnDomain: function(docDomain) { if (!docDomain || !this.getDomains() || this.getDomains()[""]) { return false; } if (this.ignoreTrailingDot) { docDomain = docDomain.replace(/\.+$/, ""); } docDomain = docDomain.toUpperCase(); for (var domain in this.getDomains()) { if (this.domains[domain] && domain != docDomain && (domain.length <= docDomain.length || domain.indexOf("." + docDomain) != domain.length - docDomain.length - 1)) { return false; } } return true; } }); function RegExpFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys) { ActiveFilter.call(this, text, domains, sitekeys); if (contentType != null) { this.contentType = contentType; } if (matchCase) { this.matchCase = matchCase; } if (thirdParty != null) { this.thirdParty = thirdParty; } if (sitekeys != null) { this.sitekeySource = sitekeys; } if (regexpSource.length >= 2 && regexpSource.charAt(0) == "/" && regexpSource.charAt(regexpSource.length - 1) == "/") { var regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), this.matchCase ? "" : "i"); this.regexp = regexp; } else { this.regexpSource = regexpSource; } } extend(RegExpFilter, ActiveFilter, { domainSourceIsUpperCase: true, length: 1, domainSeparator: "|", regexpSource: null, getRegexp: function() { var prop = getOwnPropertyDescriptor(this, "regexp"); if (prop) { return prop; } var source = this.regexpSource.replace(/\*+/g, "*").replace(/\^\|$/, "^").replace(/\W/g, "\\$&").replace(/\\\*/g, ".*").replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x60\\x7B-\\x7F]|$)").replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?").replace(/^\\\|/, "^").replace(/\\\|$/, "$").replace(/^(\.\*)/, "").replace(/(\.\*)$/, ""); var regexp = new RegExp(source, this.matchCase ? "" : "i"); this.regexp = regexp; return regexp; }, contentType: 2147483647, matchCase: false, thirdParty: null, sitekeySource: null, getSitekeys: function() { var prop = getOwnPropertyDescriptor(this, "sitekeys"); if (prop) { return prop; } var sitekeys = null; if (this.sitekeySource) { sitekeys = this.sitekeySource.split("|"); this.sitekeySource = null; } this.sitekeys = sitekeys; return this.sitekeys; }, matches: function(location, contentType, docDomain, thirdParty, sitekey) { if (this.getRegexp().test(location) && this.isActiveOnDomain(docDomain, sitekey)) { return true; } return false; } }); RegExpFilter.prototype["0"] = "#this"; RegExpFilter.fromText = function(text) { var blocking = true; var origText = text; if (text.indexOf("@@") == 0) { blocking = false; text = text.substr(2); } var contentType = null; var matchCase = null; var domains = null; var sitekeys = null; var thirdParty = null; var collapse = null; var options; var match = text.indexOf("$") >= 0 ? Filter.optionsRegExp.exec(text) : null; if (match) { options = match[1].toUpperCase().split(","); text = match.input.substr(0, match.index); for (var _loopIndex6 = 0; _loopIndex6 < options.length; ++_loopIndex6) { var option = options[_loopIndex6]; var value = null; var separatorIndex = option.indexOf("="); if (separatorIndex >= 0) { value = option.substr(separatorIndex + 1); option = option.substr(0, separatorIndex); } option = option.replace(/-/, "_"); if (option in RegExpFilter.typeMap) { if (contentType == null) { contentType = 0; } contentType |= RegExpFilter.typeMap[option]; } else if (option.charAt(0) == "~" && option.substr(1) in RegExpFilter.typeMap) { if (contentType == null) { contentType = RegExpFilter.prototype.contentType; } contentType &= ~RegExpFilter.typeMap[option.substr(1)]; } else if (option == "MATCH_CASE") { matchCase = true; } else if (option == "~MATCH_CASE") { matchCase = false; } else if (option == "DOMAIN" && typeof value != "undefined") { domains = value; } else if (option == "THIRD_PARTY") { thirdParty = true; } else if (option == "~THIRD_PARTY") { thirdParty = false; } else if (option == "COLLAPSE") { collapse = true; } else if (option == "~COLLAPSE") { collapse = false; } else if (option == "SITEKEY" && typeof value != "undefined") { sitekeys = value; } else { return new InvalidFilter(origText, "Unknown option " + option.toLowerCase()); } } } if (!blocking && (contentType == null || contentType & RegExpFilter.typeMap.DOCUMENT) && (!options || options.indexOf("DOCUMENT") < 0) && !/^\|?[\w\-]+:/.test(text)) { if (contentType == null) { contentType = RegExpFilter.prototype.contentType; } contentType &= ~RegExpFilter.typeMap.DOCUMENT; } try { if (blocking) { return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse); } else { return new WhitelistFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys); } } catch (e) { return new InvalidFilter(origText, e); } }; RegExpFilter.typeMap = { OTHER: 1, SCRIPT: 2, IMAGE: 4, STYLESHEET: 8, OBJECT: 16, SUBDOCUMENT: 32, DOCUMENT: 64, XBL: 1, PING: 1, XMLHTTPREQUEST: 2048, OBJECT_SUBREQUEST: 4096, DTD: 1, MEDIA: 16384, FONT: 32768, BACKGROUND: 4, POPUP: 268435456, ELEMHIDE: 1073741824 }; RegExpFilter.prototype.contentType &= ~ (RegExpFilter.typeMap.ELEMHIDE | RegExpFilter.typeMap.POPUP); function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys, collapse) { RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys); this.collapse = collapse; } extend(BlockingFilter, RegExpFilter, { collapse: null }); function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys) { RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys); } extend(WhitelistFilter, RegExpFilter, { }); function Matcher() { this.clear(); } Matcher.prototype = { filterByKeyword: null, keywordByFilter: null, clear: function() { this.filterByKeyword = createDict(); this.keywordByFilter = createDict(); }, add: function(filter) { if (filter.text in this.keywordByFilter) { return; } var keyword = this.findKeyword(filter); var oldEntry = this.filterByKeyword[keyword]; if (typeof oldEntry == "undefined") { this.filterByKeyword[keyword] = filter; } else if (oldEntry.length == 1) { this.filterByKeyword[keyword] = [oldEntry, filter]; } else { oldEntry.push(filter); } this.keywordByFilter[filter.text] = keyword; }, remove: function(filter) { if (!(filter.text in this.keywordByFilter)) { return; } var keyword = this.keywordByFilter[filter.text]; var list = this.filterByKeyword[keyword]; if (list.length <= 1) { delete this.filterByKeyword[keyword]; } else { var index = list.indexOf(filter); if (index >= 0) { list.splice(index, 1); if (list.length == 1) { this.filterByKeyword[keyword] = list[0]; } } } delete this.keywordByFilter[filter.text]; }, findKeyword: function(filter) { var result = ""; var text = filter.text; if (Filter.regexpRegExp.test(text)) { return result; } var match = Filter.optionsRegExp.exec(text); if (match) { text = match.input.substr(0, match.index); } if (text.substr(0, 2) == "@@") { text = text.substr(2); } var candidates = text.toLowerCase().match(/[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/g); if (!candidates) { return result; } var hash = this.filterByKeyword; var resultCount = 16777215; var resultLength = 0; for (var i = 0, l = candidates.length; i < l; i++) { var candidate = candidates[i].substr(1); var count = candidate in hash ? hash[candidate].length : 0; if (count < resultCount || count == resultCount && candidate.length > resultLength) { result = candidate; resultCount = count; resultLength = candidate.length; } } return result; }, hasFilter: function(filter) { return filter.text in this.keywordByFilter; }, getKeywordForFilter: function(filter) { if (filter.text in this.keywordByFilter) { return this.keywordByFilter[filter.text]; } else { return null; } }, _checkEntryMatch: function(keyword, location, contentType, docDomain, thirdParty, sitekey) { var list = this.filterByKeyword[keyword]; for (var i = 0; i < list.length; i++) { var filter = list[i]; if (filter == "#this") { filter = list; } if (filter.matches(location, contentType, docDomain, thirdParty, sitekey)) { return filter; } } return null; }, matchesAny: function(location, contentType, docDomain, thirdParty, sitekey) { var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); if (candidates === null) { candidates = []; } candidates.push(""); for (var i = 0, l = candidates.length; i < l; i++) { var substr = candidates[i]; if (substr in this.filterByKeyword) { var result = this._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey); if (result) { return result; } } } return null; } }; function CombinedMatcher() { this.blacklist = new Matcher(); this.whitelist = new Matcher(); this.resultCache = createDict(); } CombinedMatcher.maxCacheEntries = 1000; CombinedMatcher.prototype = { blacklist: null, whitelist: null, resultCache: null, cacheEntries: 0, clear: function() { this.blacklist.clear(); this.whitelist.clear(); this.resultCache = createDict(); this.cacheEntries = 0; }, add: function(filter) { if (filter instanceof WhitelistFilter) { this.whitelist.add(filter); } else { this.blacklist.add(filter); } if (this.cacheEntries > 0) { this.resultCache = createDict(); this.cacheEntries = 0; } }, remove: function(filter) { if (filter instanceof WhitelistFilter) { this.whitelist.remove(filter); } else { this.blacklist.remove(filter); } if (this.cacheEntries > 0) { this.resultCache = createDict(); this.cacheEntries = 0; } }, findKeyword: function(filter) { if (filter instanceof WhitelistFilter) { return this.whitelist.findKeyword(filter); } else { return this.blacklist.findKeyword(filter); } }, hasFilter: function(filter) { if (filter instanceof WhitelistFilter) { return this.whitelist.hasFilter(filter); } else { return this.blacklist.hasFilter(filter); } }, getKeywordForFilter: function(filter) { if (filter instanceof WhitelistFilter) { return this.whitelist.getKeywordForFilter(filter); } else { return this.blacklist.getKeywordForFilter(filter); } }, isSlowFilter: function(filter) { var matcher = filter instanceof WhitelistFilter ? this.whitelist : this.blacklist; if (matcher.hasFilter(filter)) { return !matcher.getKeywordForFilter(filter); } else { return !matcher.findKeyword(filter); } }, matchesAnyInternal: function(location, contentType, docDomain, thirdParty, sitekey) { var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); if (candidates === null) { candidates = []; } candidates.push(""); var blacklistHit = null; for (var i = 0, l = candidates.length; i < l; i++) { var substr = candidates[i]; if (substr in this.whitelist.filterByKeyword) { var result = this.whitelist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey); if (result) { return result; } } if (substr in this.blacklist.filterByKeyword && blacklistHit === null) { blacklistHit = this.blacklist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey); } } return blacklistHit; }, matchesAny: function(location, docDomain) { var key = location + " " + docDomain + " "; if (key in this.resultCache) { return this.resultCache[key]; } var result = this.matchesAnyInternal(location, 0, docDomain, null, null); if (this.cacheEntries >= CombinedMatcher.maxCacheEntries) { this.resultCache = createDict(); this.cacheEntries = 0; } this.resultCache[key] = result; this.cacheEntries++; return result; } }; var userrulesMatcher = new CombinedMatcher(); var defaultMatcher = new CombinedMatcher(); for (var i = 0; i < userrules.length; i++) { userrulesMatcher.add(Filter.fromText(userrules[i])); } for (var i = 0; i < rules.length; i++) { defaultMatcher.add(Filter.fromText(rules[i])); } var subnetIpRangeList = [ 0,16777216, //0.0.0.0/8 167772160,184549376, //10.0.0.0/8 1681915904,1686110208, //100.64.0.0/10 2130706432,2147483648, //127.0.0.0/8 2851995648,2852061184, //169.254.0.0/16 2886729728,2887778304, //172.16.0.0/12 3221225472,3221225728, //192.0.0.0/24 3221225984,3221226240, //192.0.2.0/24 3227017984,3227018240, //192.88.99.0/24 3232235520,3232301056, //192.168.0.0/16 3323068416,3323199488, //198.18.0.0/15 3325256704,3325256960, //198.51.100.0/24 3405803776,3405804032, //203.0.113.0/24 3758096384,4026531840 //224.0.0.0/4 ]; function convertAddress(ipchars) { var bytes = ipchars.split('.'); var result = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | (bytes[3]); return result >>> 0; } function check_ipv4(host) { var re_ipv4 = /^\d+\.\d+\.\d+\.\d+$/g; if (re_ipv4.test(host)) { return true; } } function check_ipv6(host) { var re_ipv6 = /^\[?([a-fA-F0-9]{0,4}\:){1,7}[a-fA-F0-9]{0,4}\]?$/g; if (re_ipv6.test(host)) { return true; } } function check_ipv6_dns(dnsstr) { var re_ipv6 = /([a-fA-F0-9]{0,4}\:){1,7}[a-fA-F0-9]{0,4}(%[0-9]+)?/g; if (re_ipv6.test(dnsstr)) { return true; } } function isInSubnetRange(ipRange, intIp) { for ( var i = 0; i < 28; i += 2 ) { if ( ipRange[i] <= intIp && intIp < ipRange[i+1] ) return true; } } function getProxyFromIP(strIp) { var intIp = convertAddress(strIp); if ( isInSubnetRange(subnetIpRangeList, intIp) ) { return direct; } return ip_proxy(); } function FindProxyForURL(url, host) { if ( isPlainHostName(host) === true ) { return direct; } if (userrulesMatcher.matchesAny(url, host) instanceof BlockingFilter) { return wall_proxy(); } if (userrulesMatcher.matchesAny(url, host) instanceof WhitelistFilter) { return direct; } if (defaultMatcher.matchesAny(url, host) instanceof BlockingFilter) { return wall_proxy(); } if ( check_ipv4(host) === true ) { return getProxyFromIP(host); } return direct; } ================================================ FILE: shadowsocks-csharp/Data/chn_ip.txt ================================================ 1.0.1.0/24 1.0.2.0/23 1.0.8.0/21 1.0.32.0/19 1.1.0.0/24 1.1.2.0/23 1.1.4.0/22 1.1.8.0/21 1.1.16.0/20 1.1.32.0/19 1.2.0.0/23 1.2.2.0/24 1.2.4.0/22 1.2.8.0/21 1.2.16.0/20 1.2.32.0/19 1.2.64.0/18 1.3.0.0/16 1.4.1.0/24 1.4.2.0/23 1.4.4.0/22 1.4.8.0/21 1.4.16.0/20 1.4.32.0/19 1.4.64.0/18 1.8.0.0/16 1.10.0.0/21 1.10.8.0/23 1.10.11.0/24 1.10.12.0/22 1.10.16.0/20 1.10.32.0/19 1.10.64.0/18 1.12.16.0/20 1.12.32.0/23 1.12.36.0/22 1.12.40.0/21 1.12.48.0/20 1.12.64.0/18 1.12.128.0/17 1.13.0.0/16 1.14.0.0/15 1.18.128.0/24 1.24.0.0/13 1.45.0.0/16 1.48.0.0/14 1.56.0.0/13 1.68.0.0/14 1.80.0.0/12 1.116.0.0/15 1.118.1.0/24 1.118.2.0/23 1.118.4.0/22 1.118.8.0/21 1.118.16.0/20 1.118.33.0/24 1.118.34.0/23 1.118.36.0/22 1.118.40.0/21 1.118.48.0/20 1.118.64.0/18 1.118.128.0/17 1.119.0.0/16 1.180.0.0/14 1.184.0.0/15 1.188.0.0/14 1.192.0.0/13 1.202.0.0/15 1.204.0.0/14 3.5.214.0/23 8.128.0.0/10 14.0.0.0/21 14.0.12.0/22 14.1.0.0/22 14.1.24.0/22 14.1.108.0/22 14.16.0.0/12 14.102.128.0/22 14.102.180.0/22 14.103.0.0/16 14.104.0.0/13 14.112.0.0/12 14.130.0.0/15 14.134.0.0/15 14.144.0.0/12 14.192.60.0/22 14.192.76.0/22 14.196.0.0/15 14.204.0.0/15 14.208.0.0/12 15.230.41.0/24 15.230.49.0/24 15.230.141.0/24 20.139.160.0/20 20.249.255.0/24 20.251.0.0/22 27.0.128.0/22 27.0.132.0/24 27.0.134.0/23 27.0.160.0/21 27.0.188.0/22 27.0.204.0/22 27.0.208.0/21 27.8.0.0/13 27.16.0.0/12 27.34.232.0/21 27.36.0.0/14 27.40.0.0/13 27.50.40.0/21 27.50.128.0/17 27.54.72.0/21 27.54.152.0/21 27.54.192.0/18 27.98.208.0/20 27.98.224.0/19 27.99.128.0/17 27.103.0.0/16 27.106.128.0/18 27.106.204.0/22 27.109.32.0/19 27.109.124.0/22 27.112.0.0/18 27.112.80.0/20 27.112.112.0/21 27.113.128.0/18 27.115.0.0/17 27.116.44.0/22 27.121.72.0/21 27.121.120.0/21 27.128.0.0/15 27.131.220.0/22 27.144.0.0/16 27.148.0.0/14 27.152.0.0/13 27.184.0.0/13 27.192.0.0/11 27.224.0.0/14 36.0.0.0/22 36.0.16.0/20 36.0.32.0/19 36.0.64.0/18 36.0.128.0/17 36.1.0.0/16 36.4.0.0/14 36.16.0.0/12 36.32.0.0/14 36.36.0.0/16 36.37.0.0/19 36.37.36.0/23 36.37.39.0/24 36.37.40.0/21 36.37.48.0/20 36.40.0.0/13 36.48.0.0/15 36.51.0.0/17 36.51.128.0/18 36.51.192.0/19 36.51.224.0/20 36.51.240.0/21 36.51.250.0/23 36.51.252.0/23 36.56.0.0/13 36.96.0.0/11 36.128.0.0/10 36.192.0.0/11 36.248.0.0/14 36.254.0.0/16 36.255.116.0/22 36.255.128.0/22 36.255.164.0/22 36.255.172.0/22 36.255.176.0/22 39.0.0.0/24 39.0.2.0/23 39.0.4.0/22 39.0.8.0/21 39.0.16.0/20 39.0.32.0/19 39.0.64.0/18 39.0.128.0/17 39.64.0.0/11 39.96.0.0/16 39.97.0.0/17 39.97.128.0/18 39.97.192.0/21 39.97.200.0/22 39.97.208.0/20 39.97.224.0/19 39.98.0.0/15 39.100.0.0/14 39.104.0.0/14 39.108.0.0/16 39.109.120.0/23 39.128.0.0/10 40.0.176.0/20 40.0.248.0/21 40.72.0.0/15 40.77.136.112/28 40.77.236.224/27 40.77.254.64/27 40.125.128.0/17 40.126.64.0/18 40.198.10.0/24 40.198.16.0/21 40.198.24.0/23 40.251.225.0/24 40.251.227.0/24 42.0.0.0/22 42.0.8.0/21 42.0.16.0/21 42.0.24.0/22 42.0.32.0/19 42.0.128.0/17 42.1.0.0/19 42.1.32.0/20 42.1.48.0/21 42.1.56.0/22 42.4.0.0/14 42.48.0.0/13 42.56.0.0/14 42.62.0.0/17 42.62.128.0/19 42.62.160.0/20 42.62.180.0/22 42.62.184.0/21 42.63.0.0/16 42.80.0.0/15 42.83.64.0/20 42.83.80.0/22 42.83.88.0/21 42.83.96.0/19 42.83.128.0/23 42.83.134.0/24 42.83.138.0/23 42.83.140.0/22 42.83.144.0/20 42.83.160.0/19 42.83.192.0/18 42.84.0.0/14 42.88.0.0/13 42.96.64.0/19 42.96.96.0/21 42.96.108.0/22 42.96.112.0/20 42.96.128.0/17 42.97.0.0/16 42.99.0.0/18 42.99.64.0/19 42.99.96.0/20 42.99.112.0/22 42.99.120.0/21 42.100.0.0/14 42.120.0.0/15 42.122.0.0/16 42.123.0.0/19 42.123.36.0/22 42.123.40.0/21 42.123.48.0/20 42.123.64.0/18 42.123.128.0/17 42.128.0.0/12 42.156.0.0/19 42.156.36.0/22 42.156.40.0/21 42.156.48.0/20 42.156.64.0/18 42.156.128.0/17 42.157.0.0/21 42.157.8.0/22 42.157.14.0/23 42.157.16.0/20 42.157.32.0/19 42.157.64.0/18 42.157.128.0/17 42.158.0.0/15 42.160.0.0/12 42.176.0.0/13 42.184.0.0/15 42.186.0.0/16 42.187.0.0/18 42.187.64.0/19 42.187.96.0/20 42.187.112.0/21 42.187.120.0/22 42.187.128.0/17 42.192.0.0/13 42.201.0.0/17 42.202.0.0/15 42.204.0.0/14 42.208.0.0/12 42.224.0.0/12 42.240.0.0/16 42.242.0.0/15 42.244.0.0/15 42.246.0.0/16 42.247.0.0/22 42.247.4.0/24 42.247.5.0/25 42.247.5.128/26 42.247.5.204/30 42.247.5.208/28 42.247.5.224/27 42.247.6.0/23 42.247.8.0/21 42.247.16.0/20 42.247.32.0/19 42.247.64.0/18 42.247.128.0/17 42.248.0.0/13 43.0.0.0/10 43.64.0.0/12 43.80.0.0/13 43.88.128.0/17 43.89.0.0/16 43.90.0.0/15 43.95.64.0/19 43.95.96.0/20 43.95.112.0/21 43.96.0.0/11 43.130.128.0/17 43.131.128.0/17 43.132.8.0/21 43.132.16.0/20 43.132.32.0/19 43.132.69.0/24 43.132.70.0/23 43.132.72.0/23 43.132.75.0/24 43.132.78.0/23 43.132.80.0/23 43.132.82.0/24 43.132.84.0/22 43.132.88.0/21 43.133.192.0/18 43.134.0.0/15 43.136.0.0/13 43.144.0.0/12 43.160.0.0/11 43.224.12.0/22 43.224.24.0/22 43.224.44.0/22 43.224.52.0/22 43.224.56.0/22 43.224.68.0/22 43.224.72.0/22 43.224.80.0/22 43.224.100.0/22 43.224.144.0/22 43.224.161.0/24 43.224.176.0/22 43.224.184.0/22 43.224.200.0/21 43.224.208.0/21 43.224.216.0/22 43.224.240.0/22 43.225.76.0/22 43.225.86.0/24 43.225.120.0/22 43.225.180.0/22 43.225.208.0/22 43.225.216.0/21 43.225.224.0/20 43.225.240.0/21 43.225.252.0/22 43.226.32.0/19 43.226.64.0/19 43.226.96.0/20 43.226.112.0/21 43.226.120.0/22 43.226.128.0/19 43.226.160.0/21 43.226.236.0/22 43.226.240.0/20 43.227.0.0/21 43.227.8.0/22 43.227.32.0/19 43.227.64.0/19 43.227.104.0/22 43.227.136.0/21 43.227.144.0/22 43.227.152.0/21 43.227.160.0/20 43.227.176.0/21 43.227.188.0/22 43.227.192.0/19 43.227.232.0/22 43.227.248.0/21 43.228.0.0/18 43.228.64.0/21 43.228.76.0/22 43.228.100.0/22 43.228.116.0/22 43.228.132.0/22 43.228.136.0/22 43.228.148.0/22 43.228.152.0/22 43.228.188.0/22 43.229.40.0/22 43.229.48.0/22 43.229.56.0/22 43.229.96.0/22 43.229.136.0/21 43.229.168.0/21 43.229.176.0/20 43.229.192.0/21 43.229.216.0/21 43.229.232.0/21 43.230.20.0/22 43.230.32.0/22 43.230.68.0/22 43.230.72.0/22 43.230.124.0/22 43.230.220.0/22 43.230.224.0/19 43.231.32.0/20 43.231.80.0/20 43.231.96.0/20 43.231.136.0/21 43.231.144.0/20 43.231.160.0/20 43.231.176.0/21 43.236.0.0/15 43.238.0.0/16 43.239.0.0/19 43.239.32.0/20 43.239.48.0/22 43.239.116.0/22 43.239.120.0/22 43.239.172.0/22 43.240.0.0/22 43.240.56.0/21 43.240.68.0/22 43.240.72.0/21 43.240.84.0/22 43.240.124.0/22 43.240.128.0/21 43.240.136.0/22 43.240.156.0/22 43.240.160.0/19 43.240.192.0/19 43.240.240.0/20 43.241.0.0/20 43.241.16.0/21 43.241.48.0/22 43.241.76.0/22 43.241.80.0/20 43.241.112.0/22 43.241.168.0/21 43.241.176.0/21 43.241.184.0/22 43.241.208.0/20 43.241.224.0/20 43.241.240.0/22 43.241.248.0/22 43.242.8.0/21 43.242.16.0/20 43.242.48.0/22 43.242.53.0/24 43.242.54.0/24 43.242.56.0/21 43.242.64.0/22 43.242.72.0/21 43.242.80.0/20 43.242.96.0/22 43.242.144.0/20 43.242.160.0/21 43.242.180.0/22 43.242.188.0/22 43.242.192.0/21 43.242.204.0/22 43.242.216.0/21 43.242.252.0/22 43.243.4.0/22 43.243.8.0/21 43.243.16.0/22 43.243.88.0/22 43.243.128.0/22 43.243.136.0/22 43.243.144.0/21 43.243.156.0/22 43.243.180.0/22 43.243.228.0/22 43.243.232.0/22 43.243.244.0/22 43.246.0.0/18 43.246.64.0/19 43.246.96.0/22 43.246.148.0/24 43.246.150.0/24 43.246.228.0/22 43.247.4.0/22 43.247.8.0/22 43.247.44.0/22 43.247.48.0/22 43.247.68.0/22 43.247.76.0/22 43.247.84.0/22 43.247.88.0/21 43.247.96.0/21 43.247.108.0/22 43.247.112.0/22 43.247.148.0/22 43.247.152.0/22 43.247.176.0/20 43.247.196.0/22 43.247.200.0/21 43.247.208.0/20 43.247.224.0/19 43.248.0.0/21 43.248.20.0/22 43.248.28.0/22 43.248.48.0/22 43.248.76.0/22 43.248.80.0/20 43.248.96.0/19 43.248.128.0/20 43.248.144.0/21 43.248.176.0/20 43.248.192.0/20 43.248.208.0/22 43.248.228.0/22 43.248.232.0/22 43.248.244.0/22 43.249.4.0/22 43.249.120.0/22 43.249.132.0/22 43.249.136.0/22 43.249.144.0/20 43.249.160.0/21 43.249.168.0/22 43.249.192.0/22 43.249.236.0/22 43.250.4.0/22 43.250.12.0/22 43.250.16.0/21 43.250.28.0/22 43.250.32.0/22 43.250.96.0/21 43.250.108.0/22 43.250.112.0/22 43.250.118.0/23 43.250.128.0/22 43.250.144.0/21 43.250.160.0/22 43.250.168.0/22 43.250.176.0/22 43.250.200.0/22 43.250.212.0/22 43.250.216.0/21 43.250.236.0/22 43.250.244.0/22 43.251.4.0/22 43.251.36.0/22 43.251.69.0/24 43.251.70.0/24 43.251.149.0/24 43.251.192.0/22 43.251.232.0/22 43.251.244.0/22 43.252.48.0/22 43.252.56.0/22 43.252.224.0/22 43.254.0.0/21 43.254.8.0/22 43.254.24.0/22 43.254.36.0/22 43.254.44.0/22 43.254.52.0/22 43.254.64.0/22 43.254.72.0/22 43.254.84.0/22 43.254.88.0/21 43.254.100.0/22 43.254.104.0/22 43.254.112.0/21 43.254.128.0/22 43.254.136.0/21 43.254.144.0/20 43.254.168.0/21 43.254.180.0/22 43.254.184.0/21 43.254.192.0/22 43.254.200.0/22 43.254.208.0/22 43.254.220.0/22 43.254.224.0/20 43.254.240.0/22 43.254.248.0/21 43.255.0.0/21 43.255.8.0/22 43.255.16.0/22 43.255.48.0/22 43.255.64.0/20 43.255.84.0/22 43.255.96.0/22 43.255.144.0/22 43.255.176.0/22 43.255.184.0/22 43.255.192.0/22 43.255.200.0/21 43.255.208.0/21 43.255.224.0/21 43.255.232.0/22 43.255.244.0/22 45.40.192.0/20 45.40.208.0/21 45.40.224.0/19 45.65.16.0/20 45.87.53.0/24 45.87.54.0/23 45.112.132.0/22 45.112.188.0/22 45.112.208.0/20 45.112.228.0/22 45.112.232.0/21 45.113.12.0/22 45.113.16.0/20 45.113.40.0/22 45.113.52.0/22 45.113.72.0/22 45.113.144.0/21 45.113.168.0/22 45.113.184.0/22 45.113.200.0/21 45.113.208.0/20 45.113.240.0/22 45.113.252.0/22 45.114.0.0/22 45.114.32.0/22 45.114.52.0/22 45.114.96.0/22 45.114.136.0/22 45.114.196.0/22 45.114.200.0/22 45.114.228.0/22 45.114.252.0/22 45.115.44.0/22 45.115.100.0/22 45.115.120.0/22 45.115.132.0/22 45.115.144.0/22 45.115.156.0/22 45.115.164.0/22 45.115.200.0/22 45.115.212.0/22 45.115.244.0/22 45.115.248.0/22 45.116.16.0/22 45.116.24.0/22 45.116.32.0/21 45.116.52.0/22 45.116.96.0/21 45.116.140.0/22 45.116.152.0/22 45.116.208.0/22 45.117.8.0/22 45.117.20.0/22 45.117.68.0/22 45.117.124.0/22 45.117.252.0/22 45.119.60.0/22 45.119.64.0/21 45.119.72.0/22 45.119.104.0/22 45.119.232.0/22 45.120.100.0/22 45.120.140.0/22 45.120.164.0/22 45.120.180.128/27 45.120.240.0/24 45.120.242.0/23 45.121.52.0/22 45.121.64.0/21 45.121.72.0/22 45.121.92.0/22 45.121.96.0/22 45.121.172.0/22 45.121.176.0/22 45.121.240.0/20 45.122.0.0/19 45.122.32.0/21 45.122.40.0/22 45.122.60.0/22 45.122.64.0/19 45.122.96.0/20 45.122.112.0/21 45.122.160.0/19 45.122.192.0/20 45.122.208.0/21 45.122.216.0/22 45.123.28.0/22 45.123.32.0/21 45.123.44.0/22 45.123.48.0/20 45.123.64.0/20 45.123.80.0/21 45.123.120.0/22 45.123.128.0/21 45.123.136.0/22 45.123.148.0/22 45.123.152.0/21 45.123.164.0/22 45.123.168.0/21 45.123.176.0/21 45.123.184.0/22 45.123.204.0/22 45.123.212.0/22 45.123.224.0/19 45.124.0.0/22 45.124.20.0/22 45.124.28.0/22 45.124.32.0/21 45.124.44.0/22 45.124.68.0/22 45.124.76.0/22 45.124.80.0/22 45.124.100.0/22 45.124.124.0/22 45.124.172.0/22 45.124.176.0/22 45.124.208.0/22 45.124.248.0/22 45.125.24.0/22 45.125.44.0/22 45.125.52.0/22 45.125.56.0/22 45.125.76.0/22 45.125.80.0/20 45.125.96.0/21 45.125.136.0/22 45.126.48.0/21 45.126.108.0/22 45.126.112.0/21 45.126.120.0/22 45.126.220.0/22 45.127.8.0/21 45.127.128.0/22 45.127.144.0/21 45.127.156.0/22 45.248.8.0/22 45.248.80.0/22 45.248.88.0/22 45.248.96.0/20 45.248.128.0/21 45.248.204.0/22 45.248.208.0/20 45.248.224.0/19 45.249.0.0/21 45.249.12.0/22 45.249.16.0/20 45.249.32.0/21 45.249.112.0/22 45.249.188.0/22 45.249.192.0/20 45.249.208.0/21 45.250.12.0/22 45.250.16.0/22 45.250.28.0/22 45.250.32.0/21 45.250.40.0/22 45.250.76.0/22 45.250.80.0/20 45.250.96.0/22 45.250.104.0/21 45.250.112.0/20 45.250.128.0/20 45.250.144.0/21 45.250.152.0/22 45.250.164.0/22 45.250.180.0/22 45.250.184.0/21 45.250.192.0/22 45.251.0.0/22 45.251.8.0/22 45.251.16.0/21 45.251.52.0/22 45.251.84.0/22 45.251.88.0/21 45.251.96.0/21 45.251.120.0/21 45.251.138.0/23 45.251.140.0/22 45.251.144.0/20 45.251.160.0/19 45.251.192.0/19 45.251.224.0/22 45.252.0.0/19 45.252.32.0/20 45.252.48.0/22 45.252.84.0/22 45.252.88.0/21 45.252.96.0/19 45.252.128.0/19 45.252.160.0/20 45.252.176.0/22 45.252.192.0/19 45.252.224.0/21 45.252.232.0/22 45.253.0.0/18 45.253.64.0/20 45.253.80.0/21 45.253.92.0/22 45.253.96.0/20 45.253.112.0/21 45.253.120.0/22 45.253.132.0/22 45.253.136.0/21 45.253.144.0/20 45.253.160.0/19 45.253.192.0/19 45.253.224.0/20 45.253.240.0/22 45.254.0.0/20 45.254.16.0/21 45.254.28.0/22 45.254.40.0/22 45.254.48.0/20 45.254.64.0/18 45.254.128.0/18 45.254.192.0/19 45.254.224.0/21 45.254.236.0/22 45.254.248.0/22 45.255.0.0/18 45.255.64.0/19 45.255.96.0/20 45.255.112.0/21 45.255.120.0/22 45.255.136.0/21 45.255.144.0/20 45.255.160.0/19 45.255.192.0/19 45.255.224.0/20 45.255.240.0/21 45.255.248.0/22 46.248.24.0/23 47.92.0.0/14 47.96.0.0/11 49.4.0.0/14 49.51.57.0/24 49.51.58.0/23 49.51.60.0/23 49.51.110.0/23 49.51.112.0/20 49.52.0.0/14 49.64.0.0/11 49.112.0.0/13 49.120.0.0/14 49.128.0.0/24 49.128.2.0/23 49.140.0.0/15 49.152.0.0/14 49.208.0.0/14 49.220.0.0/14 49.232.0.0/14 49.239.0.0/18 49.239.192.0/18 52.80.0.0/14 52.93.242.120/29 52.93.242.128/25 52.94.249.0/27 52.130.0.0/15 54.222.0.0/15 54.240.224.0/24 58.14.0.0/15 58.16.0.0/13 58.24.0.0/15 58.30.0.0/15 58.32.0.0/11 58.65.232.0/21 58.66.0.0/15 58.68.128.0/19 58.68.160.0/21 58.68.200.0/21 58.68.208.0/20 58.68.224.0/19 58.82.0.0/17 58.83.0.0/16 58.87.64.0/18 58.99.128.0/17 58.100.0.0/15 58.116.0.0/14 58.128.0.0/13 58.144.0.0/16 58.154.0.0/15 58.192.0.0/11 58.240.0.0/12 59.32.0.0/11 59.64.0.0/12 59.80.0.0/15 59.82.0.0/16 59.83.0.0/18 59.83.136.0/21 59.83.144.0/20 59.83.160.0/20 59.83.180.0/22 59.83.184.0/21 59.83.192.0/19 59.83.224.0/20 59.83.240.0/21 59.83.248.0/22 59.83.252.0/23 59.83.254.0/24 59.107.0.0/16 59.108.0.0/14 59.151.0.0/17 59.152.16.0/20 59.152.36.0/22 59.152.64.0/20 59.152.112.0/21 59.153.4.0/22 59.153.32.0/22 59.153.64.0/21 59.153.72.0/22 59.153.92.0/22 59.153.136.0/22 59.153.152.0/22 59.153.159.0/24 59.153.164.0/22 59.153.168.0/21 59.153.176.0/20 59.153.192.0/22 59.155.0.0/16 59.172.0.0/14 59.191.0.0/17 59.192.0.0/10 60.0.0.0/11 60.55.0.0/16 60.63.0.0/16 60.160.0.0/11 60.194.0.0/15 60.200.0.0/13 60.208.0.0/12 60.232.0.0/15 60.235.0.0/16 60.245.128.0/17 60.247.0.0/16 60.252.0.0/16 60.253.128.0/17 60.255.0.0/16 61.4.81.0/24 61.4.82.0/23 61.4.84.0/22 61.4.88.0/21 61.4.176.0/20 61.8.160.0/20 61.14.212.0/22 61.14.216.0/21 61.14.240.0/21 61.28.0.0/17 61.29.128.0/18 61.29.194.0/23 61.29.196.0/22 61.29.200.0/21 61.29.208.0/20 61.29.224.0/20 61.45.128.0/18 61.45.224.0/20 61.47.128.0/18 61.48.0.0/13 61.87.192.0/18 61.128.0.0/10 61.232.0.0/14 61.236.0.0/15 61.240.0.0/14 62.234.0.0/16 64.188.38.0/23 64.188.40.0/22 64.188.44.0/23 68.79.0.0/18 69.230.192.0/18 69.231.128.0/18 69.234.192.0/18 69.235.128.0/18 71.131.192.0/18 71.132.0.0/18 71.136.64.0/18 71.137.0.0/18 72.163.240.0/23 72.163.248.0/22 81.68.0.0/14 82.156.0.0/15 87.254.207.0/24 93.183.14.0/24 93.183.18.0/24 94.191.0.0/17 101.0.0.0/22 101.1.0.0/22 101.2.172.0/22 101.4.0.0/14 101.16.0.0/12 101.33.20.0/23 101.33.128.0/17 101.34.0.0/15 101.36.0.0/18 101.36.64.0/20 101.36.88.0/21 101.36.128.0/17 101.37.0.0/16 101.38.0.0/15 101.40.0.0/13 101.48.0.0/15 101.50.8.0/21 101.50.56.0/22 101.52.0.0/16 101.53.100.0/22 101.54.0.0/16 101.55.224.0/21 101.64.0.0/13 101.72.0.0/14 101.76.0.0/15 101.78.0.0/22 101.78.32.0/19 101.80.0.0/12 101.96.0.0/21 101.96.8.0/22 101.96.16.0/20 101.96.128.0/17 101.99.96.0/19 101.101.64.0/19 101.101.100.0/24 101.101.102.0/23 101.101.104.0/21 101.101.112.0/20 101.102.64.0/19 101.102.100.0/23 101.102.102.0/24 101.102.104.0/21 101.102.112.0/20 101.104.0.0/14 101.110.64.0/19 101.110.96.0/20 101.110.116.0/22 101.110.120.0/21 101.120.0.0/14 101.124.0.0/15 101.126.0.0/16 101.128.0.0/22 101.128.8.0/21 101.128.16.0/20 101.128.32.0/19 101.129.0.0/16 101.130.0.0/15 101.132.0.0/15 101.134.0.0/17 101.134.128.0/19 101.134.160.0/20 101.134.176.0/21 101.134.184.0/22 101.134.189.0/24 101.134.190.0/23 101.134.192.0/18 101.135.0.0/16 101.144.0.0/12 101.192.0.0/14 101.196.0.0/16 101.198.0.0/22 101.198.128.0/24 101.198.170.0/23 101.198.172.0/22 101.198.176.0/21 101.198.184.0/22 101.198.189.0/24 101.198.190.0/23 101.198.194.0/24 101.198.196.0/23 101.198.200.0/22 101.198.224.0/19 101.199.0.0/19 101.199.48.0/20 101.199.64.0/18 101.199.128.0/17 101.200.0.0/15 101.203.128.0/19 101.203.160.0/21 101.203.172.0/22 101.203.176.0/20 101.204.0.0/14 101.224.0.0/13 101.232.0.0/15 101.234.64.0/21 101.234.76.0/22 101.234.80.0/20 101.234.96.0/19 101.236.0.0/14 101.240.0.0/13 101.248.0.0/15 101.251.0.0/22 101.251.8.0/21 101.251.16.0/20 101.251.32.0/19 101.251.64.0/18 101.251.128.0/17 101.252.0.0/15 101.254.0.0/16 103.1.8.0/22 103.1.20.0/22 103.1.24.0/22 103.1.88.0/22 103.1.168.0/22 103.2.108.0/22 103.2.156.0/22 103.2.164.0/22 103.2.200.0/21 103.2.208.0/21 103.3.84.0/22 103.3.88.0/21 103.3.96.0/19 103.3.128.0/20 103.3.148.0/22 103.3.152.0/21 103.4.56.0/22 103.4.168.0/22 103.4.184.0/22 103.5.36.0/22 103.5.52.0/24 103.5.56.0/22 103.5.152.0/22 103.5.168.0/22 103.5.192.0/22 103.5.252.0/22 103.6.76.0/22 103.6.120.0/22 103.6.220.0/22 103.7.140.0/22 103.7.212.0/22 103.7.216.0/21 103.8.0.0/21 103.8.8.0/22 103.8.32.0/22 103.8.52.0/22 103.8.68.0/22 103.8.108.0/22 103.8.156.0/22 103.8.200.0/21 103.8.220.0/22 103.9.8.0/22 103.9.24.0/22 103.9.108.0/22 103.9.152.0/22 103.9.248.0/21 103.10.0.0/22 103.10.16.0/22 103.10.84.0/22 103.10.111.0/24 103.10.140.0/22 103.11.16.0/22 103.11.168.0/22 103.11.180.0/22 103.12.32.0/22 103.12.136.0/22 103.12.184.0/22 103.12.232.0/22 103.13.12.0/22 103.13.124.0/22 103.13.145.0/24 103.13.147.0/24 103.13.196.0/22 103.13.244.0/22 103.14.84.0/22 103.14.132.0/22 103.14.136.0/22 103.14.156.0/22 103.14.240.0/22 103.15.4.0/22 103.15.8.0/22 103.15.16.0/22 103.15.96.0/22 103.15.200.0/22 103.16.52.0/22 103.16.80.0/21 103.16.88.0/22 103.16.108.0/22 103.16.124.0/22 103.17.40.0/22 103.17.64.0/22 103.17.120.0/23 103.17.136.0/22 103.17.160.0/22 103.17.204.0/22 103.17.228.0/22 103.18.192.0/22 103.18.208.0/21 103.18.224.0/22 103.19.12.0/22 103.19.40.0/21 103.19.64.0/21 103.19.72.0/22 103.19.232.0/22 103.20.12.0/22 103.20.32.0/23 103.20.34.0/24 103.20.68.0/22 103.20.112.0/22 103.20.128.0/22 103.20.160.0/22 103.20.248.0/22 103.21.112.0/21 103.21.140.0/22 103.21.176.0/22 103.21.240.0/24 103.21.242.0/23 103.22.0.0/18 103.22.64.0/19 103.22.100.0/22 103.22.104.0/21 103.22.112.0/20 103.22.188.0/22 103.22.228.0/22 103.22.252.0/22 103.23.8.0/22 103.23.56.0/22 103.23.160.0/22 103.23.164.0/23 103.23.166.0/24 103.23.176.0/22 103.23.228.0/22 103.24.24.0/22 103.24.116.0/22 103.24.128.0/22 103.24.144.0/22 103.24.176.0/22 103.24.184.0/22 103.24.228.0/22 103.24.252.0/22 103.25.20.0/22 103.25.24.0/21 103.25.32.0/21 103.25.40.0/22 103.25.48.0/22 103.25.64.0/21 103.25.148.0/22 103.25.156.0/22 103.25.216.0/22 103.26.0.0/22 103.26.64.0/22 103.26.76.0/22 103.26.116.0/22 103.26.156.0/22 103.26.160.0/22 103.26.228.0/22 103.26.240.0/22 103.27.4.0/22 103.27.12.0/22 103.27.24.0/22 103.27.56.0/22 103.27.96.0/22 103.27.240.0/22 103.28.4.0/22 103.28.8.0/22 103.28.184.0/22 103.28.204.0/22 103.28.212.0/22 103.29.16.0/22 103.29.128.0/21 103.29.136.0/22 103.30.20.0/22 103.30.96.0/22 103.30.148.0/22 103.30.202.0/23 103.30.228.0/22 103.30.236.0/22 103.31.0.0/22 103.31.48.0/21 103.31.60.0/22 103.31.64.0/21 103.31.72.0/24 103.31.148.0/22 103.31.160.0/22 103.31.168.0/22 103.31.200.0/22 103.32.0.0/15 103.34.0.0/16 103.35.0.0/19 103.35.32.0/20 103.35.48.0/22 103.35.104.0/22 103.35.220.0/22 103.36.28.0/22 103.36.36.0/22 103.36.56.0/21 103.36.64.0/22 103.36.72.0/22 103.36.96.0/22 103.36.132.0/22 103.36.136.0/22 103.36.160.0/19 103.36.192.0/19 103.36.224.0/20 103.36.240.0/21 103.37.12.0/22 103.37.16.0/22 103.37.24.0/22 103.37.44.0/22 103.37.52.0/22 103.37.56.0/22 103.37.72.0/22 103.37.100.0/22 103.37.104.0/22 103.37.136.0/21 103.37.144.0/20 103.37.160.0/21 103.37.172.0/22 103.37.176.0/22 103.37.188.0/22 103.37.208.0/20 103.37.252.0/22 103.38.0.0/22 103.38.32.0/22 103.38.40.0/21 103.38.76.0/22 103.38.84.0/22 103.38.92.0/22 103.38.96.0/22 103.38.116.0/22 103.38.132.0/22 103.38.140.0/22 103.38.220.0/22 103.38.224.0/21 103.38.232.0/22 103.38.252.0/23 103.39.64.0/22 103.39.88.0/22 103.39.100.0/22 103.39.104.0/22 103.39.160.0/19 103.39.200.0/21 103.39.208.0/20 103.39.224.0/21 103.39.232.0/22 103.40.12.0/22 103.40.16.0/20 103.40.32.0/20 103.40.88.0/22 103.40.192.0/22 103.40.212.0/22 103.40.220.0/22 103.40.228.0/22 103.40.232.0/21 103.40.240.0/20 103.41.0.0/22 103.41.52.0/22 103.41.140.0/22 103.41.148.0/22 103.41.152.0/22 103.41.160.0/21 103.41.220.0/22 103.41.224.0/21 103.42.8.0/22 103.42.24.0/22 103.42.32.0/22 103.42.64.0/21 103.42.76.0/22 103.42.232.0/22 103.43.26.0/23 103.43.96.0/21 103.43.104.0/22 103.43.124.0/22 103.43.184.0/22 103.43.192.0/21 103.43.208.0/22 103.43.220.0/22 103.43.224.0/22 103.43.240.0/22 103.44.80.0/22 103.44.120.0/21 103.44.144.0/22 103.44.152.0/22 103.44.168.0/22 103.44.176.0/20 103.44.192.0/20 103.44.224.0/22 103.44.236.0/22 103.44.240.0/20 103.45.0.0/18 103.45.72.0/21 103.45.80.0/20 103.45.96.0/19 103.45.128.0/18 103.45.192.0/19 103.45.224.0/22 103.45.248.0/22 103.46.0.0/22 103.46.12.0/22 103.46.16.0/20 103.46.32.0/19 103.46.64.0/18 103.46.128.0/21 103.46.136.0/22 103.46.152.0/21 103.46.160.0/20 103.46.176.0/21 103.46.244.0/22 103.46.248.0/22 103.47.4.0/22 103.47.20.0/22 103.47.36.0/22 103.47.40.0/22 103.47.48.0/22 103.47.80.0/22 103.47.96.0/22 103.47.116.0/22 103.47.120.0/22 103.47.136.0/21 103.47.212.0/22 103.48.52.0/22 103.48.92.0/22 103.48.148.0/22 103.48.152.0/22 103.48.202.0/23 103.48.216.0/21 103.48.224.0/20 103.48.240.0/21 103.49.12.0/22 103.49.20.0/22 103.49.72.0/21 103.49.96.0/22 103.49.108.0/22 103.49.176.0/21 103.50.36.0/22 103.50.44.0/22 103.50.48.0/20 103.50.64.0/21 103.50.72.0/22 103.50.108.0/22 103.50.112.0/20 103.50.132.0/22 103.50.136.0/21 103.50.172.0/22 103.50.176.0/20 103.50.192.0/21 103.50.200.0/22 103.50.220.0/22 103.50.224.0/20 103.50.240.0/21 103.50.248.0/22 103.52.40.0/22 103.52.72.0/21 103.52.80.0/21 103.52.96.0/21 103.52.104.0/22 103.52.160.0/21 103.52.172.0/22 103.52.176.0/22 103.52.184.0/22 103.52.196.0/22 103.53.64.0/21 103.53.92.0/22 103.53.124.0/22 103.53.128.0/20 103.53.144.0/22 103.53.160.0/22 103.53.180.0/22 103.53.204.0/22 103.53.208.0/21 103.53.236.0/22 103.53.248.0/22 103.54.8.0/22 103.54.48.0/22 103.54.160.0/21 103.54.212.0/22 103.54.228.0/22 103.54.240.0/22 103.55.80.0/22 103.55.120.0/22 103.55.152.0/22 103.55.172.0/22 103.55.204.0/22 103.55.208.0/22 103.55.228.0/22 103.55.236.0/22 103.55.240.0/22 103.56.20.0/22 103.56.32.0/22 103.56.56.0/21 103.56.72.0/21 103.56.140.0/22 103.56.152.0/22 103.56.184.0/22 103.56.200.0/22 103.57.12.0/22 103.57.52.0/22 103.57.56.0/22 103.57.76.0/22 103.57.136.0/22 103.57.196.0/22 103.58.24.0/22 103.59.76.0/22 103.59.112.0/21 103.59.120.0/24 103.59.123.0/24 103.59.124.0/22 103.59.128.0/22 103.59.148.0/22 103.60.32.0/22 103.60.44.0/22 103.60.164.0/22 103.60.228.0/22 103.60.236.0/22 103.61.60.0/24 103.61.104.0/22 103.61.140.0/22 103.61.152.0/21 103.61.160.0/22 103.61.172.0/22 103.61.176.0/22 103.62.24.0/22 103.62.72.0/21 103.62.80.0/21 103.62.88.0/22 103.62.96.0/19 103.62.128.0/21 103.62.156.0/22 103.62.160.0/19 103.62.192.0/22 103.62.204.0/22 103.62.208.0/20 103.62.224.0/22 103.63.32.0/19 103.63.64.0/20 103.63.80.0/21 103.63.88.0/22 103.63.140.0/22 103.63.144.0/22 103.63.152.0/22 103.63.160.0/20 103.63.176.0/21 103.63.184.0/22 103.63.192.0/20 103.63.208.0/22 103.63.240.0/20 103.64.0.0/21 103.64.24.0/21 103.64.32.0/19 103.64.64.0/18 103.64.140.0/22 103.64.144.0/22 103.64.152.0/21 103.64.160.0/19 103.64.192.0/18 103.65.0.0/20 103.65.16.0/22 103.65.48.0/20 103.65.64.0/19 103.65.100.0/22 103.65.104.0/21 103.65.112.0/20 103.65.128.0/21 103.65.136.0/22 103.65.144.0/20 103.65.160.0/20 103.66.32.0/22 103.66.40.0/22 103.66.108.0/22 103.66.200.0/22 103.66.240.0/20 103.67.0.0/21 103.67.8.0/22 103.67.40.0/21 103.67.48.0/20 103.67.64.0/18 103.67.128.0/20 103.67.144.0/21 103.67.172.0/24 103.67.175.0/24 103.67.192.0/22 103.67.212.0/22 103.68.88.0/22 103.68.100.0/22 103.68.128.0/22 103.69.16.0/22 103.70.8.0/22 103.70.148.0/22 103.70.236.0/22 103.70.252.0/22 103.71.0.0/22 103.71.68.0/22 103.71.72.0/22 103.71.80.0/21 103.71.88.0/22 103.71.120.0/21 103.71.128.0/22 103.71.196.0/22 103.71.200.0/22 103.71.232.0/22 103.72.12.0/22 103.72.16.0/20 103.72.32.0/20 103.72.48.0/21 103.72.112.0/21 103.72.124.0/22 103.72.128.0/21 103.72.149.0/24 103.72.150.0/23 103.72.172.0/22 103.72.180.0/22 103.72.224.0/19 103.73.0.0/19 103.73.48.0/22 103.73.116.0/22 103.73.120.0/22 103.73.128.0/20 103.73.168.0/22 103.73.176.0/22 103.73.204.0/22 103.73.208.0/22 103.73.240.0/23 103.73.244.0/22 103.73.248.0/22 103.74.24.0/21 103.74.32.0/20 103.74.48.0/22 103.74.56.0/21 103.74.80.0/22 103.74.124.0/22 103.74.148.0/22 103.74.152.0/21 103.74.204.0/22 103.74.232.0/22 103.75.87.0/24 103.75.88.0/21 103.75.104.0/21 103.75.112.0/22 103.75.120.0/22 103.75.128.0/22 103.75.144.0/23 103.75.146.0/24 103.75.152.0/22 103.76.60.0/22 103.76.64.0/21 103.76.72.0/22 103.76.92.0/22 103.76.216.0/21 103.76.224.0/22 103.77.28.0/22 103.77.52.0/22 103.77.56.0/22 103.77.88.0/22 103.77.132.0/22 103.77.148.0/22 103.77.220.0/22 103.78.56.0/21 103.78.64.0/22 103.78.124.0/22 103.78.172.0/22 103.78.176.0/22 103.78.196.0/22 103.78.228.0/22 103.79.24.0/21 103.79.36.0/22 103.79.40.0/21 103.79.56.0/21 103.79.64.0/21 103.79.80.0/21 103.79.136.0/22 103.79.188.0/22 103.79.192.0/20 103.79.208.0/21 103.80.44.0/22 103.80.72.0/22 103.80.176.0/21 103.80.184.0/22 103.80.192.0/22 103.80.200.0/22 103.80.232.0/22 103.81.4.0/22 103.81.44.0/22 103.81.48.0/22 103.81.96.0/22 103.81.120.0/22 103.81.148.0/22 103.81.164.0/22 103.81.200.0/22 103.81.232.0/22 103.82.60.0/22 103.82.68.0/22 103.82.84.0/22 103.82.104.0/22 103.82.224.0/22 103.82.236.0/22 103.83.44.0/22 103.83.52.0/22 103.83.60.0/22 103.83.72.0/22 103.83.112.0/22 103.83.132.0/22 103.83.180.0/22 103.84.0.0/22 103.84.12.0/22 103.84.20.0/22 103.84.24.0/21 103.84.48.0/22 103.84.56.0/22 103.84.64.0/22 103.84.72.0/22 103.85.44.0/22 103.85.48.0/21 103.85.56.0/22 103.85.84.0/22 103.85.136.0/22 103.85.144.0/22 103.85.164.0/22 103.85.168.0/21 103.85.176.0/22 103.86.28.0/22 103.86.32.0/22 103.86.60.0/22 103.86.129.0/24 103.86.204.0/22 103.86.208.0/20 103.86.224.0/19 103.87.0.0/21 103.87.20.0/22 103.87.32.0/22 103.87.96.0/22 103.87.132.0/22 103.87.180.0/22 103.87.224.0/22 103.88.4.0/22 103.88.8.0/21 103.88.16.0/21 103.88.32.0/21 103.88.60.0/22 103.88.64.0/22 103.88.72.0/22 103.88.96.0/21 103.88.152.0/23 103.88.164.0/22 103.88.212.0/22 103.89.28.0/22 103.89.96.0/20 103.89.112.0/22 103.89.148.0/22 103.89.172.0/22 103.89.184.0/21 103.89.192.0/19 103.89.224.0/21 103.90.52.0/22 103.90.92.0/22 103.90.100.0/22 103.90.104.0/21 103.90.112.0/20 103.90.128.0/21 103.90.152.0/22 103.90.168.0/22 103.90.173.0/24 103.90.176.0/22 103.90.188.0/22 103.90.192.0/22 103.91.36.0/22 103.91.40.0/22 103.91.108.0/22 103.91.152.0/22 103.91.176.0/22 103.91.200.0/22 103.91.208.0/21 103.91.236.0/22 103.92.48.0/20 103.92.64.0/20 103.92.80.0/22 103.92.88.0/22 103.92.108.0/22 103.92.124.0/22 103.92.132.0/22 103.92.156.0/22 103.92.164.0/22 103.92.168.0/21 103.92.176.0/20 103.92.192.0/22 103.92.236.0/22 103.92.240.0/20 103.93.0.0/21 103.93.28.0/22 103.93.84.0/22 103.93.152.0/22 103.93.180.0/22 103.93.204.0/22 103.94.12.0/22 103.94.20.0/22 103.94.30.0/23 103.94.32.0/20 103.94.72.0/22 103.94.88.0/22 103.94.116.0/22 103.94.160.0/22 103.94.200.0/22 103.95.52.0/22 103.95.68.0/22 103.95.88.0/21 103.95.136.0/21 103.95.144.0/22 103.95.152.0/22 103.95.216.0/21 103.95.224.0/22 103.95.236.0/22 103.95.240.0/20 103.96.8.0/22 103.96.124.0/22 103.96.136.0/22 103.96.152.0/21 103.96.160.0/19 103.96.192.0/20 103.96.208.0/21 103.96.216.0/22 103.97.40.0/22 103.97.60.0/23 103.97.112.0/21 103.97.148.0/22 103.97.188.0/22 103.97.192.0/22 103.98.40.0/21 103.98.48.0/22 103.98.56.0/22 103.98.80.0/22 103.98.88.0/22 103.98.100.0/22 103.98.124.0/24 103.98.126.0/24 103.98.136.0/21 103.98.144.0/22 103.98.164.0/22 103.98.168.0/22 103.98.180.0/22 103.98.196.0/22 103.98.216.0/21 103.98.224.0/21 103.98.232.0/22 103.98.240.0/21 103.98.250.0/24 103.99.56.0/22 103.99.104.0/22 103.99.116.0/22 103.99.120.0/22 103.99.132.0/22 103.99.136.0/21 103.99.144.0/22 103.99.152.0/22 103.99.220.0/22 103.99.232.0/21 103.100.0.0/22 103.100.32.0/22 103.100.40.0/22 103.100.48.0/22 103.100.56.0/22 103.100.64.0/22 103.100.88.0/22 103.100.116.0/22 103.100.144.0/22 103.100.240.0/22 103.100.248.0/21 103.101.4.0/22 103.101.8.0/21 103.101.60.0/22 103.101.121.0/24 103.101.122.0/23 103.101.124.0/24 103.101.126.0/23 103.101.144.0/21 103.101.180.0/22 103.101.184.0/22 103.102.76.0/22 103.102.80.0/22 103.102.168.0/21 103.102.180.0/22 103.102.184.0/21 103.102.192.0/22 103.102.196.0/24 103.102.200.0/22 103.102.208.0/21 103.103.12.0/22 103.103.16.0/22 103.103.36.0/22 103.103.72.0/22 103.103.188.0/22 103.103.204.0/22 103.104.36.0/22 103.104.40.0/22 103.104.64.0/22 103.104.152.0/22 103.104.252.0/22 103.105.0.0/21 103.105.12.0/22 103.105.16.0/22 103.105.60.0/22 103.105.116.0/22 103.105.180.0/22 103.105.184.0/22 103.105.200.0/21 103.105.220.0/22 103.106.36.0/22 103.106.40.0/21 103.106.60.0/22 103.106.68.0/22 103.106.96.0/22 103.106.120.0/22 103.106.128.0/21 103.106.190.0/23 103.106.196.0/22 103.106.212.0/22 103.106.252.0/22 103.107.0.0/22 103.107.28.0/22 103.107.32.0/22 103.107.44.0/22 103.107.72.0/22 103.107.164.0/22 103.107.168.0/22 103.107.188.0/22 103.107.192.0/22 103.107.208.0/20 103.108.52.0/22 103.108.160.0/22 103.108.196.0/22 103.108.208.0/21 103.108.224.0/22 103.108.244.0/22 103.108.251.0/24 103.109.20.0/22 103.109.48.0/22 103.109.88.0/22 103.109.248.0/22 103.110.32.0/22 103.110.92.0/22 103.110.119.0/24 103.110.127.0/24 103.110.128.0/23 103.110.131.0/24 103.110.132.0/22 103.110.136.0/22 103.110.156.0/22 103.110.188.0/22 103.110.204.0/22 103.111.64.0/22 103.111.172.0/22 103.111.252.0/22 103.112.72.0/22 103.112.88.0/21 103.112.108.0/22 103.112.112.0/22 103.112.140.0/22 103.113.4.0/22 103.113.144.0/22 103.113.220.0/22 103.113.232.0/21 103.114.4.0/22 103.114.68.0/22 103.114.100.0/22 103.114.148.0/22 103.114.156.0/23 103.114.176.0/22 103.114.212.0/22 103.114.236.0/22 103.114.240.0/22 103.115.52.0/22 103.115.68.0/22 103.115.92.0/22 103.115.120.0/22 103.115.148.0/22 103.115.248.0/22 103.116.76.0/22 103.116.92.0/22 103.116.120.0/22 103.116.128.0/22 103.116.184.0/22 103.116.220.0/22 103.116.224.0/21 103.117.16.0/22 103.117.88.0/22 103.117.188.0/22 103.117.220.0/22 103.118.19.0/24 103.118.52.0/22 103.118.56.0/21 103.118.64.0/21 103.118.72.0/22 103.118.88.0/22 103.118.173.0/24 103.119.115.0/24 103.119.156.0/22 103.119.180.0/22 103.119.200.0/22 103.120.52.0/22 103.120.72.0/22 103.120.76.0/24 103.120.88.0/22 103.120.96.0/22 103.120.140.0/22 103.120.196.0/22 103.120.224.0/22 103.121.52.0/22 103.121.160.0/21 103.121.250.0/24 103.121.252.0/22 103.122.48.0/22 103.122.179.0/24 103.122.192.0/22 103.122.240.0/23 103.122.242.0/24 103.123.4.0/22 103.123.56.0/22 103.123.88.0/21 103.123.116.0/22 103.123.176.0/22 103.123.200.0/21 103.123.208.0/21 103.124.24.0/22 103.124.48.0/22 103.124.64.0/22 103.124.212.0/22 103.124.216.0/22 103.125.20.0/22 103.125.44.0/22 103.125.132.0/22 103.125.164.0/22 103.125.196.0/22 103.125.236.0/22 103.126.0.0/22 103.126.16.0/23 103.126.44.0/22 103.126.124.0/22 103.126.128.0/22 103.129.53.0/24 103.129.54.0/23 103.129.148.0/22 103.130.132.0/22 103.130.160.0/22 103.130.228.0/22 103.131.20.0/22 103.131.36.0/22 103.131.152.0/22 103.131.168.0/22 103.131.224.0/21 103.131.240.0/22 103.132.60.0/22 103.132.64.0/20 103.132.80.0/22 103.132.104.0/21 103.132.112.0/21 103.132.120.0/22 103.132.188.0/22 103.132.208.0/21 103.133.12.0/22 103.133.40.0/22 103.133.128.0/22 103.133.232.0/22 103.134.196.0/22 103.135.80.0/22 103.135.124.0/22 103.135.148.0/22 103.135.156.0/22 103.135.160.0/21 103.135.176.0/22 103.135.184.0/22 103.135.192.0/21 103.135.236.0/22 103.136.128.0/22 103.136.232.0/22 103.137.58.0/23 103.137.60.0/24 103.137.136.0/23 103.137.149.0/24 103.137.180.0/22 103.137.236.0/22 103.138.2.0/23 103.138.135.0/24 103.138.208.0/23 103.138.220.0/23 103.138.248.0/23 103.139.22.0/23 103.139.134.0/23 103.139.172.0/23 103.139.204.0/23 103.139.212.0/23 103.140.14.0/23 103.140.46.0/23 103.140.140.0/23 103.140.144.0/23 103.140.192.0/23 103.141.10.0/23 103.141.58.0/23 103.141.128.0/23 103.141.186.0/23 103.141.242.0/23 103.142.0.0/23 103.142.28.0/23 103.142.58.0/23 103.142.82.0/23 103.142.96.0/23 103.142.122.0/23 103.142.128.0/23 103.142.154.0/23 103.142.156.0/23 103.142.180.0/23 103.142.186.0/23 103.142.234.0/23 103.142.238.0/23 103.143.16.0/22 103.143.31.0/24 103.143.74.0/23 103.143.124.0/23 103.143.132.0/22 103.143.174.0/23 103.143.228.0/23 103.144.66.0/23 103.144.70.0/23 103.144.72.0/23 103.144.88.0/24 103.144.136.0/23 103.144.158.0/23 103.145.42.0/23 103.145.94.0/23 103.145.98.0/23 103.145.188.0/23 103.146.6.0/23 103.146.72.0/23 103.146.126.0/23 103.146.138.0/23 103.146.236.0/23 103.146.252.0/23 103.147.124.0/23 103.147.206.0/23 103.148.174.0/23 103.149.6.0/23 103.149.17.0/24 103.149.44.0/23 103.149.210.0/23 103.149.214.0/23 103.149.220.0/23 103.149.242.0/23 103.149.244.0/22 103.150.24.0/23 103.150.66.0/23 103.150.72.0/23 103.150.122.0/23 103.150.126.0/23 103.150.128.0/23 103.150.146.0/23 103.150.164.0/23 103.150.200.0/23 103.150.216.0/23 103.150.244.0/23 103.151.142.0/23 103.151.148.0/23 103.151.158.0/23 103.152.28.0/22 103.152.56.0/23 103.152.76.0/23 103.152.80.0/23 103.152.120.0/22 103.152.152.0/23 103.152.168.0/23 103.152.186.0/23 103.152.190.0/23 103.152.192.0/23 103.152.200.0/23 103.152.208.0/23 103.152.224.0/23 103.152.250.0/23 103.153.99.0/24 103.153.114.0/23 103.153.122.0/23 103.153.128.0/24 103.153.132.0/23 103.153.146.0/23 103.153.160.0/23 103.154.18.0/23 103.154.30.0/23 103.154.32.0/23 103.154.40.0/23 103.154.66.0/23 103.154.162.0/23 103.154.164.0/23 103.154.168.0/23 103.155.14.0/23 103.155.17.0/24 103.155.34.0/23 103.155.48.0/23 103.155.76.0/23 103.155.100.0/23 103.155.248.0/23 103.156.28.0/23 103.156.68.0/23 103.156.78.0/23 103.156.104.0/23 103.156.158.0/23 103.156.166.0/23 103.156.174.0/23 103.156.186.0/23 103.156.228.0/23 103.157.30.0/23 103.157.174.0/23 103.157.212.0/23 103.157.234.0/23 103.157.254.0/23 103.158.0.0/23 103.158.8.0/23 103.158.16.0/23 103.158.200.0/23 103.158.224.0/23 103.159.122.0/23 103.159.124.0/23 103.159.134.0/23 103.159.142.0/23 103.160.32.0/22 103.160.112.0/22 103.160.244.0/23 103.160.254.0/23 103.161.14.0/23 103.161.102.0/23 103.161.138.0/23 103.161.208.0/23 103.161.220.0/23 103.161.254.0/23 103.162.10.0/23 103.162.32.0/23 103.162.38.0/23 103.162.116.0/23 103.163.28.0/23 103.163.32.0/23 103.163.46.0/23 103.163.74.0/23 103.163.180.0/23 103.164.4.0/23 103.164.32.0/23 103.164.40.0/22 103.164.64.0/23 103.164.76.0/23 103.164.178.0/23 103.164.226.0/23 103.165.44.0/23 103.165.52.0/23 103.165.82.0/23 103.165.110.0/23 103.166.50.0/23 103.166.52.0/22 103.166.84.0/23 103.166.138.0/23 103.166.242.0/23 103.167.0.0/23 103.167.36.0/23 103.168.98.0/23 103.168.170.0/23 103.169.50.0/23 103.169.62.0/23 103.169.108.0/23 103.169.162.0/23 103.169.202.0/23 103.169.216.0/23 103.170.4.0/23 103.170.134.0/23 103.170.210.0/23 103.170.212.0/23 103.192.0.0/19 103.192.48.0/21 103.192.56.0/22 103.192.84.0/22 103.192.88.0/21 103.192.96.0/20 103.192.112.0/22 103.192.128.0/20 103.192.144.0/22 103.192.164.0/22 103.192.188.0/22 103.192.208.0/21 103.192.216.0/22 103.192.252.0/22 103.193.40.0/21 103.193.120.0/22 103.193.140.0/22 103.193.160.0/22 103.193.188.0/22 103.193.192.0/22 103.193.212.0/22 103.193.216.0/21 103.193.224.0/20 103.194.16.0/22 103.195.112.0/22 103.195.152.0/22 103.195.160.0/22 103.196.64.0/22 103.196.72.0/22 103.196.88.0/21 103.196.96.0/22 103.196.168.0/22 103.196.185.0/24 103.196.186.0/23 103.197.181.0/24 103.197.183.0/24 103.197.228.0/22 103.197.253.0/24 103.197.254.0/23 103.198.20.0/22 103.198.60.0/22 103.198.64.0/22 103.198.72.0/22 103.198.124.0/22 103.198.156.0/22 103.198.180.0/22 103.198.196.0/22 103.198.201.0/24 103.198.202.0/23 103.199.164.0/22 103.199.196.0/22 103.199.228.0/22 103.199.252.0/22 103.200.52.0/22 103.200.64.0/21 103.200.136.0/21 103.200.144.0/20 103.200.160.0/19 103.200.192.0/22 103.200.220.0/22 103.200.224.0/19 103.201.0.0/20 103.201.16.0/21 103.201.28.0/22 103.201.32.0/19 103.201.64.0/22 103.201.76.0/22 103.201.80.0/20 103.201.96.0/20 103.201.112.0/21 103.201.120.0/22 103.201.152.0/21 103.201.160.0/19 103.201.192.0/18 103.202.0.0/19 103.202.32.0/20 103.202.56.0/21 103.202.64.0/18 103.202.128.0/20 103.202.144.0/22 103.202.152.0/21 103.202.160.0/19 103.202.192.0/20 103.202.212.0/22 103.202.228.0/22 103.202.236.0/22 103.202.240.0/20 103.203.0.0/19 103.203.32.0/22 103.203.96.0/19 103.203.128.0/22 103.203.140.0/22 103.203.164.0/22 103.203.168.0/22 103.203.192.0/22 103.203.200.0/22 103.203.212.0/22 103.203.216.0/22 103.204.24.0/22 103.204.72.0/22 103.204.88.0/22 103.204.112.0/22 103.204.136.0/21 103.204.144.0/21 103.204.152.0/22 103.204.196.0/22 103.204.232.0/21 103.205.4.0/22 103.205.40.0/21 103.205.52.0/22 103.205.108.0/22 103.205.116.0/22 103.205.136.0/22 103.205.162.0/24 103.205.188.0/22 103.205.192.0/21 103.205.200.0/22 103.205.236.0/22 103.205.248.0/21 103.206.0.0/22 103.206.44.0/22 103.206.148.0/22 103.207.104.0/22 103.207.184.0/21 103.207.192.0/20 103.207.208.0/21 103.207.220.0/22 103.207.228.0/22 103.207.232.0/22 103.208.12.0/22 103.208.16.0/22 103.208.28.0/22 103.208.48.0/22 103.208.148.0/22 103.209.112.0/22 103.209.136.0/22 103.209.200.0/22 103.209.208.0/22 103.209.216.0/22 103.210.0.0/22 103.210.96.0/22 103.210.156.0/22 103.210.164.0/22 103.210.168.0/21 103.210.176.0/20 103.210.217.0/24 103.210.218.0/23 103.211.44.0/22 103.211.96.0/23 103.211.98.0/24 103.211.102.0/23 103.211.156.0/22 103.211.165.0/24 103.211.168.0/22 103.211.220.0/22 103.211.248.0/22 103.212.0.0/20 103.212.44.0/22 103.212.48.0/22 103.212.84.0/22 103.212.100.0/22 103.212.148.0/22 103.212.164.0/22 103.212.196.0/22 103.212.200.0/22 103.212.252.0/22 103.213.40.0/21 103.213.48.0/20 103.213.64.0/19 103.213.96.0/22 103.213.132.0/22 103.213.136.0/21 103.213.144.0/20 103.213.160.0/19 103.213.252.0/22 103.214.48.0/22 103.214.84.0/22 103.214.212.0/22 103.214.240.0/21 103.215.28.0/22 103.215.32.0/21 103.215.44.0/22 103.215.100.0/23 103.215.108.0/22 103.215.116.0/22 103.215.120.0/22 103.215.140.0/22 103.216.4.0/22 103.216.8.0/21 103.216.16.0/20 103.216.32.0/20 103.216.64.0/22 103.216.108.0/22 103.216.136.0/22 103.216.152.0/22 103.216.224.0/21 103.216.240.0/20 103.217.0.0/18 103.217.168.0/22 103.217.180.0/22 103.217.184.0/21 103.217.192.0/20 103.218.8.0/21 103.218.16.0/21 103.218.28.0/22 103.218.32.0/19 103.218.64.0/19 103.218.192.0/20 103.218.208.0/21 103.218.216.0/22 103.219.24.0/21 103.219.32.0/21 103.219.64.0/22 103.219.84.0/22 103.219.88.0/21 103.219.96.0/21 103.219.176.0/22 103.219.184.0/22 103.220.48.0/20 103.220.64.0/22 103.220.92.0/22 103.220.96.0/22 103.220.104.0/21 103.220.116.0/22 103.220.120.0/21 103.220.128.0/20 103.220.144.0/21 103.220.152.0/22 103.220.160.0/19 103.220.192.0/21 103.220.200.0/22 103.220.240.0/21 103.221.32.0/22 103.221.88.0/22 103.221.96.0/19 103.221.128.0/18 103.221.192.0/20 103.222.0.0/20 103.222.16.0/22 103.222.24.0/21 103.222.33.0/24 103.222.34.0/23 103.222.36.0/22 103.222.40.0/21 103.222.48.0/20 103.222.64.0/18 103.222.128.0/18 103.222.192.0/19 103.222.224.0/21 103.222.232.0/22 103.222.240.0/21 103.223.16.0/20 103.223.32.0/19 103.223.64.0/19 103.223.96.0/20 103.223.112.0/21 103.223.124.0/22 103.223.128.0/21 103.223.140.0/22 103.223.144.0/20 103.223.160.0/20 103.223.176.0/21 103.223.188.0/22 103.223.192.0/18 103.224.0.0/22 103.224.40.0/21 103.224.60.0/22 103.224.220.0/22 103.224.224.0/21 103.224.232.0/22 103.225.32.0/22 103.226.40.0/22 103.226.57.0/24 103.226.58.0/23 103.226.60.0/22 103.226.80.0/22 103.226.116.0/22 103.226.132.0/22 103.226.156.0/22 103.226.180.0/22 103.226.196.0/22 103.227.48.0/22 103.227.72.0/21 103.227.80.0/22 103.227.100.0/22 103.227.120.0/22 103.227.132.0/22 103.227.136.0/22 103.227.196.0/22 103.227.204.0/23 103.227.206.0/24 103.227.212.0/22 103.227.228.0/22 103.228.12.0/22 103.228.88.0/22 103.228.136.0/22 103.228.160.0/22 103.228.176.0/22 103.228.204.0/22 103.228.208.0/22 103.228.228.0/22 103.228.232.0/22 103.229.20.0/22 103.229.136.0/22 103.229.148.0/22 103.229.172.0/22 103.229.212.0/22 103.229.216.0/21 103.229.228.0/22 103.229.236.0/22 103.229.240.0/22 103.230.0.0/22 103.230.28.0/22 103.230.40.0/21 103.230.96.0/22 103.230.196.0/22 103.230.200.0/21 103.230.212.0/22 103.230.236.0/22 103.231.16.0/21 103.231.64.0/21 103.231.144.0/22 103.231.180.0/22 103.231.244.0/22 103.232.4.0/22 103.232.17.168/29 103.232.144.0/22 103.233.4.0/22 103.233.44.0/22 103.233.52.0/22 103.233.104.0/22 103.233.128.0/22 103.233.136.0/22 103.233.228.0/22 103.234.0.0/22 103.234.20.0/22 103.234.56.0/22 103.234.124.0/22 103.234.128.0/22 103.234.172.0/22 103.234.180.0/22 103.235.56.0/21 103.235.80.0/22 103.235.85.0/24 103.235.87.0/24 103.235.128.0/20 103.235.144.0/21 103.235.184.0/22 103.235.192.0/22 103.235.200.0/22 103.235.220.0/22 103.235.224.0/19 103.236.0.0/18 103.236.64.0/19 103.236.96.0/22 103.236.120.0/22 103.236.184.0/22 103.236.240.0/20 103.237.0.0/20 103.237.24.0/21 103.237.68.0/22 103.237.88.0/22 103.237.152.0/22 103.237.176.0/20 103.237.192.0/18 103.238.0.0/21 103.238.18.0/23 103.238.20.0/22 103.238.24.0/21 103.238.32.0/20 103.238.48.0/21 103.238.56.0/22 103.238.88.0/21 103.238.96.0/22 103.238.132.0/22 103.238.140.0/22 103.238.144.0/22 103.238.160.0/22 103.238.165.0/24 103.238.166.0/23 103.238.168.0/21 103.238.176.0/20 103.238.196.0/22 103.238.204.0/22 103.238.252.0/22 103.239.0.0/22 103.239.44.0/22 103.239.68.0/22 103.239.152.0/21 103.239.180.0/22 103.239.184.0/22 103.239.192.0/21 103.239.204.0/22 103.239.208.0/22 103.239.224.0/22 103.239.244.0/22 103.240.16.0/22 103.240.36.0/22 103.240.72.0/22 103.240.84.0/22 103.240.124.0/22 103.240.172.0/22 103.240.188.0/22 103.240.244.0/22 103.241.12.0/22 103.241.92.0/22 103.241.96.0/22 103.241.160.0/22 103.241.184.0/21 103.241.220.0/22 103.242.64.0/23 103.242.128.0/24 103.242.160.0/22 103.242.168.0/21 103.242.176.0/22 103.242.200.0/22 103.242.212.0/22 103.242.220.0/22 103.242.240.0/22 103.243.136.0/22 103.243.252.0/22 103.244.16.0/22 103.244.58.0/23 103.244.60.0/22 103.244.64.0/20 103.244.80.0/21 103.244.164.0/22 103.244.232.0/22 103.244.252.0/22 103.245.23.0/24 103.245.52.0/22 103.245.60.0/22 103.245.80.0/22 103.245.124.0/22 103.245.128.0/22 103.246.8.0/21 103.246.120.0/21 103.246.132.0/22 103.246.152.0/22 103.247.168.0/21 103.247.176.0/22 103.247.200.0/22 103.247.212.0/22 103.248.64.0/23 103.248.100.0/22 103.248.124.0/22 103.248.152.0/22 103.248.168.0/22 103.248.192.0/22 103.248.212.0/22 103.248.224.0/21 103.249.8.0/21 103.249.52.0/22 103.249.128.0/22 103.249.136.0/22 103.249.144.0/22 103.249.164.0/22 103.249.168.0/21 103.249.176.0/22 103.249.188.0/22 103.249.192.0/22 103.249.244.0/22 103.249.252.0/22 103.250.32.0/22 103.250.104.0/22 103.250.124.0/22 103.250.180.0/22 103.250.192.0/22 103.250.216.0/22 103.250.224.0/22 103.250.236.0/22 103.250.248.0/21 103.251.32.0/22 103.251.84.0/22 103.251.96.0/22 103.251.124.0/22 103.251.160.0/22 103.251.192.0/22 103.251.204.0/22 103.251.240.0/22 103.252.28.0/22 103.252.36.0/22 103.252.64.0/22 103.252.96.0/22 103.252.104.0/22 103.252.172.0/22 103.252.204.0/22 103.252.208.0/22 103.252.232.0/22 103.252.248.0/22 103.253.4.0/22 103.253.60.0/22 103.253.204.0/22 103.253.220.0/22 103.253.224.0/22 103.253.232.0/22 103.254.8.0/22 103.254.20.0/22 103.254.64.0/21 103.254.76.0/22 103.254.112.0/22 103.254.176.0/22 103.254.188.0/22 103.255.68.0/22 103.255.88.0/21 103.255.136.0/21 103.255.184.0/22 103.255.200.0/22 103.255.208.0/22 103.255.228.0/22 106.0.0.0/24 106.0.2.0/23 106.0.4.0/22 106.0.8.0/21 106.0.16.0/20 106.0.44.0/22 106.0.64.0/18 106.2.0.0/17 106.2.128.0/20 106.2.144.0/21 106.2.152.0/22 106.2.156.0/23 106.2.160.0/19 106.2.192.0/18 106.3.16.0/20 106.3.32.0/19 106.3.64.0/20 106.3.80.0/22 106.3.88.0/21 106.3.96.0/19 106.3.128.0/19 106.3.164.0/22 106.3.168.0/21 106.3.176.0/20 106.3.192.0/18 106.4.0.0/14 106.8.0.0/15 106.11.0.0/16 106.12.0.0/14 106.16.0.0/12 106.32.0.0/12 106.48.0.0/21 106.48.8.0/22 106.48.16.0/20 106.48.32.0/20 106.48.57.0/24 106.48.60.0/24 106.48.63.0/24 106.48.64.0/18 106.48.128.0/17 106.49.1.0/24 106.49.2.0/23 106.49.4.0/22 106.49.8.0/21 106.49.16.0/20 106.49.32.0/19 106.49.64.0/19 106.49.96.0/24 106.49.98.0/23 106.49.100.0/22 106.49.104.0/21 106.49.112.0/20 106.49.128.0/17 106.50.0.0/16 106.52.0.0/14 106.56.0.0/13 106.74.0.0/16 106.75.0.0/17 106.75.128.0/18 106.75.201.0/24 106.75.204.0/22 106.75.208.0/20 106.75.224.0/19 106.80.0.0/12 106.108.0.0/14 106.112.0.0/12 106.224.0.0/12 107.176.0.0/15 109.71.4.0/24 109.244.0.0/16 110.6.0.0/15 110.16.0.0/14 110.34.40.0/21 110.40.0.0/14 110.44.12.0/22 110.44.144.0/20 110.48.0.0/16 110.51.0.0/16 110.52.0.0/15 110.56.0.0/13 110.64.0.0/15 110.72.0.0/15 110.75.0.0/16 110.76.0.0/20 110.76.16.0/22 110.76.20.0/24 110.76.22.0/24 110.76.24.0/21 110.76.32.0/19 110.76.132.0/22 110.76.156.0/22 110.76.184.0/22 110.76.192.0/18 110.77.0.0/17 110.80.0.0/13 110.88.0.0/14 110.92.68.0/22 110.93.32.0/19 110.94.0.0/15 110.96.0.0/11 110.152.0.0/14 110.156.0.0/15 110.166.0.0/15 110.172.192.0/18 110.173.0.0/19 110.173.32.0/20 110.173.64.0/19 110.173.192.0/19 110.176.0.0/12 110.192.0.0/11 110.228.0.0/14 110.232.32.0/19 110.236.0.0/15 110.240.0.0/12 111.0.0.0/10 111.66.0.0/17 111.66.128.0/19 111.66.160.0/20 111.66.176.0/23 111.66.178.0/24 111.66.180.0/22 111.66.184.0/21 111.66.192.0/18 111.67.192.0/20 111.68.64.0/19 111.72.0.0/13 111.85.0.0/16 111.91.192.0/19 111.92.248.0/21 111.112.0.0/14 111.116.0.0/15 111.118.200.0/21 111.119.64.0/18 111.119.128.0/19 111.120.0.0/14 111.124.0.0/16 111.126.0.0/15 111.128.0.0/11 111.160.0.0/13 111.170.0.0/16 111.172.0.0/14 111.176.0.0/13 111.186.0.0/15 111.192.0.0/12 111.208.0.0/13 111.221.28.0/24 111.221.128.0/17 111.222.0.0/16 111.223.4.0/22 111.223.8.0/21 111.223.16.0/22 111.223.240.0/22 111.223.249.0/24 111.223.250.0/23 111.224.0.0/13 111.235.96.0/19 111.235.156.0/22 111.235.160.0/21 111.235.170.0/23 111.235.172.0/22 111.235.176.0/20 112.0.0.0/10 112.64.0.0/14 112.73.64.0/18 112.74.0.0/15 112.80.0.0/12 112.96.0.0/13 112.109.128.0/17 112.111.0.0/16 112.112.0.0/14 112.116.0.0/15 112.122.0.0/15 112.124.0.0/14 112.128.0.0/14 112.132.0.0/16 112.137.48.0/21 112.192.0.0/14 112.224.0.0/11 113.0.0.0/13 113.8.0.0/15 113.11.192.0/19 113.12.0.0/14 113.16.0.0/15 113.18.0.0/16 113.21.232.0/24 113.21.236.0/22 113.24.0.0/14 113.31.0.0/16 113.44.0.0/14 113.48.0.0/14 113.52.160.0/19 113.52.228.0/22 113.54.0.0/15 113.56.0.0/15 113.58.0.0/16 113.59.0.0/17 113.59.224.0/22 113.62.0.0/15 113.64.0.0/10 113.128.0.0/15 113.130.96.0/20 113.130.112.0/21 113.132.0.0/14 113.136.0.0/13 113.194.0.0/15 113.197.100.0/23 113.197.102.0/24 113.197.104.0/22 113.200.0.0/15 113.202.0.0/16 113.204.0.0/14 113.208.96.0/19 113.208.128.0/17 113.209.0.0/16 113.212.0.0/18 113.212.100.0/22 113.212.184.0/21 113.213.0.0/17 113.214.0.0/15 113.218.0.0/15 113.220.0.0/14 113.224.0.0/12 113.240.0.0/13 113.248.0.0/14 114.28.0.0/17 114.28.128.0/18 114.28.194.0/23 114.28.196.0/22 114.28.200.0/21 114.28.208.0/20 114.28.232.0/22 114.28.240.0/20 114.31.64.0/21 114.54.0.0/15 114.60.0.0/14 114.64.0.0/14 114.68.0.0/18 114.68.64.0/19 114.68.96.0/22 114.68.101.0/24 114.68.102.0/23 114.68.104.0/21 114.68.112.0/20 114.68.128.0/17 114.79.64.0/18 114.80.0.0/12 114.96.0.0/13 114.104.0.0/14 114.110.0.0/20 114.110.64.0/18 114.111.0.0/19 114.111.160.0/19 114.112.4.0/22 114.112.8.0/22 114.112.24.0/21 114.112.32.0/19 114.112.64.0/19 114.112.96.0/20 114.112.116.0/22 114.112.120.0/21 114.112.136.0/21 114.112.144.0/20 114.112.160.0/19 114.112.192.0/19 114.113.0.0/17 114.113.128.0/21 114.113.140.0/22 114.113.144.0/20 114.113.160.0/19 114.113.196.0/22 114.113.200.0/21 114.113.208.0/20 114.113.224.0/20 114.114.0.0/15 114.116.0.0/15 114.118.0.0/16 114.119.0.0/17 114.119.192.0/18 114.132.0.0/16 114.135.0.0/16 114.138.0.0/15 114.141.64.0/21 114.141.80.0/21 114.141.128.0/18 114.196.0.0/15 114.198.248.0/21 114.208.0.0/12 114.224.0.0/11 115.24.0.0/14 115.28.0.0/15 115.31.64.0/20 115.32.0.0/14 115.42.56.0/22 115.44.0.0/14 115.48.0.0/12 115.69.64.0/20 115.84.0.0/18 115.84.192.0/19 115.85.192.0/18 115.100.0.0/14 115.104.0.0/14 115.120.0.0/14 115.124.16.0/20 115.148.0.0/14 115.152.0.0/13 115.166.64.0/19 115.168.0.0/16 115.169.0.0/23 115.169.3.0/24 115.169.6.0/24 115.169.9.0/24 115.169.14.0/23 115.169.16.0/20 115.169.39.0/24 115.169.42.0/23 115.169.44.0/22 115.169.48.0/20 115.169.64.0/18 115.169.128.0/17 115.170.0.0/15 115.172.0.0/14 115.180.0.0/14 115.187.0.0/20 115.190.0.0/15 115.192.0.0/11 115.224.0.0/12 116.0.8.0/21 116.0.24.0/21 116.1.0.0/16 116.2.0.0/15 116.4.0.0/14 116.8.0.0/14 116.13.0.0/16 116.16.0.0/12 116.50.0.0/20 116.52.0.0/14 116.56.0.0/15 116.58.128.0/20 116.58.208.0/20 116.60.0.0/14 116.66.0.0/18 116.66.64.0/19 116.66.96.0/20 116.66.120.0/22 116.68.136.0/21 116.68.176.0/21 116.69.0.0/16 116.70.0.0/17 116.76.0.0/14 116.85.0.0/17 116.85.128.0/18 116.85.192.0/19 116.85.224.0/20 116.85.240.0/21 116.85.248.0/23 116.85.250.0/24 116.85.252.0/22 116.89.144.0/20 116.90.80.0/20 116.90.184.0/21 116.95.0.0/16 116.112.0.0/14 116.116.0.0/15 116.128.0.0/10 116.192.0.0/16 116.193.16.0/20 116.193.32.0/19 116.193.176.0/21 116.194.0.0/15 116.196.0.0/21 116.196.8.0/22 116.196.12.0/23 116.196.16.0/20 116.196.32.0/19 116.196.64.0/18 116.196.128.0/18 116.196.192.0/21 116.196.201.0/24 116.196.203.0/24 116.196.204.0/22 116.196.208.0/20 116.196.224.0/19 116.197.160.0/21 116.197.180.0/23 116.198.0.0/16 116.199.0.0/17 116.199.128.0/19 116.204.0.0/17 116.204.232.0/22 116.205.0.0/16 116.207.0.0/16 116.208.0.0/14 116.212.160.0/20 116.213.64.0/18 116.213.128.0/17 116.214.32.0/19 116.214.64.0/20 116.214.128.0/17 116.215.0.0/16 116.216.0.0/14 116.224.0.0/12 116.242.0.0/15 116.244.0.0/14 116.248.0.0/15 116.252.0.0/15 116.254.104.0/21 116.254.129.0/24 116.254.130.0/23 116.254.132.0/22 116.254.136.0/21 116.254.144.0/20 116.254.160.0/19 116.254.192.0/18 116.255.128.0/17 117.8.0.0/13 117.21.0.0/16 117.22.0.0/15 117.24.0.0/13 117.32.0.0/13 117.40.0.0/14 117.44.0.0/15 117.48.0.0/15 117.50.0.0/16 117.51.128.0/23 117.51.131.0/24 117.51.132.0/22 117.51.136.0/21 117.51.144.0/20 117.51.160.0/19 117.51.192.0/18 117.53.48.0/20 117.53.176.0/20 117.57.0.0/16 117.58.0.0/17 117.59.0.0/16 117.60.0.0/14 117.64.0.0/13 117.72.0.0/15 117.74.64.0/19 117.74.128.0/17 117.75.0.0/16 117.76.0.0/14 117.80.0.0/12 117.100.0.0/15 117.103.16.0/20 117.103.40.0/21 117.103.72.0/21 117.103.128.0/20 117.104.168.0/21 117.106.0.0/15 117.112.0.0/13 117.120.64.0/18 117.120.128.0/17 117.121.0.0/17 117.121.128.0/20 117.121.148.0/22 117.121.152.0/21 117.121.160.0/19 117.121.192.0/21 117.122.128.0/17 117.124.0.0/14 117.128.0.0/10 118.24.0.0/15 118.26.0.0/19 118.26.40.0/21 118.26.48.0/20 118.26.64.0/19 118.26.98.0/23 118.26.112.0/21 118.26.121.0/24 118.26.122.0/23 118.26.124.0/23 118.26.128.0/20 118.26.144.0/22 118.26.149.0/24 118.26.150.0/23 118.26.152.0/21 118.26.160.0/19 118.26.192.0/18 118.28.0.0/15 118.30.0.0/20 118.30.16.0/21 118.30.24.0/22 118.30.32.0/19 118.30.64.0/18 118.30.128.0/17 118.31.0.0/16 118.64.0.0/15 118.66.0.0/16 118.67.112.0/20 118.72.0.0/13 118.80.0.0/15 118.84.0.0/15 118.88.32.0/19 118.88.64.0/18 118.88.128.0/17 118.89.0.0/16 118.102.16.0/20 118.102.32.0/21 118.103.164.0/22 118.103.168.0/21 118.103.176.0/22 118.103.245.0/24 118.103.246.0/23 118.112.0.0/13 118.120.0.0/14 118.124.0.0/15 118.126.1.0/24 118.126.2.0/23 118.126.4.0/22 118.126.8.0/21 118.126.16.0/23 118.126.18.0/24 118.126.32.0/19 118.126.64.0/18 118.126.128.0/17 118.127.128.0/19 118.132.0.0/14 118.144.0.0/14 118.178.0.0/16 118.180.0.0/14 118.184.5.0/24 118.184.128.0/18 118.184.192.0/19 118.184.240.0/20 118.186.0.0/15 118.188.0.0/16 118.190.0.0/16 118.191.0.0/20 118.191.32.0/19 118.191.64.0/18 118.191.144.0/21 118.191.153.0/24 118.191.154.0/23 118.191.156.0/22 118.191.160.0/19 118.191.192.0/20 118.191.209.0/24 118.191.210.0/23 118.191.212.0/22 118.191.248.0/21 118.192.0.0/16 118.193.0.0/22 118.193.96.0/19 118.194.0.0/17 118.194.128.0/18 118.194.192.0/19 118.194.240.0/21 118.195.0.0/16 118.196.0.0/14 118.202.0.0/15 118.204.0.0/14 118.212.0.0/15 118.215.192.0/18 118.224.0.0/14 118.228.0.0/17 118.228.128.0/20 118.228.144.0/21 118.228.156.0/22 118.228.160.0/19 118.228.192.0/18 118.229.0.0/16 118.230.0.0/16 118.239.0.0/16 118.242.0.0/16 118.244.0.0/14 118.248.0.0/13 119.0.0.0/15 119.2.0.0/19 119.2.128.0/17 119.3.0.0/16 119.4.0.0/14 119.10.0.0/17 119.15.136.0/21 119.16.0.0/16 119.18.192.0/20 119.18.208.0/21 119.18.224.0/19 119.19.0.0/16 119.20.0.0/14 119.27.64.0/18 119.27.128.0/17 119.28.28.0/24 119.29.0.0/16 119.30.48.0/20 119.31.192.0/19 119.32.0.0/14 119.36.0.0/15 119.38.0.0/17 119.38.128.0/18 119.38.192.0/20 119.38.208.0/22 119.38.212.0/23 119.38.214.0/27 119.38.214.56/29 119.38.214.64/26 119.38.214.128/25 119.38.215.0/24 119.38.216.0/21 119.39.0.0/16 119.40.0.0/18 119.40.64.0/20 119.40.128.0/17 119.41.0.0/16 119.42.0.0/19 119.42.128.0/20 119.42.224.0/19 119.44.0.0/15 119.48.0.0/13 119.57.0.0/16 119.58.0.0/16 119.59.128.0/17 119.60.0.0/15 119.62.0.0/16 119.63.32.0/19 119.75.208.0/20 119.78.0.0/15 119.80.0.0/16 119.82.208.0/20 119.84.0.0/14 119.88.0.0/16 119.89.0.0/17 119.89.128.0/21 119.89.136.0/23 119.89.139.0/24 119.89.140.0/22 119.89.144.0/20 119.89.160.0/20 119.89.176.0/22 119.89.180.0/23 119.89.183.0/24 119.89.184.0/21 119.89.192.0/23 119.89.194.0/24 119.89.196.0/22 119.89.200.0/21 119.89.208.0/21 119.89.217.0/24 119.89.218.0/23 119.89.220.0/22 119.89.224.0/19 119.90.0.0/15 119.96.0.0/13 119.108.0.0/15 119.112.0.0/12 119.128.0.0/12 119.144.0.0/14 119.148.160.0/19 119.151.192.0/18 119.160.200.0/21 119.161.120.0/21 119.161.128.0/21 119.161.160.0/19 119.161.192.0/18 119.162.0.0/15 119.164.0.0/14 119.176.0.0/12 119.232.0.0/15 119.235.128.0/19 119.235.160.0/20 119.235.184.0/22 119.248.0.0/14 119.252.96.0/21 119.252.240.0/21 119.252.249.0/24 119.252.252.0/23 119.253.0.0/16 119.254.0.0/15 120.0.0.0/12 120.24.0.0/14 120.30.0.0/15 120.32.0.0/12 120.48.0.0/15 120.52.0.0/16 120.53.0.0/19 120.53.32.0/20 120.53.48.0/22 120.53.54.0/23 120.53.56.0/21 120.53.64.0/18 120.53.128.0/17 120.54.0.0/15 120.64.0.0/13 120.72.32.0/19 120.72.128.0/17 120.76.0.0/14 120.80.0.0/13 120.88.8.0/21 120.90.0.0/15 120.92.0.0/17 120.92.128.0/18 120.92.192.0/22 120.92.198.0/23 120.92.200.0/21 120.92.208.0/20 120.92.224.0/19 120.94.0.0/15 120.128.0.0/13 120.136.16.0/21 120.136.128.0/18 120.137.0.0/17 120.143.128.0/19 120.192.0.0/10 121.0.8.0/21 121.0.16.0/20 121.4.0.0/22 121.4.8.0/21 121.4.16.0/20 121.4.32.0/19 121.4.64.0/18 121.4.128.0/17 121.5.0.0/16 121.8.0.0/13 121.16.0.0/12 121.32.0.0/13 121.40.0.0/14 121.46.0.0/18 121.46.76.0/22 121.46.128.0/17 121.47.0.0/16 121.48.0.0/15 121.50.8.0/21 121.51.0.0/16 121.52.160.0/19 121.52.208.0/20 121.52.224.0/19 121.54.176.0/21 121.55.0.0/18 121.56.0.0/15 121.58.0.0/17 121.58.136.0/21 121.58.144.0/20 121.58.160.0/21 121.59.0.0/20 121.59.16.0/21 121.59.24.0/22 121.59.28.0/24 121.59.31.0/24 121.59.33.0/24 121.59.36.0/22 121.59.40.0/21 121.59.48.0/20 121.59.64.0/19 121.59.96.0/22 121.59.101.0/24 121.59.102.0/23 121.59.104.0/21 121.59.112.0/21 121.59.121.0/24 121.59.122.0/23 121.59.124.0/22 121.59.128.0/21 121.59.136.0/22 121.59.141.0/24 121.59.142.0/23 121.59.144.0/21 121.59.152.0/24 121.59.154.0/23 121.59.156.0/22 121.59.160.0/19 121.59.192.0/18 121.60.0.0/14 121.68.0.0/14 121.76.0.0/15 121.79.128.0/18 121.89.0.0/16 121.100.128.0/17 121.101.0.0/18 121.101.208.0/20 121.192.0.0/13 121.200.192.0/23 121.200.194.0/24 121.200.196.0/22 121.201.0.0/16 121.204.0.0/14 121.224.0.0/12 121.248.0.0/14 121.255.0.0/16 122.0.64.0/18 122.0.128.0/17 122.4.0.0/14 122.9.0.0/16 122.10.132.0/23 122.10.136.0/23 122.10.216.0/22 122.10.228.0/22 122.10.232.0/21 122.10.240.0/22 122.11.0.0/17 122.12.0.0/15 122.14.0.0/17 122.14.192.0/18 122.48.0.0/16 122.49.0.0/18 122.51.0.0/16 122.64.0.0/14 122.68.0.0/15 122.70.0.0/18 122.70.64.0/19 122.70.96.0/20 122.70.112.0/21 122.70.120.0/22 122.70.124.0/23 122.70.126.0/24 122.70.128.0/17 122.71.0.0/16 122.72.0.0/13 122.80.0.0/12 122.96.0.0/15 122.98.144.0/20 122.98.160.0/21 122.98.172.0/22 122.98.176.0/20 122.98.192.0/21 122.98.232.0/21 122.98.240.0/20 122.102.0.0/20 122.102.64.0/19 122.112.0.0/18 122.112.64.0/19 122.112.96.0/22 122.112.118.0/24 122.112.122.0/24 122.112.125.0/24 122.112.128.0/17 122.113.0.0/16 122.114.0.0/16 122.115.0.0/18 122.115.80.0/20 122.115.96.0/19 122.115.128.0/17 122.119.0.0/16 122.128.100.0/22 122.128.120.0/21 122.136.0.0/13 122.144.128.0/17 122.152.192.0/18 122.156.0.0/14 122.188.0.0/14 122.192.0.0/14 122.198.0.0/16 122.200.40.0/21 122.200.64.0/18 122.201.48.0/20 122.204.0.0/14 122.224.0.0/12 122.240.0.0/13 122.248.24.0/21 122.248.48.0/20 122.255.64.0/21 123.0.128.0/21 123.0.136.0/23 123.0.139.0/24 123.0.140.0/22 123.0.144.0/20 123.0.160.0/19 123.4.0.0/14 123.8.0.0/13 123.49.130.0/23 123.49.132.0/22 123.49.136.0/22 123.49.152.0/21 123.49.160.0/19 123.49.192.0/18 123.50.160.0/19 123.52.0.0/14 123.56.0.0/15 123.58.0.0/18 123.58.64.0/20 123.58.80.0/21 123.58.88.0/22 123.58.96.0/19 123.58.128.0/18 123.58.224.0/19 123.59.0.0/16 123.60.0.0/15 123.62.0.0/16 123.64.0.0/11 123.96.0.0/15 123.98.0.0/17 123.99.128.0/19 123.99.160.0/20 123.99.176.0/21 123.99.184.0/22 123.99.188.0/24 123.99.190.0/23 123.99.192.0/18 123.100.0.0/19 123.100.232.0/24 123.101.0.0/16 123.103.0.0/20 123.103.16.0/21 123.103.24.0/22 123.103.28.0/23 123.103.30.0/24 123.103.32.0/19 123.103.64.0/18 123.108.134.0/24 123.108.138.0/23 123.108.140.0/24 123.108.142.0/24 123.108.208.0/20 123.112.0.0/12 123.128.0.0/13 123.137.0.0/16 123.138.0.0/15 123.144.0.0/12 123.160.0.0/12 123.176.60.0/22 123.176.80.0/20 123.177.0.0/16 123.178.0.0/15 123.180.0.0/14 123.184.0.0/13 123.196.0.0/15 123.199.128.0/17 123.206.0.0/15 123.232.0.0/14 123.242.0.0/17 123.242.192.0/21 123.244.0.0/14 123.249.0.0/16 123.253.240.0/22 123.254.96.0/21 124.6.64.0/18 124.14.0.0/15 124.16.0.0/15 124.20.0.0/14 124.28.192.0/18 124.29.0.0/17 124.31.0.0/16 124.40.112.0/20 124.40.128.0/18 124.40.192.0/19 124.40.240.0/22 124.42.0.0/16 124.47.0.0/18 124.64.0.0/15 124.66.0.0/17 124.67.0.0/16 124.68.0.0/19 124.68.32.0/20 124.68.48.0/21 124.68.56.0/22 124.68.60.0/23 124.68.63.0/24 124.68.64.0/18 124.68.128.0/18 124.68.192.0/19 124.68.224.0/23 124.68.226.0/24 124.68.228.0/22 124.68.232.0/21 124.68.240.0/23 124.68.242.0/24 124.68.244.0/23 124.68.254.0/24 124.69.0.0/16 124.70.0.0/16 124.71.0.0/17 124.71.128.0/18 124.71.192.0/19 124.71.224.0/20 124.71.240.0/21 124.71.250.0/23 124.71.252.0/22 124.72.0.0/13 124.88.0.0/13 124.108.8.0/21 124.108.40.0/21 124.109.96.0/21 124.112.0.0/13 124.126.0.0/15 124.128.0.0/13 124.147.128.0/17 124.150.137.0/24 124.151.0.0/16 124.152.0.0/16 124.160.0.0/13 124.172.0.0/16 124.173.32.0/19 124.173.64.0/18 124.173.128.0/17 124.174.0.0/15 124.192.0.0/15 124.196.0.0/16 124.200.0.0/13 124.220.0.0/14 124.224.0.0/12 124.240.0.0/17 124.240.128.0/18 124.242.0.0/16 124.243.192.0/18 124.248.0.0/17 124.249.0.0/16 124.250.0.0/15 124.254.0.0/18 125.31.192.0/18 125.32.0.0/12 125.58.128.0/17 125.61.128.0/17 125.62.0.0/18 125.64.0.0/11 125.96.0.0/15 125.98.0.0/16 125.104.0.0/13 125.112.0.0/12 125.169.0.0/16 125.171.0.0/16 125.208.0.0/19 125.208.37.0/24 125.208.40.0/24 125.208.45.0/24 125.208.46.0/23 125.208.48.0/20 125.210.0.0/15 125.213.0.0/17 125.214.96.0/19 125.215.0.0/18 125.216.0.0/13 125.254.128.0/17 128.108.0.0/16 129.28.0.0/16 129.204.0.0/16 129.211.0.0/16 129.223.254.0/24 130.36.146.0/23 130.214.218.0/23 131.228.96.0/24 131.253.12.0/29 131.253.12.80/28 131.253.12.240/29 132.232.0.0/16 132.237.134.0/24 134.175.0.0/16 135.84.254.0/23 135.159.208.0/20 135.244.80.0/20 137.59.59.0/24 137.59.88.0/22 138.32.244.0/24 139.5.56.0/22 139.5.61.0/24 139.5.62.0/23 139.5.80.0/22 139.5.92.0/22 139.5.128.0/22 139.5.160.0/22 139.5.192.0/22 139.5.204.0/22 139.5.244.0/22 139.9.0.0/16 139.129.0.0/16 139.138.238.0/28 139.148.0.0/16 139.155.0.0/16 139.159.0.0/19 139.159.32.0/21 139.159.40.0/22 139.159.52.0/22 139.159.56.0/21 139.159.64.0/19 139.159.96.0/20 139.159.112.0/24 139.159.113.24/29 139.159.113.32/27 139.159.113.64/26 139.159.113.128/25 139.159.114.0/23 139.159.116.0/23 139.159.120.0/21 139.159.128.0/17 139.170.0.0/16 139.176.0.0/16 139.183.0.0/16 139.186.0.0/16 139.189.0.0/16 139.196.0.0/15 139.198.0.0/18 139.198.66.0/23 139.198.68.0/22 139.198.72.0/21 139.198.80.0/20 139.198.96.0/20 139.198.116.0/22 139.198.122.0/23 139.198.124.0/22 139.198.128.0/17 139.199.0.0/16 139.200.0.0/13 139.208.0.0/13 139.217.0.0/16 139.219.0.0/16 139.220.0.0/17 139.220.128.0/18 139.220.192.0/22 139.220.196.0/23 139.220.200.0/21 139.220.208.0/23 139.220.212.0/22 139.220.216.0/21 139.220.224.0/19 139.221.0.0/16 139.224.0.0/16 139.226.0.0/15 140.75.0.0/16 140.101.208.0/24 140.143.0.0/16 140.179.0.0/16 140.205.0.0/16 140.206.0.0/15 140.210.0.0/16 140.224.0.0/16 140.237.0.0/16 140.240.0.0/16 140.242.223.0/24 140.242.224.0/24 140.243.0.0/16 140.246.0.0/16 140.249.0.0/16 140.250.0.0/16 140.255.0.0/16 142.70.0.0/16 142.86.0.0/16 144.0.0.0/16 144.7.0.0/16 144.12.0.0/16 144.36.146.0/23 144.48.64.0/22 144.48.88.0/22 144.48.156.0/22 144.48.180.0/22 144.48.184.0/22 144.48.204.0/22 144.48.208.0/21 144.52.0.0/16 144.123.0.0/16 144.211.80.0/24 144.211.138.0/24 144.255.0.0/16 146.56.192.0/18 146.88.175.0/24 146.196.56.0/22 146.196.68.0/22 146.196.92.0/22 146.196.112.0/21 146.196.124.0/22 146.217.137.0/24 146.222.79.0/24 146.222.81.0/24 146.222.94.0/24 147.243.13.32/27 147.243.13.64/27 147.243.14.32/27 148.70.0.0/16 150.0.0.0/16 150.115.0.0/16 150.121.0.0/16 150.122.0.0/16 150.129.136.0/22 150.129.192.0/22 150.129.252.0/22 150.138.0.0/15 150.158.0.0/16 150.222.88.0/23 150.223.0.0/16 150.242.0.0/21 150.242.8.0/22 150.242.28.0/22 150.242.44.0/22 150.242.48.0/21 150.242.56.0/22 150.242.76.0/22 150.242.80.0/22 150.242.92.0/22 150.242.96.0/22 150.242.112.0/21 150.242.120.0/22 150.242.152.0/22 150.242.158.0/24 150.242.160.0/21 150.242.168.0/22 150.242.184.0/21 150.242.192.0/22 150.242.226.0/23 150.242.232.0/21 150.242.240.0/21 150.242.248.0/22 150.248.0.0/16 150.255.0.0/16 152.32.178.0/23 152.104.128.0/17 152.136.0.0/16 153.0.0.0/16 153.3.0.0/16 153.34.0.0/15 153.36.0.0/15 153.99.0.0/16 153.101.0.0/16 153.118.0.0/15 154.8.128.0/17 154.209.251.0/24 155.126.176.0/23 156.107.160.0/24 156.107.170.0/24 156.107.179.0/24 156.107.181.0/24 156.154.62.0/23 157.0.0.0/16 157.18.0.0/16 157.61.0.0/16 157.119.8.0/21 157.119.16.0/22 157.119.28.0/22 157.119.132.0/22 157.119.136.0/21 157.119.144.0/20 157.119.160.0/21 157.119.172.0/22 157.119.192.0/21 157.119.240.0/22 157.119.252.0/22 157.122.0.0/16 157.133.186.0/23 157.133.192.0/21 157.133.212.0/24 157.133.236.0/24 157.148.0.0/16 157.156.0.0/16 157.255.0.0/16 158.60.128.0/17 158.79.0.0/24 158.79.2.0/23 158.79.4.0/22 158.79.8.0/21 158.79.16.0/20 158.79.32.0/19 158.79.64.0/18 158.79.128.0/17 159.27.0.0/16 159.75.0.0/16 159.221.232.0/22 159.226.0.0/16 160.19.208.0/21 160.19.216.0/22 160.20.48.0/22 160.62.10.0/24 160.83.109.0/24 160.83.110.0/23 160.202.60.0/23 160.202.62.0/24 160.202.148.0/22 160.202.152.0/22 160.202.212.0/22 160.202.216.0/21 160.202.224.0/19 160.238.64.0/22 161.120.0.0/16 161.163.0.0/21 161.163.28.0/23 161.189.0.0/16 161.207.0.0/16 162.14.0.0/21 162.14.12.0/22 162.14.16.0/21 162.14.26.0/23 162.14.28.0/22 162.14.32.0/19 162.14.64.0/18 162.14.128.0/17 162.105.0.0/16 163.0.0.0/16 163.47.4.0/22 163.53.0.0/20 163.53.36.0/22 163.53.40.0/22 163.53.48.0/20 163.53.64.0/22 163.53.88.0/21 163.53.96.0/19 163.53.128.0/21 163.53.136.0/22 163.53.160.0/20 163.53.188.0/22 163.53.220.0/22 163.53.240.0/22 163.125.0.0/16 163.142.0.0/16 163.177.0.0/16 163.179.0.0/16 163.204.0.0/16 163.228.0.0/16 163.244.246.0/24 164.52.80.0/24 165.84.197.0/24 165.154.56.0/21 165.154.64.0/18 165.154.128.0/18 165.154.192.0/19 165.154.254.0/23 165.156.30.0/24 166.111.0.0/16 167.139.0.0/16 167.189.0.0/16 167.220.244.0/22 168.159.144.0/21 168.159.152.0/22 168.159.156.0/23 168.159.158.0/24 168.160.0.0/16 168.230.0.0/24 170.179.0.0/16 170.225.224.0/23 170.252.152.0/21 171.8.0.0/13 171.34.0.0/15 171.36.0.0/14 171.40.0.0/13 171.80.0.0/12 171.104.0.0/13 171.112.0.0/12 171.208.0.0/12 172.81.192.0/18 173.39.200.0/23 175.0.0.0/12 175.16.0.0/13 175.24.0.0/14 175.30.0.0/15 175.42.0.0/15 175.44.0.0/16 175.46.0.0/15 175.48.0.0/12 175.64.0.0/11 175.102.0.0/16 175.106.128.0/17 175.111.144.0/20 175.111.160.0/20 175.111.184.0/22 175.146.0.0/15 175.148.0.0/14 175.152.0.0/14 175.158.96.0/22 175.160.0.0/12 175.176.156.0/22 175.176.188.0/22 175.178.0.0/16 175.184.128.0/18 175.185.0.0/16 175.186.0.0/15 175.188.0.0/14 180.76.16.0/20 180.76.32.0/19 180.76.64.0/18 180.76.128.0/17 180.77.0.0/16 180.78.0.0/15 180.84.0.0/15 180.86.0.0/16 180.88.0.0/14 180.92.176.0/23 180.94.56.0/21 180.94.96.0/23 180.94.98.0/24 180.94.100.0/22 180.94.104.0/21 180.94.120.0/21 180.95.128.0/17 180.96.0.0/11 180.129.128.0/17 180.130.0.0/16 180.136.0.0/13 180.148.16.0/21 180.148.152.0/21 180.148.216.0/21 180.148.224.0/19 180.149.128.0/19 180.150.160.0/21 180.150.176.0/20 180.152.0.0/13 180.160.0.0/12 180.178.112.0/21 180.178.192.0/18 180.184.0.0/14 180.188.0.0/17 180.189.148.0/22 180.200.252.0/22 180.201.0.0/16 180.202.0.0/15 180.208.0.0/15 180.210.212.0/22 180.210.233.0/24 180.210.236.0/22 180.212.0.0/15 180.222.224.0/19 180.223.0.0/18 180.223.83.0/24 180.223.84.0/22 180.223.88.0/21 180.223.96.0/19 180.233.0.0/18 180.233.64.0/19 180.233.144.0/22 180.235.64.0/19 180.235.112.0/22 182.16.144.0/21 182.16.192.0/19 182.18.0.0/17 182.23.184.0/21 182.23.200.0/21 182.32.0.0/12 182.48.96.0/19 182.49.0.0/16 182.50.0.0/22 182.50.8.0/21 182.50.112.0/20 182.51.0.0/16 182.54.0.0/17 182.61.0.0/18 182.61.128.0/19 182.61.192.0/18 182.80.0.0/13 182.88.0.0/14 182.92.0.0/16 182.96.0.0/11 182.128.0.0/12 182.144.0.0/13 182.157.0.0/16 182.160.52.0/22 182.160.56.0/22 182.160.60.0/23 182.160.62.0/24 182.160.64.0/19 182.174.0.0/15 182.200.0.0/13 182.236.128.0/17 182.237.24.0/21 182.238.0.0/16 182.239.0.0/19 182.240.0.0/13 182.254.0.0/18 182.254.64.0/19 182.254.96.0/20 182.254.112.0/22 182.254.117.0/24 182.254.119.0/24 182.254.120.0/21 182.254.128.0/17 183.0.0.0/10 183.64.0.0/13 183.78.160.0/21 183.78.180.0/22 183.81.180.0/22 183.84.0.0/15 183.91.128.0/22 183.91.136.0/21 183.91.144.0/20 183.92.0.0/14 183.128.0.0/11 183.160.0.0/13 183.168.0.0/15 183.170.0.0/16 183.172.0.0/14 183.184.0.0/13 183.192.0.0/10 185.109.236.0/24 188.131.128.0/17 192.11.23.0/24 192.11.26.0/24 192.11.39.0/24 192.11.236.0/24 192.23.191.0/24 192.55.10.0/23 192.55.40.0/24 192.55.46.0/24 192.55.68.0/22 192.102.204.0/22 192.124.154.0/24 192.137.31.0/24 192.140.128.0/21 192.140.136.0/22 192.140.156.0/22 192.140.160.0/19 192.140.192.0/20 192.140.208.0/21 192.144.128.0/17 192.163.11.0/24 192.232.97.0/24 193.17.120.0/22 193.20.64.0/22 193.112.0.0/16 193.200.222.160/28 194.138.136.0/24 194.138.202.0/23 194.138.245.0/24 195.142.215.0/24 198.175.100.0/22 198.208.17.0/24 198.208.19.0/24 199.7.72.0/24 199.65.192.0/21 199.244.144.0/24 202.0.100.0/23 202.0.122.0/23 202.1.64.0/23 202.1.68.0/23 202.1.72.0/21 202.1.80.0/20 202.1.96.0/23 202.1.100.0/22 202.1.104.0/22 202.1.110.0/23 202.1.112.0/23 202.3.128.0/23 202.4.128.0/19 202.4.252.0/22 202.5.208.0/21 202.5.216.0/22 202.6.6.0/23 202.6.66.0/23 202.6.72.0/23 202.6.87.0/24 202.6.88.0/23 202.6.92.0/23 202.6.103.0/24 202.6.108.0/24 202.6.110.0/23 202.6.114.0/24 202.6.176.0/20 202.8.0.0/24 202.8.2.0/23 202.8.4.0/23 202.8.12.0/24 202.8.24.0/24 202.8.77.0/24 202.8.128.0/19 202.8.192.0/20 202.9.32.0/24 202.9.34.0/23 202.9.48.0/23 202.9.51.0/24 202.9.52.0/23 202.9.54.0/24 202.9.57.0/24 202.9.58.0/23 202.10.64.0/21 202.10.74.0/23 202.10.76.0/22 202.10.112.0/20 202.12.1.0/24 202.12.2.0/24 202.12.17.0/24 202.12.18.0/23 202.12.72.0/24 202.12.84.0/23 202.12.96.0/24 202.12.98.0/23 202.12.106.0/24 202.12.111.0/24 202.12.116.0/24 202.14.64.0/23 202.14.69.0/24 202.14.73.0/24 202.14.74.0/23 202.14.76.0/24 202.14.78.0/23 202.14.88.0/24 202.14.97.0/24 202.14.104.0/23 202.14.108.0/23 202.14.111.0/24 202.14.114.0/23 202.14.118.0/23 202.14.124.0/23 202.14.127.0/24 202.14.129.0/24 202.14.135.0/24 202.14.136.0/24 202.14.149.0/24 202.14.151.0/24 202.14.157.0/24 202.14.158.0/23 202.14.169.0/24 202.14.170.0/23 202.14.172.0/22 202.14.176.0/24 202.14.184.0/23 202.14.208.0/23 202.14.213.0/24 202.14.219.0/24 202.14.220.0/24 202.14.222.0/23 202.14.225.0/24 202.14.226.0/23 202.14.231.0/24 202.14.235.0/24 202.14.236.0/22 202.14.246.0/24 202.14.251.0/24 202.20.66.0/24 202.20.79.0/24 202.20.87.0/24 202.20.88.0/23 202.20.90.0/24 202.20.94.0/23 202.20.114.0/24 202.20.117.0/24 202.20.120.0/24 202.20.125.0/24 202.20.126.0/23 202.21.48.0/20 202.21.131.0/24 202.21.132.0/24 202.21.141.0/24 202.21.142.0/24 202.21.147.0/24 202.21.148.0/24 202.21.150.0/23 202.21.152.0/23 202.21.154.0/24 202.21.156.0/24 202.21.208.0/24 202.22.248.0/21 202.27.12.0/24 202.27.14.0/24 202.27.136.0/23 202.36.226.0/24 202.38.0.0/22 202.38.8.0/21 202.38.48.0/20 202.38.64.0/18 202.38.128.0/21 202.38.136.0/23 202.38.138.0/24 202.38.140.0/22 202.38.146.0/23 202.38.149.0/24 202.38.150.0/23 202.38.152.0/22 202.38.156.0/24 202.38.158.0/23 202.38.160.0/23 202.38.164.0/22 202.38.168.0/22 202.38.176.0/23 202.38.184.0/21 202.38.192.0/18 202.40.4.0/23 202.40.7.0/24 202.40.15.0/24 202.40.135.0/24 202.40.136.0/24 202.40.140.0/24 202.40.143.0/24 202.40.144.0/23 202.40.150.0/24 202.40.155.0/24 202.40.156.0/24 202.40.158.0/23 202.40.162.0/24 202.41.8.0/23 202.41.11.0/24 202.41.12.0/23 202.41.128.0/24 202.41.130.0/23 202.41.142.0/24 202.41.152.0/21 202.41.192.0/24 202.41.196.0/22 202.41.200.0/22 202.41.240.0/20 202.43.76.0/22 202.43.144.0/20 202.44.16.0/20 202.44.48.0/22 202.44.67.0/24 202.44.74.0/24 202.44.97.0/24 202.44.129.0/24 202.44.132.0/23 202.44.146.0/23 202.45.0.0/23 202.45.2.0/24 202.45.15.0/24 202.45.16.0/20 202.46.16.0/23 202.46.18.0/24 202.46.20.0/23 202.46.128.0/24 202.46.224.0/20 202.47.82.0/23 202.47.96.0/20 202.47.126.0/24 202.47.128.0/24 202.47.130.0/23 202.52.34.0/24 202.52.143.0/24 202.53.140.0/24 202.53.143.0/24 202.57.212.0/22 202.57.216.0/22 202.57.240.0/20 202.58.0.0/24 202.58.112.0/22 202.59.0.0/23 202.59.212.0/22 202.59.236.0/24 202.59.240.0/24 202.60.48.0/21 202.60.96.0/21 202.60.112.0/20 202.60.132.0/22 202.60.136.0/21 202.60.144.0/20 202.61.68.0/22 202.61.76.0/22 202.61.88.0/22 202.61.123.0/24 202.61.127.0/24 202.62.112.0/22 202.62.248.0/22 202.62.252.0/24 202.62.255.0/24 202.63.80.0/20 202.63.160.0/19 202.63.248.0/22 202.63.253.0/24 202.65.0.0/21 202.65.8.0/23 202.67.0.0/22 202.69.4.0/23 202.69.16.0/20 202.70.0.0/19 202.70.96.0/20 202.70.192.0/20 202.71.32.0/20 202.72.40.0/21 202.72.80.0/20 202.72.112.0/20 202.73.128.0/22 202.73.240.0/20 202.74.8.0/21 202.74.36.0/24 202.74.42.0/24 202.74.52.0/24 202.74.80.0/20 202.74.254.0/23 202.75.208.0/20 202.75.252.0/22 202.76.247.0/24 202.76.252.0/22 202.77.80.0/21 202.77.92.0/22 202.78.8.0/21 202.79.224.0/21 202.79.248.0/22 202.80.192.0/20 202.81.0.0/22 202.81.176.0/20 202.83.252.0/22 202.84.4.0/22 202.84.8.0/21 202.84.16.0/23 202.84.22.0/24 202.84.24.0/21 202.85.208.0/20 202.86.249.0/24 202.87.80.0/20 202.88.32.0/22 202.89.8.0/21 202.89.96.0/22 202.89.108.0/22 202.89.119.0/24 202.89.232.0/21 202.90.0.0/22 202.90.16.0/20 202.90.37.0/24 202.90.96.0/19 202.90.193.0/24 202.90.196.0/24 202.90.205.0/24 202.90.224.0/20 202.91.0.0/22 202.91.96.0/20 202.91.128.0/22 202.91.176.0/20 202.91.224.0/19 202.92.0.0/22 202.92.8.0/21 202.92.48.0/20 202.92.252.0/22 202.93.0.0/22 202.93.252.0/22 202.94.0.0/19 202.94.74.0/24 202.94.81.0/24 202.94.92.0/22 202.95.240.0/21 202.95.252.0/22 202.96.0.0/12 202.112.0.0/13 202.120.0.0/15 202.122.0.0/21 202.122.32.0/21 202.122.64.0/19 202.122.112.0/20 202.122.128.0/24 202.122.132.0/24 202.123.96.0/20 202.123.116.0/22 202.123.120.0/22 202.124.16.0/21 202.124.24.0/22 202.125.107.0/24 202.125.109.0/24 202.125.112.0/20 202.125.176.0/20 202.127.0.0/21 202.127.12.0/22 202.127.16.0/20 202.127.40.0/21 202.127.48.0/20 202.127.112.0/20 202.127.128.0/19 202.127.160.0/21 202.127.192.0/20 202.127.208.0/23 202.127.212.0/22 202.127.216.0/21 202.127.224.0/19 202.129.208.0/24 202.130.0.0/19 202.130.39.0/24 202.130.224.0/19 202.131.16.0/21 202.131.59.0/24 202.131.208.0/20 202.133.32.0/20 202.134.58.0/24 202.134.128.0/20 202.134.208.0/20 202.136.48.0/20 202.136.208.0/20 202.136.224.0/20 202.136.248.0/22 202.136.254.0/23 202.137.231.0/24 202.140.140.0/22 202.140.144.0/20 202.141.160.0/19 202.142.16.0/20 202.143.4.0/22 202.143.16.0/20 202.143.32.0/20 202.143.56.0/21 202.143.100.0/22 202.143.104.0/22 202.146.160.0/20 202.146.186.0/24 202.146.188.0/22 202.146.196.0/22 202.146.200.0/21 202.147.144.0/20 202.148.32.0/20 202.148.64.0/18 202.149.32.0/19 202.149.160.0/19 202.149.224.0/19 202.150.16.0/20 202.150.32.0/20 202.150.56.0/22 202.150.192.0/20 202.150.224.0/19 202.151.0.0/22 202.151.128.0/19 202.152.176.0/20 202.153.0.0/22 202.153.7.0/24 202.153.48.0/20 202.157.192.0/19 202.158.160.0/19 202.158.242.0/24 202.160.140.0/22 202.160.156.0/22 202.160.176.64/26 202.160.176.128/25 202.160.177.0/24 202.160.178.0/23 202.160.180.0/22 202.160.184.0/21 202.162.67.0/24 202.162.75.0/24 202.164.0.0/20 202.164.96.0/19 202.165.176.0/20 202.165.208.0/20 202.165.239.0/24 202.165.240.0/23 202.165.243.0/24 202.165.245.0/24 202.165.251.0/24 202.165.252.0/22 202.166.224.0/19 202.168.80.0/22 202.168.128.0/20 202.168.160.0/19 202.170.128.0/19 202.170.216.0/21 202.170.224.0/19 202.171.216.0/21 202.171.232.0/24 202.171.235.0/24 202.172.0.0/22 202.172.7.0/24 202.173.0.0/22 202.173.6.0/24 202.173.8.0/21 202.173.112.0/22 202.173.224.0/19 202.174.64.0/20 202.174.124.0/22 202.176.224.0/19 202.179.160.0/20 202.179.240.0/20 202.180.128.0/19 202.180.208.0/21 202.181.8.0/22 202.181.28.0/22 202.181.112.0/20 202.182.32.0/20 202.182.192.0/19 202.189.0.0/18 202.189.80.0/20 202.189.184.0/21 202.191.0.0/24 202.191.68.0/22 202.191.72.0/21 202.191.80.0/20 202.192.0.0/12 203.0.4.0/22 203.0.10.0/23 203.0.18.0/24 203.0.24.0/24 203.0.42.0/23 203.0.45.0/24 203.0.46.0/23 203.0.81.0/24 203.0.82.0/23 203.0.90.0/23 203.0.96.0/23 203.0.104.0/21 203.0.114.0/23 203.0.122.0/24 203.0.128.0/24 203.0.130.0/23 203.0.132.0/22 203.0.137.0/24 203.0.142.0/24 203.0.144.0/24 203.0.146.0/24 203.0.148.0/24 203.0.150.0/23 203.0.152.0/24 203.0.177.0/24 203.0.224.0/24 203.1.4.0/22 203.1.18.0/24 203.1.26.0/23 203.1.65.0/24 203.1.66.0/23 203.1.70.0/23 203.1.76.0/23 203.1.90.0/24 203.1.97.0/24 203.1.98.0/23 203.1.100.0/22 203.1.108.0/24 203.1.253.0/24 203.1.254.0/24 203.2.64.0/21 203.2.73.0/24 203.2.112.0/21 203.2.126.0/23 203.2.140.0/24 203.2.150.0/24 203.2.152.0/22 203.2.156.0/23 203.2.160.0/21 203.2.180.0/23 203.2.196.0/23 203.2.209.0/24 203.2.214.0/23 203.2.226.0/23 203.2.229.0/24 203.2.236.0/23 203.3.68.0/24 203.3.72.0/23 203.3.75.0/24 203.3.80.0/21 203.3.96.0/22 203.3.105.0/24 203.3.112.0/21 203.3.120.0/24 203.3.123.0/24 203.3.135.0/24 203.3.139.0/24 203.3.143.0/24 203.4.132.0/23 203.4.134.0/24 203.4.151.0/24 203.4.152.0/22 203.4.174.0/23 203.4.180.0/24 203.4.186.0/24 203.4.205.0/24 203.4.208.0/22 203.4.227.0/24 203.4.230.0/23 203.5.4.0/23 203.5.7.0/24 203.5.8.0/23 203.5.11.0/24 203.5.21.0/24 203.5.22.0/24 203.5.44.0/24 203.5.46.0/23 203.5.52.0/22 203.5.56.0/23 203.5.60.0/23 203.5.114.0/23 203.5.118.0/24 203.5.120.0/24 203.5.172.0/24 203.5.180.0/23 203.5.182.0/24 203.5.185.0/24 203.5.186.0/24 203.5.188.0/23 203.5.190.0/24 203.5.195.0/24 203.5.214.0/23 203.5.218.0/23 203.6.131.0/24 203.6.136.0/24 203.6.138.0/23 203.6.142.0/24 203.6.150.0/23 203.6.157.0/24 203.6.159.0/24 203.6.224.0/20 203.6.248.0/23 203.7.129.0/24 203.7.138.0/23 203.7.147.0/24 203.7.150.0/23 203.7.158.0/24 203.7.192.0/23 203.7.200.0/24 203.8.0.0/24 203.8.8.0/24 203.8.23.0/24 203.8.70.0/24 203.8.82.0/24 203.8.86.0/23 203.8.91.0/24 203.8.110.0/23 203.8.115.0/24 203.8.166.0/23 203.8.169.0/24 203.8.173.0/24 203.8.184.0/24 203.8.186.0/23 203.8.190.0/23 203.8.192.0/24 203.8.197.0/24 203.8.198.0/23 203.8.203.0/24 203.8.209.0/24 203.8.210.0/23 203.8.212.0/22 203.8.217.0/24 203.8.220.0/24 203.9.32.0/24 203.9.36.0/23 203.9.57.0/24 203.9.63.0/24 203.9.65.0/24 203.9.70.0/23 203.9.72.0/24 203.9.75.0/24 203.9.76.0/23 203.9.96.0/22 203.9.100.0/23 203.9.108.0/24 203.9.158.0/24 203.10.34.0/24 203.10.56.0/24 203.10.74.0/23 203.10.84.0/22 203.10.88.0/24 203.10.95.0/24 203.10.125.0/24 203.11.70.0/24 203.11.76.0/22 203.11.82.0/24 203.11.84.0/22 203.11.100.0/22 203.11.109.0/24 203.11.117.0/24 203.11.122.0/24 203.11.126.0/24 203.11.136.0/22 203.11.141.0/24 203.11.142.0/23 203.11.180.0/22 203.11.208.0/22 203.12.16.0/24 203.12.19.0/24 203.12.24.0/24 203.12.57.0/24 203.12.65.0/24 203.12.66.0/24 203.12.70.0/23 203.12.87.0/24 203.12.100.0/23 203.12.103.0/24 203.12.114.0/24 203.12.118.0/24 203.12.130.0/24 203.12.137.0/24 203.12.196.0/22 203.12.211.0/24 203.12.219.0/24 203.12.226.0/24 203.12.240.0/22 203.13.18.0/24 203.13.24.0/24 203.13.44.0/23 203.13.88.0/23 203.13.92.0/22 203.13.173.0/24 203.13.224.0/23 203.13.227.0/24 203.13.233.0/24 203.14.24.0/22 203.14.33.0/24 203.14.56.0/24 203.14.61.0/24 203.14.62.0/24 203.14.104.0/24 203.14.114.0/23 203.14.118.0/24 203.14.162.0/24 203.14.184.0/21 203.14.192.0/24 203.14.194.0/23 203.14.214.0/24 203.14.231.0/24 203.14.246.0/24 203.15.0.0/20 203.15.20.0/23 203.15.22.0/24 203.15.87.0/24 203.15.88.0/23 203.15.105.0/24 203.15.112.0/21 203.15.130.0/23 203.15.149.0/24 203.15.151.0/24 203.15.156.0/22 203.15.174.0/24 203.15.227.0/24 203.15.232.0/22 203.15.238.0/23 203.15.240.0/23 203.15.246.0/24 203.16.10.0/24 203.16.12.0/23 203.16.16.0/21 203.16.27.0/24 203.16.38.0/24 203.16.49.0/24 203.16.50.0/23 203.16.58.0/24 203.16.63.0/24 203.16.133.0/24 203.16.161.0/24 203.16.162.0/24 203.16.186.0/23 203.16.228.0/24 203.16.238.0/24 203.16.240.0/24 203.16.245.0/24 203.17.2.0/24 203.17.18.0/24 203.17.28.0/24 203.17.39.0/24 203.17.56.0/24 203.17.74.0/23 203.17.88.0/23 203.17.136.0/24 203.17.164.0/24 203.17.187.0/24 203.17.190.0/23 203.17.231.0/24 203.17.233.0/24 203.17.248.0/23 203.17.255.0/24 203.18.2.0/23 203.18.4.0/24 203.18.7.0/24 203.18.31.0/24 203.18.37.0/24 203.18.48.0/23 203.18.52.0/24 203.18.72.0/22 203.18.80.0/23 203.18.87.0/24 203.18.100.0/23 203.18.105.0/24 203.18.107.0/24 203.18.110.0/24 203.18.129.0/24 203.18.131.0/24 203.18.132.0/23 203.18.144.0/24 203.18.153.0/24 203.18.199.0/24 203.18.208.0/24 203.18.211.0/24 203.18.215.0/24 203.19.1.0/24 203.19.18.0/24 203.19.24.0/24 203.19.30.0/24 203.19.41.0/24 203.19.44.0/23 203.19.46.0/24 203.19.58.0/24 203.19.60.0/23 203.19.64.0/24 203.19.68.0/24 203.19.72.0/24 203.19.101.0/24 203.19.111.0/24 203.19.131.0/24 203.19.133.0/24 203.19.144.0/24 203.19.147.0/24 203.19.149.0/24 203.19.156.0/24 203.19.176.0/24 203.19.178.0/23 203.19.208.0/24 203.19.228.0/22 203.19.233.0/24 203.19.242.0/24 203.19.248.0/23 203.19.255.0/24 203.20.17.0/24 203.20.40.0/23 203.20.44.0/24 203.20.48.0/24 203.20.61.0/24 203.20.65.0/24 203.20.84.0/23 203.20.89.0/24 203.20.106.0/23 203.20.115.0/24 203.20.117.0/24 203.20.118.0/23 203.20.122.0/24 203.20.126.0/23 203.20.135.0/24 203.20.140.0/22 203.20.150.0/24 203.20.230.0/24 203.20.232.0/24 203.20.236.0/24 203.21.0.0/23 203.21.2.0/24 203.21.8.0/24 203.21.10.0/24 203.21.18.0/24 203.21.33.0/24 203.21.34.0/24 203.21.41.0/24 203.21.44.0/24 203.21.68.0/24 203.21.82.0/24 203.21.96.0/22 203.21.124.0/24 203.21.136.0/23 203.21.145.0/24 203.21.206.0/24 203.22.24.0/24 203.22.28.0/23 203.22.31.0/24 203.22.68.0/24 203.22.76.0/24 203.22.78.0/24 203.22.84.0/24 203.22.87.0/24 203.22.92.0/22 203.22.99.0/24 203.22.106.0/24 203.22.122.0/23 203.22.131.0/24 203.22.163.0/24 203.22.166.0/24 203.22.170.0/24 203.22.194.0/24 203.22.242.0/23 203.22.245.0/24 203.22.246.0/24 203.22.252.0/23 203.23.0.0/24 203.23.47.0/24 203.23.61.0/24 203.23.62.0/23 203.23.73.0/24 203.23.85.0/24 203.23.92.0/22 203.23.98.0/24 203.23.107.0/24 203.23.112.0/24 203.23.130.0/24 203.23.140.0/23 203.23.172.0/24 203.23.182.0/24 203.23.186.0/23 203.23.192.0/24 203.23.197.0/24 203.23.198.0/24 203.23.204.0/22 203.23.224.0/24 203.23.226.0/23 203.23.228.0/22 203.23.249.0/24 203.23.251.0/24 203.24.13.0/24 203.24.18.0/24 203.24.27.0/24 203.24.43.0/24 203.24.56.0/24 203.24.58.0/24 203.24.67.0/24 203.24.74.0/24 203.24.79.0/24 203.24.80.0/23 203.24.84.0/23 203.24.86.0/24 203.24.90.0/24 203.24.111.0/24 203.24.112.0/24 203.24.116.0/24 203.24.122.0/23 203.24.145.0/24 203.24.152.0/23 203.24.157.0/24 203.24.161.0/24 203.24.167.0/24 203.24.186.0/23 203.24.199.0/24 203.24.202.0/24 203.24.212.0/23 203.24.217.0/24 203.24.219.0/24 203.24.244.0/24 203.25.19.0/24 203.25.20.0/23 203.25.46.0/24 203.25.64.0/23 203.25.91.0/24 203.25.99.0/24 203.25.100.0/24 203.25.106.0/24 203.25.131.0/24 203.25.135.0/24 203.25.138.0/24 203.25.147.0/24 203.25.153.0/24 203.25.154.0/23 203.25.164.0/24 203.25.166.0/24 203.25.174.0/23 203.25.180.0/24 203.25.182.0/24 203.25.191.0/24 203.25.199.0/24 203.25.200.0/24 203.25.202.0/23 203.25.208.0/20 203.25.229.0/24 203.25.235.0/24 203.25.236.0/24 203.25.242.0/24 203.26.12.0/24 203.26.34.0/24 203.26.49.0/24 203.26.50.0/24 203.26.55.0/24 203.26.56.0/23 203.26.60.0/24 203.26.65.0/24 203.26.68.0/24 203.26.76.0/24 203.26.80.0/24 203.26.84.0/24 203.26.97.0/24 203.26.102.0/23 203.26.115.0/24 203.26.116.0/24 203.26.129.0/24 203.26.143.0/24 203.26.144.0/24 203.26.148.0/23 203.26.154.0/24 203.26.158.0/23 203.26.170.0/24 203.26.173.0/24 203.26.176.0/24 203.26.185.0/24 203.26.202.0/23 203.26.210.0/24 203.26.214.0/24 203.26.222.0/24 203.26.224.0/24 203.26.228.0/24 203.26.232.0/24 203.27.0.0/24 203.27.10.0/24 203.27.15.0/24 203.27.16.0/24 203.27.20.0/24 203.27.22.0/23 203.27.40.0/24 203.27.45.0/24 203.27.53.0/24 203.27.65.0/24 203.27.66.0/24 203.27.81.0/24 203.27.88.0/24 203.27.102.0/24 203.27.109.0/24 203.27.117.0/24 203.27.121.0/24 203.27.122.0/23 203.27.125.0/24 203.27.200.0/24 203.27.202.0/24 203.27.233.0/24 203.27.241.0/24 203.27.250.0/24 203.28.10.0/24 203.28.12.0/24 203.28.33.0/24 203.28.34.0/23 203.28.43.0/24 203.28.44.0/24 203.28.54.0/24 203.28.56.0/24 203.28.73.0/24 203.28.74.0/24 203.28.76.0/24 203.28.86.0/24 203.28.88.0/24 203.28.112.0/24 203.28.131.0/24 203.28.136.0/24 203.28.140.0/24 203.28.145.0/24 203.28.165.0/24 203.28.169.0/24 203.28.170.0/24 203.28.178.0/23 203.28.185.0/24 203.28.187.0/24 203.28.196.0/24 203.28.226.0/23 203.28.239.0/24 203.29.2.0/24 203.29.8.0/23 203.29.13.0/24 203.29.14.0/24 203.29.28.0/24 203.29.46.0/24 203.29.57.0/24 203.29.61.0/24 203.29.63.0/24 203.29.69.0/24 203.29.73.0/24 203.29.81.0/24 203.29.90.0/24 203.29.95.0/24 203.29.100.0/24 203.29.103.0/24 203.29.112.0/24 203.29.120.0/22 203.29.182.0/23 203.29.187.0/24 203.29.189.0/24 203.29.190.0/24 203.29.205.0/24 203.29.210.0/24 203.29.217.0/24 203.29.227.0/24 203.29.231.0/24 203.29.233.0/24 203.29.234.0/24 203.29.248.0/24 203.29.254.0/23 203.30.16.0/23 203.30.25.0/24 203.30.27.0/24 203.30.29.0/24 203.30.66.0/24 203.30.81.0/24 203.30.87.0/24 203.30.111.0/24 203.30.121.0/24 203.30.123.0/24 203.30.152.0/24 203.30.156.0/24 203.30.162.0/24 203.30.173.0/24 203.30.175.0/24 203.30.187.0/24 203.30.194.0/24 203.30.217.0/24 203.30.220.0/24 203.30.222.0/24 203.30.232.0/23 203.30.235.0/24 203.30.240.0/23 203.30.246.0/24 203.30.250.0/23 203.31.45.0/24 203.31.46.0/24 203.31.49.0/24 203.31.51.0/24 203.31.54.0/23 203.31.69.0/24 203.31.72.0/24 203.31.80.0/24 203.31.85.0/24 203.31.97.0/24 203.31.105.0/24 203.31.106.0/24 203.31.108.0/23 203.31.124.0/24 203.31.162.0/24 203.31.174.0/24 203.31.177.0/24 203.31.181.0/24 203.31.187.0/24 203.31.189.0/24 203.31.204.0/24 203.31.220.0/24 203.31.222.0/23 203.31.225.0/24 203.31.229.0/24 203.31.248.0/23 203.31.253.0/24 203.32.20.0/24 203.32.48.0/23 203.32.56.0/24 203.32.60.0/24 203.32.62.0/24 203.32.68.0/23 203.32.76.0/24 203.32.81.0/24 203.32.84.0/23 203.32.95.0/24 203.32.102.0/24 203.32.105.0/24 203.32.130.0/24 203.32.133.0/24 203.32.140.0/24 203.32.152.0/24 203.32.186.0/23 203.32.192.0/24 203.32.196.0/24 203.32.203.0/24 203.32.204.0/23 203.32.212.0/24 203.33.4.0/24 203.33.7.0/24 203.33.12.0/23 203.33.21.0/24 203.33.26.0/24 203.33.32.0/24 203.33.63.0/24 203.33.64.0/24 203.33.67.0/24 203.33.68.0/24 203.33.73.0/24 203.33.79.0/24 203.33.100.0/24 203.33.122.0/24 203.33.129.0/24 203.33.131.0/24 203.33.145.0/24 203.33.156.0/24 203.33.158.0/23 203.33.174.0/24 203.33.185.0/24 203.33.200.0/24 203.33.202.0/23 203.33.204.0/24 203.33.206.0/23 203.33.214.0/23 203.33.224.0/23 203.33.226.0/24 203.33.233.0/24 203.33.243.0/24 203.33.250.0/24 203.34.4.0/24 203.34.21.0/24 203.34.27.0/24 203.34.39.0/24 203.34.48.0/23 203.34.54.0/24 203.34.56.0/23 203.34.67.0/24 203.34.69.0/24 203.34.76.0/24 203.34.92.0/24 203.34.106.0/24 203.34.113.0/24 203.34.147.0/24 203.34.150.0/24 203.34.152.0/23 203.34.161.0/24 203.34.162.0/24 203.34.187.0/24 203.34.198.0/24 203.34.204.0/22 203.34.232.0/24 203.34.240.0/24 203.34.242.0/24 203.34.245.0/24 203.34.251.0/24 203.55.2.0/23 203.55.4.0/24 203.55.10.0/24 203.55.13.0/24 203.55.22.0/24 203.55.30.0/24 203.55.93.0/24 203.55.101.0/24 203.55.109.0/24 203.55.110.0/24 203.55.116.0/23 203.55.119.0/24 203.55.128.0/23 203.55.146.0/23 203.55.192.0/24 203.55.196.0/24 203.55.218.0/23 203.55.221.0/24 203.55.224.0/24 203.56.1.0/24 203.56.4.0/24 203.56.12.0/24 203.56.24.0/24 203.56.38.0/24 203.56.40.0/24 203.56.46.0/24 203.56.68.0/23 203.56.82.0/23 203.56.84.0/23 203.56.95.0/24 203.56.110.0/24 203.56.121.0/24 203.56.161.0/24 203.56.169.0/24 203.56.172.0/23 203.56.175.0/24 203.56.183.0/24 203.56.185.0/24 203.56.187.0/24 203.56.192.0/24 203.56.198.0/24 203.56.201.0/24 203.56.208.0/23 203.56.210.0/24 203.56.214.0/24 203.56.216.0/24 203.56.227.0/24 203.56.228.0/24 203.56.232.0/24 203.56.240.0/24 203.56.252.0/24 203.56.254.0/24 203.57.5.0/24 203.57.6.0/24 203.57.12.0/23 203.57.28.0/24 203.57.39.0/24 203.57.46.0/24 203.57.58.0/24 203.57.61.0/24 203.57.66.0/24 203.57.69.0/24 203.57.70.0/23 203.57.73.0/24 203.57.90.0/24 203.57.101.0/24 203.57.109.0/24 203.57.123.0/24 203.57.157.0/24 203.57.200.0/24 203.57.202.0/24 203.57.206.0/24 203.57.222.0/24 203.57.224.0/20 203.57.246.0/23 203.57.249.0/24 203.57.253.0/24 203.57.254.0/23 203.62.2.0/24 203.62.131.0/24 203.62.139.0/24 203.62.161.0/24 203.62.197.0/24 203.62.228.0/22 203.62.234.0/24 203.62.246.0/24 203.65.240.0/22 203.76.160.0/22 203.76.168.0/22 203.76.208.0/21 203.76.216.0/22 203.76.240.0/22 203.77.180.0/22 203.78.48.0/20 203.78.156.0/22 203.79.0.0/20 203.80.4.0/23 203.80.32.0/20 203.80.57.0/24 203.80.129.0/24 203.80.132.0/22 203.80.144.0/20 203.81.16.0/20 203.81.244.0/22 203.82.0.0/23 203.82.112.0/20 203.82.224.0/20 203.83.0.0/22 203.83.12.0/22 203.83.56.0/21 203.83.224.0/20 203.86.0.0/17 203.86.250.0/24 203.86.254.0/23 203.88.32.0/19 203.88.100.0/22 203.88.192.0/19 203.89.0.0/22 203.89.136.0/22 203.89.144.0/24 203.90.0.0/22 203.90.8.0/21 203.90.128.0/18 203.90.192.0/19 203.91.32.0/19 203.91.96.0/20 203.91.120.0/21 203.92.0.0/22 203.92.6.0/24 203.92.160.0/19 203.93.0.0/16 203.94.0.0/19 203.95.0.0/21 203.95.96.0/19 203.95.129.0/24 203.95.130.0/23 203.95.132.0/22 203.95.136.0/21 203.95.144.0/20 203.95.160.0/19 203.95.200.0/21 203.95.208.0/22 203.95.224.0/19 203.99.16.0/22 203.99.30.0/23 203.99.80.0/20 203.100.32.0/20 203.100.58.0/24 203.100.60.0/24 203.100.63.0/24 203.100.80.0/20 203.100.96.0/19 203.100.192.0/20 203.104.32.0/20 203.105.96.0/19 203.105.128.0/19 203.107.0.0/19 203.107.32.0/20 203.107.52.0/22 203.107.56.0/21 203.107.69.0/24 203.107.70.0/23 203.107.72.0/21 203.107.80.0/20 203.107.96.0/19 203.110.160.0/19 203.110.208.0/20 203.110.232.0/23 203.110.234.0/24 203.114.80.0/20 203.114.244.0/22 203.118.192.0/19 203.118.241.0/24 203.118.248.0/22 203.119.24.0/22 203.119.28.0/23 203.119.30.0/24 203.119.32.0/24 203.119.34.0/23 203.119.80.0/22 203.119.85.0/24 203.119.113.0/24 203.119.114.0/23 203.119.116.0/22 203.119.128.0/17 203.123.58.0/24 203.128.32.0/19 203.128.96.0/19 203.128.128.0/24 203.130.32.0/20 203.130.49.0/24 203.130.51.0/24 203.130.53.0/24 203.130.54.0/23 203.130.56.0/22 203.130.60.0/23 203.132.32.0/19 203.134.240.0/22 203.134.246.0/23 203.135.96.0/19 203.135.160.0/20 203.142.12.0/23 203.142.219.0/24 203.142.224.0/19 203.144.96.0/19 203.145.0.0/19 203.148.0.0/18 203.148.64.0/20 203.148.80.0/22 203.148.86.0/23 203.149.92.0/22 203.152.64.0/19 203.152.128.0/19 203.153.0.0/22 203.156.192.0/18 203.158.16.0/21 203.160.129.0/24 203.160.192.0/19 203.161.0.0/22 203.161.180.0/24 203.161.183.0/24 203.161.192.0/19 203.166.160.0/19 203.167.28.0/22 203.168.0.0/19 203.170.58.0/23 203.171.0.0/22 203.171.208.0/24 203.171.224.0/20 203.174.4.0/24 203.174.6.0/24 203.174.96.0/20 203.175.128.0/19 203.175.192.0/18 203.176.0.0/18 203.176.64.0/19 203.176.168.0/21 203.184.80.0/20 203.187.160.0/19 203.189.0.0/23 203.189.6.0/23 203.189.112.0/22 203.189.192.0/19 203.189.240.0/22 203.190.96.0/20 203.190.249.0/24 203.191.0.0/23 203.191.2.0/24 203.191.5.0/24 203.191.7.0/24 203.191.29.0/24 203.191.31.0/24 203.191.64.0/18 203.191.133.0/24 203.191.144.0/20 203.192.0.0/19 203.193.224.0/19 203.195.64.0/19 203.195.128.0/17 203.196.0.0/21 203.196.28.0/22 203.201.181.0/24 203.201.182.0/24 203.202.236.0/22 203.205.64.0/19 203.207.64.0/18 203.207.128.0/17 203.208.0.0/20 203.208.16.0/22 203.208.32.0/19 203.209.224.0/19 203.212.0.0/20 203.212.80.0/20 203.217.164.0/22 203.223.0.0/20 204.55.160.0/24 204.74.96.0/24 204.114.176.0/23 210.2.0.0/23 210.2.2.0/24 210.2.5.0/24 210.2.6.0/23 210.2.8.0/21 210.2.24.0/21 210.5.0.0/19 210.5.60.0/24 210.5.128.0/19 210.7.56.0/21 210.12.0.0/15 210.14.64.0/19 210.14.112.0/20 210.14.128.0/17 210.15.0.0/17 210.15.128.0/18 210.16.128.0/21 210.16.136.0/22 210.16.156.0/22 210.16.160.0/24 210.16.162.0/23 210.16.164.0/22 210.16.168.0/21 210.16.176.0/20 210.21.0.0/16 210.22.0.0/16 210.23.32.0/19 210.25.0.0/17 210.25.128.0/19 210.25.160.0/20 210.25.176.0/21 210.25.184.0/23 210.25.186.0/26 210.25.186.128/25 210.25.187.0/24 210.25.188.0/22 210.25.192.0/18 210.26.0.0/15 210.28.0.0/14 210.32.0.0/12 210.51.0.0/16 210.52.0.0/18 210.52.64.0/23 210.52.66.0/24 210.52.69.0/24 210.52.70.0/23 210.52.72.0/21 210.52.80.0/20 210.52.96.0/21 210.52.104.0/22 210.52.108.0/24 210.52.110.0/23 210.52.112.0/20 210.52.128.0/17 210.53.0.0/16 210.56.192.0/19 210.72.0.0/14 210.76.0.0/15 210.78.0.0/16 210.79.64.0/18 210.79.224.0/19 210.82.0.0/15 210.87.128.0/18 210.185.192.0/18 210.192.96.0/19 211.64.0.0/13 211.80.0.0/12 211.96.0.0/14 211.100.0.0/17 211.100.128.0/19 211.100.160.0/20 211.100.184.0/21 211.100.192.0/18 211.101.0.0/16 211.102.0.0/15 211.136.0.0/13 211.144.0.0/13 211.152.0.0/17 211.152.134.0/23 211.152.140.0/22 211.152.150.0/23 211.152.157.0/24 211.152.160.0/19 211.152.192.0/18 211.153.0.0/16 211.154.0.0/19 211.154.32.0/20 211.154.48.0/21 211.154.64.0/18 211.154.128.0/17 211.155.0.0/18 211.155.67.0/24 211.155.68.0/24 211.155.72.0/21 211.155.80.0/20 211.155.97.0/24 211.155.98.0/23 211.155.100.0/22 211.155.104.0/21 211.155.113.0/24 211.155.116.0/22 211.155.120.0/21 211.155.128.0/17 211.156.0.0/18 211.156.64.0/19 211.156.96.0/21 211.156.104.0/22 211.156.108.0/23 211.156.112.0/20 211.156.128.0/17 211.157.0.0/16 211.158.0.0/15 211.160.0.0/13 212.64.0.0/17 212.129.128.0/17 213.199.169.0/24 213.255.230.0/23 218.0.0.0/12 218.16.0.0/13 218.24.0.0/14 218.28.0.0/15 218.30.0.0/19 218.30.64.0/18 218.30.128.0/17 218.31.0.0/16 218.56.0.0/13 218.64.0.0/11 218.96.0.0/15 218.98.0.0/18 218.98.77.0/24 218.98.78.0/23 218.98.80.0/20 218.98.96.0/22 218.98.100.0/24 218.98.102.0/23 218.98.104.0/21 218.98.112.0/20 218.98.128.0/19 218.98.192.0/18 218.99.0.0/16 218.100.96.0/19 218.100.128.0/17 218.104.0.0/14 218.108.0.0/15 218.185.192.0/19 218.192.0.0/12 218.240.0.0/14 218.244.0.0/15 218.246.0.0/19 218.246.32.0/20 218.246.48.0/21 218.246.56.0/23 218.246.58.0/24 218.246.60.0/22 218.246.64.0/18 218.246.129.0/24 218.246.131.0/24 218.246.132.0/23 218.246.134.0/24 218.246.139.0/24 218.246.144.0/20 218.246.160.0/19 218.246.192.0/18 218.247.0.0/18 218.247.96.0/19 218.247.128.0/17 218.249.0.0/16 219.72.0.0/16 219.82.0.0/16 219.83.128.0/17 219.90.68.0/22 219.90.72.0/21 219.128.0.0/11 219.216.0.0/13 219.224.0.0/13 219.232.0.0/15 219.234.0.0/21 219.234.10.0/23 219.234.12.0/22 219.234.32.0/19 219.234.64.0/18 219.234.128.0/17 219.235.0.0/16 219.236.0.0/14 219.242.0.0/15 219.244.0.0/14 220.101.192.0/18 220.112.0.0/14 220.152.128.0/17 220.154.0.0/16 220.155.0.0/21 220.155.9.0/24 220.155.10.0/23 220.155.12.0/22 220.155.16.0/21 220.155.24.0/22 220.155.28.0/23 220.155.31.0/24 220.155.32.0/19 220.155.64.0/18 220.155.128.0/17 220.158.241.0/24 220.158.243.0/24 220.160.0.0/11 220.192.0.0/12 220.231.0.0/18 220.231.128.0/17 220.232.64.0/18 220.234.0.0/16 220.242.0.0/23 220.242.6.0/24 220.242.8.0/24 220.242.12.0/23 220.242.14.0/24 220.242.17.0/24 220.242.18.0/23 220.242.20.0/24 220.242.32.0/20 220.242.48.0/23 220.242.53.0/24 220.242.55.0/24 220.242.56.0/22 220.242.60.0/23 220.242.62.0/24 220.242.64.0/19 220.242.96.0/20 220.242.112.0/21 220.242.120.0/22 220.242.124.0/23 220.242.126.0/24 220.242.134.0/23 220.242.173.0/24 220.242.183.0/24 220.242.197.0/24 220.242.205.0/24 220.242.207.0/24 220.242.217.0/24 220.242.218.0/23 220.242.220.0/22 220.242.224.0/19 220.243.0.0/17 220.243.128.0/18 220.243.192.0/23 220.243.196.0/24 220.243.198.0/23 220.243.201.0/24 220.243.204.0/24 220.243.214.0/24 220.243.216.0/23 220.243.218.0/24 220.243.220.0/23 220.243.223.0/24 220.243.225.0/24 220.243.226.0/23 220.243.229.0/24 220.243.230.0/24 220.243.234.0/23 220.243.237.0/24 220.243.238.0/23 220.243.243.0/24 220.243.244.0/24 220.243.246.0/23 220.243.249.0/24 220.243.250.0/24 220.243.252.0/24 220.243.254.0/23 220.247.136.0/21 220.248.0.0/14 220.252.0.0/16 221.0.0.0/13 221.8.0.0/14 221.12.0.0/17 221.12.128.0/18 221.13.0.0/16 221.14.0.0/15 221.122.0.0/15 221.128.128.0/17 221.129.0.0/16 221.130.0.0/15 221.133.224.0/19 221.136.0.0/15 221.172.0.0/14 221.176.0.0/19 221.176.32.0/20 221.176.48.0/21 221.176.56.0/24 221.176.58.0/23 221.176.60.0/22 221.176.64.0/18 221.176.128.0/17 221.177.0.0/16 221.178.0.0/15 221.180.0.0/14 221.192.0.0/14 221.196.0.0/15 221.198.0.0/16 221.199.0.0/17 221.199.128.0/18 221.199.192.0/20 221.199.224.0/19 221.200.0.0/13 221.208.0.0/12 221.224.0.0/12 222.16.0.0/12 222.32.0.0/11 222.64.0.0/11 222.125.0.0/16 222.126.128.0/19 222.126.160.0/21 222.126.168.0/22 222.126.172.0/23 222.126.174.40/29 222.126.174.76/30 222.126.174.88/29 222.126.174.144/28 222.126.178.0/23 222.126.180.0/22 222.126.184.0/21 222.126.192.0/21 222.126.200.104/29 222.126.206.0/23 222.126.208.0/22 222.126.212.0/26 222.126.212.64/27 222.126.212.96/28 222.126.212.112/29 222.126.212.128/25 222.126.213.0/24 222.126.214.0/23 222.126.216.0/21 222.126.224.0/19 222.128.0.0/12 222.160.0.0/14 222.168.0.0/13 222.176.0.0/12 222.192.0.0/11 222.240.0.0/13 222.248.0.0/15 223.0.0.0/12 223.20.0.0/15 223.27.184.0/22 223.29.208.0/22 223.64.0.0/11 223.96.0.0/12 223.112.0.0/14 223.116.0.0/15 223.120.0.0/13 223.128.0.0/15 223.144.0.0/12 223.160.0.0/14 223.166.0.0/15 223.192.0.0/15 223.198.0.0/15 223.201.0.0/22 223.201.8.0/21 223.201.16.0/20 223.201.32.0/19 223.201.64.0/18 223.201.128.0/17 223.202.0.0/15 223.208.0.0/13 223.220.0.0/15 223.223.176.0/20 223.223.192.0/20 223.240.0.0/13 223.248.0.0/14 223.252.128.0/19 223.252.192.0/18 223.254.0.0/16 223.255.0.0/17 223.255.236.0/22 223.255.252.0/23 2001:250::/35 2001:250:2000::/35 2001:250:4000::/34 2001:250:8000::/33 2001:251::/32 2001:252::/32 2001:253::/32 2001:254::/32 2001:255::/32 2001:256::/32 2001:7fa:5::/48 2001:7fa:10::/48 2001:c68::/32 2001:cc0::/32 2001:da8::/32 2001:da9::/32 2001:daa::/32 2001:dc7::/32 2001:dd8:1::/48 2001:dd8:5::/48 2001:dd8:1a::/48 2001:dd9::/48 2001:df0:27e::/48 2001:df0:423::/48 2001:df0:2180::/48 2001:df0:2d80::/48 2001:df0:2e00::/48 2001:df0:2e80::/48 2001:df0:4500::/48 2001:df0:9a00::/48 2001:df0:b180::/48 2001:df0:bf80::/48 2001:df0:d180::/48 2001:df0:d880::/48 2001:df1:c80::/48 2001:df1:4580::/48 2001:df1:5280::/48 2001:df1:5b80::/48 2001:df1:6180::/48 2001:df1:6b80::/48 2001:df1:8b00::/48 2001:df1:a100::/48 2001:df1:bd80::/48 2001:df1:c900::/48 2001:df1:d100::/48 2001:df1:d180::/48 2001:df1:da00::/48 2001:df1:f480::/48 2001:df1:f580::/48 2001:df1:fd80::/48 2001:df2:80::/48 2001:df2:180::/48 2001:df2:5200::/48 2001:df2:5780::/48 2001:df2:5a80::/48 2001:df2:a580::/48 2001:df3:1480::/48 2001:df3:2a80::/48 2001:df3:3a80::/48 2001:df3:a680::/48 2001:df3:b100::/48 2001:df3:b380::/48 2001:df3:c380::/48 2001:df3:c680::/48 2001:df3:d880::/48 2001:df3:ed80::/48 2001:df3:ef80::/48 2001:df4:80::/48 2001:df4:880::/48 2001:df4:d80::/48 2001:df4:1280::/48 2001:df4:1500::/48 2001:df4:1880::/48 2001:df4:2780::/48 2001:df4:2e80::/48 2001:df4:2f00::/48 2001:df4:3c80::/48 2001:df4:3d80::/48 2001:df4:4b80::/48 2001:df4:4d80::/48 2001:df4:a680::/48 2001:df4:a980::/48 2001:df4:c180::/48 2001:df4:c580::/48 2001:df4:c780::/48 2001:df4:cf00::/48 2001:df4:de80::/48 2001:df5:2080::/48 2001:df5:5f80::/48 2001:df5:7800::/48 2001:df6:100::/48 2001:df6:1c00::/48 2001:df6:3d00::/48 2001:df6:5d00::/48 2001:df6:6800::/48 2001:df6:9e80::/48 2001:df6:9f80::/48 2001:df6:df00::/48 2001:df6:f400::/48 2001:df7:1480::/48 2001:df7:2b80::/48 2001:df7:5900::/48 2001:df7:6600::/48 2001:df7:ab00::/48 2001:e08::/32 2001:e18::/32 2001:e80::/32 2001:e88::/32 2001:f38::/32 2001:f88::/32 2001:4438::/32 2001:4510::/29 2400:1040::/32 2400:12c0::/32 2400:1340::/32 2400:1380::/32 2400:15c0::/32 2400:1640::/32 2400:16c0::/32 2400:1740::/32 2400:17c0::/32 2400:1840::/32 2400:18c0::/32 2400:1940::/32 2400:19c0::/32 2400:1a40::/32 2400:1ac0::/32 2400:1b40::/32 2400:1cc0::/32 2400:1d40::/32 2400:1dc0::/32 2400:1e40::/32 2400:1ec0::/32 2400:1f40::/32 2400:1fc0::/32 2400:3040::/32 2400:3140::/32 2400:31c0::/32 2400:3200::/32 2400:3280::/32 2400:32c0::/32 2400:3340::/32 2400:33c0::/32 2400:3440::/32 2400:34c0::/32 2400:3540::/32 2400:35c0::/32 2400:3600::/32 2400:3640::/32 2400:36c0::/32 2400:38c0::/32 2400:39c0::/32 2400:3a00::/32 2400:3a40::/32 2400:3b40::/32 2400:3bc0::/32 2400:3c40::/32 2400:3cc0::/32 2400:3e00::/32 2400:3f40::/32 2400:3fc0::/32 2400:4440::/32 2400:44c0::/32 2400:4540::/32 2400:4600::/32 2400:4640::/32 2400:46c0::/32 2400:4740::/32 2400:4bc0::/32 2400:4e00::/32 2400:4e40::/32 2400:5080::/32 2400:5280::/32 2400:5400::/32 2400:5580::/32 2400:55c0::/32 2400:5600::/32 2400:5640::/32 2400:56c0::/32 2400:57c0::/32 2400:5840::/32 2400:5a00::/32 2400:5a40::/32 2400:5ac0::/32 2400:5b40::/32 2400:5bc0::/32 2400:5c40::/32 2400:5c80::/32 2400:5cc0::/32 2400:5e80::/32 2400:5fc0::/32 2400:6000::/32 2400:6040::/32 2400:60c0::/32 2400:61c0::/32 2400:6200::/32 2400:6600::/32 2400:6640::/32 2400:66c0::/32 2400:6740::/32 2400:67c0::/32 2400:6840::/32 2400:68c0::/32 2400:6940::/32 2400:69c0::/32 2400:6a00::/32 2400:6a40::/32 2400:6ac0::/32 2400:6b40::/32 2400:6bc0::/32 2400:6c40::/32 2400:6cc0::/32 2400:6d40::/32 2400:6dc0::/32 2400:6e00::/32 2400:6e40::/32 2400:6ec0::/32 2400:6f40::/32 2400:6f80::/32 2400:6fc0::/32 2400:7040::/32 2400:7100::/32 2400:7140::/32 2400:71c0::/32 2400:7200::/32 2400:7240::/32 2400:72c0::/32 2400:7340::/32 2400:73c0::/32 2400:7440::/32 2400:74c0::/32 2400:7540::/32 2400:75c0::/32 2400:7640::/32 2400:7680::/32 2400:76c0::/32 2400:7740::/32 2400:77c0::/32 2400:79c0::/32 2400:7ac0::/32 2400:7bc0::/32 2400:7f80::/32 2400:7fc0::/32 2400:8080::/32 2400:8200::/32 2400:82c0::/32 2400:8580::/32 2400:8600::/32 2400:8780::/32 2400:87c0::/32 2400:8840::/32 2400:8980::/32 2400:89c0::/32 2400:8e00::/32 2400:8f00::/32 2400:8fc0::/32 2400:9040::/32 2400:9340::/32 2400:9580::/32 2400:95c0::/32 2400:9600::/32 2400:98c0::/32 2400:9a00::/32 2400:9dc0::/32 2400:9e00::/32 2400:a040::/32 2400:a380::/32 2400:a480::/32 2400:a780::/32 2400:a8c0::/32 2400:a900::/32 2400:a980::/32 2400:a981::/32 2400:a982::/31 2400:a984::/30 2400:abc0::/32 2400:ae00::/32 2400:b200::/32 2400:b2c0::/32 2400:b500::/32 2400:b600::/32 2400:b6c0::/32 2400:b700::/32 2400:b8c0::/32 2400:b9c0::/32 2400:ba00::/32 2400:ba40::/32 2400:ba41::/32 2400:bac0::/32 2400:bc40::/32 2400:be00::/32 2400:bf00::/32 2400:c200::/32 2400:c380::/32 2400:c840::/32 2400:c8c0::/32 2400:c940::/32 2400:c9c0::/32 2400:ca40::/32 2400:cac0::/32 2400:cb40::/32 2400:cb80::/32 2400:cbc0::/32 2400:cc40::/32 2400:cc80::/32 2400:ccc0::/32 2400:cd40::/32 2400:cdc0::/32 2400:ce00::/32 2400:ce40::/32 2400:cf40::/32 2400:cf80::/32 2400:cfc0::/32 2400:d0c0::/32 2400:d100::/32 2400:d1c0::/32 2400:d200::/32 2400:d300::/32 2400:d440::/32 2400:d600::/32 2400:d6c0::/32 2400:d780::/32 2400:da00::/32 2400:dd00::/28 2400:dd40::/32 2400:de00::/32 2400:de80::/32 2400:e0c0::/32 2400:e5c0::/32 2400:e680::/32 2400:e880::/32 2400:ebc0::/32 2400:edc0::/32 2400:ee00::/32 2400:eec0::/32 2400:ef40::/32 2400:f480::/32 2400:f5c0::/32 2400:f7c0::/32 2400:f840::/32 2400:f980::/32 2400:fac0::/32 2400:fb40::/32 2400:fbc0::/32 2400:fc40::/32 2400:fcc0::/32 2400:fe00::/32 2401:80::/32 2401:140::/32 2401:1c0::/32 2401:540::/32 2401:7c0::/32 2401:800::/32 2401:9c0::/32 2401:a00::/32 2401:a40::/32 2401:ac0::/32 2401:b40::/32 2401:bc0::/32 2401:c40::/32 2401:cc0::/32 2401:d40::/32 2401:e00::/32 2401:1000::/32 2401:11c0::/32 2401:1200::/32 2401:12c0::/32 2401:15c0::/32 2401:1740::/32 2401:18c0::/32 2401:1940::/32 2401:19c0::/32 2401:1a40::/32 2401:1ac0::/32 2401:1d40::/32 2401:1dc0::/32 2401:1e00::/32 2401:1ec0::/32 2401:1f40::/32 2401:2040::/32 2401:2080::/32 2401:23c0::/32 2401:2600::/32 2401:2780::/32 2401:2980::/32 2401:2a00::/32 2401:2b40::/32 2401:2e00::/32 2401:3100::/32 2401:3380::/32 2401:33c0::/32 2401:3440::/32 2401:3480::/32 2401:34c0::/32 2401:3640::/32 2401:3780::/32 2401:3800::/32 2401:3880::/32 2401:3980::/32 2401:3a00::/32 2401:3a80::/32 2401:3b80::/32 2401:3c80::/32 2401:3d80::/32 2401:3e80::/32 2401:3f80::/32 2401:4080::/32 2401:4180::/32 2401:4280::/32 2401:4380::/32 2401:4480::/32 2401:4580::/32 2401:4680::/32 2401:4780::/32 2401:4880::/32 2401:4a80::/32 2401:4b00::/32 2401:4f80::/32 2401:5180::/32 2401:5680::/32 2401:56c0::/32 2401:59c0::/32 2401:5b40::/32 2401:5c80::/32 2401:7180::/32 2401:71c0::/32 2401:7240::/32 2401:7340::/32 2401:7580::/32 2401:7680::/32 2401:7700::/32 2401:7780::/32 2401:7880::/32 2401:7980::/32 2401:7a00::/32 2401:7a80::/32 2401:7b80::/32 2401:7bc0::/32 2401:7c80::/32 2401:7cc0::/32 2401:7d40::/32 2401:7d80::/32 2401:7e00::/32 2401:7f80::/32 2401:8200::/32 2401:82c0::/32 2401:8380::/32 2401:8540::/32 2401:8600::/32 2401:8680::/32 2401:8840::/32 2401:8d00::/32 2401:8e40::/32 2401:8f40::/32 2401:8fc0::/32 2401:9340::/32 2401:9600::/32 2401:96c0::/32 2401:9740::/32 2401:98c0::/32 2401:9a00::/32 2401:9ac0::/32 2401:9b40::/32 2401:9bc0::/32 2401:9dc0::/32 2401:9e40::/32 2401:9f80::/32 2401:a140::/32 2401:a180::/32 2401:a340::/32 2401:a3c0::/32 2401:a4c0::/32 2401:a540::/32 2401:a5c0::/32 2401:a640::/32 2401:a940::/32 2401:a980::/32 2401:aa00::/32 2401:aa40::/32 2401:acc0::/32 2401:ad40::/32 2401:adc0::/32 2401:b040::/32 2401:b180::/32 2401:b340::/32 2401:b400::/32 2401:b480::/32 2401:b4c0::/32 2401:b540::/32 2401:b580::/32 2401:b600::/32 2401:b680::/32 2401:b6c0::/32 2401:b7c0::/32 2401:b940::/32 2401:ba00::/32 2401:ba40::/32 2401:bb80::/32 2401:be00::/32 2401:c200::/32 2401:c540::/32 2401:c600::/32 2401:c640::/32 2401:c6c0::/32 2401:c840::/32 2401:c8c0::/32 2401:ca00::/32 2401:cb80::/32 2401:cc00::/32 2401:ce00::/32 2401:cf40::/32 2401:cfc0::/32 2401:d0c0::/32 2401:d140::/32 2401:d180::/32 2401:d2c0::/32 2401:d340::/32 2401:d780::/32 2401:da00::/32 2401:de00::/32 2401:e080::/32 2401:e0c0::/32 2401:e140::/32 2401:e240::/32 2401:e2c0::/32 2401:e340::/32 2401:e6c0::/32 2401:e840::/32 2401:e8c0::/32 2401:e940::/32 2401:e9c0::/32 2401:ec00::/32 2401:ec40::/32 2401:f300::/32 2401:f7c0::/32 2401:fa80::/32 2401:fac0::/32 2401:fb80::/32 2401:fc80::/32 2401:fe80::/32 2401:ffc0::/32 2402:440::/32 2402:5c0::/32 2402:840::/32 2402:ac0::/32 2402:e00::/32 2402:fc0::/32 2402:1000::/32 2402:1440::/32 2402:14c0::/32 2402:1540::/32 2402:1600::/32 2402:1740::/32 2402:19c0::/32 2402:1ec0::/32 2402:1f40::/32 2402:1f80::/32 2402:2000::/32 2402:2280::/32 2402:22c0::/32 2402:2440::/32 2402:24c0::/32 2402:2540::/32 2402:2640::/32 2402:27c0::/32 2402:2a00::/32 2402:2b80::/32 2402:2bc0::/32 2402:2d00::/32 2402:2d80::/32 2402:2e80::/32 2402:2f40::/32 2402:3040::/32 2402:3080::/32 2402:3140::/32 2402:3180::/32 2402:31c0::/32 2402:3240::/32 2402:33c0::/32 2402:39c0::/32 2402:3a40::/32 2402:3ac0::/32 2402:3c00::/32 2402:3e00::/32 2402:3ec0::/32 2402:3f40::/32 2402:3f80::/32 2402:4140::/32 2402:42c0::/32 2402:4340::/32 2402:43c0::/32 2402:4440::/32 2402:4500::/32 2402:4540::/32 2402:4a00::/32 2402:4a40::/32 2402:4a80::/32 2402:4ac0::/32 2402:4b80::/32 2402:4bc0::/32 2402:4c40::/32 2402:4d80::/32 2402:4e00::/32 2402:4ec0::/32 2402:4f80::/32 2402:50c0::/32 2402:5140::/32 2402:5180::/32 2402:51c0::/32 2402:5240::/32 2402:52c0::/32 2402:5340::/32 2402:5880::/32 2402:5940::/32 2402:59c0::/32 2402:5a40::/32 2402:5b40::/32 2402:5bc0::/32 2402:5d00::/32 2402:5e00::/32 2402:5e40::/32 2402:5ec0::/32 2402:5f40::/32 2402:6280::/32 2402:62c0::/32 2402:64c0::/32 2402:66c0::/32 2402:6740::/32 2402:67c0::/32 2402:6a00::/32 2402:6b40::/32 2402:6bc0::/32 2402:6e00::/32 2402:6e80::/32 2402:6ec0::/32 2402:6f40::/32 2402:6fc0::/32 2402:7040::/32 2402:7080::/32 2402:70c0::/32 2402:7140::/32 2402:71c0::/32 2402:7240::/32 2402:72c0::/32 2402:7540::/32 2402:75c0::/32 2402:7740::/32 2402:7d00::/32 2402:7d80::/32 2402:8180::/32 2402:8300::/32 2402:8380::/32 2402:85c0::/32 2402:8800::/32 2402:8840::/32 2402:8900::/32 2402:8940::/32 2402:89c0::/32 2402:8b40::/32 2402:8bc0::/32 2402:8cc0::/32 2402:8d40::/32 2402:8f40::/32 2402:8f80::/32 2402:9240::/32 2402:92c0::/32 2402:93c0::/32 2402:9440::/32 2402:9480::/32 2402:94c0::/32 2402:9580::/32 2402:95c0::/32 2402:9680::/32 2402:96c0::/32 2402:9840::/32 2402:98c0::/32 2402:9940::/32 2402:9a80::/32 2402:9b80::/32 2402:9f80::/32 2402:9fc0::/32 2402:a080::/32 2402:a180::/32 2402:a200::/32 2402:a240::/32 2402:a280::/32 2402:a380::/32 2402:a3c0::/32 2402:a640::/32 2402:a680::/32 2402:a6c0::/32 2402:a840::/32 2402:a880::/32 2402:a9c0::/32 2402:aa80::/32 2402:ab80::/32 2402:ae00::/32 2402:ae40::/32 2402:aec0::/32 2402:af80::/32 2402:afc0::/32 2402:b080::/32 2402:b200::/32 2402:b380::/32 2402:b3c0::/32 2402:b440::/32 2402:b6c0::/32 2402:b880::/32 2402:b8c0::/32 2402:b940::/32 2402:b980::/32 2402:ba80::/32 2402:bac0::/32 2402:bbc0::/32 2402:bf80::/32 2402:c280::/32 2402:c3c0::/32 2402:c5c0::/32 2402:c9c0::/32 2402:cbc0::/32 2402:cc40::/32 2402:cc80::/32 2402:cf00::/32 2402:cf40::/32 2402:d040::/32 2402:d140::/32 2402:d2c0::/32 2402:d300::/32 2402:d340::/32 2402:d380::/32 2402:d5c0::/32 2402:d6c0::/32 2402:d740::/32 2402:d780::/32 2402:d880::/32 2402:d980::/32 2402:da40::/32 2402:db40::/32 2402:dcc0::/32 2402:de40::/32 2402:dec0::/32 2402:df40::/32 2402:dfc0::/32 2402:e040::/32 2402:e0c0::/32 2402:e140::/32 2402:e2c0::/32 2402:e3c0::/32 2402:e480::/32 2402:e540::/32 2402:e680::/32 2402:e740::/32 2402:e780::/32 2402:e7c0::/32 2402:e880::/32 2402:e980::/32 2402:eb80::/32 2402:ec80::/32 2402:ed80::/32 2402:ef40::/32 2402:ef80::/32 2402:f000::/32 2402:f140::/32 2402:f340::/32 2402:f3c0::/32 2402:f480::/32 2402:f540::/32 2402:f580::/32 2402:f740::/32 2402:f780::/32 2402:f8c0::/32 2402:f980::/32 2402:f9c0::/32 2402:fac0::/32 2402:fcc0::/32 2402:ff40::/32 2402:ffc0::/32 2403:600::/32 2403:700::/32 2403:7c0::/32 2403:800::/31 2403:980::/32 2403:a80::/32 2403:b80::/32 2403:c80::/32 2403:d40::/32 2403:d80::/32 2403:e80::/32 2403:f00::/32 2403:f40::/32 2403:f80::/32 2403:fc0::/32 2403:1180::/32 2403:1340::/32 2403:1440::/32 2403:1580::/32 2403:16c0::/32 2403:17c0::/32 2403:1980::/32 2403:1a40::/32 2403:1b80::/32 2403:1c80::/32 2403:1d80::/32 2403:1dc0::/32 2403:1e80::/32 2403:1ec0::/32 2403:1f80::/32 2403:2040::/32 2403:2080::/32 2403:2180::/32 2403:2240::/32 2403:2280::/32 2403:2380::/32 2403:2440::/32 2403:24c0::/32 2403:2580::/32 2403:25c0::/32 2403:2680::/32 2403:26c0::/32 2403:2740::/32 2403:2780::/32 2403:28c0::/32 2403:2940::/32 2403:2a00::/32 2403:2a40::/32 2403:2ac0::/32 2403:2b40::/32 2403:2bc0::/32 2403:2cc0::/32 2403:2f40::/32 2403:2fc0::/32 2403:3040::/32 2403:30c0::/32 2403:3140::/32 2403:3280::/32 2403:32c0::/32 2403:3380::/32 2403:3480::/32 2403:3580::/32 2403:3640::/32 2403:3680::/32 2403:36c0::/32 2403:3740::/32 2403:3780::/32 2403:37c0::/32 2403:3840::/32 2403:3880::/32 2403:38c0::/32 2403:3940::/32 2403:3980::/32 2403:39c0::/32 2403:3a40::/32 2403:3b40::/32 2403:3b80::/32 2403:3bc0::/32 2403:3c40::/32 2403:3c80::/32 2403:3cc0::/32 2403:3d40::/32 2403:3d80::/32 2403:3dc0::/32 2403:3e80::/32 2403:3ec0::/32 2403:3f40::/32 2403:3f80::/32 2403:4080::/32 2403:4180::/32 2403:4240::/32 2403:4280::/32 2403:4300::/32 2403:4380::/32 2403:4580::/32 2403:4680::/32 2403:4780::/32 2403:4840::/32 2403:4880::/32 2403:4980::/32 2403:4a40::/32 2403:4a80::/32 2403:4b40::/32 2403:4b80::/32 2403:4c80::/32 2403:4cc0::/32 2403:4d40::/32 2403:4d80::/32 2403:4ec0::/32 2403:5040::/32 2403:5080::/32 2403:50c0::/32 2403:5280::/32 2403:5380::/32 2403:54c0::/32 2403:5540::/32 2403:5580::/32 2403:5640::/32 2403:5780::/32 2403:58c0::/32 2403:5980::/32 2403:5a80::/32 2403:5b40::/32 2403:5b80::/32 2403:5c80::/32 2403:5d80::/32 2403:5e40::/32 2403:5e80::/32 2403:5ec0::/32 2403:5f80::/32 2403:5fc0::/32 2403:6080::/32 2403:6180::/32 2403:6280::/32 2403:62c0::/32 2403:6380::/32 2403:6580::/32 2403:6680::/32 2403:6740::/32 2403:6780::/32 2403:6880::/32 2403:6980::/32 2403:6a00::/32 2403:6c80::/32 2403:6d40::/32 2403:6d80::/32 2403:6e80::/32 2403:6f40::/32 2403:6fc0::/32 2403:7040::/32 2403:7080::/32 2403:7180::/32 2403:7280::/32 2403:7380::/32 2403:7480::/32 2403:7540::/32 2403:7580::/32 2403:76c0::/32 2403:7700::/32 2403:7840::/32 2403:78c0::/32 2403:7a80::/32 2403:7b00::/32 2403:7d80::/32 2403:7e80::/32 2403:7f80::/32 2403:8080::/32 2403:8180::/32 2403:8280::/32 2403:8380::/32 2403:83c0::/32 2403:8480::/32 2403:8580::/32 2403:8880::/32 2403:8900::/32 2403:8980::/32 2403:8a40::/32 2403:8a80::/32 2403:8b00::/32 2403:8b80::/32 2403:8c00::/32 2403:8c80::/32 2403:8d00::/32 2403:8d80::/32 2403:8f80::/32 2403:9080::/32 2403:9180::/32 2403:9280::/32 2403:9380::/32 2403:9480::/32 2403:9580::/32 2403:9680::/32 2403:9780::/32 2403:9880::/32 2403:9a80::/32 2403:9ac0::/32 2403:9b00::/32 2403:9b40::/32 2403:9b80::/32 2403:9c80::/32 2403:9d00::/32 2403:9d80::/32 2403:9e40::/32 2403:9e80::/32 2403:9ec0::/32 2403:9f80::/32 2403:a100::/32 2403:a140::/32 2403:a200::/32 2403:a300::/32 2403:a480::/32 2403:a580::/32 2403:a680::/32 2403:a6c0::/32 2403:a780::/32 2403:a880::/32 2403:a940::/32 2403:a980::/32 2403:a9c0::/32 2403:aa40::/32 2403:aa80::/32 2403:ab80::/32 2403:ac00::/32 2403:af80::/32 2403:b080::/32 2403:b180::/32 2403:b280::/32 2403:b380::/32 2403:b400::/32 2403:b480::/32 2403:b580::/32 2403:b680::/32 2403:b780::/32 2403:b880::/32 2403:b980::/32 2403:ba40::/32 2403:c040::/32 2403:c080::/32 2403:c100::/32 2403:c140::/32 2403:c180::/32 2403:c3c0::/32 2403:c440::/32 2403:c480::/32 2403:c4c0::/32 2403:c980::/32 2403:cdc0::/32 2403:cec0::/32 2403:cf80::/32 2403:d080::/32 2403:d180::/32 2403:d280::/32 2403:d2c0::/32 2403:d380::/32 2403:d400::/32 2403:d440::/32 2403:d480::/32 2403:d580::/32 2403:d680::/32 2403:d780::/32 2403:d7c0::/32 2403:d880::/32 2403:d980::/32 2403:d9c0::/32 2403:da80::/32 2403:dac0::/32 2403:db00::/32 2403:db80::/32 2403:dc80::/32 2403:dd80::/32 2403:de80::/32 2403:df80::/32 2403:e080::/32 2403:e180::/32 2403:e280::/32 2403:e300::/32 2403:e480::/32 2403:e500::/32 2403:e580::/32 2403:e640::/32 2403:e680::/32 2403:e700::/32 2403:e780::/32 2403:e7c0::/32 2403:e880::/32 2403:e980::/32 2403:ea80::/32 2403:eac0::/32 2403:eb80::/32 2403:ec80::/32 2403:ed00::/32 2403:ed40::/32 2403:ed80::/32 2403:ee80::/32 2403:ef80::/32 2403:f080::/32 2403:f100::/32 2403:f180::/32 2403:f240::/32 2403:f280::/32 2403:f300::/32 2403:f380::/32 2403:f4c0::/32 2403:f580::/32 2403:f740::/32 2403:f8c0::/32 2403:f980::/32 2403:fb00::/32 2403:fb80::/32 2403:fc40::/32 2403:fe40::/32 2403:fe80::/32 2403:fec0::/32 2403:ff80::/32 2403:ffc0::/32 2404:100::/32 2404:158::/32 2404:240::/32 2404:280::/32 2404:440::/32 2404:480::/32 2404:680::/32 2404:a80::/32 2404:b80::/32 2404:bc0::/32 2404:c40::/32 2404:d80::/32 2404:f00::/32 2404:f80::/32 2404:1080::/32 2404:10c0::/32 2404:1180::/32 2404:14c0::/32 2404:1880::/32 2404:1c80::/32 2404:1cc0::/32 2404:1d80::/32 2404:1e80::/32 2404:1f40::/32 2404:21c0::/32 2404:30c0::/32 2404:3140::/32 2404:31c0::/32 2404:3240::/32 2404:32c0::/32 2404:3300::/32 2404:3340::/32 2404:3480::/32 2404:35c0::/32 2404:3640::/32 2404:36c0::/32 2404:3700::/32 2404:3740::/32 2404:37c0::/32 2404:3840::/32 2404:3940::/32 2404:3b00::/32 2404:3bc0::/32 2404:3c40::/32 2404:3f40::/32 2404:4080::/32 2404:41c0::/32 2404:4540::/32 2404:4740::/32 2404:4bc0::/32 2404:4d00::/32 2404:4dc0::/32 2404:51c0::/32 2404:5640::/32 2404:5a80::/32 2404:5b00::/32 2404:5d00::/32 2404:5e80::/32 2404:6000::/32 2404:6100::/32 2404:6380::/32 2404:6500::/32 2404:65c0::/32 2404:6a40::/32 2404:6f80::/32 2404:7100::/32 2404:7180::/32 2404:71c0::/32 2404:7240::/32 2404:74c0::/32 2404:7600::/32 2404:7740::/32 2404:7940::/32 2404:7d00::/32 2404:8040::/32 2404:80c0::/32 2404:8140::/32 2404:81c0::/32 2404:8480::/32 2404:8580::/32 2404:8700::/32 2404:8880::/32 2404:8a80::/32 2404:8b00::/32 2404:8dc0::/32 2404:9340::/32 2404:9880::/32 2404:9b80::/32 2404:9c80::/32 2404:a000::/32 2404:a080::/32 2404:a0c0::/32 2404:a180::/32 2404:a240::/32 2404:a740::/32 2404:b100::/32 2404:b340::/32 2404:b3c0::/32 2404:b440::/32 2404:b4c0::/32 2404:b900::/32 2404:bbc0::/32 2404:bc40::/32 2404:c1c0::/32 2404:c240::/32 2404:c2c0::/32 2404:c300::/32 2404:c3c0::/32 2404:c440::/32 2404:c4c0::/32 2404:c540::/32 2404:c5c0::/32 2404:c640::/32 2404:c940::/32 2404:c9c0::/32 2404:cd00::/32 2404:d040::/32 2404:d080::/32 2404:d140::/32 2404:d280::/32 2404:d3c0::/32 2404:d480::/32 2404:d640::/32 2404:d6c0::/32 2404:d7c0::/32 2404:d840::/32 2404:dd80::/32 2404:df00::/32 2404:e280::/32 2404:e540::/32 2404:e5c0::/32 2404:e780::/32 2404:e880::/32 2404:e8c0::/32 2404:eb40::/32 2404:eb80::/32 2404:ec40::/32 2404:ecc0::/32 2404:edc0::/32 2404:f040::/32 2404:f4c0::/32 2404:f7c0::/32 2405:80::/32 2405:480::/32 2405:580::/32 2405:680::/32 2405:6c0::/32 2405:780::/32 2405:880::/32 2405:940::/32 2405:980::/32 2405:9c0::/32 2405:a80::/32 2405:b80::/32 2405:c80::/32 2405:d80::/32 2405:e80::/32 2405:f80::/32 2405:1080::/32 2405:1180::/32 2405:1280::/32 2405:1380::/32 2405:1480::/32 2405:1580::/32 2405:1680::/32 2405:18c0::/32 2405:1c80::/32 2405:1d80::/32 2405:1e80::/32 2405:1f80::/32 2405:1fc0::/32 2405:2080::/32 2405:2180::/32 2405:2280::/32 2405:2340::/32 2405:2380::/32 2405:2480::/32 2405:24c0::/32 2405:2580::/32 2405:2680::/32 2405:2780::/32 2405:2880::/32 2405:2980::/32 2405:2a80::/32 2405:2b80::/32 2405:2bc0::/32 2405:2c80::/32 2405:2d80::/32 2405:2e80::/32 2405:2ec0::/32 2405:2f40::/32 2405:2f80::/32 2405:3140::/32 2405:31c0::/32 2405:37c0::/32 2405:3880::/32 2405:3980::/32 2405:39c0::/32 2405:3a80::/32 2405:3ac0::/32 2405:3b00::/32 2405:3b80::/32 2405:3bc0::/32 2405:3c40::/32 2405:3c80::/32 2405:3d80::/32 2405:3e80::/32 2405:3f40::/32 2405:3f80::/32 2405:4080::/32 2405:4140::/32 2405:4180::/32 2405:41c0::/32 2405:4280::/32 2405:4380::/32 2405:4480::/32 2405:44c0::/32 2405:4540::/32 2405:4580::/32 2405:4680::/32 2405:4780::/32 2405:4880::/32 2405:4980::/32 2405:4a80::/32 2405:4b80::/32 2405:4d40::/32 2405:4e80::/32 2405:4f80::/32 2405:5080::/32 2405:5180::/32 2405:5240::/32 2405:5280::/32 2405:52c0::/32 2405:5380::/32 2405:5480::/32 2405:5580::/32 2405:5680::/32 2405:5780::/32 2405:57c0::/32 2405:5880::/32 2405:5980::/32 2405:5a80::/32 2405:5b00::/32 2405:5b80::/32 2405:5c80::/32 2405:5cc0::/32 2405:5d40::/32 2405:5d80::/32 2405:5dc0::/32 2405:5e80::/32 2405:5f80::/32 2405:6080::/32 2405:6180::/32 2405:6200::/32 2405:66c0::/32 2405:6880::/32 2405:68c0::/32 2405:6940::/32 2405:69c0::/32 2405:6a80::/32 2405:6b80::/32 2405:6c80::/32 2405:6d80::/32 2405:6e80::/32 2405:6f00::/32 2405:6f80::/32 2405:7040::/32 2405:7080::/32 2405:7180::/32 2405:7240::/32 2405:7280::/32 2405:7380::/32 2405:7480::/32 2405:7580::/32 2405:7680::/32 2405:7780::/32 2405:7880::/32 2405:78c0::/32 2405:7980::/32 2405:79c0::/32 2405:7a80::/32 2405:7b80::/32 2405:7c80::/32 2405:7d40::/32 2405:7f40::/32 2405:7fc0::/32 2405:8280::/32 2405:83c0::/32 2405:8480::/32 2405:84c0::/32 2405:8580::/32 2405:8680::/32 2405:8780::/32 2405:8880::/32 2405:8980::/32 2405:8a40::/32 2405:8a80::/32 2405:8ac0::/32 2405:8b80::/32 2405:8c80::/32 2405:8d80::/32 2405:8e80::/32 2405:8f40::/32 2405:8f80::/32 2405:9080::/32 2405:9180::/32 2405:9280::/32 2405:9300::/32 2405:9340::/32 2405:9380::/32 2405:93c0::/32 2405:9480::/32 2405:94c0::/32 2405:9580::/32 2405:9680::/32 2405:9700::/32 2405:9780::/32 2405:97c0::/32 2405:9880::/32 2405:9900::/32 2405:9980::/32 2405:99c0::/32 2405:9a80::/32 2405:9b00::/32 2405:9b80::/32 2405:9bc0::/32 2405:9e00::/32 2405:a240::/32 2405:a3c0::/32 2405:a500::/32 2405:a680::/32 2405:a900::/32 2405:a980::/32 2405:aa80::/32 2405:ab00::/32 2405:ad00::/32 2405:af00::/32 2405:b100::/32 2405:b300::/32 2405:b7c0::/32 2405:b880::/32 2405:b980::/32 2405:bb00::/32 2405:bd00::/32 2405:bd80::/32 2405:bdc0::/32 2405:be80::/32 2405:bf00::/32 2405:c040::/32 2405:c280::/32 2405:c380::/32 2405:c480::/32 2405:c500::/32 2405:c580::/32 2405:c680::/32 2405:c780::/32 2405:c880::/32 2405:c980::/32 2405:ca80::/32 2405:cb80::/32 2405:cc80::/32 2405:cd80::/32 2405:ce80::/32 2405:d280::/32 2405:d4c0::/32 2405:d700::/32 2405:d740::/32 2405:d900::/32 2405:df40::/32 2405:e000::/32 2405:e040::/32 2405:e1c0::/32 2405:e600::/32 2405:ed40::/32 2405:ee80::/32 2405:ef40::/30 2405:f340::/32 2405:f380::/32 2405:f3c0::/32 2405:f580::/32 2405:f6c0::/32 2405:f940::/32 2405:fdc0::/32 2405:fe80::/32 2405:fec0::/32 2405:ff80::/32 2406:40::/32 2406:80::/32 2406:c0::/32 2406:140::/32 2406:280::/32 2406:440::/32 2406:4c0::/32 2406:7c0::/32 2406:840::/32 2406:880::/32 2406:8c0::/32 2406:9c0::/32 2406:d80::/32 2406:e80::/32 2406:f80::/32 2406:1080::/32 2406:1100::/32 2406:1180::/32 2406:1280::/32 2406:1380::/32 2406:1480::/32 2406:1580::/32 2406:15c0::/32 2406:1680::/32 2406:1780::/32 2406:1880::/32 2406:1980::/32 2406:1a80::/32 2406:1b80::/32 2406:1c80::/32 2406:1d80::/32 2406:1e40::/32 2406:1e80::/32 2406:1f80::/32 2406:2080::/32 2406:2580::/32 2406:2640::/32 2406:2700::/32 2406:2780::/32 2406:2880::/32 2406:2980::/32 2406:2a80::/32 2406:2b80::/32 2406:2c40::/32 2406:2c80::/32 2406:2d80::/32 2406:2e80::/32 2406:2f80::/32 2406:3080::/32 2406:3180::/32 2406:31c0::/32 2406:3280::/32 2406:3300::/32 2406:3340::/32 2406:3380::/32 2406:3440::/32 2406:3480::/32 2406:34c0::/32 2406:3580::/32 2406:3640::/32 2406:3680::/32 2406:3700::/32 2406:3780::/32 2406:3880::/32 2406:3980::/32 2406:39c0::/32 2406:3ac0::/32 2406:3d80::/32 2406:3e80::/32 2406:3f80::/32 2406:4080::/32 2406:40c0::/32 2406:4180::/32 2406:4280::/32 2406:42c0::/32 2406:4340::/32 2406:4380::/32 2406:43c0::/32 2406:4480::/32 2406:4500::/32 2406:4680::/32 2406:4980::/32 2406:4b80::/32 2406:4c80::/32 2406:4d00::/32 2406:4d80::/32 2406:4e80::/32 2406:4f00::/32 2406:4f80::/32 2406:5080::/32 2406:50c0::/32 2406:5180::/32 2406:5280::/32 2406:52c0::/32 2406:5340::/32 2406:5380::/32 2406:5480::/32 2406:5580::/32 2406:5680::/32 2406:5780::/32 2406:5840::/32 2406:5880::/32 2406:5940::/32 2406:5980::/32 2406:5a40::/32 2406:5ac0::/32 2406:5b40::/32 2406:5d80::/32 2406:5e80::/32 2406:5f80::/32 2406:6080::/32 2406:6100::/32 2406:6180::/32 2406:61c0::/30 2406:6280::/32 2406:6300::/32 2406:6340::/32 2406:6380::/32 2406:6480::/32 2406:6500::/32 2406:6580::/32 2406:65c0::/32 2406:6640::/32 2406:6680::/32 2406:6780::/32 2406:6880::/32 2406:6980::/32 2406:6a80::/32 2406:6b80::/32 2406:6bc0::/32 2406:6c80::/32 2406:6d80::/32 2406:6e80::/32 2406:6f80::/32 2406:7080::/32 2406:7280::/32 2406:7380::/32 2406:7480::/32 2406:7580::/32 2406:7680::/32 2406:7780::/32 2406:7880::/32 2406:7980::/32 2406:7a80::/32 2406:7b80::/32 2406:7c80::/32 2406:7cc0::/32 2406:7d00::/32 2406:7d80::/32 2406:7e80::/32 2406:7f80::/32 2406:7fc0::/32 2406:8080::/32 2406:8180::/32 2406:8280::/32 2406:8380::/32 2406:8480::/32 2406:8500::/32 2406:8580::/32 2406:8780::/32 2406:8880::/32 2406:8980::/32 2406:8a80::/32 2406:8b80::/32 2406:8bc0::/32 2406:8c80::/32 2406:8d80::/32 2406:8e80::/32 2406:8f40::/32 2406:8f80::/32 2406:9180::/32 2406:9200::/32 2406:9280::/32 2406:9380::/32 2406:9480::/32 2406:94c0::/32 2406:9780::/32 2406:9d80::/32 2406:9e40::/32 2406:9e80::/32 2406:9f80::/32 2406:a080::/32 2406:a180::/32 2406:a280::/32 2406:a380::/32 2406:a480::/32 2406:a580::/32 2406:a680::/32 2406:a780::/32 2406:a7c0::/32 2406:a880::/32 2406:a8c0::/32 2406:a980::/32 2406:aa80::/32 2406:aac0::/32 2406:ab80::/32 2406:abc0::/32 2406:ac80::/32 2406:acc0::/32 2406:ad40::/32 2406:ad80::/32 2406:ae80::/32 2406:af80::/32 2406:b080::/32 2406:b640::/32 2406:b880::/32 2406:b980::/32 2406:ba80::/32 2406:bb80::/32 2406:bc80::/32 2406:bd40::/32 2406:bd80::/32 2406:bdc0::/32 2406:be80::/32 2406:bf80::/32 2406:c080::/32 2406:c180::/32 2406:c280::/32 2406:c340::/32 2406:c480::/32 2406:c580::/32 2406:c680::/32 2406:c780::/32 2406:c880::/32 2406:c900::/32 2406:c980::/32 2406:ca80::/32 2406:cac0::/32 2406:cb80::/32 2406:cc80::/32 2406:cd80::/32 2406:ce80::/32 2406:cf00::/32 2406:cf01::/32 2406:cf02::/31 2406:cf80::/32 2406:d080::/32 2406:d140::/32 2406:d180::/32 2406:d280::/32 2406:d2c0::/32 2406:d380::/32 2406:d440::/32 2406:d480::/32 2406:d580::/32 2406:d680::/32 2406:d780::/32 2406:d880::/32 2406:d980::/32 2406:db80::/32 2406:dc80::/32 2406:dd00::/32 2406:dd80::/32 2406:de80::/32 2406:df80::/32 2406:e080::/32 2406:e180::/32 2406:e280::/32 2406:e2c0::/32 2406:e380::/32 2406:e3c0::/32 2406:e500::/32 2406:e580::/32 2406:e680::/32 2406:e780::/32 2406:e8c0::/32 2406:ea40::/28 2406:f280::/32 2406:f300::/32 2406:f4c0::/32 2406:f7c0::/32 2406:f980::/32 2406:fc80::/32 2406:fd80::/32 2406:fe80::/32 2406:ff00::/32 2407:480::/32 2407:580::/32 2407:cc0::/32 2407:f40::/32 2407:1180::/32 2407:17c0::/32 2407:1900::/32 2407:1d00::/32 2407:1e80::/32 2407:2280::/32 2407:2380::/32 2407:23c0::/32 2407:2440::/32 2407:2780::/32 2407:2840::/32 2407:2ac0::/32 2407:31c0::/32 2407:3340::/32 2407:3540::/32 2407:3700::/32 2407:3740::/32 2407:37c0::/32 2407:3900::/32 2407:3f40::/32 2407:43c0::/32 2407:4440::/32 2407:4580::/32 2407:4680::/32 2407:4740::/32 2407:4880::/32 2407:4980::/32 2407:4a80::/32 2407:4c80::/32 2407:4d80::/32 2407:4e80::/32 2407:4f00::/32 2407:5380::/32 2407:53c0::/32 2407:5500::/32 2407:5780::/32 2407:5840::/32 2407:6040::/32 2407:6580::/32 2407:6c40::/32 2407:7680::/32 2407:7780::/32 2407:7880::/32 2407:7980::/32 2407:7c80::/32 2407:7d00::/32 2407:7d80::/32 2407:7e80::/32 2407:8880::/32 2407:8b80::/32 2407:8f40::/32 2407:9080::/32 2407:9180::/32 2407:94c0::/32 2407:9680::/32 2407:9980::/32 2407:9b40::/32 2407:9bc0::/32 2407:9f00::/32 2407:9f80::/32 2407:a040::/32 2407:a480::/32 2407:a640::/32 2407:a7c0::/32 2407:a880::/32 2407:a940::/32 2407:ad80::/32 2407:ae80::/32 2407:af80::/32 2407:b080::/32 2407:b180::/32 2407:b280::/32 2407:b380::/32 2407:b580::/32 2407:b680::/32 2407:b780::/32 2407:b880::/32 2407:b980::/32 2407:ba00::/32 2407:ba80::/32 2407:bb80::/32 2407:bc00::/32 2407:bc80::/32 2407:bd80::/32 2407:bdc0::/32 2407:be80::/32 2407:bf80::/32 2407:c080::/32 2407:c380::/32 2407:c400::/32 2407:c480::/32 2407:c580::/32 2407:c680::/32 2407:c780::/32 2407:c880::/32 2407:c900::/32 2407:c980::/32 2407:cb80::/32 2407:cc80::/32 2407:cd80::/32 2407:ce80::/32 2407:cf00::/32 2407:cf80::/32 2407:d480::/32 2407:d580::/32 2407:d680::/32 2407:d780::/32 2407:d880::/32 2407:d980::/32 2407:da80::/32 2407:db80::/32 2407:dc80::/32 2407:dd80::/32 2407:de80::/32 2407:df80::/32 2407:e080::/32 2407:e180::/32 2407:e280::/32 2407:e380::/32 2407:e480::/32 2407:e580::/32 2407:e680::/32 2407:e780::/32 2407:e800::/32 2407:ea80::/32 2407:eb80::/32 2407:ec80::/32 2407:ed80::/32 2407:ee80::/32 2407:ef80::/32 2407:f080::/32 2407:f180::/32 2407:f280::/32 2407:f380::/32 2407:f480::/32 2407:f580::/32 2407:f680::/32 2407:f780::/32 2407:f880::/32 2407:f980::/32 2407:fa80::/32 2407:fb80::/32 2407:fc80::/32 2407:fd80::/32 2408:4000::/22 2408:6000::/24 2408:8000::/22 2408:8400::/22 2408:8800::/21 2409:2000::/21 2409:6000::/20 2409:8000::/20 240a:2000::/24 240a:4000::/21 240a:6000::/24 240a:8000::/21 240a:a000::/20 240a:c000::/20 240b:8000::/21 240c::/28 240c:4000::/22 240c:8000::/21 240c:c000::/20 240d:4000::/21 240d:8000::/24 240e::/24 240e:100::/24 240e:200::/23 240e:400::/22 240e:800::/21 240e:1000::/20 240e:2000::/19 240f:4000::/24 240f:8000::/24 240f:c000::/24 ================================================ FILE: shadowsocks-csharp/Data/proxy.pac.txt ================================================ var direct = "__DIRECT__"; if (direct == "__DIR" + "ECT__") direct = "DIRECT;"; var wall_proxy = function(){ return "__PROXY__"; }; var wall_v6_proxy = function(){ return "__PROXY__"; }; var nowall_proxy = function(){ return direct; }; var ip_proxy = function(){ return nowall_proxy(); }; var ipv6_proxy = function(){ return nowall_proxy(); }; var userrules = []; var rules = [ "|http://85.17.73.31/", "||afreecatv.com", "||agnesb.fr", "||akiba-web.com", "||altrec.com", "||angela-merkel.de", "||angola.org", "||apartmentratings.com", "||apartments.com", "||arena.taipei", "||asianspiss.com", "||assimp.org", "||athenaeizou.com", "||azubu.tv", "||bankmobilevibe.com", "||banorte.com", "||beeg.com", "||global.bing.com", "||booktopia.com.au", "||boysmaster.com", "||bynet.co.il", "||carfax.com", ".casinobellini.com", "||casinobellini.com", "||centauro.com.br", "||chobit.cc", "||clearsurance.com", "||images.comico.tw", "||static.comico.tw", "||counter.social", "||costco.com", "||crossfire.co.kr", "||crunchyroll.com", "||d2pass.com", "||darpa.mil", "||dawangidc.com", "||deezer.com", "||desipro.de", "||dingchin.com.tw", "||discord.com", "||discord.gg", "||discordapp.com", "||discordapp.net", "||dish.com", "|http://img.dlsite.jp/", "||dm530.net", "share.dmhy.org", "||dmhy.org", "||dmm.co.jp", "|http://www.dmm.com/netgame", "||dnvod.tv", "||dubox.com", "||dvdpac.com", "||eesti.ee", "||esurance.com", ".expekt.com", "||expekt.com", ".extmatrix.com", "||extmatrix.com", "||fakku.net", "||fastpic.ru", "||filesor.com", "||financetwitter.com", "||flipboard.com", "||flitto.com", "||fnac.be", "||fnac.com", "||funkyimg.com", "||fxnetworks.com", "||g-area.org", "||gettyimages.com", "||getuploader.com", "||ghidra-sre.org", "|https://raw.githubusercontent.com/programthink/zhao", "||glass8.eu", "||glype.com", "||go141.com", "||guo.media", "||hautelook.com", "||hautelookcdn.com", "||wego.here.com", "||gamer-cds.cdn.hinet.net", "||gamer2-cds.cdn.hinet.net", "||hmvdigital.ca", "||hmvdigital.com", "||homedepot.com", "||hoovers.com", "||hulu.com", "||huluim.com", "|http://secure.hustler.com", "|http://hustlercash.com", "|http://www.hustlercash.com", "||hybrid-analysis.com", "||cdn*.i-scmp.com", "||ilbe.com", "||ilovelongtoes.com", "|http://imgmega.com/*.gif.html", "|http://imgmega.com/*.jpg.html", "|http://imgmega.com/*.jpeg.html", "|http://imgmega.com/*.png.html", "||imlive.com", "||tw.iqiyi.com", "||javhub.net", "||javhuge.com", ".javlibrary.com", "||javlibrary.com", "||jcpenney.com", "||jims.net", "||tv.jtbc.joins.com", "||jukujo-club.com", "||juliepost.com", "||kawaiikawaii.jp", "||kendatire.com", "||khatrimaza.org", "||kkbox.com", "||leisurepro.com", "||lifemiles.com", "||longtoes.com", "||lovetvshow.com", "|http://www.m-sport.co.uk", "||macgamestore.com", "||madonna-av.com", "||mangafox.com", "||mangafox.me", "||manta.com", "||matome-plus.com", "||matome-plus.net", "||mattwilcox.net", "||metarthunter.com", "||mfxmedia.com", "||mojim.com", "||kb.monitorware.com", "||monster.com", "||moodyz.com", "||moonbingo.com", "||mos.ru", "||msha.gov", "||muzu.tv", "||mvg.jp", ".mybet.com", "||mybet.com", "||nationwide.com", "|http://www.nbc.com/live", "||neo-miracle.com", "||netflix.com", "||netflix.net", "||nflximg.com", "||nflximg.net", "||nflxext.com", "||nflxso.net", "||nflxvideo.net", "||nic.gov", "|http://mo.nightlife141.com", "||purpose.nike.com", "||noxinfluencer.com", "@@||cn.noxinfluencer.com", "||nordstrom.com", "||nordstromimage.com", "||nordstromrack.com", "||nottinghampost.com", "||npsboost.com", "||ntdtv.cz", "||s1.nudezz.com", "||nusatrip.com", "||nuuvem.com", "||omni7.jp", "||onapp.com", "||ontrac.com", "@@|http://blog.ontrac.com", "||pandora.com", ".pandora.tv", "||parkansky.com", "||phmsociety.org", "|http://*.pimg.tw/", "||pure18.com", "||pytorch.org", "||qq.co.za", "||r18.com", "|http://radiko.jp", "||ramcity.com.au", "||rateyourmusic.com", "||rd.com", "||rdio.com", "|https://riseup.net", "||sadistic-v.com", "||isc.sans.edu", "|http://cdn*.search.xxx/", "||shiksha.com", "||slacker.com", "||sm-miracle.com", "||softnology.biz", "||soylentnews.org", "||spotify.com", "||spreadshirt.es", "||springboardplatform.com", "||sprite.org", "@@|http://store.sprite.org", "||superokayama.com", "||superpages.com", "||swagbucks.com", "||switch1.jp", "||tapanwap.com", "||gsp.target.com", "||login.target.com", "||rcam.target.com", "||technews.tw", "||thinkgeek.com", "||thebodyshop-usa.com", "||tma.co.jp", "||tracfone.com", "||tryheart.jp", "||turntable.fm", "||twerkingbutt.com", "||ulop.net", "||uukanshu.com", "||vegasred.com", "||vevo.com", "||vip-enterprise.com", "|http://viu.tv/ch/", "|http://viu.tv/encore/", "||vmpsoft.com", "|http://ecsm.vs.com/", "||wanz-factory.com", "||ssl.webpack.de", "||wheretowatch.com", "||wingamestore.com", "||wizcrafts.net", "||vod.wwe.com", "||xfinity.com", "||youwin.com", "||ytn.co.kr", "||zattoo.com", "||zim.vn", "||zozotown.com", "14.102.250.18", "14.102.250.19", "50.7.31.230:8898", "174.142.105.153", "69.65.19.160", "||xn--4gq171p.com", "||xn--czq75pvv1aj5c.org", "||xn--i2ru8q2qg.com", "||xn--oiq.cc", "||xn--p8j9a0d9c9a.xn--q9jyb4c", "||abebooks.com", "|https://*.s3.amazonaws.com", "||s3-ap-southeast-2.amazonaws.com", "||43110.cf", "||9cache.com", "||9gag.com", "||agro.hk", "||share.america.gov", "||apkmirror.com", "||arte.tv", "||artstation.com", "||bangdream.space", "||behance.net", "||bird.so", "||bitterwinter.org", "||bnn.co", "||businessinsider.com", "||boomssr.com", "||bwgyhw.com", "||castbox.fm", "||chinatimes.com", "||clyp.it", "||cmcn.org", "||cmx.im", "||dailyview.tw", "||daum.net", "||depositphotos.com", "||disconnect.me", "||documentingreality.com", "||doubibackup.com", "||doubmirror.cf", "||encyclopedia.com", "||fangeqiang.com", "||fanqiangdang.com", "||feedly.com", "||feedx.net", "||flyzy2005.com", "||foreignpolicy.com", "||free-ss.site", "||freehongkong.org", "||blog.fuckgfw233.org", "||g0v.social", "||globalvoices.org", "||glorystar.me", "||goregrish.com", "||guangnianvpn.com", "||hanime.tv", "||hbo.com", "||spaces.hightail.com", "||hkgalden.com", "||hkgolden.com", "||hudson.org", "||ipfs.io", "||japantimes.co.jp", "||jiji.com", "||jintian.net", "||jinx.com", "||joinmastodon.org", "||liangzhichuanmei.com", "||lighti.me", "||lightyearvpn.com", "||lihkg.com", "||line-scdn.net", "||i.lithium.com", "||cloud.mail.ru", "||cdn-images.mailchimp.com", "||mastodon.cloud", "||mastodon.host", "||mastodon.social", "||mastodon.xyz", "||matters.news", "||me.me", "||metart.com", "||mohu.club", "||mohu.ml", "||motiyun.com", "||msa-it.org", "||dictionary.goo.ne.jp", "||go.nesnode.com", "||international-news.newsmagazine.asia", "||nikkei.com", "||nitter.cc", "||nitter.net", "||niu.moe", "||nofile.io", "||now.com", "||openvpn.org", "||onejav.com", "||paste.ee", "||my.pcloud.com", "||picacomic.com", "||pincong.rocks", "||pixiv.net", "||potato.im", "||premproxy.com", "||prism-break.org", "||protonvpn.com", "||api.pureapk.com", "||quora.com", "||quoracdn.net", "||qz.com", "||cdn.seatguru.com", "||secure.raxcdn.com", "||redd.it", "||reddit.com", ".redditlist.com", "|http://redditlist.com", "||redditmedia.com", "||redditstatic.com", "||rixcloud.com", "||rixcloud.us", "||rsdlmonitor.com", "||shadowsocks.be", "||shadowsocks9.com", "||tn1.shemalez.com", "||tn2.shemalez.com", "||tn3.shemalez.com", "||static.shemalez.com", "||six-degrees.io", "||softfamous.com", "||softsmirror.cf", "||sosreader.com", "||sspanel.net", "||sulian.me", "||supchina.com", "||teddysun.com", "||textnow.me", "||tineye.com", "||top10vpn.com", "||tubepornclassic.com", "||uku.im", "||unseen.is", "||cn.uptodown.com", "||uraban.me", "||vrsmash.com", "||vultryhw.com", "||scache.vzw.com", "||scache1.vzw.com", "||scache2.vzw.com", "||ss7.vzw.com", "||ssr.tools", "||steemit.com", "||taiwanjustice.net", "||tinc-vpn.org", "||u15.info", "||washingtonpost.com", "||wenzhao.ca", "||whatsonweibo.com", "||wire.com", "||blog.workflow.is", "||xm.com", "||xuehua.us", "||yes-news.com", "||yigeni.com", "||you-get.org", "||zzcloud.me", "||aex.com", "||allcoin.com", "||adcex.com", "||bcex.ca", "||bibox.com", "||big.one", "||bigone.com", "||binance.com", "||bit-z.com", "||bitz.ai", "||bitbay.net", "||bitcoinworld.com", "||bitfinex.com", "||bithumb.com", "||bitinka.com.ar", "||bitmex.com", "||btc98.com", "||btcbank.bank", "||btctrade.im", "||c2cx.com", "||chaoex.com", "||cobinhood.com", "||coin2co.in", "||coinbene.com", ".coinegg.com", "||coinegg.com", "||coinex.com", "||coingi.com", "||coinrail.co.kr", "||cointiger.com", "||cointobe.com", "||coinut.com", "||discoins.com", "||dragonex.io", "||ebtcbank.com", "||etherdelta.com", "||etherscan.io", "||exmo.com", "||exrates.me", "||exx.com", "||fatbtc.com", "||gate.io", "||gatecoin.com", "||hbg.com", "||hitbtc.com", "||huobi.co", "||huobi.com", "||huobi.me", "||huobi.pro", "||huobi.sc", "||huobipro.com", "||bx.in.th", "||jex.com", "||kex.com", "||kspcoin.com", "||kucoin.com", "||lbank.info", "||livecoin.net", "||localbitcoins.com", "||mercatox.com", "||oex.com", "||okex.com", "||otcbtc.com", "||paxful.com", "||rightbtc.com", "||topbtc.com", "||xbtce.com", "||yobit.net", "||zb.com", "||read01.com", "||kknews.cc", "china-mmm.jp.net", ".lsxszzg.com", ".china-mmm.net", "||china-mmm.net", "china-mmm.sa.com", ".allowed.org", ".now.im", "||amazon.co.jp", ".amazon.com/Dalai-Lama", "amazon.com/Prisoner-State-Secret-Journal-Premier", "s3-ap-northeast-1.amazonaws.com", "||aolchannels.aol.com", "video.aol.ca/video-detail", "video.aol.co.uk/video-detail", "video.aol.com", "||video.aol.com", "||search.aol.com", "www.aolnews.com", ".avmo.pw", ".avmoo.com", "|http://avmoo.com", ".avmoo.net", "|http://avmoo.net", "||avmoo.pw", ".javmoo.xyz", "|http://javmoo.xyz", ".javtag.com", "|http://javtag.com", ".javzoo.com", "|http://javzoo.com", ".tellme.pw", ".bbc.com", "||bbc.com", ".bbc.co.uk", "||bbc.co.uk", "||bbci.co.uk", ".bbcchinese.com", "||bbcchinese.com", "|http://bbc.in", ".bloomberg.cn", "||bloomberg.cn", ".bloomberg.com", "||bloomberg.com", "bloomberg.de", "||bloomberg.de", "||bloombergview.com", ".businessweek.com", ".1dumb.com", ".25u.com", ".2waky.com", ".3-a.net", ".4dq.com", ".4mydomain.com", ".4pu.com", ".acmetoy.com", ".almostmy.com", ".americanunfinished.com", ".authorizeddns.net", ".authorizeddns.org", ".authorizeddns.us", ".bigmoney.biz", ".changeip.name", ".changeip.net", ".changeip.org", ".cleansite.biz", ".cleansite.info", ".cleansite.us", ".compress.to", ".ddns.info", ".ddns.me.uk", ".ddns.mobi", ".ddns.ms", ".ddns.name", ".ddns.us", ".dhcp.biz", ".dns-dns.com", ".dns-stuff.com", ".dns04.com", ".dns05.com", ".dns1.us", ".dns2.us", ".dnset.com", ".dnsrd.com", ".dsmtp.com", ".dumb1.com", ".dynamic-dns.net", ".dynamicdns.biz", ".dynamicdns.co.uk", ".dynamicdns.me.uk", ".dynamicdns.org.uk", ".dyndns.pro", ".dynssl.com", ".edns.biz", ".epac.to", ".esmtp.biz", ".ezua.com", ".faqserv.com", ".fartit.com", ".freeddns.com", ".freetcp.com", ".freewww.biz", ".freewww.info", ".ftp1.biz", ".ftpserver.biz", ".gettrials.com", ".got-game.org", ".gr8domain.biz", ".gr8name.biz", ".https443.net", ".https443.org", ".ikwb.com", ".instanthq.com", ".iownyour.biz", ".iownyour.org", ".isasecret.com", ".itemdb.com", ".itsaol.com", ".jetos.com", ".jkub.com", ".jungleheart.com", ".justdied.com", ".lflink.com", ".lflinkup.com", ".lflinkup.net", ".lflinkup.org", ".longmusic.com", ".mefound.com", ".moneyhome.biz", ".mrbasic.com", ".mrbonus.com", ".mrface.com", ".mrslove.com", ".my03.com", ".mydad.info", ".myddns.com", ".myftp.info", ".myftp.name", ".mylftv.com", ".mymom.info", ".mynetav.net", ".mynetav.org", ".mynumber.org", ".mypicture.info", ".mypop3.net", ".mypop3.org", ".mysecondarydns.com", ".mywww.biz", ".myz.info", ".ninth.biz", ".ns01.biz", ".ns01.info", ".ns01.us", ".ns02.biz", ".ns02.info", ".ns02.us", ".ns1.name", ".ns2.name", ".ns3.name", ".ocry.com", ".onedumb.com", ".onmypc.biz", ".onmypc.info", ".onmypc.net", ".onmypc.org", ".onmypc.us", ".organiccrap.com", ".otzo.com", ".ourhobby.com", ".pcanywhere.net", ".port25.biz", ".proxydns.com", ".qhigh.com", ".qpoe.com", ".rebatesrule.net", ".sellclassics.com", ".sendsmtp.com", ".serveuser.com", ".serveusers.com", ".sexidude.com", ".sexxxy.biz", ".sixth.biz", ".squirly.info", ".ssl443.org", ".toh.info", ".toythieves.com", ".trickip.net", ".trickip.org", ".vizvaz.com", ".wha.la", ".wikaba.com", ".www1.biz", ".wwwhost.biz", "@@|http://xx.wwwhost.biz", ".x24hr.com", ".xxuz.com", ".xxxy.biz", ".xxxy.info", ".ygto.com", ".youdontcare.com", ".yourtrap.com", ".zyns.com", ".zzux.com", "d1b183sg0nvnuh.cloudfront.net", "|https://d1b183sg0nvnuh.cloudfront.net", "d1c37gjwa26taa.cloudfront.net", "|https://d1c37gjwa26taa.cloudfront.net", "d3c33hcgiwev3.cloudfront.net", "|https://d3c33hcgiwev3.cloudfront.net", "||d3rhr7kgmtrq1v.cloudfront.net", ".3d-game.com", ".4irc.com", ".b0ne.com", ".chatnook.com", ".darktech.org", ".deaftone.com", ".dtdns.net", ".effers.com", ".etowns.net", ".etowns.org", ".flnet.org", ".gotgeeks.com", ".scieron.com", ".slyip.com", ".slyip.net", ".suroot.com", ".blogdns.org", ".dyndns.org", ".dyndns-ip.com", ".dyndns-pics.com", ".from-sd.com", ".from-pr.com", ".is-a-hunter.com", ".dynu.com", "||dynu.com", ".dynu.net", ".freeddns.org", "||accountkit.com", "cdninstagram.com", "||cdninstagram.com", "||f8.com", "||facebook.br", ".facebook.com", "||facebook.com", "@@||v6.facebook.com", "||facebook.design", "||connect.facebook.net", "||facebook.hu", "||facebook.in", "||facebook.nl", "||facebook.se", "||facebookmail.com", "||fb.com", "||fb.me", "||fb.watch", "||fbcdn.net", "||fbsbx.com", "||fbaddins.com", "||fbworkmail.com", ".instagram.com", "||instagram.com", "||m.me", "||messenger.com", "||oculus.com", "||oculuscdn.com", "||rocksdb.org", "@@||ip6.static.sl-reverse.com", "||parse.com", "||thefacebook.com", "||whatsapp.com", "||whatsapp.net", "||auntology.fandom.com", "||hongkong.fandom.com", ".ftchinese.com", "||ftchinese.com", "||1e100.net", "||466453.com", "||abc.xyz", "||about.google", "||admob.com", "||adsense.com", "||advertisercommunity.com", "||agoogleaday.com", "||ai.google", "||ampproject.org", "@@|https://www.ampproject.org", "@@|https://cdn.ampproject.org", "||android.com", "||androidify.com", "||androidtv.com", "||api.ai", ".appspot.com", "||appspot.com", "||autodraw.com", "||blog.google", "||blogblog.com", "blogspot.com", "/^https?:\\/\\/[^\\/]+blogspot\\.(.*)/", ".blogspot.hk", ".blogspot.jp", ".blogspot.tw", "||certificate-transparency.org", "||chrome.com", "||chromecast.com", "||chromeenterprise.google", "||chromeexperiments.com", "||chromercise.com", "||chromestatus.com", "||chromium.org", "||com.google", "||crbug.com", "||creativelab5.com", "||crisisresponse.google", "||crrev.com", "||data-vocabulary.org", "||debug.com", "||deepmind.com", "||deja.com", "||design.google", "||digisfera.com", "||dns.google", "||domains.google", "||duck.com", "||environment.google", "||feedburner.com", "||firebaseio.com", "||g.co", "||gcr.io", "||get.app", "||get.dev", "||get.how", "||get.page", "||getmdl.io", "||getoutline.org", "||ggpht.com", "||gmail.com", "||gmodules.com", "||godoc.org", "||golang.org", "||goo.gl", ".google.ae", ".google.as", ".google.am", ".google.at", ".google.az", ".google.ba", ".google.be", ".google.bg", ".google.ca", ".google.cd", ".google.ci", ".google.co.id", ".google.co.jp", ".google.co.kr", ".google.co.ma", ".google.co.uk", ".google.com", ".google.de", "||google.dev", ".google.dj", ".google.dk", ".google.es", ".google.fi", ".google.fm", ".google.fr", ".google.gg", ".google.gl", ".google.gr", ".google.ie", ".google.is", ".google.it", ".google.jo", ".google.kz", ".google.lv", ".google.mn", ".google.ms", ".google.nl", ".google.nu", ".google.no", ".google.ro", ".google.ru", ".google.rw", ".google.sc", ".google.sh", ".google.sk", ".google.sm", ".google.sn", ".google.tk", ".google.tm", ".google.to", ".google.tt", ".google.vu", ".google.ws", "/^https?:\\/\\/([^\\/]+\\.)*google\\.(ac|ad|ae|af|ai|al|am|as|at|az|ba|be|bf|bg|bi|bj|bs|bt|by|ca|cat|cd|cf|cg|ch|ci|cl|cm|co.ao|co.bw|co.ck|co.cr|co.id|co.il|co.in|co.jp|co.ke|co.kr|co.ls|co.ma|com|com.af|com.ag|com.ai|com.ar|com.au|com.bd|com.bh|com.bn|com.bo|com.br|com.bz|com.co|com.cu|com.cy|com.do|com.ec|com.eg|com.et|com.fj|com.gh|com.gi|com.gt|com.hk|com.jm|com.kh|com.kw|com.lb|com.ly|com.mm|com.mt|com.mx|com.my|com.na|com.nf|com.ng|com.ni|com.np|com.om|com.pa|com.pe|com.pg|com.ph|com.pk|com.pr|com.py|com.qa|com.sa|com.sb|com.sg|com.sl|com.sv|com.tj|com.tr|com.tw|com.ua|com.uy|com.vc|com.vn|co.mz|co.nz|co.th|co.tz|co.ug|co.uk|co.uz|co.ve|co.vi|co.za|co.zm|co.zw|cv|cz|de|dj|dk|dm|dz|ee|es|eu|fi|fm|fr|ga|ge|gg|gl|gm|gp|gr|gy|hk|hn|hr|ht|hu|ie|im|iq|is|it|it.ao|je|jo|kg|ki|kz|la|li|lk|lt|lu|lv|md|me|mg|mk|ml|mn|ms|mu|mv|mw|mx|ne|nl|no|nr|nu|org|pl|pn|ps|pt|ro|rs|ru|rw|sc|se|sh|si|sk|sm|sn|so|sr|st|td|tg|tk|tl|tm|tn|to|tt|us|vg|vn|vu|ws)\\/.*/", "||googleapis.cn", "||googleapis.com", "||googleapps.com", "||googleartproject.com", "||googleblog.com", "||googlebot.com", "||googlechinawebmaster.com", "||googlecode.com", "||googlecommerce.com", "||googledomains.com", "||googlearth.com", "||googleearth.com", "||googledrive.com", "||googlefiber.net", "||googlegroups.com", "||googlehosted.com", "||googleideas.com", "||googleinsidesearch.com", "||googlelabs.com", "||googlemail.com", "||googlemashups.com", "||googlepagecreator.com", "||googleplay.com", "||googleplus.com", "||googlescholar.comUSA", "||googlesource.com", "||googleusercontent.com", ".googlevideo.com", "||googlevideo.com", "||googleweblight.com", "||googlezip.net", "||groups.google.cn", "||grow.google", "||gstatic.com", "||gvt0.com", "||gvt1.com", "@@||redirector.gvt1.com", "||gvt3.com", "||gwtproject.org", "||html5rocks.com", "||iam.soy", "||igoogle.com", "||itasoftware.com", "||lers.google", "||like.com", "||madewithcode.com", "||material.io", "||nic.google", "||on2.com", "||opensource.google", "||panoramio.com", "||picasaweb.com", "||pki.goog", "||plus.codes", "||polymer-project.org", "||pride.google", "||questvisual.com", "||admin.recaptcha.net", "||api.recaptcha.net", "||api-secure.recaptcha.net", "||api-verify.recaptcha.net", "||redhotlabs.com", "||registry.google", "||research.google", "||safety.google", "||savethedate.foo", "||schema.org", "||shattered.io", "|http://sipml5.org/", "||stories.google", "||sustainability.google", "||synergyse.com", "||teachparentstech.org", "||tensorflow.org", "||tfhub.dev", "||thinkwithgoogle.com", "||tiltbrush.com", "||translate.google", "||tv.google", "||urchin.com", "||waveprotocol.org", "||waymo.com", "||web.dev", "||webmproject.org", "||webrtc.org", "||whatbrowser.org", "||widevine.com", "||withgoogle.com", "||withyoutube.com", "||x.company", "||xn--ngstr-lra8j.com", "||youtu.be", ".youtube.com", "||youtube.com", "||youtube-nocookie.com", "||youtubeeducation.com", "||youtubegaming.com", "||youtubekids.com", "||yt.be", "||ytimg.com", "||zynamics.com", "||naughtyamerica.com", "static01.nyt.com", "||nyt.com", "nytchina.com", "nytcn.me", "||nytcn.me", "||nytco.com", "|http://nyti.ms/", ".nytimes.com", "||nytimes.com", "||nytimg.com", "userapi.nytlog.com", "cn.nytstyle.com", "||nytstyle.com", ".steamcommunity.com", "||steamcommunity.com", "|http://store.steampowered.com", "||t.me", "||updates.tdesktop.com", "||telegram.dog", "||telegram.me", "||telegram.org", ".telegramdownload.com", "||telesco.pe", "||jtvnw.net", "||ttvnw.net", "||twitch.tv", "||twitchcdn.net", "||periscope.tv", ".pscp.tv", "||pscp.tv", ".t.co", "||t.co", ".tweetdeck.com", "||tweetdeck.com", "||twimg.com", ".twitpic.com", "||twitpic.com", ".twitter.com", "||twitter.com", "||twitter.jp", "||vine.co", "||gov.taipei", ".gov.tw", "|https://aiss.anws.gov.tw", "||archives.gov.tw", "||tacc.cwb.gov.tw", "||data.gov.tw", "||epa.gov.tw", "||fa.gov.tw", "||fda.gov.tw", "||hpa.gov.tw", "||immigration.gov.tw", "||itaiwan.gov.tw", "||mjib.gov.tw", "||moeaic.gov.tw", "||mofa.gov.tw", "||mol.gov.tw", "||mvdis.gov.tw", "||nat.gov.tw", "||nhi.gov.tw", "||npa.gov.tw", "||nsc.gov.tw", "||ntbk.gov.tw", "||ntbna.gov.tw", "||ntbt.gov.tw", "||ntsna.gov.tw", "||pcc.gov.tw", "||stat.gov.tw", "||taipei.gov.tw", "||taiwanjobs.gov.tw", "||thb.gov.tw", "||tipo.gov.tw", "||wda.gov.tw", "||teco-hk.org", "||teco-mo.org", "@@||aftygh.gov.tw", "@@||aide.gov.tw", "@@||tpde.aide.gov.tw", "@@||arte.gov.tw", "@@||chukuang.gov.tw", "@@||cwb.gov.tw", "@@||cycab.gov.tw", "@@||dbnsa.gov.tw", "@@||df.gov.tw", "@@||eastcoast-nsa.gov.tw", "@@||erv-nsa.gov.tw", "@@||grb.gov.tw", "@@||gysd.nyc.gov.tw", "@@||hchcc.gov.tw", "@@||hsinchu-cc.gov.tw", "@@||iner.gov.tw", "@@||klsio.gov.tw", "@@||kmseh.gov.tw", "@@||lungtanhr.gov.tw", "@@||maolin-nsa.gov.tw", "@@||matsu-news.gov.tw", "@@||matsu-nsa.gov.tw", "@@||matsucc.gov.tw", "@@||moe.gov.tw", "@@||mvdis.gov.tw", "@@||nankan.gov.tw", "@@||ncree.gov.tw", "@@||necoast-nsa.gov.tw", "@@||siraya-nsa.gov.tw", "@@||cromotc.nat.gov.tw", "@@||tax.nat.gov.tw", "@@||necoast-nsa.gov.tw", "@@||ner.gov.tw", "@@||nmmba.gov.tw", "@@||nmp.gov.tw", "@@||nmvttc.gov.tw", "@@||northguan-nsa.gov.tw", "@@||npm.gov.tw", "@@||nstm.gov.tw", "@@||ntdmh.gov.tw", "@@||ntl.gov.tw", "@@||ntsec.gov.tw", "@@||ntuh.gov.tw", "@@||nvri.gov.tw", "@@||penghu-nsa.gov.tw", "@@||post.gov.tw", "@@||siraya-nsa.gov.tw", "@@||stdtime.gov.tw", "@@||sunmoonlake.gov.tw", "@@||taitung-house.gov.tw", "@@||taoyuan.gov.tw", "@@||tphcc.gov.tw", "@@||trimt-nsa.gov.tw", "@@||vghtpe.gov.tw", "@@||vghks.gov.tw", "@@||vghtc.gov.tw", "@@||wanfang.gov.tw", "@@||yatsen.gov.tw", "@@||yda.gov.tw", "||kinmen.org.tw", "|http://www.americorps.gov", "||jpl.nasa.gov", "||pds.nasa.gov", "||solarsystem.nasa.gov", "iipdigital.usembassy.gov", "||usfk.mil", "||usmc.mil", "|http://tarr.uspto.gov/", "||tsdr.uspto.gov", "||v2ex.com", "cn.voa.mobi", "tw.voa.mobi", "||voacambodia.com", ".voachineseblog.com", "||voachineseblog.com", ".voacantonese.com", "||voacantonese.com", "voachinese.com", "||voachinese.com", "voagd.com", "||voaindonesia.com", ".voanews.com", "||voanews.com", "voatibetan.com", "||voatibetan.com", ".voatibetanenglish.com", "||voatibetanenglish.com", "||zh.ecdm.wikia.com", "||evchk.wikia.com", "fq.wikia.com", "zh.pttpedia.wikia.com/wiki/%E7%BF%92%E5%8C%85%E5%AD%90%E4%B9%8B%E4%BA%82", "cn.uncyclopedia.wikia.com", "zh.uncyclopedia.wikia.com", "||wikimedia.org", "|http://zh.wikisource.org", "||zh.wikiquote.org", "||zh.wikinews.org", "||ja.wikipedia.org", "||wikipedia.org", "||data.flurry.com", "page.bid.yahoo.com", "tw.bid.yahoo.com", "|https://tw.bid.yahoo.com", "blogs.yahoo.co.jp", "||search.yahoo.co.jp", "buy.yahoo.com.tw/gdsale", "hk.yahoo.com", "hk.knowledge.yahoo.com", "tw.money.yahoo.com", "hk.myblog.yahoo.com", "news.yahoo.com/china-blocks-bbc", "||hk.news.yahoo.com", "hk.rd.yahoo.com", "hk.search.yahoo.com/search", "hk.video.news.yahoo.com/video", "meme.yahoo.com", "tw.answers.yahoo.com", "|https://tw.answers.yahoo.com", "||tw.knowledge.yahoo.com", "||tw.mall.yahoo.com", "tw.yahoo.com", "||tw.mobi.yahoo.com", "tw.myblog.yahoo.com", "||tw.news.yahoo.com", "pulse.yahoo.com", "||search.yahoo.com", "upcoming.yahoo.com", "video.yahoo.com", "||yahoo.com.hk", "||duckduckgo-owned-server.yahoo.net", "||000webhost.com", ".030buy.com", ".0rz.tw", "|http://0rz.tw", "1-apple.com.tw", "||1-apple.com.tw", ".10.tt", ".100ke.org", ".1000giri.net", "||1000giri.net", "||10beasts.net", ".10conditionsoflove.com", "||10musume.com", "123rf.com", ".12bet.com", "||12bet.com", ".12vpn.com", ".12vpn.net", "||12vpn.com", "||12vpn.net", "||1337x.to", ".138.com", "141hongkong.com/forum", "||141jj.com", ".141tube.com", ".1688.com.au", ".173ng.com", "||173ng.com", ".177pic.info", ".17t17p.com", "||18board.com", "||18board.info", "18onlygirls.com", ".18p2p.com", ".18virginsex.com", ".1949er.org", "zhao.1984.city", "||zhao.1984.city", "1984bbs.com", "||1984bbs.com", ".1984bbs.org", "||1984bbs.org", ".1991way.com", "||1991way.com", ".1998cdp.org", ".1bao.org", "|http://1bao.org", ".1eew.com", ".1mobile.com", "|http://*.1mobile.tw", "||1pondo.tv", ".2-hand.info", ".2000fun.com/bbs", ".2008xianzhang.info", "||2008xianzhang.info", "||2017.hk", "||2047.name", "21andy.com/blog", ".21join.com", ".21pron.com", "21sextury.com", ".228.net.tw", "||233abc.com", "||24hrs.ca", "24smile.org", "2lipstube.com", ".2shared.com", "30boxes.com", ".315lz.com", "||32red.com", "||36rain.com", ".3a5a.com", "3arabtv.com", ".3boys2girls.com", ".3proxy.ru", ".3ren.ca", ".3tui.net", "||404museum.com", "||4bluestones.biz", ".4chan.com", ".4everproxy.com", "||4everproxy.com", "||4rbtv.com", "||4shared.com", "taiwannation.50webs.com", "||51.ca", "||51jav.org", ".51luoben.com", "||51luoben.com", ".5278.cc", ".5299.tv", "5aimiku.com", "5i01.com", ".5isotoi5.org", ".5maodang.com", "||63i.com", ".64museum.org", "64tianwang.com", "64wiki.com", ".66.ca", "666kb.com", "||6do.news", ".6park.com", "||6park.com", "||6parkbbs.com", "||6parker.com", "||6parknews.com", "||7capture.com", ".7cow.com", ".8-d.com", "|http://8-d.com", "85cc.net", ".85cc.us", "|http://85cc.us", "|http://85st.com", ".881903.com/page/zh-tw/", "||881903.com", ".888.com", ".888poker.com", "89.64.charter.constitutionalism.solutions", "89-64.org", "||89-64.org", "||8964museum.com", ".8news.com.tw", ".8z1.net", "||8z1.net", ".9001700.com", "|http://908taiwan.org/", "||91porn.com", "||91vps.club", ".92ccav.com", ".991.com", "|http://991.com", ".99btgc01.com", "||99btgc01.com", ".99cn.info", "|http://99cn.info", "||9bis.com", "||9bis.net", "||9news.com.au", ".tibet.a.se", "|http://tibet.a.se", "||a-normal-day.com", "a5.com.ru", "|http://aamacau.com", ".abc.com", ".abc.net.au", "||abc.net.au", ".abchinese.com", "abclite.net", "|https://www.abclite.net", ".ablwang.com", ".aboluowang.com", "||aboluowang.com", ".aboutgfw.com", ".abs.edu", ".accim.org", ".aceros-de-hispania.com", ".acevpn.com", "||acevpn.com", ".acg18.me", "|http://acg18.me", "||acgbox.org", "||acgkj.com", "||acgnx.se", ".acmedia365.com", ".acnw.com.au", "actfortibet.org", "actimes.com.au", "activpn.com", "||activpn.com", "||aculo.us", "||addictedtocoffee.de", "||addyoutube.com", ".adelaidebbs.com/bbs", ".adpl.org.hk", "|http://adpl.org.hk", ".adult-sex-games.com", "||adult-sex-games.com", "adultfriendfinder.com", "adultkeep.net/peepshow/members/main.htm", "||advanscene.com", "||advertfan.com", ".ae.org", "||aenhancers.com", "||af.mil", ".afantibbs.com", "|http://afantibbs.com", "||afr.com", ".ai-kan.net", "||ai-kan.net", "ai-wen.net", ".aiph.net", "||aiph.net", ".airasia.com", "||airconsole.com", "|http://download.aircrack-ng.org", ".airvpn.org", "||airvpn.org", ".aisex.com", "||ait.org.tw", "aiweiwei.com", ".aiweiweiblog.com", "||aiweiweiblog.com", "||www.ajsands.com", "a248.e.akamai.net", "||a248.e.akamai.net", "rfalive1.akacast.akamaistream.net", "voa-11.akacast.akamaistream.net", "||abematv.akamaized.net", "||linear-abematv.akamaized.net", "||vod-abematv.akamaized.net", "|https://fbcdn*.akamaihd.net/", "rthklive2-lh.akamaihd.net", ".akademiye.org/ug", "|http://akademiye.org/ug", "||akiba-online.com", "||akow.org", ".al-islam.com", "||al-qimmah.net", "||alabout.com", ".alanhou.com", "|http://alanhou.com", ".alarab.qa", "||alasbarricadas.org", "alexlur.org", "||alforattv.net", ".alhayat.com", ".alicejapan.co.jp", "aliengu.com", "||alive.bar", "||alkasir.com", "||all4mom.org", "||allconnected.co", ".alldrawnsex.com", "||alldrawnsex.com", ".allervpn.com", "||allfinegirls.com", ".allgirlmassage.com", "allgirlsallowed.org", ".allgravure.com", "alliance.org.hk", ".allinfa.com", "||allinfa.com", ".alljackpotscasino.com", "||allmovie.com", "||almasdarnews.com", ".alphaporno.com", "||alternate-tools.com", "alternativeto.net/software", "alvinalexander.com", "alwaysdata.com", "||alwaysdata.com", "||alwaysdata.net", ".alwaysvpn.com", "||alwaysvpn.com", "||am730.com.hk", "ameblo.jp", "||ameblo.jp", "www1.american.edu/ted/ice/tibet", "||americangreencard.com", "||amiblockedornot.com", ".amigobbs.net", ".amitabhafoundation.us", "|http://amitabhafoundation.us", ".amnesty.org", "||amnesty.org", "||amnesty.org.hk", ".amnesty.tw", ".amnestyusa.org", "||amnestyusa.org", ".amnyemachen.org", ".amoiist.com", ".amtb-taipei.org", "androidplus.co/apk", ".andygod.com", "|http://andygod.com", "annatam.com/chinese", "||anchor.fm", "||anchorfree.com", "||ancsconf.org", "||andfaraway.net", "||android-x86.org", "angelfire.com/hi/hayashi", "||angularjs.org", "animecrazy.net", "aniscartujo.com", "||aniscartujo.com", "||anobii.com", "anonymise.us", ".anonymitynetwork.com", ".anonymizer.com", ".anonymouse.org", "||anonymouse.org", "anontext.com", ".anpopo.com", ".answering-islam.org", "|http://www.antd.org", "||anthonycalzadilla.com", ".anti1984.com", "antichristendom.com", ".antiwave.net", "|http://antiwave.net", ".anyporn.com", ".anysex.com", "|http://anysex.com", ".ao3.org", "||ao3.org", "||aobo.com.au", ".aofriend.com", "|http://aofriend.com", ".aofriend.com.au", ".aojiao.org", "||aomiwang.com", "video.ap.org", "||apat1989.org", ".apetube.com", "||apiary.io", ".apigee.com", "||apigee.com", "||apk.support", "||apk-dl.com", "||apkcombo.com", ".apkmonk.com/app", "||apkmonk.com", "||apkplz.com", "apkpure.com", "||apkpure.com", ".aplusvpn.com", "||appbrain.com", ".appdownloader.net/Android", ".appledaily.com", "||appledaily.com", "appledaily.com.hk", "||appledaily.com.hk", "appledaily.com.tw", "||appledaily.com.tw", ".appshopper.com", "|http://appshopper.com", "||appsocks.net", "||appsto.re", ".aptoide.com", "||aptoide.com", "||archives.gov", ".archive.fo", "||archive.fo", ".archive.is", "||archive.is", ".archive.li", "||archive.li", "||archive.org", "||archive.ph", "archive.today", "|https://archive.today", "||archiveofourown.com", "||archiveofourown.org", ".arctosia.com", "|http://arctosia.com", "||areca-backup.org", ".arethusa.su", "||arethusa.su", "||arlingtoncemetery.mil", "||army.mil", ".art4tibet1998.org", "artofpeacefoundation.org", "artsy.net", "||asacp.org", "asdfg.jp/dabr", "asg.to", ".asia-gaming.com", ".asiaharvest.org", "||asiaharvest.org", "||asianage.com", "||asianews.it", "|http://japanfirst.asianfreeforum.com/", "||asiansexdiary.com", "||asianwomensfilm.de", ".asiatgp.com", ".asiatoday.us", "||askstudent.com", ".askynz.net", "||askynz.net", "||aspi.org.au", "||aspistrategist.org.au", "||assembla.com", "||astrill.com", "||atc.org.au", ".atchinese.com", "|http://atchinese.com", "atgfw.org", ".atlaspost.com", "||atlaspost.com", "||atdmt.com", ".atlanta168.com", "||atlanta168.com", ".atnext.com", "||atnext.com", "ice.audionow.com", ".av.com", "||av.movie", ".av-e-body.com", "avaaz.org", "||avaaz.org", ".avbody.tv", ".avcity.tv", ".avcool.com", ".avdb.in", "||avdb.in", ".avdb.tv", "||avdb.tv", ".avfantasy.com", "||avg.com", ".avgle.com", "||avgle.com", "||avidemux.org", "||avoision.com", ".avyahoo.com", "||axios.com", "||axureformac.com", ".azerbaycan.tv", "azerimix.com", "boxun*.azurewebsites.net", "||boxun*.azurewebsites.net", "||b-ok.cc", "forum.baby-kingdom.com", "||babylonbee.com", "babynet.com.hk", "backchina.com", "||backchina.com", ".backpackers.com.tw/forum", "backtotiananmen.com", ".badiucao.com", "||badiucao.com", ".badjojo.com", "badoo.com", "|http://*2.bahamut.com.tw", "||baidu.jp", ".baijie.org", "|http://baijie.org", "||bailandaily.com", "||baixing.me", "||bakgeekhome.tk", ".banana-vpn.com", "||banana-vpn.com", ".band.us", "||bandcamp.com", ".bandwagonhost.com", "||bandwagonhost.com", ".bangbrosnetwork.com", ".bangchen.net", "|http://bangchen.net", "||bangkokpost.com", "||bangyoulater.com", "bannedbook.org", "||bannedbook.org", ".bannednews.org", ".baramangaonline.com", "|http://baramangaonline.com", ".barenakedislam.com", "||barnabu.co.uk", "||barton.de", ".bastillepost.com", "||bastillepost.com", "bayvoice.net", "||bayvoice.net", "dajusha.baywords.com", "||bbchat.tv", "||bb-chat.tv", ".bbg.gov", ".bbkz.com/forum", ".bbnradio.org", "bbs-tw.com", ".bbsdigest.com/thread", "||bbsfeed.com", "bbsland.com", ".bbsmo.com", ".bbsone.com", "bbtoystore.com", ".bcast.co.nz", ".bcc.com.tw/board", ".bcchinese.net", ".bcmorning.com", "bdsmvideos.net", ".beaconevents.com", ".bebo.com", "||bebo.com", ".beevpn.com", "||beevpn.com", ".behindkink.com", "||beijing1989.com", "beijingspring.com", "||beijingspring.com", ".beijingzx.org", "|http://beijingzx.org", ".belamionline.com", ".bell.wiki", "|http://bell.wiki", "bemywife.cc", "beric.me", "||berlinerbericht.de", ".berlintwitterwall.com", "||berlintwitterwall.com", ".berm.co.nz", ".bestforchina.org", "||bestforchina.org", ".bestgore.com", ".bestpornstardb.com", "||bestvpn.com", ".bestvpnanalysis.com", ".bestvpnserver.com", ".bestvpnservice.com", ".bestvpnusa.com", "||bet365.com", ".betfair.com", "||betternet.co", ".bettervpn.com", "||bettervpn.com", ".bettween.com", "||bettween.com", "||betvictor.com", ".bewww.net", ".beyondfirewall.com", "||bfnn.org", "||bfsh.hk", ".bgvpn.com", "||bgvpn.com", ".bianlei.com", "@@||bianlei.com", "biantailajiao.com", "biantailajiao.in", ".biblesforamerica.org", "|http://biblesforamerica.org", ".bic2011.org", "||biedian.me", "bigfools.com", "||bigjapanesesex.com", ".bignews.org", "||bignews.org", ".bigsound.org", "||bild.de", ".biliworld.com", "|http://biliworld.com", "|http://billypan.com/wiki", ".binux.me", "ai.binwang.me/couplet", ".bit.do", "|http://bit.do", ".bit.ly", "|http://bit.ly", "||bitchute.com", "||bitcointalk.org", ".bitshare.com", "||bitshare.com", "bitsnoop.com", ".bitvise.com", "||bitvise.com", "bizhat.com", "||bl-doujinsouko.com", ".bjnewlife.org", ".bjs.org", "bjzc.org", "||bjzc.org", ".blacklogic.com", ".blackvpn.com", "||blackvpn.com", "blewpass.com", "tor.blingblingsquad.net", ".blinkx.com", "||blinkx.com", "blinw.com", ".blip.tv", "||blip.tv/", ".blockcn.com", "||blockcn.com", "||blockless.com", "||blog.de", ".blog.jp", "|http://blog.jp", "@@||jpush.cn", ".blogcatalog.com", "||blogcatalog.com", "||blogcity.me", ".blogger.com", "||blogger.com", "blogimg.jp", "||blog.kangye.org", ".bloglines.com", "||bloglines.com", "||bloglovin.com", "rconversation.blogs.com", "blogtd.net", ".blogtd.org", "|http://blogtd.org", "||bloodshed.net", "||assets.bwbx.io", "||bloomfortune.com", "blueangellive.com", ".bmfinn.com", ".bnews.co", "||bnews.co", "||bnrmetal.com", "boardreader.com/thread", "||boardreader.com", ".bod.asia", "|http://bod.asia", ".bodog88.com", ".bolehvpn.net", "||bolehvpn.net", "bonbonme.com", ".bonbonsex.com", ".bonfoundation.org", ".bongacams.com", "||boobstagram.com", "||book.com.tw", "bookepub.com", "||books.com.tw", "||botanwang.com", ".bot.nu", ".bowenpress.com", "||bowenpress.com", "||app.box.com", "dl.box.net", "||dl.box.net", ".boxpn.com", "||boxpn.com", "boxun.com", "||boxun.com", ".boxun.tv", "||boxun.tv", "boxunblog.com", "||boxunblog.com", ".boxunclub.com", "boyangu.com", ".boyfriendtv.com", ".boysfood.com", "||br.st", ".brainyquote.com/quotes/authors/d/dalai_lama", "||brandonhutchinson.com", "||braumeister.org", "||brave.com", ".bravotube.net", "||bravotube.net", ".brazzers.com", "||brazzers.com", ".break.com", "||break.com", "breakgfw.com", "||breakgfw.com", "breaking911.com", ".breakingtweets.com", "||breakingtweets.com", "||breakwall.net", "briian.com/6511/freegate", ".briefdream.com/%E7%B4%A0%E6%A3%BA", "brizzly.com", "||brizzly.com", "||brkmd.com", "broadbook.com", ".broadpressinc.com", "||broadpressinc.com", "bbs.brockbbs.com", "||brookings.edu", "brucewang.net", ".brutaltgp.com", "||brutaltgp.com", ".bt2mag.com", "||bt95.com", ".btaia.com", ".btbtav.com", "|http://btdigg.org", ".btku.me", "||btku.me", "||btku.org", ".btspread.com", ".btsynckeys.com", ".budaedu.org", "||budaedu.org", ".buddhanet.com.tw/zfrop/tibet", ".buddhistchannel.tv", ".buffered.com", "|http://buffered.com", "||bullguard.com", ".bullog.org", "||bullog.org", ".bullogger.com", "||bullogger.com", "||bunbunhk.com", ".busayari.com", "|http://busayari.com", "||business-humanrights.org", ".businessinsider.com/bing-could-be-censoring-search-results-2014", ".businessinsider.com/china-banks-preparing-for-debt-implosion-2014", ".businessinsider.com/hong-kong-activists-defy-police-tear-gas-as-protests-continue-overnight-2014", ".businessinsider.com/internet-outages-reported-in-north-korea-2014", ".businessinsider.com/iphone-6-is-approved-for-sale-in-china-2014", ".businessinsider.com/nfl-announcers-surface-tablets-2014", ".businessinsider.com/panama-papers", ".businessinsider.com/umbrella-man-hong-kong-2014", "|http://www.businessinsider.com.au/*", ".businesstoday.com.tw", "||businesstoday.com.tw", ".busu.org/news", "|http://busu.org/news", "busytrade.com", ".buugaa.com", ".buzzhand.com", ".buzzhand.net", ".buzzorange.com", "||buzzorange.com", "||bvpn.com", "||bwh1.net", "bwsj.hk", "||bx.tl", "||bypasscensorship.org", "||c-span.org", ".c-spanvideo.org", "||c-spanvideo.org", "||c-est-simple.com", ".c100tibet.org", "||cablegatesearch.net", ".cachinese.com", ".cacnw.com", "|http://cacnw.com", ".cactusvpn.com", "||cactusvpn.com", ".cafepress.com", ".cahr.org.tw", ".caijinglengyan.com", "||caijinglengyan.com", ".calameo.com/books", ".calgarychinese.ca", ".calgarychinese.com", ".calgarychinese.net", "|http://blog.calibre-ebook.com", "falun.caltech.edu", ".its.caltech.edu/~falun/", ".cam4.com", ".cam4.jp", ".cam4.sg", ".camfrog.com", "||camfrog.com", "||campaignforuyghurs.org", "||cams.com", ".cams.org.sg", "canadameet.com", ".canalporno.com", "|http://bbs.cantonese.asia/", ".canyu.org", "||canyu.org", ".cao.im", ".caobian.info", "||caobian.info", "caochangqing.com", "||caochangqing.com", ".cap.org.hk", "||cap.org.hk", ".carabinasypistolas.com", "cardinalkungfoundation.org", "||posts.careerengine.us", "carmotorshow.com", "||carrd.co", "ss.carryzhou.com", ".cartoonmovement.com", "||cartoonmovement.com", ".casadeltibetbcn.org", ".casatibet.org.mx", "|http://casatibet.org.mx", ".cari.com.my", "||cari.com.my", "||caribbeancom.com", ".casinoking.com", ".casinoriva.com", "||catch22.net", ".catchgod.com", "|http://catchgod.com", "||catfightpayperview.xxx", ".catholic.org.hk", "||catholic.org.hk", "catholic.org.tw", "||catholic.org.tw", ".cathvoice.org.tw", "||cato.org", "||cattt.com", ".cbc.ca", "||cbc.ca", ".cbsnews.com/video", ".cbtc.org.hk", "||southpark.cc.com", "||cccat.cc", "||cccat.co", ".ccdtr.org", "||ccdtr.org", ".cchere.com", "||cchere.com", ".ccim.org", ".cclife.ca", "cclife.org", "||cclife.org", "cclifefl.org", "||cclifefl.org", ".ccthere.com", "||ccthere.com", "||ccthere.net", ".cctmweb.net", ".cctongbao.com/article/2078732", "ccue.ca", "ccue.com", ".ccvoice.ca", ".ccw.org.tw", ".cgdepot.org", "|http://cgdepot.org", "||cdbook.org", ".cdcparty.com", ".cdef.org", "||cdef.org", "||cdig.info", "cdjp.org", "||cdjp.org", ".cdn-apple.com", "||cdn-apple.com", ".cdnews.com.tw", "cdp1989.org", "cdp1998.org", "||cdp1998.org", "cdp2006.org", "||cdp2006.org", ".cdpa.url.tw", "cdpeu.org", "cdpusa.org", "cdpweb.org", "||cdpweb.org", "cdpwu.org", "||cdpwu.org", "||cdw.com", ".cecc.gov", "||cecc.gov", "||cellulo.info", "||cenews.eu", "||centerforhumanreprod.com", "||centralnation.com", ".centurys.net", "|http://centurys.net", ".cfhks.org.hk", ".cfos.de", "||cfr.org", ".cftfc.com", ".cgst.edu", ".change.org", "||change.org", ".changp.com", "||changp.com", ".changsa.net", "|http://changsa.net", "||channelnewsasia.com", ".chapm25.com", ".chaturbate.com", "||chaturbate.com", ".chuang-yen.org", "||checkgfw.com", "chengmingmag.com", ".chenguangcheng.com", "||chenguangcheng.com", ".chenpokong.com", "||chenpokong.com", ".chenpokong.net", "|http://chenpokong.net", "||chenpokongvip.com", "||cherrysave.com", ".chhongbi.org", "chicagoncmtv.com", "|http://chicagoncmtv.com", ".china-week.com", "china101.com", "||china101.com", "||china18.org", "||china21.com", "china21.org", "||china21.org", ".china5000.us", "chinaaffairs.org", "||chinaaffairs.org", "||chinaaid.me", "chinaaid.us", "chinaaid.org", "chinaaid.net", "||chinaaid.net", "chinacomments.org", "||chinacomments.org", ".chinachange.org", "||chinachange.org", "chinachannel.hk", "||chinachannel.hk", ".chinacitynews.be", ".chinadialogue.net", ".chinadigitaltimes.net", "||chinadigitaltimes.net", ".chinaelections.org", "||chinaelections.org", ".chinaeweekly.com", "||chinaeweekly.com", "||chinafreepress.org", ".chinagate.com", "chinageeks.org", "chinagfw.org", "||chinagfw.org", ".chinagonet.com", ".chinagreenparty.org", "||chinagreenparty.org", ".chinahorizon.org", "||chinahorizon.org", ".chinahush.com", ".chinainperspective.com", "||chinainterimgov.org", "chinalaborwatch.org", "chinalawtranslate.com", ".chinapost.com.tw/taiwan/national/national-news", "chinaxchina.com/howto", "chinalawandpolicy.com", ".chinamule.com", "||chinamule.com", "chinamz.org", ".chinanewscenter.com", "|https://chinanewscenter.com", ".chinapress.com.my", "||chinapress.com.my", ".china-review.com.ua", "|http://china-review.com.ua", ".chinarightsia.org", "chinasmile.net/forums", "chinasocialdemocraticparty.com", "||chinasocialdemocraticparty.com", "chinasoul.org", "||chinasoul.org", ".chinasucks.net", "||chinatopsex.com", ".chinatown.com.au", "chinatweeps.com", "chinaway.org", ".chinaworker.info", "||chinaworker.info", "chinayouth.org.hk", "chinayuanmin.org", "||chinayuanmin.org", ".chinese-hermit.net", "chinese-leaders.org", "chinese-memorial.org", ".chinesedaily.com", "||chinesedailynews.com", ".chinesedemocracy.com", "||chinesedemocracy.com", "||chinesegay.org", ".chinesen.de", "||chinesen.de", ".chinesenews.net.au/", ".chinesepen.org", "||chineseradioseattle.com", ".chinesetalks.net/ch", "||chineseupress.com", ".chingcheong.com", "||chingcheong.com", ".chinman.net", "|http://chinman.net", "chithu.org", "||cnnews.chosun.com", ".chrdnet.com", "|http://chrdnet.com", ".christianfreedom.org", "||christianfreedom.org", "christianstudy.com", "||christianstudy.com", "christusrex.org/www1/sdc", ".chubold.com", "chubun.com", "||christiantimes.org.hk", ".chrlawyers.hk", "||chrlawyers.hk", ".churchinhongkong.org/b5/index.php", "|http://churchinhongkong.org/b5/index.php", ".chushigangdrug.ch", ".cienen.com", ".cineastentreff.de", ".cipfg.org", "||circlethebayfortibet.org", "||cirosantilli.com", ".citizencn.com", "||citizencn.com", "||citizenlab.ca", "||citizenlab.org", "||citizenscommission.hk", ".citizenlab.org", "citizensradio.org", ".city365.ca", "|http://city365.ca", "city9x.com", "||citypopulation.de", ".citytalk.tw/event", ".civicparty.hk", "||civicparty.hk", ".civildisobediencemovement.org", "civilhrfront.org", "||civilhrfront.org", ".civiliangunner.com", ".civilmedia.tw", "||civilmedia.tw", "psiphon.civisec.org", "||vpn.cjb.net", ".ck101.com", "||ck101.com", ".clarionproject.org/news/islamic-state-isis-isil-propaganda", "||classicalguitarblog.net", ".clb.org.hk", "clearharmony.net", "clearwisdom.net", "||clinica-tibet.ru", ".clipfish.de", "cloakpoint.com", "||app.cloudcone.com", "||club1069.com", "||clubhouseapi.com", "cmi.org.tw", "|http://www.cmoinc.org", "cmp.hku.hk", "hkupop.hku.hk", "||cmule.com", "||cmule.org", "||cms.gov", "|http://vpn.cmu.edu", "|http://vpn.sv.cmu.edu", ".cn6.eu", ".cna.com.tw", "||cna.com.tw", ".cnabc.com", ".cnd.org", "||cnd.org", "download.cnet.com", ".cnex.org.cn", ".cnineu.com", "wiki.cnitter.com", ".cnn.com/video", ".cnpolitics.org", "||cnpolitics.org", ".cn-proxy.com", "|http://cn-proxy.com", ".cnproxy.com", "blog.cnyes.com", "news.cnyes.com", "||coat.co.jp", ".cochina.co", "||cochina.co", "||cochina.org", ".code1984.com/64", "|http://goagent.codeplex.com", "||codeshare.io", "||codeskulptor.org", "||conoha.jp", "|http://tosh.comedycentral.com", "comefromchina.com", "||comefromchina.com", ".comic-mega.me", "commandarms.com", "||commentshk.com", ".communistcrimes.org", "||communistcrimes.org", "||communitychoicecu.com", "||comparitech.com", "||compileheart.com", "||conoha.jp", ".contactmagazine.net", ".convio.net", ".coobay.com", "|http://www.cool18.com/bbs*/", ".coolaler.com", "||coolaler.com", "coolder.com", "||coolder.com", "||coolloud.org.tw", ".coolncute.com", "||coolstuffinc.com", "corumcollege.com", ".cos-moe.com", "|http://cos-moe.com", ".cosplayjav.pl", "|http://cosplayjav.pl", ".cotweet.com", "||cotweet.com", ".coursehero.com", "||coursehero.com", "cpj.org", "||cpj.org", ".cq99.us", "|http://cq99.us", "crackle.com", "||crackle.com", ".crazys.cc", ".crazyshit.com", "||crazyshit.com", "||crchina.org", "crd-net.org", "creaders.net", "||creaders.net", ".creadersnet.com", "||cristyli.com", ".crocotube.com", "|http://crocotube.com", ".crossthewall.net", "||crossthewall.net", ".crossvpn.net", "||crossvpn.net", "||crucial.com", "||blog.cryptographyengineering.com", "csdparty.com", "||csdparty.com", "||csis.org", "||csmonitor.com", "||csuchen.de", ".csw.org.uk", ".ct.org.tw", "||ct.org.tw", ".ctao.org", ".ctfriend.net", ".ctitv.com.tw", "||ctowc.org", ".cts.com.tw", "||cts.com.tw", "||ctwant.com", "|http://library.usc.cuhk.edu.hk/", "|http://mjlsh.usc.cuhk.edu.hk/", ".cuhkacs.org/~benng", ".cuihua.org", "||cuihua.org", ".cuiweiping.net", "||cuiweiping.net", "||culture.tw", ".cumlouder.com", "||cumlouder.com", "||curvefish.com", "||cusp.hk", ".cusu.hk", "||cusu.hk", ".cutscenes.net", "||cutscenes.net", ".cw.com.tw", "||cw.com.tw", "|http://forum.cyberctm.com", "cyberghostvpn.com", "||cyberghostvpn.com", "||cynscribe.com", "cytode.us", "||ifan.cz.cc", "||mike.cz.cc", "||nic.cz.cc", ".d-fukyu.com", "|http://d-fukyu.com", "cl.d0z.net", ".d100.net", "||d100.net", ".d2bay.com", "|http://d2bay.com", ".dabr.co.uk", "||dabr.co.uk", "dabr.eu", "dabr.mobi", "||dabr.mobi", "||dabr.me", "dadazim.com", "||dadazim.com", ".dadi360.com", ".dafabet.com", "dafagood.com", "dafahao.com", ".dafoh.org", ".daftporn.com", ".dagelijksestandaard.nl", ".daidostup.ru", "|http://daidostup.ru", ".dailidaili.com", "||dailidaili.com", "||dailymail.co.uk", ".dailymotion.com", "||dailymotion.com", "||dailysabah.com", "daiphapinfo.net", ".dajiyuan.com", "||dajiyuan.de", "dajiyuan.eu", "dalailama.com", ".dalailama.mn", "|http://dalailama.mn", ".dalailama.ru", "||dalailama.ru", "dalailama80.org", ".dalailama-archives.org", ".dalailamacenter.org", "|http://dalailamacenter.org", "dalailamafellows.org", ".dalailamafilm.com", ".dalailamafoundation.org", ".dalailamahindi.com", ".dalailamainaustralia.org", ".dalailamajapanese.com", ".dalailamaprotesters.info", ".dalailamaquotes.org", ".dalailamatrust.org", ".dalailamavisit.org.nz", ".dalailamaworld.com", "||dalailamaworld.com", "dalianmeng.org", "||dalianmeng.org", ".daliulian.org", "||daliulian.org", ".danke4china.net", "||danke4china.net", ".danwei.org", "daolan.net", ".daozhongxing.org", "darktoy.net", "||dastrassi.org", "||daum.net", ".david-kilgour.com", "|http://david-kilgour.com", "daxa.cn", "||daxa.cn", "cn.dayabook.com", ".daylife.com/topic/dalai_lama", "||db.tt", ".dbc.hk/main", "||dbgjd.com", "||dcard.tw", "dcmilitary.com", ".ddc.com.tw", ".ddhw.info", "||de-sci.org", ".de-sci.org", "||deadline.com", "||decodet.co", ".definebabe.com", "||delcamp.net", "delicious.com/GFWbookmark", ".democrats.org", "||democrats.org", ".demosisto.hk", "||demosisto.hk", "||desc.se", "||dessci.com", ".destroy-china.jp", "||deutsche-welle.de", "||deviantart.com", "||deviantart.net", "||devio.us", "||devpn.com", "||dfas.mil", "dfn.org", "dharmakara.net", ".dharamsalanet.com", ".diaoyuislands.org", "||diaoyuislands.org", ".difangwenge.org", "|http://digiland.tw/", "||digitalnomadsproject.org", ".diigo.com", "||diigo.com", "||dilber.se", "||furl.net", ".dipity.com", "||directcreative.com", ".discuss.com.hk", "||discuss.com.hk", ".discuss4u.com", "disp.cc", ".disqus.com", "||disqus.com", ".dit-inc.us", "||dit-inc.us", ".dizhidizhi.com", "||dizhuzhishang.com", "djangosnippets.org", ".djorz.com", "||djorz.com", "||dl-laby.jp", "||dlive.tv", "||dlsite.com", "||dlyoutube.com", "||dmcdn.net", ".dnscrypt.org", "||dnscrypt.org", "||dns2go.com", "||dnssec.net", "doctorvoice.org", ".dogfartnetwork.com/tour", "gloryhole.com", ".dojin.com", ".dok-forum.net", "||dolc.de", "||dolf.org.hk", "||dollf.com", ".domain.club.tw", ".domaintoday.com.au", "chinese.donga.com", "dongtaiwang.com", "||dongtaiwang.com", ".dongtaiwang.net", "||dongtaiwang.net", ".dongyangjing.com", "|http://danbooru.donmai.us", ".dontfilter.us", "||dontmovetochina.com", ".dorjeshugden.com", ".dotplane.com", "||dotplane.com", "||dotsub.com", ".dotvpn.com", "||dotvpn.com", ".doub.io", "||doub.io", "||dougscripts.com", "||douhokanko.net", "||doujincafe.com", "dowei.org", "|https://bartender.dowjones.com", "dphk.org", "dpp.org.tw", "||dpp.org.tw", "||dpr.info", "||dragonsprings.org", ".dreamamateurs.com", ".drepung.org", "||drgan.net", ".drmingxia.org", "|http://drmingxia.org", "||dropbooks.tv", "||dropbox.com", "||api.dropboxapi.com", "||notify.dropboxapi.com", "||dropboxusercontent.com", "drsunacademy.com", ".drtuber.com", ".dscn.info", "|http://dscn.info", ".dstk.dk", "|http://dstk.dk", "||dtiblog.com", "||dtic.mil", ".dtwang.org", ".duanzhihu.com", ".duckdns.org", "|http://duckdns.org", ".duckduckgo.com", "||duckduckgo.com", ".duckload.com/download", "||duckmylife.com", ".duga.jp", "|http://duga.jp", ".duihua.org", "||duihua.org", "||duihuahrjournal.org", ".dunyabulteni.net", ".duoweitimes.com", "||duoweitimes.com", "duping.net", "||duplicati.com", "dupola.com", "dupola.net", ".dushi.ca", "||duyaoss.com", "||dvorak.org", ".dw.com", "||dw.com", "||dw.de", ".dw-world.com", "||dw-world.com", ".dw-world.de", "|http://dw-world.de", "www.dwheeler.com", "dwnews.com", "||dwnews.com", "dwnews.net", "||dwnews.net", "xys.dxiong.com", "||dynawebinc.com", "||dysfz.cc", ".dzze.com", "||e-classical.com.tw", "||e-gold.com", ".e-gold.com", ".e-hentai.org", "||e-hentai.org", ".e-hentaidb.com", "|http://e-hentaidb.com", "e-info.org.tw", ".e-traderland.net/board", ".e-zone.com.hk/discuz", "|http://e-zone.com.hk/discuz", ".e123.hk", "||e123.hk", ".earlytibet.com", "|http://earlytibet.com", ".earthcam.com", ".earthvpn.com", "||earthvpn.com", "eastern-ark.com", ".easternlightning.org", ".eastturkestan.com", "|http://www.eastturkistan.net/", ".eastturkistan-gov.org", ".eastturkistancc.org", ".eastturkistangovernmentinexile.us", "||eastturkistangovernmentinexile.us", ".easyca.ca", ".easypic.com", "||fnc.ebc.net.tw", ".ebony-beauty.com", "ebookbrowse.com", "ebookee.com", "||ecfa.org.tw", "ushuarencity.echainhost.com", "||ecimg.tw", "ecministry.net", ".economist.com", "bbs.ecstart.com", "edgecastcdn.net", "||edgecastcdn.net", "/twimg\\.edgesuite\\.net\\/\\/?appledaily/", "edicypages.com", ".edmontonchina.cn", ".edmontonservice.com", "edoors.com", ".edubridge.com", "||edubridge.com", ".edupro.org", "||eevpn.com", "efcc.org.hk", ".efukt.com", "|http://efukt.com", "||eic-av.com", "||eireinikotaerukai.com", ".eisbb.com", ".eksisozluk.com", "||eksisozluk.com", "electionsmeter.com", "||elgoog.im", ".ellawine.org", ".elpais.com", "||elpais.com", ".eltondisney.com", ".emaga.com/info/3407", "emilylau.org.hk", ".emanna.com/chineseTraditional", "bitc.bme.emory.edu/~lzhou/blogs", ".empfil.com", ".emule-ed2k.com", "|http://emule-ed2k.com", ".emulefans.com", "|http://emulefans.com", ".emuparadise.me", ".enanyang.my", "||encrypt.me", "||enewstree.com", ".enfal.de", "chinese.engadget.com", "||engagedaily.org", "englishforeveryone.org", "||englishfromengland.co.uk", "englishpen.org", ".enlighten.org.tw", "||entermap.com", "||app.evozi.com", ".episcopalchurch.org", ".epochhk.com", "|http://epochhk.com", "epochtimes-bg.com", "||epochtimes-bg.com", "epochtimes-romania.com", "||epochtimes-romania.com", "epochtimes.co.il", "||epochtimes.co.il", "epochtimes.co.kr", "||epochtimes.co.kr", "epochtimes.com", "||epochtimes.com", ".epochtimes.cz", "epochtimes.de", "epochtimes.fr", ".epochtimes.ie", ".epochtimes.it", "epochtimes.jp", "epochtimes.ru", "epochtimes.se", "epochtimestr.com", ".epochweek.com", "||epochweek.com", "||epochweekly.com", ".eporner.com", ".equinenow.com", "erabaru.net", ".eracom.com.tw", ".eraysoft.com.tr", ".erepublik.com", ".erights.net", "||erights.net", ".erktv.com", "|http://erktv.com", "||ernestmandel.org", "||erodaizensyu.com", "||erodoujinlog.com", "||erodoujinworld.com", "||eromanga-kingdom.com", "||eromangadouzin.com", ".eromon.net", "|http://eromon.net", ".eroprofile.com", ".eroticsaloon.net", ".eslite.com", "||eslite.com", "wiki.esu.im/%E8%9B%A4%E8%9B%A4%E8%AF%AD%E5%BD%95", "||esu.dog", ".etaa.org.au", ".etadult.com", "etaiwannews.com", "||etizer.org", "||etokki.com", "||etsy.com", ".ettoday.net/news/20151216/614081", "etvonline.hk", ".eu.org", "||eu.org", ".eucasino.com", ".eulam.com", ".eurekavpt.com", "||eurekavpt.com", ".euronews.com", "||euronews.com", "eeas.europa.eu/delegations/china/press_corner/all_news/news/2015/20150716_zh", "eeas.europa.eu/statements-eeas/2015/151022", ".evschool.net", "|http://evschool.net", "||exblog.jp", "||blog.exblog.co.jp", "@@||www.exblog.jp", ".exchristian.hk", "||exchristian.hk", "|http://blog.excite.co.jp", "||exhentai.org", "||exmormon.org", "||expatshield.com", ".expecthim.com", "||expecthim.com", "experts-univers.com", "||exploader.net", ".expressvpn.com", "||expressvpn.com", ".extremetube.com", "eyevio.jp", "||eyevio.jp", ".eyny.com", "||eyny.com", ".ezpc.tk/category/soft", ".ezpeer.com", "||facebookquotes4u.com", ".faceless.me", "||faceless.me", "|http://facesoftibetanselfimmolators.info", "||facesofnyfw.com", "||factpedia.org", ".faith100.org", "|http://faith100.org", ".faithfuleye.com", "||faiththedog.info", ".fakku.net", "||fallenark.com", ".falsefire.com", "||falsefire.com", "falun-co.org", "falunart.org", "||falunasia.info", "|http://falunau.org", ".falunaz.net", "falundafa.org", "falundafa-dc.org", "||falundafa-florida.org", "||falundafa-nc.org", "||falundafa-pa.net", "||falundafa-sacramento.org", "falun-ny.net", "||falundafaindia.org", "falundafamuseum.org", ".falungong.club", ".falungong.de", "falungong.org.uk", "||falunhr.org", "faluninfo.de", "faluninfo.net", ".falunpilipinas.net", "||falunworld.net", "familyfed.org", ".fangeming.com", "||fanglizhi.info", "||fangong.org", "fangongheike.com", ".fanqiang.tk", "fanqianghou.com", "||fanqianghou.com", ".fanqiangzhe.com", "||fanqiangzhe.com", "||fantv.hk", "fapdu.com", "faproxy.com", ".fawanghuihui.org", "fanqiangyakexi.net", "fail.hk", "||famunion.com", ".fan-qiang.com", ".fangbinxing.com", "||fangbinxing.com", "fangeming.com", ".fangmincn.org", "||fangmincn.org", ".fanhaodang.com", "||fanqiang.network", "||fanswong.com", ".fanyue.info", ".farwestchina.com", "en.favotter.net", "nytimes.map.fastly.net", "||nytimes.map.fastly.net", "||fast.wistia.com", "||fastestvpn.com", "||fastssh.com", "||faststone.org", "favstar.fm", "||favstar.fm", "faydao.com/weblog", "||faz.net", ".fc2.com", ".fc2china.com", ".fc2cn.com", "||fc2cn.com", "fc2blog.net", "|http://uygur.fc2web.com/", "video.fdbox.com", ".fdc64.de", ".fdc64.org", ".fdc89.jp", "||fourface.nodesnoop.com", "||feeder.co", "||feelssh.com", "feer.com", ".feifeiss.com", "|http://feitianacademy.org", ".feitian-california.org", "||feixiaohao.com", "||feministteacher.com", ".fengzhenghu.com", "||fengzhenghu.com", ".fengzhenghu.net", "||fengzhenghu.net", ".fevernet.com", "|http://ff.im", "fffff.at", "fflick.com", ".ffvpn.com", "fgmtv.net", ".fgmtv.org", ".fhreports.net", "|http://fhreports.net", ".figprayer.com", "||figprayer.com", ".fileflyer.com", "||fileflyer.com", "|http://feeds.fileforum.com", ".files2me.com", ".fileserve.com/file", "fillthesquare.org", "filmingfortibet.org", ".filthdump.com", ".finchvpn.com", "||finchvpn.com", "findmespot.com", "||findyoutube.com", "||findyoutube.net", ".fingerdaily.com", "finler.net", ".firearmsworld.net", "|http://firearmsworld.net", ".fireofliberty.org", "||fireofliberty.org", ".firetweet.io", "||firetweet.io", "||firstpost.com", ".flagsonline.it", "fleshbot.com", ".fleursdeslettres.com", "|http://fleursdeslettres.com", "||flgg.us", "||flgjustice.org", "||flickr.com", "||staticflickr.com", "flickrhivemind.net", ".flickriver.com", ".fling.com", "||flipkart.com", "||flog.tw", ".flyvpn.com", "||flyvpn.com", "|http://cn.fmnnow.com", "fofldfradio.org", "blog.foolsmountain.com", ".forum4hk.com", "fangong.forums-free.com", "pioneer-worker.forums-free.com", "|https://ss*.4sqi.net", "video.foxbusiness.com", "|http://foxgay.com", "||fringenetwork.com", "||flecheinthepeche.fr", ".fochk.org", "||fochk.org", "||focustaiwan.tw", ".focusvpn.com", "||fofg.org", ".fofg-europe.net", ".fooooo.com", "||fooooo.com", "||foreignaffairs.com", ".fotile.me", "||fourthinternational.org", "||foxdie.us", "||foxsub.com", "foxtang.com", ".fpmt.org", "|http://fpmt.org", ".fpmt.tw", ".fpmt-osel.org", "||fpmtmexico.org", "fqok.org", "||fqrouter.com", "||franklc.com", ".freakshare.com", "|http://freakshare.com", "||free4u.com.ar", "free-gate.org", ".free-hada-now.org", "free-proxy.cz", ".free.fr/adsl", "kineox.free.fr", "tibetlibre.free.fr", "||freealim.com", "whitebear.freebearblog.org", "||freebrowser.org", ".freechal.com", ".freedomchina.info", "||freedomchina.info", ".freedomhouse.org", "||freedomhouse.org", ".freedomsherald.org", "||freedomsherald.org", ".freefq.com", ".freefuckvids.com", ".freegao.com", "||freegao.com", "freeilhamtohti.org", "||freekazakhs.org", ".freekwonpyong.org", "||saveliuxiaobo.com", ".freelotto.com", "||freelotto.com", "freeman2.com", ".freeopenvpn.com", "freemoren.com", "freemorenews.com", "freemuse.org/archives/789", "freenet-china.org", "freenewscn.com", "cn.freeones.com", ".freeoz.org/bbs", "||freeoz.org", "||freessh.us", "free4u.com.ar", ".free-ssh.com", "||free-ssh.com", "||freebeacon.com", ".freechina.news", "||freechinaforum.org", "||freechinaweibo.com", ".freedomcollection.org/interviews/rebiya_kadeer", ".freeforums.org", "||freenetproject.org", ".freeoz.org", ".freetibet.net", "||freetibet.org", ".freetibetanheroes.org", "|http://freetibetanheroes.org", "||freetribe.me", ".freeviewmovies.com", ".freevpn.me", "|http://freevpn.me", "||freewallpaper4.me", ".freewebs.com", ".freewechat.com", "||freewechat.com", "freeweibo.com", "||freeweibo.com", ".freexinwen.com", ".freeyoutubeproxy.net", "||freeyoutubeproxy.net", "friendfeed.com", "friendfeed-media.com/e99a4ebe2fb4c1985c2a58775eb4422961aa5a2e", "friends-of-tibet.org", ".friendsoftibet.org", "freechina.net", "|http://www.zensur.freerk.com/", "freevpn.nl", "freeyellow.com", "hk.frienddy.com/hk", "|http://adult.friendfinder.com/", ".fring.com", "||fring.com", ".fromchinatousa.net", "||frommel.net", ".frontlinedefenders.org", "||frontlinedefenders.org", ".frootvpn.com", "||frootvpn.com", "||fscked.org", ".fsurf.com", ".ftv.com.tw", "||ftv.com.tw", "||ftvnews.com.tw", "fucd.com", ".fuckcnnic.net", "||fuckcnnic.net", "fuckgfw.org", ".fulione.com", "|https://fulione.com", "||fullerconsideration.com", "fulue.com", ".funf.tw", "funp.com", ".fuq.com", ".furhhdl.org", "||furinkan.com", ".futurechinaforum.org", "||futuremessage.org", ".fux.com", ".fuyin.net", ".fuyindiantai.org", ".fuyu.org.tw", "||fw.cm", ".fxcm-chinese.com", "||fxcm-chinese.com", "fzh999.com", "fzh999.net", "fzlm.com", ".g6hentai.com", "|http://g6hentai.com", "||g-queen.com", "||gab.com", "||gabocorp.com", ".gaeproxy.com", ".gaforum.org", ".gagaoolala.com", "||gagaoolala.com", ".galaxymacau.com", "||galenwu.com", ".galstars.net", "||game735.com", "gamebase.com.tw", "gamejolt.com", "|http://wiki.gamerp.jp", "||gamer.com.tw", ".gamer.com.tw", ".gamez.com.tw", "||gamez.com.tw", ".gamousa.com", ".gaoming.net", "||gaoming.net", "ganges.com", ".gaopi.net", "|http://gaopi.net", ".gaozhisheng.org", ".gaozhisheng.net", "gardennetworks.com", "||gardennetworks.org", "72.52.81.22", "||gartlive.com", "||gate-project.com", "||gather.com", ".gatherproxy.com", "gati.org.tw", ".gaybubble.com", ".gaycn.net", ".gayhub.com", "||gaymap.cc", ".gaymenring.com", ".gaytube.com", "||images-gaytube.com", ".gaywatch.com", "|http://gaywatch.com", ".gazotube.com", "||gazotube.com", "||gcc.org.hk", "||gclooney.com", "||gclubs.com", "||gcmasia.com", ".gcpnews.com", "|http://gcpnews.com", ".gdbt.net/forum", "gdzf.org", "||geek-art.net", "geekerhome.com/2010/03/xixiang-project-cross-gfw", "||geekheart.info", ".gekikame.com", "|http://gekikame.com", ".gelbooru.com", "|http://gelbooru.com", "||genius.com", ".geocities.co.jp", ".geocities.com/SiliconValley/Circuit/5683/download.html", "hk.geocities.com", "geocities.jp", "||geph.io", ".gerefoundation.org", "||getastrill.com", ".getchu.com", ".getcloak.com", "||getcloak.com", "||getfoxyproxy.org", ".getfreedur.com", "||getgom.com", ".geti2p.net", "||geti2p.net", "getiton.com", ".getjetso.com/forum", ".getlantern.org", "||getlantern.org", "||getmalus.com", ".getsocialscope.com", "||getsync.com", "||gettr.com", "gfbv.de", ".gfgold.com.hk", ".gfsale.com", "||gfsale.com", "gfw.org.ua", ".gfw.press", "||gfw.press", ".ggssl.com", "||ggssl.com", ".ghostpath.com", "||ghostpath.com", "||ghut.org", ".giantessnight.com", "|http://giantessnight.com", ".gifree.com", "||giga-web.jp", "tw.gigacircle.com", "|http://cn.giganews.com/", "gigporno.ru", "||girlbanker.com", ".git.io", "||git.io", "|http://softwaredownload.gitbooks.io", "||github.blog", "||github.com", ".github.io", "||github.io", "||githubusercontent.com", "||githubassets.com", ".gizlen.net", "||gizlen.net", ".gjczz.com", "||gjczz.com", "globaljihad.net", "globalmediaoutreach.com", "globalmuseumoncommunism.org", "||globalrescue.net", ".globaltm.org", ".globalvoicesonline.org", "||globalvoicesonline.org", "||globalvpn.net", ".glock.com", "gluckman.com/DalaiLama", "gmbd.cn", "||gmhz.org", "|http://www.gmiddle.com", "|http://www.gmiddle.net", ".gmll.org", "||suche.gmx.net", "||gnci.org.hk", "||gnews.org", "go-pki.com", "||goagent.biz", "||goagentplus.com", "gobet.cc", "godfootsteps.org", "||godfootsteps.org", "godns.work", "godsdirectcontact.co.uk", ".godsdirectcontact.org", "godsdirectcontact.org.tw", ".godsimmediatecontact.com", "||gofundme.com", ".gogotunnel.com", "||gohappy.com.tw", ".gokbayrak.com", ".goldbet.com", "||goldbetsports.com", "||golden-ages.org", "||goldeneyevault.com", ".goldenfrog.com", "||goldenfrog.com", ".goldjizz.com", "|http://goldjizz.com", ".goldstep.net", "||goldwave.com", "gongmeng.info", "gongm.in", "gongminliliang.com", ".gongwt.com", "|http://gongwt.com", "blog.goo.ne.jp/duck-tail_2009", ".gooday.xyz", "|http://gooday.xyz", ".goodreads.com", "||goodreads.com", ".goodreaders.com", "||goodreaders.com", ".goodtv.com.tw", ".goodtv.tv", "||goofind.com", ".googlesile.com", ".gopetition.com", "||gopetition.com", ".goproxing.net", "||goreforum.com", ".gotrusted.com", "||gotrusted.com", "||gotw.ca", "||grammaly.com", "grandtrial.org", ".graphis.ne.jp", "||graphis.ne.jp", "||graphql.org", "greatfirewall.biz", "||greatfirewallofchina.net", ".greatfirewallofchina.org", "||greatfirewallofchina.org", "||greenfieldbookstore.com.hk", ".greenparty.org.tw", "||greenpeace.org", ".greenreadings.com/forum", "great-firewall.com", "great-roc.org", "greatroc.org", "greatzhonghua.org", ".greenpeace.com.tw", ".greenvpn.net", "||greenvpn.net", ".greenvpn.org", "||grotty-monday.com", "gs-discuss.com", "||gsearch.media", "||gtricks.com", "guancha.org", "guaneryu.com", ".guardster.com", ".gun-world.net", "gunsandammo.com", "||gutteruncensored.com", "||gvm.com.tw", "||gwins.org", ".gzm.tv", "||gzone-anime.info", "||clementine-player.org", "echofon.com", "||greasespot.net", "||www.klip.me", "@@||site.locql.com", "||stephaniered.com", "@@||download.syniumsoftware.com", "|http://ub0.cc", "wozy.in", "gospelherald.com", "||gospelherald.com", "|http://hk.gradconnection.com/", "||grangorz.org", "greatfire.org", "||greatfire.org", "greatfirewallofchina.org", "||greatroc.tw", ".gts-vpn.com", "|http://gts-vpn.com", "||gtv.org", "||gtv1.org", ".gu-chu-sum.org", "|http://gu-chu-sum.org", ".guaguass.com", "|http://guaguass.com", ".guaguass.org", "|http://guaguass.org", ".guangming.com.my", "guishan.org", "||guishan.org", ".gumroad.com", "||gumroad.com", "||gunsamerica.com", "guruonline.hk", "|http://gvlib.com", ".gyalwarinpoche.com", ".gyatsostudio.com", ".h528.com", ".h5dm.com", ".h5galgame.me", "||h-china.org", ".h-moe.com", "|http://h-moe.com", "h1n1china.org", ".hacg.club", "||hacg.club", ".hacg.in", "|http://hacg.in", ".hacg.li", "|http://hacg.li", ".hacg.me", "|http://hacg.me", ".hacg.red", "|http://hacg.red", ".hacken.cc/bbs", ".hacker.org", "||hackmd.io", "||hackthatphone.net", "hahlo.com", "||hakkatv.org.tw", ".handcraftedsoftware.org", "|http://bbs.hanminzu.org/", ".hanunyi.com", ".hao.news/news", "|http://ae.hao123.com", "|http://ar.hao123.com", "|http://br.hao123.com", "|http://en.hao123.com", "|http://id.hao123.com", "|http://jp.hao123.com", "|http://ma.hao123.com", "|http://mx.hao123.com", "|http://sa.hao123.com", "|http://th.hao123.com", "|http://tw.hao123.com", "|http://vn.hao123.com", "|http://hk.hao123img.com", "|http://ld.hao123img.com", "||happy-vpn.com", ".haproxy.org", "||hardsextube.com", ".harunyahya.com", "|http://harunyahya.com", "bbs.hasi.wang", "have8.com", "@@||haygo.com", ".hclips.com", "||hdlt.me", "||hdtvb.net", ".hdzog.com", "|http://hdzog.com", "||ordns.he.net", "||heartyit.com", ".heavy-r.com", ".hec.su", "|http://hec.su", ".hecaitou.net", "||hecaitou.net", ".hechaji.com", "||hechaji.com", "||heeact.edu.tw", ".hegre-art.com", "|http://hegre-art.com", "||cdn.helixstudios.net", "||helplinfen.com", "||helpuyghursnow.org", "||helloandroid.com", "||helloqueer.com", ".helloss.pw", "hellotxt.com", "||hellotxt.com", ".hentai.to", ".hellouk.org/forum/lofiversion", ".helpeachpeople.com", "||helpeachpeople.com", "||helpster.de", ".helpzhuling.org", "hentaitube.tv", ".hentaivideoworld.com", "||id.heroku.com", "heqinglian.net", "||heqinglian.net", "||heritage.org", "||heungkongdiscuss.com", ".hexieshe.com", "||hexieshe.com", "||hexieshe.xyz", "||hexxeh.net", "app.heywire.com", ".heyzo.com", ".hgseav.com", ".hhdcb3office.org", ".hhthesakyatrizin.org", "hi-on.org.tw", "hidden-advent.org", "||hidden-advent.org", "hidecloud.com/blog/2008/07/29/fuck-beijing-olympics.html", "||hide.me", ".hidein.net", ".hideipvpn.com", "||hideipvpn.com", ".hideman.net", "||hideman.net", "hideme.nl", "||hidemy.name", ".hidemyass.com", "||hidemyass.com", "hidemycomp.com", "||hidemycomp.com", ".hihiforum.com", ".hihistory.net", "||hihistory.net", ".higfw.com", "highpeakspureearth.com", "||highrockmedia.com", "||hiitch.com", "||hikinggfw.org", ".hilive.tv", ".himalayan-foundation.org", "||himalayan-foundation.org", "himalayanglacier.com", ".himemix.com", "||himemix.com", ".himemix.net", "times.hinet.net", ".hitomi.la", "|http://hitomi.la", ".hiwifi.com", "@@||hiwifi.com", "hizbuttahrir.org", "hizb-ut-tahrir.info", "hizb-ut-tahrir.org", ".hjclub.info", ".hk-pub.com/forum", "|http://hk-pub.com", ".hk01.com", "||hk01.com", ".hk32168.com", "||hk32168.com", "||hkacg.com", "||hkacg.net", ".hkatvnews.com", "hkbc.net", ".hkbf.org", ".hkbookcity.com", "||hkbookcity.com", "||hkchronicles.com", ".hkchurch.org", "hkci.org.hk", ".hkcmi.edu", "||hkcnews.com", "||hkcoc.com", "||hkctu.org.hk", "hkday.net", ".hkdailynews.com.hk/china.php", "||hkdc.us", "hkdf.org", ".hkej.com", ".hkepc.com/forum/viewthread.php?tid=1153322", "||hket.com", "||hkfaa.com", "hkfreezone.com", "hkfront.org", "m.hkgalden.com", "|https://m.hkgalden.com", ".hkgreenradio.org/home", "||hkgpao.com", ".hkheadline.com*blog", ".hkheadline.com/instantnews", "hkhkhk.com", "hkhrc.org.hk", "hkhrm.org.hk", "||hkip.org.uk", "1989report.hkja.org.hk", "hkjc.com", ".hkjp.org", ".hklft.com", ".hklts.org.hk", "||hklts.org.hk", "||hkmap.live", "||hkopentv.com", "||hkpeanut.com", "hkptu.org", ".hkreporter.com", "||hkreporter.com", "|http://hkupop.hku.hk/", ".hkusu.net", "||hkusu.net", ".hkvwet.com", ".hkwcc.org.hk", "||hkzone.org", ".hmonghot.com", "|http://hmonghot.com", ".hmv.co.jp/", "hnjhj.com", "||hnjhj.com", ".hnntube.com", "||hola.com", "||hola.org", "holymountaincn.com", "holyspiritspeaks.org", "||holyspiritspeaks.org", "||derekhsu.homeip.net", ".homeperversion.com", "|http://homeservershow.com", "|http://old.honeynet.org/scans/scan31/sub/doug_eric/spam_translation.html", ".hongkongfp.com", "||hongkongfp.com", "hongmeimei.com", "||hongzhi.li", "||honven.xyz", ".hootsuite.com", "||hootsuite.com", "||hoover.org", ".hopedialogue.org", "|http://hopedialogue.org", ".hopto.org", ".hornygamer.com", ".hornytrip.com", "|http://hornytrip.com", "||hotair.com", ".hotav.tv", ".hotels.cn", "hotfrog.com.tw", "hotgoo.com", ".hotpornshow.com", "hotpot.hk", ".hotshame.com", "||hotspotshield.com", "||hottg.com", ".hotvpn.com", "||hotvpn.com", "||hougaige.com", "||howtoforge.com", "||hoxx.com", ".hqcdp.org", "||hqcdp.org", "||hqjapanesesex.com", "hqmovies.com", ".hrcir.com", ".hrcchina.org", ".hrea.org", ".hrichina.org", "||hrichina.org", ".hrtsea.com", ".hrw.org", "||hrw.org", "hrweb.org", "||hsjp.net", "||hsselite.com", "|http://hst.net.tw", ".hstern.net", ".hstt.net", ".htkou.net", "||htkou.net", ".hua-yue.net", ".huaglad.com", "||huaglad.com", ".huanghuagang.org", "||huanghuagang.org", ".huangyiyu.com", ".huaren.us", "||huaren.us", ".huaren4us.com", ".huashangnews.com", "|http://huashangnews.com", "bbs.huasing.org", "huaxia-news.com", "huaxiabao.org", "huaxin.ph", "||huayuworld.org", ".huffingtonpost.com/rebiya-kadeer", "||hugoroy.eu", "||huhaitai.com", "||huhamhire.com", ".huhangfei.com", "||huhangfei.com", "huiyi.in", ".hulkshare.com", "||hung-ya.com", "||hungerstrikeforaids.org", "||huping.net", "hurgokbayrak.com", ".hurriyet.com.tr", ".hut2.ru", "||hutianyi.net", "hutong9.net", "huyandex.com", ".hwadzan.tw", "||hwayue.org.tw", "||hwinfo.com", "||hxwk.org", "hxwq.org", "||hyperrate.com", "ebook.hyread.com.tw", "||ebook.hyread.com.tw", "||i1.hk", "||i2p2.de", "||i2runner.com", "||i818hk.com", ".i-cable.com", ".i-part.com.tw", ".iamtopone.com", "iask.ca", "||iask.ca", "iask.bz", "||iask.bz", ".iav19.com", "ibiblio.org/pub/packages/ccic", "||ibit.am", ".iblist.com", "||iblogserv-f.net", "ibros.org", "|http://cn.ibtimes.com", ".ibvpn.com", "||ibvpn.com", "icams.com", "blogs.icerocket.com/tag", ".icij.org", "||icij.org", "||icl-fi.org", ".icoco.com", "||icoco.com", "||furbo.org", "||warbler.iconfactory.net", "||iconpaper.org", "||icu-project.org", "w.idaiwan.com/forum", "idemocracy.asia", ".identi.ca", "||identi.ca", "||idiomconnection.com", "|http://www.idlcoyote.com", ".idouga.com", ".idreamx.com", "forum.idsam.com", ".idv.tw", ".ieasy5.com", "|http://ieasy5.com", ".ied2k.net", ".ienergy1.com", "||iepl.us", "||ift.tt", "ifanqiang.com", ".ifcss.org", "||ifcss.org", "ifjc.org", ".ift.tt", "|http://ift.tt", "||ifreewares.com", "||igcd.net", ".igfw.net", "||igfw.net", ".igfw.tech", "||igfw.tech", ".igmg.de", "||ignitedetroit.net", ".igotmail.com.tw", "||igvita.com", "||ihakka.net", ".ihao.org/dz5", "||iicns.com", ".ikstar.com", "||ilhamtohtiinstitute.org", "||illusionfactory.com", "||ilove80.be", "||im.tv", "@@||myvlog.im.tv", "||im88.tw", ".imgchili.net", "|http://imgchili.net", ".imageab.com", ".imagefap.com", "||imagefap.com", "||imageflea.com", "imageshack.us", "||imagevenue.com", "||imagezilla.net", ".imb.org", "|http://imb.org", "|http://www.imdb.com/name/nm0482730", ".imdb.com/title/tt0819354", ".imdb.com/title/tt1540068", ".imdb.com/title/tt4908644", ".img.ly", "||img.ly", ".imgur.com", "||imgur.com", ".imkev.com", "||imkev.com", ".imlive.com", ".immoral.jp", "impact.org.au", "impp.mn", "|http://tech2.in.com/video/", "in99.org", "in-disguise.com", ".incapdns.net", ".incloak.com", "||incloak.com", "||incredibox.fr", "||independent.co.uk", "||indiablooms.com", "||indiandefensenews.in", "||indianarrative.com", "||timesofindia.indiatimes.com", ".indiemerch.com", "||indiemerch.com", "info-graf.fr", "website.informer.com", "||initiativesforchina.org", ".inkui.com", ".inmediahk.net", "||inmediahk.net", "||innermongolia.org", "||inoreader.com", ".inote.tw", ".insecam.org", "|http://insecam.org", "||insidevoa.com", ".institut-tibetain.org", "|http://internet.org/", "internetdefenseleague.org", "internetfreedom.org", "||internetpopculture.com", ".inthenameofconfuciusmovie.com", "||inthenameofconfuciusmovie.com", "inxian.com", "||inxian.com", "ipalter.com", ".ipfire.org", "||iphone4hongkong.com", "||iphonehacks.com", "||iphonetaiwan.org", "||iphonix.fr", "||ipicture.ru", ".ipjetable.net", "||ipjetable.net", ".ipobar.com/read.php?", "ipoock.com/img", ".iportal.me", "|http://iportal.me", "||ippotv.com", ".ipredator.se", "||ipredator.se", ".iptv.com.tw", "||iptvbin.com", "||ipvanish.com", "iredmail.org", "chinese.irib.ir", "||ironbigfools.compython.net", "||ironpython.net", ".ironsocket.com", "||ironsocket.com", ".is.gd", ".islahhaber.net", ".islam.org.hk", "|http://islam.org.hk", ".islamawareness.net/Asia/China", ".islamhouse.com", "||islamhouse.com", ".islamicity.com", ".islamicpluralism.org", ".islamtoday.net", ".isaacmao.com", "||isaacmao.com", "||isgreat.org", "||ismaelan.com", ".ismalltits.com", "||ismprofessional.net", "isohunt.com", "||israbox.com", ".issuu.com", "||issuu.com", ".istars.co.nz", "oversea.istarshine.com", "||oversea.istarshine.com", "blog.istef.info/2007/10/21/myentunnel", ".istiqlalhewer.com", ".istockphoto.com", "isunaffairs.com", "isuntv.com", "itaboo.info", "||itaboo.info", ".italiatibet.org", "download.ithome.com.tw", "ithelp.ithome.com.tw", "||itshidden.com", ".itsky.it", ".itweet.net", "|http://itweet.net", ".iu45.com", ".iuhrdf.org", "||iuhrdf.org", ".iuksky.com", ".ivacy.com", "||ivacy.com", ".iverycd.com", ".ivpn.net", "||ixquick.com", ".ixxx.com", "iyouport.com", "||iyouport.com", ".izaobao.us", "||gmozomg.izihost.org", ".izles.net", ".izlesem.org", "||j.mp", "blog.jackjia.com", "jamaat.org", "||jamestown.org", ".jamyangnorbu.com", "|http://jamyangnorbu.com", ".jandyx.com", "||janwongphoto.com", "||japan-whores.com", ".jav.com", ".jav101.com", ".jav2be.com", "||jav2be.com", ".jav68.tv", ".javakiba.org", "|http://javakiba.org", ".javbus.com", "||javbus.com", "||javfor.me", ".javhd.com", ".javhip.com", ".javmobile.net", "|http://javmobile.net", ".javmoo.com", ".javseen.com", "|http://javseen.com", "jbtalks.cc", "jbtalks.com", "jbtalks.my", ".jdwsy.com", "jeanyim.com", "||jfqu36.club", "||jfqu37.xyz", "||jgoodies.com", ".jiangweiping.com", "||jiangweiping.com", "||jiaoyou8.com", ".jiehua.cz", "||hk.jiepang.com", "||tw.jiepang.com", "jieshibaobao.com", ".jigglegifs.com", "56cun04.jigsy.com", "jigong1024.com", "daodu14.jigsy.com", "specxinzl.jigsy.com", "wlcnew.jigsy.com", ".jihadology.net", "|http://jihadology.net", "jinbushe.org", "||jinbushe.org", ".jingsim.org", "zhao.jinhai.de", "jingpin.org", "||jingpin.org", "jinpianwang.com", ".jinroukong.com", "ac.jiruan.net", "||jitouch.com", ".jizzthis.com", "jjgirls.com", ".jkb.cc", "|http://jkb.cc", "jkforum.net", "||jma.go.jp", "research.jmsc.hku.hk/social", "weiboscope.jmsc.hku.hk", ".jmscult.com", "|http://jmscult.com", "||joachims.org", "||jobso.tv", ".sunwinism.joinbbs.net", "||joinclubhouse.com", ".journalchretien.net", "||journalofdemocracy.org", ".joymiihub.com", ".joyourself.com", "jpopforum.net", "||fiddle.jshell.net", ".jubushoushen.com", "||jubushoushen.com", ".juhuaren.com", "||juliereyc.com", "||junauza.com", ".june4commemoration.org", ".junefourth-20.net", "||junefourth-20.net", "||bbs.junglobal.net", ".juoaa.com", "|http://juoaa.com", "justfreevpn.com", ".justicefortenzin.org", "justpaste.it", "||justmysocks1.net", "justtristan.com", "juyuange.org", "juziyue.com", "||juziyue.com", "||jwmusic.org", "@@||music.jwmusic.org", ".jyxf.net", "||k-doujin.net", "||ka-wai.com", "||kadokawa.co.jp", ".kagyu.org", "||kagyu.org.za", ".kagyumonlam.org", ".kagyunews.com.hk", ".kagyuoffice.org", "||kagyuoffice.org", "||kagyuoffice.org.tw", ".kaiyuan.de", ".kakao.com", "||kakao.com", ".kalachakralugano.org", ".kankan.today", ".kannewyork.com", "||kannewyork.com", ".kanshifang.com", "||kanshifang.com", "||kantie.org", "kanzhongguo.com", "kanzhongguo.eu", ".kaotic.com", "||kaotic.com", "||karayou.com", "karkhung.com", ".karmapa.org", ".karmapa-teachings.org", "||kawase.com", ".kba-tx.org", ".kcoolonline.com", ".kebrum.com", "||kebrum.com", ".kechara.com", ".keepandshare.com/visit/visit_page.php?i=688154", ".keezmovies.com", ".kendincos.net", ".kenengba.com", "||kenengba.com", "||keontech.net", ".kepard.com", "||kepard.com", "wiki.keso.cn/Home", "||keycdn.com", ".khabdha.org", ".khmusic.com.tw", "||kichiku-doujinko.com", ".kik.com", "||kik.com", "bbs.kimy.com.tw", ".kindleren.com", "|http://kindleren.com", "|http://www.kindleren.com", ".kingdomsalvation.org", "||kingdomsalvation.org", "kinghost.com", "||kingstone.com.tw", ".kink.com", ".kinokuniya.com", "||kinokuniya.com", "killwall.com", "||killwall.com", "||kinmen.travel", ".kir.jp", ".kissbbao.cn", "|http://kiwi.kz", "||kk-whys.co.jp", ".kmuh.org.tw", ".knowledgerush.com/kr/encyclopedia", "||knowyourmeme.com", ".kobo.com", "||kobo.com", ".kobobooks.com", "||kobobooks.com", "||kodingen.com", "@@||www.kodingen.com", "||kompozer.net", ".konachan.com", "|http://konachan.com", ".kone.com", "||koolsolutions.com", ".koornk.com", "||koornk.com", "||koranmandarin.com", ".korenan2.com", "||kqes.net", "|http://gojet.krtco.com.tw", ".ksdl.org", ".ksnews.com.tw", "||ktzhk.com", ".kui.name/event", "kun.im", ".kurashsultan.com", "||kurtmunger.com", "kusocity.com", "||kwcg.ca", "||kwok7.com", ".kwongwah.com.my", "||kwongwah.com.my", ".kxsw.life", "||kxsw.life", ".kyofun.com", "kyohk.net", "||kyoyue.com", ".kyzyhello.com", "||kyzyhello.com", ".kzeng.info", "||kzeng.info", "la-forum.org", "ladbrokes.com", "||labiennale.org", ".lagranepoca.com", "||lagranepoca.com", "||lala.im", ".lalulalu.com", ".lama.com.tw", "||lama.com.tw", ".lamayeshe.com", "|http://lamayeshe.com", "|http://www.lamenhu.com", ".lamnia.co.uk", "||lamnia.co.uk", "lamrim.com", "||landofhope.tv", ".lanterncn.cn", "|http://lanterncn.cn", ".lantosfoundation.org", ".laod.cn", "|http://laod.cn", "laogai.org", "||laogai.org", "||laogairesearch.org", "laomiu.com", ".laoyang.info", "|http://laoyang.info", "||laptoplockdown.com", ".laqingdan.net", "||laqingdan.net", "||larsgeorge.com", ".lastcombat.com", "|http://lastcombat.com", "||lastfm.es", "latelinenews.com", "||lausan.hk", "||le-vpn.com", ".leafyvpn.net", "||leafyvpn.net", "leeao.com.cn/bbs/forum.php", "lefora.com", "||left21.hk", ".legalporno.com", ".legsjapan.com", "|http://leirentv.ca", "leisurecafe.ca", "||lematin.ch", ".lemonde.fr", "||lenwhite.com", "||leorockwell.com", "lerosua.org", "||lerosua.org", "blog.lester850.info", "||lesoir.be", ".letou.com", "letscorp.net", "||letscorp.net", "||ocsp.int-x3.letsencrypt.org", "||ss.levyhsu.com", "||cdn.assets.lfpcontent.com", ".lhakar.org", "|http://lhakar.org", ".lhasocialwork.org", ".liangyou.net", "||liangyou.net", ".lianyue.net", "||liaowangxizang.net", ".liaowangxizang.net", "||liberal.org.hk", ".libertytimes.com.tw", "blogs.libraryinformationtechnology.com/jxyz", ".lidecheng.com/blog/fucking-gfw", ".lighten.org.tw", ".lightnovel.cn", "@@|https://www.lightnovel.cn", "limiao.net", "linkuswell.com", "abitno.linpie.com/use-ipv6-to-fuck-gfw", "||line.me", "||line-apps.com", ".linglingfa.com", "||lingvodics.com", ".link-o-rama.com", "|http://link-o-rama.com", ".linkideo.com", "||api.linksalpha.com", "||apidocs.linksalpha.com", "||www.linksalpha.com", "||help.linksalpha.com", "||linux.org.hk", "linuxtoy.org/archives/installing-west-chamber-on-ubuntu", ".lionsroar.com", ".lipuman.com", "||liquidvpn.com", "||greatfire.us7.list-manage.com", "||listennotes.com", "||listentoyoutube.com", "listorious.com", ".liu-xiaobo.org", "||liudejun.com", ".liuhanyu.com", ".liujianshu.com", "||liujianshu.com", ".liuxiaobo.net", "|http://liuxiaobo.net", "liuxiaotong.com", "||liuxiaotong.com", ".livedoor.jp", ".liveleak.com", "||liveleak.com", "||livemint.com", ".livestation.com", "livestream.com", "||livestream.com", "||livingonline.us", "||livingstream.com", "||livevideo.com", ".livevideo.com", ".liwangyang.com", "lizhizhuangbi.com", "lkcn.net", ".llss.me/", "||lncn.org", ".load.to", ".lobsangwangyal.com", ".localdomain.ws", "||localdomain.ws", "localpresshk.com", "||lockestek.com", "logbot.net", "||logiqx.com", "secure.logmein.com", "||secure.logmein.com", "||logos.com.hk", ".londonchinese.ca", ".longhair.hk", "longmusic.com", "||longtermly.net", "||lookpic.com", ".looktoronto.com", "|http://looktoronto.com", ".lotsawahouse.org/tibetan-masters/fourteenth-dalai-lama", ".lotuslight.org.hk", ".lotuslight.org.tw", "hkreporter.loved.hk", "||lpsg.com", "||lrfz.com", ".lrip.org", "||lrip.org", ".lsd.org.hk", "||lsd.org.hk", "lsforum.net", ".lsm.org", "||lsm.org", ".lsmchinese.org", "||lsmchinese.org", ".lsmkorean.org", "||lsmkorean.org", ".lsmradio.com/rad_archives", ".lsmwebcast.com", ".ltn.com.tw", "||ltn.com.tw", "||luckydesigner.space", ".luke54.com", ".luke54.org", ".lupm.org", "||lupm.org", "||lushstories.com", "luxebc.com", "lvhai.org", "||lvhai.org", "||lvv2.com", ".lyfhk.net", "|http://lyfhk.net", "||lzjscript.com", ".lzmtnews.org", "||lzmtnews.org", "http://*.m-team.cc", ".macrovpn.com", "macts.com.tw", "||mad-ar.ch", "||madrau.com", "||madthumbs.com", "||magic-net.info", "mahabodhi.org", "my.mail.ru", ".maiplus.com", "|http://maiplus.com", ".maizhong.org", "makkahnewspaper.com", ".mamingzhe.com", "manicur4ik.ru", "||manyvoices.news", ".maplew.com", "|http://maplew.com", "||marc.info", "marguerite.su", "||martincartoons.com", "maskedip.com", ".maiio.net", ".mail-archive.com", ".malaysiakini.com", "||makemymood.com", ".manchukuo.net", ".maniash.com", "|http://maniash.com", ".mansion.com", ".mansionpoker.com", "||martau.com", "|http://blog.martinoei.com", ".martsangkagyuofficial.org", "|http://martsangkagyuofficial.org", "maruta.be/forget", ".marxist.com", "||marxist.net", ".marxists.org/chinese", "||matainja.com", "||mathable.io", "||mathiew-badimon.com", "||matrix.org", "||matsushimakaede.com", "|http://maturejp.com", "mayimayi.com", ".maxing.jp", ".mcaf.ee", "|http://mcaf.ee", "||mcadforums.com", "mcfog.com", "mcreasite.com", ".md-t.org", "||md-t.org", "||meansys.com", ".media.org.hk", ".mediachinese.com", "||mediachinese.com", ".mediafire.com/?", ".mediafire.com/download", ".mediafreakcity.com", "||mediafreakcity.com", ".medium.com", "||medium.com", ".meetav.com", "||meetup.com", "mefeedia.com", "jihadintel.meforum.org", "||mega.co.nz", "||mega.io", "||mega.nz", "||megaproxy.com", "||megarotic.com", "megavideo.com", "||megurineluka.com", "meirixiaochao.com", ".meltoday.com", ".memehk.com", "||memehk.com", "memorybbs.com", ".memri.org", ".memrijttm.org", "||mercdn.net", ".mercyprophet.org", "|http://mercyprophet.org", "||mergersandinquisitions.org", ".meridian-trust.org", "|http://meridian-trust.org", ".meripet.biz", "|http://meripet.biz", ".meripet.com", "|http://meripet.com", "merit-times.com.tw", "meshrep.com", ".mesotw.com/bbs", "metacafe.com/watch", "||metafilter.com", "||meteorshowersonline.com", "|http://www.metro.taipei/", ".metrohk.com.hk/?cmd=detail&categoryID=2", "||metrolife.ca", ".metroradio.com.hk", "|http://metroradio.com.hk", "||mewe.com", "meyou.jp", ".meyul.com", "||mgoon.com", "||mgstage.com", "||mh4u.org", "mhradio.org", "|http://michaelanti.com", "||michaelmarketl.com", "|http://bbs.mikocon.com", ".microvpn.com", "|http://microvpn.com", "middle-way.net", ".mihk.hk/forum", ".mihr.com", "mihua.org", "||mikesoltys.com", ".milph.net", "|http://milph.net", ".milsurps.com", "mimiai.net", ".mimivip.com", ".mimivv.com", ".mindrolling.org", "|http://mindrolling.org", "||mingdemedia.org", ".minghui.or.kr", "|http://minghui.or.kr", "minghui.org", "||minghui.org", "minghui-a.org", "minghui-b.org", "minghui-school.org", ".mingjinglishi.com", "||mingjinglishi.com", "mingjingnews.com", "||mingjingtimes.com", ".mingpao.com", "||mingpao.com", ".mingpaocanada.com", ".mingpaomonthly.com", "|http://mingpaomonthly.com", "mingpaonews.com", ".mingpaony.com", ".mingpaosf.com", ".mingpaotor.com", ".mingpaovan.com", ".mingshengbao.com", ".minhhue.net", ".miniforum.org", ".ministrybooks.org", ".minzhuhua.net", "||minzhuhua.net", "minzhuzhanxian.com", "minzhuzhongguo.org", "||miroguide.com", "mirrorbooks.com", "||mirrormedia.mg", ".mist.vip", "||thecenter.mit.edu", "||scratch.mit.edu", ".mitao.com.tw", ".mitbbs.com", "||mitbbs.com", "mitbbsau.com", ".mixero.com", "||mixero.com", "||mixi.jp", "mixpod.com", ".mixx.com", "||mixx.com", "||mizzmona.com", ".mk5000.com", ".mlcool.com", "||mlzs.work", ".mm-cg.com", "||mmaaxx.com", ".mmmca.com", "mnewstv.com", "||mobatek.net", ".mobile01.com", "||mobile01.com", "||mobileways.de", ".mobypicture.com", "|http://moby.to", "||modernchinastudies.org", "||moeerolibrary.com", "wiki.moegirl.org", ".mofaxiehui.com", ".mofos.com", "||mog.com", "||mohu.rocks", "molihua.org", "||mondex.org", ".money-link.com.tw", "|http://money-link.com.tw", "|http://www.monlamit.org", ".moonbbs.com", "||moonbbs.com", "||moptt.tw", "||monitorchina.org", "bbs.morbell.com", "||morningsun.org", "||moroneta.com", ".motherless.com", "|http://motherless.com", "motor4ik.ru", ".mousebreaker.com", ".movements.org", "||movements.org", "||moviefap.com", "||www.moztw.org", ".mp3buscador.com", "||mpettis.com", ".mpfinance.com", "||mpfinance.com", ".mpinews.com", "||mpinews.com", "mponline.hk", ".mqxd.org", "|http://mqxd.org", "mrtweet.com", "||mrtweet.com", "news.hk.msn.com", "news.msn.com.tw", "msguancha.com", ".mswe1.org", "|http://mswe1.org", "||mthruf.com", "||mubi.com", "muchosucko.com", "||multiply.com", "multiproxy.org", "multiupload.com", ".mullvad.net", "||mullvad.net", ".mummysgold.com", ".murmur.tw", "|http://murmur.tw", ".musicade.net", ".muslimvideo.com", "||muzi.com", "||muzi.net", "||mx981.com", ".my-formosa.com", ".my-proxy.com", ".my-private-network.co.uk", "||my-private-network.co.uk", "forum.my903.com", ".myactimes.com/actimes", "||myanniu.com", ".myaudiocast.com", "||myaudiocast.com", ".myav.com.tw/bbs", ".mybbs.us", ".myca168.com", ".mycanadanow.com", "||bbs.mychat.to", "||mychinamyhome.com", ".mychinamyhome.com", ".mychinanet.com", ".mychinanews.com", "||mychinanews.com", ".mychinese.news", "||mycnnews.com", "||mykomica.org", "mycould.com/discuz", ".myeasytv.com", "||myeclipseide.com", ".myforum.com.hk", "||myforum.com.hk", "||myforum.com.uk", ".myfreecams.com", ".myfreepaysite.com", ".myfreshnet.com", ".myiphide.com", "||myiphide.com", "forum.mymaji.com", "mymediarom.com/files/box", "||mymoe.moe", "||mymusic.net.tw", "||myparagliding.com", "||mypopescu.com", "myradio.hk/podcast", ".myreadingmanga.info", "mysinablog.com", ".myspace.com", "||myspacecdn.com", ".mytalkbox.com", ".mytizi.com", "||naacoalition.org", "old.nabble.com", "||naitik.net", ".nakido.com", "||nakido.com", ".nakuz.com/bbs", "||nalandabodhi.org", "||nalandawest.org", ".namgyal.org", "namgyalmonastery.org", "||namsisi.com", ".nanyang.com", "||nanyang.com", ".nanyangpost.com", "||nanyangpost.com", ".nanzao.com", ".naol.ca", ".naol.cc", "uighur.narod.ru", ".nat.moe", "||nat.moe", "cyberghost.natado.com", "||national-lottery.co.uk", "||nationalawakening.org", "||nationalinterest.org", "news.nationalgeographic.com/news/2014/06/140603-tiananmen-square", "||nationalreview.com", ".nationsonline.org/oneworld/tibet", "||line.naver.jp", "||navyfamily.navy.mil", "||navyreserve.navy.mil", "||nko.navy.mil", "||usno.navy.mil", "naweeklytimes.com", "||nbcnews.com", ".nbtvpn.com", "|http://nbtvpn.com", "nccwatch.org.tw", ".nch.com.tw", ".ncn.org", "||nchrd.org", "||ncn.org", "||etools.ncol.com", ".nde.de", "||ndi.org", ".ndr.de", ".ned.org", "||nekoslovakia.net", "||neowin.net", "||nepusoku.com", "||net-fits.pro", "||netalert.me", "bbs.netbig.com", ".netbirds.com", "netcolony.com", "bolin.netfirms.com", "||netflav.com", "||netme.cc", "netsneak.com", ".network54.com", "networkedblogs.com", ".networktunnel.net", "neverforget8964.org", "new-3lunch.net", ".new-akiba.com", ".new96.ca", ".newcenturymc.com", "|http://newcenturymc.com", "newcenturynews.com", "||newchen.com", ".newchen.com", ".newgrounds.com", "||newhighlandvision.com", "newipnow.com", ".newlandmagazine.com.au", ".newnews.ca", "news100.com.tw", "newschinacomment.org", ".newscn.org", "||newscn.org", "newspeak.cc/story", ".newsancai.com", "||newsancai.com", ".newsdetox.ca", ".newsdh.com", "||newstamago.com", "||newstapa.org", "newstarnet.com", "||newsweek.com", ".newtaiwan.com.tw", "newtalk.tw", "||newtalk.tw", "||newyorker.com", "newyorktimes.com", "||nexon.com", ".next11.co.jp", "||nextdigital.com.hk", ".nextmag.com.tw", ".nextmedia.com", "||nexton-net.jp", "nexttv.com.tw", ".nfjtyd.com", "||co.ng.mil", "||nga.mil", "ngensis.com", "||ngodupdongchung.com", ".nhentai.net", "|http://nhentai.net", ".nhk-ondemand.jp", ".nicovideo.jp/watch", "||nicovideo.jp", "||nighost.org", "av.nightlife141.com", "ninecommentaries.com", ".ninjacloak.com", "||ninjaproxy.ninja", "nintendium.com", "taiwanyes.ning.com", "usmgtcg.ning.com/forum", "||niusnews.com", "||njactb.org", "njuice.com", "||njuice.com", "||nlfreevpn.com", "||nmsl.website", "||nnews.eu", ".ddns.net/", ".gooddns.info", "||gotdns.ch", ".maildns.xyz", ".no-ip.org", ".opendn.xyz", ".servehttp.com", "sytes.net", ".whodns.xyz", ".zapto.org", "|http://dynupdate.no-ip.com/", "||nobel.se", "nobelprize.org/nobel_prizes/peace/laureates/1989", "nobelprize.org/nobel_prizes/peace/laureates/2010", "nobodycanstop.us", "||nobodycanstop.us", "||nokogiri.org", "||nokola.com", "noodlevpn.com", ".norbulingka.org", "nordvpn.com", "||nordvpn.com", "||novelasia.com", ".news.now.com", "|http://news.now.com", "news.now.com%2Fhome", "||nownews.com", ".nowtorrents.com", ".noypf.com", "||noypf.com", "||npa.go.jp", ".npnt.me", "|http://npnt.me", ".nps.gov", ".nradio.me", "|http://nradio.me", ".nrk.no", "||nrk.no", ".ntd.tv", "||ntd.tv", ".ntdtv.com", "||ntdtv.com", "||ntdtv.com.tw", ".ntdtv.co.kr", "ntdtv.ca", "ntdtv.org", "ntdtv.ru", "ntdtvla.com", ".ntrfun.com", "||cbs.ntu.edu.tw", "||media.nu.nl", ".nubiles.net", "||nuexpo.com", ".nukistream.com", "||nurgo-software.com", "||nutaku.net", "||nutsvpn.work", ".nuvid.com", "||nvdst.com", "nuzcom.com", ".nvquan.org", ".nvtongzhisheng.org", "|http://nvtongzhisheng.org", ".nwtca.org", "|http://nyaa.eu", "||nyaa.si", "||nybooks.com", ".nydus.ca", "nylon-angel.com", "nylonstockingsonline.com", "||nypost.com", ".nzchinese.com", "||nzchinese.net.nz", "observechina.net", ".obutu.com", "ocaspro.com", "occupytiananmen.com", "oclp.hk", ".ocreampies.com", "||october-review.org", "||odysee.com", "offbeatchina.com", "||officeoftibet.com", "|http://ofile.org", "||ogaoga.org", "twtr2src.ogaoga.org", ".ogate.org", "||ogate.org", "www2.ohchr.org/english/bodies/cat/docs/ngos/II_China_41.pdf", "||ohmyrss.com", ".oikos.com.tw/v4", ".oiktv.com", "oizoblog.com", ".ok.ru", "||ok.ru", ".okayfreedom.com", "||okayfreedom.com", "okk.tw", "|http://filmy.olabloga.pl/player", "old-cat.net", "||olumpo.com", ".olympicwatch.org", "omgili.com", "||omnitalk.com", "||omnitalk.org", "||omny.fm", "cling.omy.sg", "forum.omy.sg", "news.omy.sg", "showbiz.omy.sg", "||on.cc", "||onedrive.live.com", "||onion.city", ".onlinecha.com", "||onlineyoutube.com", "||onlygayvideo.com", ".onlytweets.com", "|http://onlytweets.com", "onmoon.net", "onmoon.com", ".onthehunt.com", "|http://onthehunt.com", ".oopsforum.com", "open.com.hk", "openallweb.com", "opendemocracy.net", "||opendemocracy.net", ".openervpn.in", "openid.net", "||openid.net", ".openleaks.org", "||openleaks.org", "||opentech.fund", "openvpn.net", "||openvpn.net", "||openwebster.com", ".openwrt.org.cn", "@@||openwrt.org.cn", "my.opera.com/dahema", "||demo.opera-mini.net", ".opus-gaming.com", "|http://opus-gaming.com", "www.orchidbbs.com", ".organcare.org.tw", "organharvestinvestigation.net", ".orgasm.com", ".orgfree.com", "||orient-doll.com", "orientaldaily.com.my", "||orientaldaily.com.my", "||orn.jp", "t.orzdream.com", "||t.orzdream.com", "tui.orzdream.com", "||orzistic.org", "||osfoora.com", ".otnd.org", "||otnd.org", "||otto.de", "||ourdearamy.com", "oursogo.com", ".oursteps.com.au", "||oursteps.com.au", ".oursweb.net", "||ourtv.hk", "xinqimeng.over-blog.com", "||overdaily.org", "||overplay.net", "share.ovi.com/media", "||ovpn.com", "|http://owl.li", "|http://ht.ly", "|http://htl.li", "|http://mash.to", "www.owind.com", "||owltail.com", "||oxfordscholarship.com", "|http://www.oxid.it", "oyax.com", "oyghan.com/wps", ".ozchinese.com/bbs", "||ow.ly", "bbs.ozchinese.com", ".ozvoice.org", "||ozvoice.org", ".ozxw.com", ".ozyoyo.com", "||pachosting.com", ".pacificpoker.com", ".packetix.net", "||pacopacomama.com", ".padmanet.com", "page2rss.com", "||pagodabox.com", ".palacemoon.com", "forum.palmislife.com", "||eriversoft.com", ".paldengyal.com", "paljorpublications.com", ".paltalk.com", "||pandapow.co", ".pandapow.net", ".pandavpn-jp.com", "||pandavpn-jp.com", "||pandavpnpro.com", ".panluan.net", "||panluan.net", "||pao-pao.net", "paper.li", "paperb.us", ".paradisehill.cc", ".paradisepoker.com", "||parler.com", "||parsevideo.com", ".partycasino.com", ".partypoker.com", ".passion.com", "||passion.com", ".passiontimes.hk", "pastebin.com", ".pastie.org", "||pastie.org", "||blog.pathtosharepoint.com", "pbs.org/wgbh/pages/frontline/tankman", "pbs.org/wgbh/pages/frontline/tibet", "video.pbs.org", "pbwiki.com", "||pbworks.com", "||developers.box.net", "||wiki.oauth.net", "||wiki.phonegap.com", "||wiki.jqueryui.com", "||pbxes.com", "||pbxes.org", "pcdvd.com.tw", ".pchome.com.tw", "|http://pcij.org", ".pcstore.com.tw", "||pct.org.tw", "pdetails.com", "||pdproxy.com", "||peace.ca", "peacefire.org", "peacehall.com", "||peacehall.com", "|http://pearlher.org", ".peeasian.com", "||peing.net", ".pekingduck.org", "||pekingduck.org", ".pemulihan.or.id", "|http://pemulihan.or.id", "||pen.io", "penchinese.com", "||penchinese.net", ".penchinese.net", "pengyulong.com", "penisbot.com", "||blog.pentalogic.net", ".penthouse.com", ".pentoy.hk/%E4%B8%AD%E5%9C%8B", ".pentoy.hk/%E6%99%82%E4%BA%8B", ".peoplebookcafe.com", ".peoplenews.tw", "||peoplenews.tw", ".peopo.org", "||peopo.org", ".percy.in", ".perfectgirls.net", "perfectvpn.net", ".persecutionblog.com", ".persiankitty.com", "pfd.org.hk", "phapluan.org", ".phayul.com", "||phayul.com", "philborges.com", "philly.com", "||phncdn.com", "||photodharma.net", "||photofocus.com", "||phuquocservices.com", "||picacomiccn.com", ".picidae.net", "||img*.picturedip.com", "picturesocial.com", "||pin-cong.com", ".pin6.com", "||pin6.com", ".ping.fm", "||ping.fm", "||pinimg.com", ".pinkrod.com", "||pinoy-n.com", "||pinterest.at", "||pinterest.ca", "||pinterest.co.kr", "||pinterest.co.uk", ".pinterest.com", "||pinterest.com", "||pinterest.com.mx", "||pinterest.de", "||pinterest.dk", "||pinterest.fr", "||pinterest.jp", "||pinterest.nl", "||pinterest.se", ".pipii.tv", ".piposay.com", "piraattilahti.org", ".piring.com", "||pixelqi.com", "||css.pixnet.in", "||pixnet.net", ".pixnet.net", ".pk.com", "||placemix.com", "|http://pictures.playboy.com", "||playboy.com", ".playboyplus.com", "||playboyplus.com", "||player.fm", ".playno1.com", "||playno1.com", "||playpcesor.com", "plays.com.tw", "||plexvpn.pro", "||m.plixi.com", "plm.org.hk", "plunder.com", ".plurk.com", "||plurk.com", ".plus28.com", ".plusbb.com", ".pmatehunter.com", "||pmatehunter.com", ".pmates.com", "||po2b.com", "pobieramy.top", "||podbean.com", "||podictionary.com", ".pokerstars.com", "||pokerstars.com", ".pokerstars.net", "zh.pokerstrategy.com", "politicalchina.org", "politicalconsultation.org", ".politiscales.net", "||poloniex.com", ".polymerhk.com", "|http://polymerhk.com", ".popo.tw", "||popvote.hk", ".popyard.com", "||popyard.org", ".porn.com", ".porn2.com", ".porn5.com", ".pornbase.org", ".pornerbros.com", "||pornhd.com", ".pornhost.com", ".pornhub.com", "||pornhub.com", ".pornhubdeutsch.net", "|http://pornhubdeutsch.net", "||pornmm.net", ".pornoxo.com", ".pornrapidshare.com", "||pornrapidshare.com", ".pornsharing.com", "|http://pornsharing.com", ".pornsocket.com", ".pornstarclub.com", "||pornstarclub.com", ".porntube.com", ".porntubenews.com", ".porntvblog.com", "||porntvblog.com", ".pornvisit.com", ".portablevpn.nl", "||poskotanews.com", ".post01.com", ".post76.com", "||post76.com", ".post852.com", "||post852.com", "postadult.com", ".postimg.org", "||potvpn.com", "||powercx.com", ".powerphoto.org", "||www.powerpointninja.com", "||presidentlee.tw", "||cdn.printfriendly.com", ".pritunl.com", "provpnaccounts.com", "||provpnaccounts.com", ".proxfree.com", "||proxfree.com", "proxyanonimo.es", ".proxynetwork.org.uk", "||proxynetwork.org.uk", "||pts.org.tw", ".pttvan.org", "pubu.com.tw", "puffinbrowser.com", "pureinsight.org", ".pushchinawall.com", ".putty.org", "||putty.org", "||calebelston.com", "||blog.fizzik.com", "||nf.id.au", "||sogrady.me", "||vatn.org", "||ventureswell.com", "||whereiswerner.com", ".power.com", "||power.com", "powerapple.com", "||powerapple.com", "||abc.pp.ru", "heix.pp.ru", "||prayforchina.net", "||premeforwindows7.com", "||presentationzen.com", "||prestige-av.com", "prisoner-state-secret-journal-premier", ".prisoneralert.com", "||pritunl.com", "||privacybox.de", ".private.com/home", "||privateinternetaccess.com", "privatepaste.com", "||privatepaste.com", "privatetunnel.com", "||privatetunnel.com", "||privatevpn.com", "||procopytips.com", "||project-syndicate.org", "provideocoalition.com", "||prosiben.de", "proxifier.com", "api.proxlet.com", "||proxomitron.info", ".proxpn.com", "||proxpn.com", ".proxylist.org.uk", "||proxylist.org.uk", ".proxypy.net", "||proxypy.net", "proxyroad.com", ".proxytunnel.net", "||proyectoclubes.com", "prozz.net", "psblog.name", "||psblog.name", "||pshvpn.com", "||psiphon.ca", ".psiphon3.com", "||psiphon3.com", ".psiphontoday.com", "||pt.im", ".ptt.cc", "||ptt.cc", ".puffstore.com", ".puuko.com", "||pullfolio.com", ".punyu.com/puny", "||pureconcepts.net", "||pureinsight.org", "||purepdf.com", "||purevpn.com", ".purplelotus.org", ".pursuestar.com", "||pursuestar.com", "||nitter.pussthecat.org", ".pussyspace.com", ".putihome.org", ".putlocker.com/file", "pwned.com", "python.com", ".python.com.tw", "|http://python.com.tw", "pythonhackers.com/p", "ss.pythonic.life/", ".qanote.com", "||qanote.com", ".qgirl.com.tw", "||qianbai.tw", "||qiandao.today", "||qiangwaikan.com", ".qi-gong.me", "||qi-gong.me", "||qiangyou.org", ".qidian.ca", ".qienkuen.org", "||qienkuen.org", "||qiwen.lu", "qixianglu.cn", "bbs.qmzdd.com", ".qkshare.com", "qoos.com", "||qoos.com", "blog.qooza.hk/dafengqixi", "||efksoft.com", "||qstatus.com", "||qtweeter.com", "||qtrac.eu", ".quannengshen.org", "|http://quannengshen.org", "quantumbooter.net", "||quitccp.net", ".quitccp.net", "||quitccp.org", ".quitccp.org", ".quora.com/Chinas-Future", ".quran.com", "|http://quran.com", ".quranexplorer.com", "qusi8.net", ".qvodzy.org", "nemesis2.qx.net/pages/MyEnTunnel", "qxbbs.org", "||r0.ru", ".ra.gg", "|http://ra.gg/", ".radicalparty.org", "||rael.org", "radicalparty.org", "||radio.garden", "radioaustralia.net.au", ".radiohilight.net", "||radiohilight.net", "||radioline.co", "opml.radiotime.com", "||radiovaticana.org", "||radiovncr.com", "||raggedbanner.com", "||raidcall.com.tw", ".raidtalk.com.tw", ".rainbowplan.org/bbs", "|https://raindrop.io/", ".raizoji.or.jp", "|http://raizoji.or.jp", "rangwang.biz", "rangzen.com", "rangzen.net", "rangzen.org", "|http://blog.ranxiang.com/", "ranyunfei.com", "||ranyunfei.com", ".rapbull.net", "|http://rapidgator.net/", "||rapidmoviez.com", "rapidvpn.com", "||rapidvpn.com", "||rarbgprx.org", ".raremovie.cc", "|http://raremovie.cc", ".raremovie.net", "|http://raremovie.net", "||rationalwiki.org", "||rawgit.com", "||rawgithub.com", "||razyboard.com", "rcinet.ca", ".read100.com", ".readingtimes.com.tw", "||readingtimes.com.tw", "||readmoo.com", ".readydown.com", "|http://readydown.com", ".realcourage.org", ".realitykings.com", "||realitykings.com", ".realraptalk.com", ".realsexpass.com", "||reason.com", ".recordhistory.org", ".recovery.org.tw", "|http://online.recoveryversion.org", "||recoveryversion.com.tw", "||red-lang.org", "redballoonsolidarity.org", "||redbubble.com", ".redchinacn.net", "|http://redchinacn.net", "redchinacn.org", "redtube.com", "referer.us", "||referer.us", "||reflectivecode.com", "relaxbbs.com", ".relay.com.tw", ".releaseinternational.org", "religioustolerance.org", "renminbao.com", "||renminbao.com", ".renyurenquan.org", "||renyurenquan.org", "|http://certificate.revocationcheck.com", "subacme.rerouted.org", "||resilio.com", ".reuters.com", "||reuters.com", "||reutersmedia.net", ".revleft.com", "||resistchina.org", "retweetist.com", "||retweetrank.com", "revver.com", ".rfa.org", "||rfa.org", ".rfachina.com", ".rfamobile.org", "rfaweb.org", "||rferl.org", ".rfi.fr", "||rfi.fr", "|http://rfi.my/", "|http://vds.rightster.com/", ".rigpa.org", ".rileyguide.com", "riku.me/", ".ritouki.jp", "||ritter.vg", ".rlwlw.com", "||rlwlw.com", ".rmjdw.com", ".rmjdw132.info", ".roadshow.hk", ".roboforex.com", "||robustnessiskey.com", "||rocket-inc.net", "|http://www2.rocketbbs.com/11/bbs.cgi?id=5mus", "|http://www2.rocketbbs.com/11/bbs.cgi?id=freemgl", "||rojo.com", "||ronjoneswriter.com", "||rolfoundation.org", "||rolia.net", "||rolsociety.org", ".roodo.com", ".rosechina.net", ".rotten.com", ".rsf.org", "||rsf.org", ".rsf-chinese.org", "||rsf-chinese.org", ".rsgamen.org", "||rsshub.app", "||phosphation13.rssing.com", ".rssmeme.com", "||rssmeme.com", "||rtalabel.org", ".rthk.hk", "||rthk.hk", ".rthk.org.hk", "||rthk.org.hk", ".rti.org.tw", "||rti.org.tw", "||rti.tw", ".rtycminnesota.org", ".ruanyifeng.com/blog*some_ways_to_break_the_great_firewall", "rukor.org", "||rule34.xxx", ".runbtx.com", ".rushbee.com", ".ruten.com.tw", "||ruten.com.tw", "rutube.ru", ".ruyiseek.com", ".rxhj.net", "|http://rxhj.net", ".s1s1s1.com", "||s-cute.com", ".s-dragon.org", "||s1heng.com", "|http://www.s4miniarchive.com", "||s8forum.com", "cdn1.lp.saboom.com", "||sacks.com", "sacom.hk", "||sacom.hk", "||sadpanda.us", ".safervpn.com", "||safervpn.com", ".saintyculture.com", "|http://saintyculture.com", ".saiq.me", "||saiq.me", "||sakuralive.com", ".sakya.org", ".salvation.org.hk", "||salvation.org.hk", ".samair.ru/proxy/type-01", ".sambhota.org", ".cn.sandscotaicentral.com", "|http://cn.sandscotaicentral.com", "||sankei.com", ".sanmin.com.tw", "sapikachu.net", "savemedia.com", "||savethesounds.info", ".savetibet.de", "||savetibet.de", "savetibet.fr", "savetibet.nl", ".savetibet.org", "||savetibet.org", "savetibet.ru", ".savetibetstore.org", "||savetibetstore.org", "||saveuighur.org", "savevid.com", "||say2.info", ".sbme.me", "|http://sbme.me", ".sbs.com.au/yourlanguage", ".scasino.com", "|http://www.sciencemag.org/content/344/6187/953", ".sciencenets.com", ".scmp.com", "||scmp.com", ".scmpchinese.com", "||scramble.io", ".scribd.com", "||scribd.com", "||scriptspot.com", "||search.com", ".searchtruth.com", "||searx.me", "||seattlefdc.com", ".secretchina.com", "||secretchina.com", "||secretgarden.no", ".secretsline.biz", "||secretsline.biz", "||secureservercdn.net", "||securetunnel.com", "securityinabox.org", "|https://securityinabox.org", ".securitykiss.com", "||securitykiss.com", "||seed4.me", "news.seehua.com", "seesmic.com", "||seevpn.com", "||seezone.net", "sejie.com", ".sendspace.com", "|http://tweets.seraph.me/", "sesawe.net", "||sesawe.net", ".sesawe.org", "||sethwklein.net", ".setn.com", ".settv.com.tw", "forum.setty.com.tw", ".sevenload.com", "||sevenload.com", ".sex.com", ".sex-11.com", "||sex3.com", "||sex8.cc", ".sexandsubmission.com", ".sexbot.com", ".sexhu.com", ".sexhuang.com", "sexinsex.net", "||sexinsex.net", ".sextvx.com", "67.220.91.15", "67.220.91.18", "67.220.91.23", "|http://*.sf.net", ".sfileydy.com", "||sfshibao.com", ".sftindia.org", ".sftuk.org", "||sftuk.org", "||shadeyouvpn.com", "shadow.ma", ".shadowsky.xyz", ".shadowsocks.asia", "||www.shadowsocks.com", ".shadowsocks.com", "||shadowsocks.com.hk", ".shadowsocks.org", "||shadowsocks.org", "||shadowsocks-r.com", "|http://cn.shafaqna.com", ".shambalapost.com", ".shambhalasun.com", ".shangfang.org", "||shangfang.org", "shapeservices.com", ".sharebee.com", "||sharecool.org", "sharpdaily.com.hk", "||sharpdaily.com.hk", ".sharpdaily.hk", ".sharpdaily.tw", ".shat-tibet.com", "sheikyermami.com", ".shellfire.de", "||shellfire.de", ".shenshou.org", "shenyun.com", "shenyunperformingarts.org", "||shenyunperformingarts.org", "||shenyunshop.com", "shenzhoufilm.com", "||shenzhoufilm.com", "||shenzhouzhengdao.org", "||sherabgyaltsen.com", ".shiatv.net", ".shicheng.org", "shinychan.com", "shipcamouflage.com", ".shireyishunjian.com", ".shitaotv.org", "||shixiao.org", "||shizhao.org", "shizhao.org", "shkspr.mobi/dabr", "||shodanhq.com", "||shooshtime.com", ".shop2000.com.tw", "||shopee.tw", ".shopping.com", ".showhaotu.com", ".showtime.jp", "||showwe.tw", ".shutterstock.com", "||shutterstock.com", "ch.shvoong.com", ".shwchurch.org", "||shwchurch.org", ".shwchurch3.com", "|http://shwchurch3.com", ".siddharthasintent.org", "||sidelinesnews.com", ".sidelinessportseatery.com", "||signal.org", ".sijihuisuo.club", ".sijihuisuo.com", ".silkbook.com", "||simbolostwitter.com", "simplecd.org", "||simplecd.org", "@@||simplecd.me", "simpleproductivityblog.com", "bbs.sina.com/", "bbs.sina.com%2F", "blog.sina.com.tw", "dailynews.sina.com/", "dailynews.sina.com%2F", "forum.sina.com.hk", "home.sina.com", "||magazines.sina.com.tw", "news.sina.com.hk", "news.sina.com.tw", "news.sinchew.com.my", ".sinchew.com.my/node/", ".sinchew.com.my/taxonomy/term", ".singaporepools.com.sg", "||singaporepools.com.sg", ".singfortibet.com", ".singpao.com.hk", "singtao.com", "||singtao.com", "news.singtao.ca", ".singtaousa.com", "||singtaousa.com", "sino-monthly.com", "||sinoca.com", "||sinocast.com", "sinocism.com", "sinomontreal.ca", ".sinonet.ca", ".sinopitt.info", ".sinoants.com", "||sinoants.com", "||sinoinsider.com", ".sinoquebec.com", ".sierrafriendsoftibet.org", "sis.xxx", "||sis001.com", "sis001.us", ".site2unblock.com", "||site90.net", ".sitebro.tw", "||sitekreator.com", "||siteks.uk.to", "||sitemaps.org", ".sjrt.org", "|http://sjrt.org", "||sjum.cn", "||sketchappsources.com", "||skimtube.com", "||lab.skk.moe", "||skybet.com", "|http://users.skynet.be/reves/tibethome.html", ".skyking.com.tw", "bbs.skykiwi.com", "|http://www.skype.com/intl/", "|http://www.skype.com/zh-Hant", "||skyvegas.com", ".xskywalker.com", "||xskywalker.com", "||skyxvpn.com", "m.slandr.net", ".slaytizle.com", ".sleazydream.com", "||slheng.com", "||slideshare.net", "forum.slime.com.tw", ".slinkset.com", "||slickvpn.com", ".slutload.com", "||smartdnsproxy.com", ".smarthide.com", "||app.smartmailcloud.com", "smchbooks.com", ".smh.com.au/world/death-of-chinese-playboy-leaves-fresh-scratches-in-party-paintwork-20120903-25a8v", "smhric.org", ".smith.edu/dalailama", ".smyxy.org", "||snapchat.com", ".snaptu.com", "||snaptu.com", "||sndcdn.com", "sneakme.net", "snowlionpub.com", "home.so-net.net.tw/yisa_tsai", "||soc.mil", "||socialblade.com", ".socks-proxy.net", "||socks-proxy.net", ".sockscap64.com", "||sockslist.net", ".socrec.org", "|http://socrec.org", ".sod.co.jp", ".softether.org", "||softether.org", ".softether-download.com", "||softether-download.com", "||cdn.softlayer.net", "||sogclub.com", "sohcradio.com", "||sohcradio.com", ".sokmil.com", "||sorting-algorithms.com", ".sostibet.org", ".soumo.info", "||soup.io", "@@||static.soup.io", ".sobees.com", "||sobees.com", "socialwhale.com", ".softether.co.jp", "||softwarebychuck.com", "blog.sogoo.org", "soh.tw", "||soh.tw", "sohfrance.org", "||sohfrance.org", "chinese.soifind.com", "sokamonline.com", ".solidaritetibet.org", ".solidfiles.com", "||somee.com", ".songjianjun.com", "||songjianjun.com", ".sonicbbs.cc", ".sonidodelaesperanza.org", ".sopcast.com", ".sopcast.org", ".sorazone.net", "||sos.org", "bbs.sou-tong.org", ".soubory.com", "|http://soubory.com", ".soul-plus.net", ".soulcaliburhentai.net", "||soulcaliburhentai.net", "||soundcloud.com", ".soundofhope.kr", "soundofhope.org", "||soundofhope.org", "||soupofmedia.com", "|http://sourceforge.net/p*/shadowsocksgui/", ".sourcewadio.com", "||south-plus.org", "southnews.com.tw", "sowers.org.hk", "||wlx.sowiki.net", "||spankbang.com", ".spankingtube.com", ".spankwire.com", "||spb.com", "||speakerdeck.com", "||speedify.com", "spem.at", "||spencertipping.com", "||spendee.com", "||spicevpn.com", ".spideroak.com", "||spideroak.com", ".spike.com", ".spotflux.com", "||spotflux.com", ".spring4u.info", "|http://spring4u.info", "||sproutcore.com", "||sproxy.info", "||squirrelvpn.com", "||srocket.us", ".ss-link.com", "||ss-link.com", ".ssglobal.co/wp", "|http://ssglobal.co", ".ssglobal.me", "||ssh91.com", ".sspro.ml", "|http://sspro.ml", ".ssrshare.com", "||ssrshare.com", "||sss.camp", "||sstm.moe", "||sstmlt.moe", "sstmlt.net", "||sstmlt.net", "|http://stackoverflow.com/users/895245", ".stage64.hk", "||stage64.hk", "||standupfortibet.org", "||standwithhk.org", "stanford.edu/group/falun", "usinfo.state.gov", "||statueofdemocracy.org", ".starfishfx.com", ".starp2p.com", "||starp2p.com", ".startpage.com", "||startpage.com", ".startuplivingchina.com", "|http://startuplivingchina.com", "||static-economist.com", "||stboy.net", "||stc.com.sa", "||steel-storm.com", ".steganos.com", "||steganos.com", ".steganos.net", ".stepchina.com", "ny.stgloballink.com", "hd.stheadline.com/news/realtime", "sthoo.com", "||sthoo.com", ".stickam.com", "stickeraction.com/sesawe", ".stileproject.com", ".sto.cc", ".stoporganharvesting.org", "||storagenewsletter.com", ".storm.mg", "||storm.mg", ".stoptibetcrisis.net", "||stoptibetcrisis.net", "||storify.com", ".stormmediagroup.com", "||stoweboyd.com", "||straitstimes.com", "stranabg.com", "||straplessdildo.com", "||streamable.com", "||streamate.com", "||streamingthe.net", "streema.com/tv/NTDTV_Chinese", "cn.streetvoice.com/article", "cn.streetvoice.com/diary", "cn2.streetvoice.com", "tw.streetvoice.com", ".strikingly.com", "||strongvpn.com", ".strongwindpress.com", ".student.tw/db", "||studentsforafreetibet.org", "||stumbleupon.com", "stupidvideos.com", ".successfn.com", "panamapapers.sueddeutsche.de", ".sugarsync.com", "||sugarsync.com", ".sugobbs.com", "||sugumiru18.com", "||suissl.com", "summify.com", ".sumrando.com", "||sumrando.com", "sun1911.com", "||sundayguardianlive.com", ".sunporno.com", "||sunmedia.ca", "||sunporno.com", ".sunskyforum.com", ".sunta.com.tw", ".sunvpn.net", ".suoluo.org", ".superfreevpn.com", ".supervpn.net", "||supervpn.net", ".superzooi.com", "|http://superzooi.com", ".suppig.net", ".suprememastertv.com", "|http://suprememastertv.com", ".surfeasy.com", "||surfeasy.com", ".surfeasy.com.au", "|http://surfeasy.com.au", "||surfshark.com", "||surrenderat20.net", ".svsfx.com", ".swissinfo.ch", "||swissinfo.ch", ".swissvpn.net", "||swissvpn.net", "switchvpn.net", "||switchvpn.net", ".sydneytoday.com", "||sydneytoday.com", ".sylfoundation.org", "||sylfoundation.org", "||syncback.com", "sysresccd.org", ".sytes.net", "blog.syx86.com/2009/09/puff", "blog.syx86.cn/2009/09/puff", ".szbbs.net", ".szetowah.org.hk", "||t-g.com", ".t35.com", ".t66y.com", "||t66y.com", "||esg.t91y.com", ".taa-usa.org", "|http://taa-usa.org", ".taaze.tw", "||taaze.tw", "|http://www.tablesgenerator.com/", "tabtter.jp", ".tacem.org", ".taconet.com.tw", "||taedp.org.tw", ".tafm.org", ".tagwa.org.au", "tagwalk.com", "||tagwalk.com", "tahr.org.tw", ".taipeisociety.org", "||taipeisociety.org", ".taiwanbible.com", ".taiwancon.com", ".taiwandaily.net", "||taiwandaily.net", ".taiwandc.org", "||taiwanhot.net", ".taiwanjustice.com", "taiwankiss.com", "taiwannation.com", "taiwannation.com.tw", "||taiwanncf.org.tw", "||taiwannews.com.tw", "|http://www.taiwanonline.cc/", "taiwantp.net", "||taiwantt.org.tw", "taiwanus.net", "taiwanyes.com", "taiwan-sex.com", ".talk853.com", ".talkboxapp.com", "||talkboxapp.com", ".talkcc.com", "||talkcc.com", ".talkonly.net", "||talkonly.net", "||tamiaode.tk", "||tanc.org", "tangben.com", ".tangren.us", ".taoism.net", "|http://taoism.net", ".taolun.info", "||taolun.info", ".tapatalk.com", "||tapatalk.com", "blog.taragana.com", ".tascn.com.au", "||taup.net", "|http://www.taup.org.tw", ".taweet.com", "||taweet.com", ".tbcollege.org", "||tbcollege.org", ".tbi.org.hk", ".tbicn.org", ".tbjyt.org", "||tbpic.info", ".tbrc.org", "tbs-rainbow.org", ".tbsec.org", "||tbsec.org", "tbskkinabalu.page.tl", ".tbsmalaysia.org", ".tbsn.org", "||tbsn.org", ".tbsseattle.org", ".tbssqh.org", "|http://tbssqh.org", "tbswd.org", ".tbtemple.org.uk", ".tbthouston.org", ".tccwonline.org", ".tcewf.org", "tchrd.org", "tcnynj.org", "||tcpspeed.co", ".tcpspeed.com", "||tcpspeed.com", ".tcsofbc.org", ".tcsovi.org", ".tdm.com.mo", "teamamericany.com", "||static.techspot.com", "||techviz.net", "||teck.in", ".teeniefuck.net", "teensinasia.com", "||tehrantimes.com", ".telecomspace.com", "||telegraph.co.uk", "||telegra.ph", ".tenacy.com", "||tenzinpalmo.com", ".tew.org", "||tew.org", "||tfiflve.com", ".thaicn.com", "||theatlantic.com", "||theatrum-belli.com", "||cn.theaustralian.com.au", "theblemish.com", "||thebcomplex.com", "||theblaze.com", ".thebobs.com", "||thebobs.com", ".thechinabeat.org", "||thechinacollection.org", "|http://www.thechinastory.org/yearbooks/yearbook-2012/", "||theconversation.com", ".thedalailamamovie.com", "|http://thedalailamamovie.com", "||thediplomat.com", "||thedw.us", "thefrontier.hk/tf", "||theguardian.com", "||thegay.com", "|http://thegioitinhoc.vn/", ".thegly.com", ".thehots.info", "thehousenews.com", "||thehun.net", ".theinitium.com", "||theinitium.com", ".thenewslens.com", "||thenewslens.com", ".thepiratebay.org", "||thepiratebay.org", ".theporndude.com", "||theporndude.com", "||theportalwiki.com", "||theprint.in", "thereallove.kr", "therock.net.nz", "||thesaturdaypaper.com.au", "||thestandnews.com", "thetibetcenter.org", "thetibetconnection.org", ".thetibetmuseum.org", ".thetibetpost.com", "||thetibetpost.com", "||thetinhat.com", "thetrotskymovie.com", "thevivekspot.com", "||thewgo.org", ".theync.com", "|http://theync.com", ".thinkingtaiwan.com", "||thinkingtaiwan.com", ".thisav.com", "|http://thisav.com", ".thlib.org", "||thomasbernhard.org", ".thongdreams.com", "threatchaos.com", "||throughnightsfire.com", ".thumbzilla.com", "||thywords.com", ".thywords.com.tw", "tiananmenmother.org", ".tiananmenduizhi.com", "||tiananmenduizhi.com", "||tiananmenuniv.com", "||tiananmenuniv.net", "||tiandixing.org", ".tianhuayuan.com", ".tianlawoffice.com", "||tianti.io", "tiantibooks.org", "||tiantibooks.org", "tianyantong.org.cn", ".tianzhu.org", ".tibet.at", "tibet.ca", ".tibet.com", "||tibet.com", "tibet.fr", ".tibet.net", "||tibet.net", "tibet.nu", ".tibet.org", "||tibet.org", ".tibet.sk", "tibet.org.tw", ".tibet.to", ".tibet-envoy.eu", "||tibet-envoy.eu", ".tibet-foundation.org", ".tibet-house-trust.co.uk", "||tibet-initiative.de", ".tibet-munich.de", ".tibet3rdpole.org", "|http://tibet3rdpole.org", "tibetaction.net", "||tibetaction.net", ".tibetaid.org", "tibetalk.com", ".tibetan.fr", "tibetan-alliance.org", ".tibetanarts.org", ".tibetanbuddhistinstitute.org", "|http://tibetanbuddhistinstitute.org", "tibetancommunity.org", ".tibetanjournal.com", ".tibetanlanguage.org", ".tibetanliberation.org", "||tibetanliberation.org", ".tibetcollection.com", ".tibetanaidproject.org", ".tibetancommunityuk.net", "|http://tibetancommunityuk.net", "tibetanculture.org", "tibetanfeministcollective.org", ".tibetanpaintings.com", ".tibetanphotoproject.com", ".tibetanpoliticalreview.org", ".tibetanreview.net", "|http://tibetansports.org", ".tibetanwomen.org", "|http://tibetanwomen.org", ".tibetanyouth.org", ".tibetanyouthcongress.org", "||tibetanyouthcongress.org", ".tibetcharity.dk", "tibetcharity.in", ".tibetchild.org", ".tibetcity.com", ".tibetcorps.org", ".tibetexpress.net", "|http://tibetexpress.net", "tibetfocus.com", "tibetfund.org", ".tibetgermany.com", "||tibetgermany.de", ".tibethaus.com", ".tibetheritagefund.org", "||tibethouse.jp", "||tibethouse.org", "||tibethouse.us", ".tibetinfonet.net", ".tibetjustice.org", ".tibetkomite.dk", "||tibetmuseum.org", "||tibetnetwork.org", ".tibetoffice.ch", "|http://tibetoffice.ch", "tibetoffice.eu", "||tibetoffice.org", "tibetonline.com", "||tibetonline.com", ".tibetoffice.com.au", "|http://tibetoffice.com.au", "||tibetonline.tv", ".tibetonline.tv", ".tibetoralhistory.org", "|http://tibetoralhistory.org", ".tibetpolicy.eu", ".tibetrelieffund.co.uk", "tibetsites.com", ".tibetsociety.com", "||tibetsociety.com", ".tibetsun.com", ".tibetsupportgroup.org", "|http://tibetsupportgroup.org", ".tibetswiss.ch", ".tibettelegraph.com", "tibettimes.net", "||tibetwrites.org", ".ticket.com.tw", ".tigervpn.com", "||tigervpn.com", ".timdir.com", "|http://timdir.com", ".time.com", "|http://time.com", "||timesnownews.com", ".timsah.com", "||timtales.com", "||blog.tiney.com", "tintuc101.com", ".tiny.cc", "|http://tiny.cc", "tinychat.com", "||tinypaste.com", ".tistory.com", "||tkcs-collins.com", ".tmagazine.com", "||tmagazine.com", ".tmdfish.com", "|http://tmi.me", ".tmpp.org", "|http://tmpp.org", ".tnaflix.com", "||tnaflix.com", ".tngrnow.com", ".tngrnow.net", ".tnp.org", "|http://tnp.org", ".to-porno.com", "||to-porno.com", "togetter.com", ".tokyo-247.com", ".tokyo-hot.com", "||tokyo-porn-tube.com", "||tokyocn.com", "tw.tomonews.net", ".tongil.or.kr", ".tono-oka.jp", "tonyyan.net", ".toodoc.com", "toonel.net", "top81.ws", ".topnews.in", ".toppornsites.com", "|http://toppornsites.com", ".torguard.net", "||torguard.net", "||top.tv", ".topshareware.com", ".topsy.com", "||topsy.com", "||toptip.ca", "tora.to", ".torcn.com", "||torlock.com", ".torproject.org", "||torproject.org", "||torrentkitty.tv", "torrentprivacy.com", "||torrentprivacy.com", "|http://torrentproject.se", "||torrenty.org", "||torrentz.eu", "||torvpn.com", "||totalvpn.com", ".toutiaoabc.com", "towngain.com", "toypark.in", "toytractorshow.com", ".tparents.org", ".tpi.org.tw", "||tpi.org.tw", "traffichaus.com", "||transparency.org", "||treemall.com.tw", "trendsmap.com", "||trendsmap.com", ".trialofccp.org", "||trialofccp.org", ".trimondi.de/SDLE", ".trouw.nl", "|http://trouw.nl", ".trt.net.tr", "trtc.com.tw", ".truebuddha-md.org", "|http://truebuddha-md.org", "trulyergonomic.com", ".truth101.co.tv", "|http://truth101.co.tv", ".truthontour.org", "|http://truthontour.org", ".truveo.com", ".tsctv.net", ".tsemtulku.com", "tsquare.tv", ".tsu.org.tw", "tsunagarumon.com", ".tsctv.net", "||tt1069.com", ".tttan.com", "||tttan.com", "bb.ttv.com.tw/bb", "tu8964.com", ".tubaholic.com", ".tube.com", "tube8.com", "||tube8.com", ".tube911.com", "||tube911.com", ".tubecup.com", ".tubegals.com", ".tubeislam.com", "|http://tubeislam.com", ".tubestack.com", "||tubewolf.com", ".tuibeitu.net", "tuidang.net", ".tuidang.org", "||tuidang.org", ".tuidang.se", "bbs.tuitui.info", ".tumutanzi.com", "|http://tumutanzi.com", "||tumview.com", ".tunein.com", "|http://tunein.com", "||tunnelbear.com", ".tunnelr.com", "||tunnelr.com", "||tunsafe.com", "tuitwit.com", ".turansam.org", ".turbobit.net", "||turbobit.net", ".turbohide.com", "||turbohide.com", "||turkistantimes.com", ".tushycash.com", "|http://tushycash.com", "||app.tutanota.com", ".tuvpn.com", "||tuvpn.com", "|http://tuzaijidi.com", "|http://*.tuzaijidi.com", ".tw01.org", "|http://tw01.org", ".tumblr.com", "||tumblr.com", "||lecloud.net", "|http://cosmic.monar.ch", "||slutmoonbeam.com", "|http://blog.soylent.com", ".tv.com", "|http://tv.com", "tvants.com", "forum.tvb.com", "news.tvb.com/list/world", "news.tvb.com/local", "news.tvbs.com.tw", ".tvboxnow.com", "|http://tvboxnow.com/", "tvider.com", ".tvmost.com.hk", ".tvplayvideos.com", "||tvunetworks.com", ".tw-blog.com", "|https://tw-blog.com", ".tw-npo.org", ".twaitter.com", "twapperkeeper.com", "||twapperkeeper.com", "||twaud.io", ".twaud.io", ".twavi.com", ".twbbs.net.tw", "twbbs.org", "twbbs.tw", "||twblogger.com", "tweepmag.com", ".tweepml.org", "||tweepml.org", ".tweetbackup.com", "||tweetbackup.com", "tweetboard.com", "||tweetboard.com", ".tweetboner.biz", "||tweetboner.biz", ".tweetcs.com", "|http://tweetcs.com", "|http://deck.ly", "||mtw.tl", "||tweetedtimes.com", "||tweetmylast.fm", "tweetphoto.com", "||tweetphoto.com", "||tweetrans.com", "tweetree.com", "||tweetree.com", ".tweettunnel.com", "||tweettunnel.com", "||tweetwally.com", "tweetymail.com", "||twelve.today", ".tweez.net", "|http://tweez.net", "||twftp.org", "||twgreatdaily.com", "twibase.com", ".twibble.de", "||twibble.de", "twibbon.com", "||twibs.com", ".twicountry.org", "|http://twicountry.org", "twicsy.com", ".twiends.com", "|http://twiends.com", ".twifan.com", "|http://twifan.com", "twiffo.com", "||twiffo.com", ".twilightsex.com", "twilog.org", "twimbow.com", "||twindexx.com", "twipple.jp", "||twipple.jp", "||twip.me", "twishort.com", "||twishort.com", "twistar.cc", "||twister.net.co", "||twisterio.com", "twisternow.com", "twistory.net", "twitbrowser.net", "||twitcause.com", "||twitgether.com", "||twiggit.org", "twitgoo.com", "twitiq.com", "||twitiq.com", ".twitlonger.com", "||twitlonger.com", "|http://tl.gd/", "twitmania.com", "twitoaster.com", "||twitoaster.com", "||twitonmsn.com", ".twit2d.com", "||twit2d.com", ".twitstat.com", "||twitstat.com", "||firstfivefollowers.com", "||retweeteffect.com", "||tweeplike.me", "||tweepguide.com", "||turbotwitter.com", ".twitvid.com", "||twitvid.com", "|http://twt.tl", "twittbot.net", "||ads-twitter.com", "||twttr.com", "||twitter4j.org", ".twittercounter.com", "||twittercounter.com", "twitterfeed.com", ".twittergadget.com", "||twittergadget.com", ".twitterkr.com", "||twitterkr.com", "||twittermail.com", "||twitterrific.com", "twittertim.es", "||twittertim.es", "twitthat.com", "||twitturk.com", ".twitturly.com", "||twitturly.com", ".twitzap.com", "twiyia.com", "||twstar.net", ".twtkr.com", "|http://twtkr.com", ".twnorth.org.tw", "||twreporter.org", "twskype.com", "twtrland.com", "twurl.nl", ".twyac.org", "||twyac.org", ".txxx.com", ".tycool.com", "||tycool.com", "||typepad.com", "@@||www.typepad.com", "@@||static.typepad.com", "||blog.expofutures.com", "||legaltech.law.com", "||blogs.tampabay.com", "||contests.twilio.com", ".embr.in", "||embr.in", ".u9un.com", "||u9un.com", ".ubddns.org", "|http://ubddns.org", "||uberproxy.net", ".uc-japan.org", "||uc-japan.org", ".srcf.ucam.org/salon/", "|http://china.ucanews.com/", "||ucdc1998.org", "|http://hum*.uchicago.edu/faculty/ywang/history", "||uderzo.it", ".udn.com", "||udn.com", "||udn.com.tw", "udnbkk.com/bbs", "||uforadio.com.tw", "ufreevpn.com", ".ugo.com", "||uhdwallpapers.org", "||uhrp.org", ".uighur.nl", "||uighur.nl", "uighurbiz.net", ".ulike.net", "ukcdp.co.uk", "ukliferadio.co.uk", "||ukliferadio.co.uk", "ultravpn.fr", "||ultravpn.fr", "ultraxs.com", "umich.edu/~falun", "||unblock.cn.com", ".unblocker.yt", "unblock-us.com", "||unblock-us.com", ".unblockdmm.com", "|http://unblockdmm.com", "||unblocksit.es", "uncyclomedia.org", ".uncyclopedia.hk/wiki", "|http://uncyclopedia.hk", "|http://uncyclopedia.tw", "underwoodammo.com", "||underwoodammo.com", "||unholyknight.com", ".uni.cc", "||cldr.unicode.org", ".unification.net", ".unification.org.tw", "||unirule.cloud", ".unitedsocialpress.com", ".unix100.com", "||unknownspace.org", ".unodedos.com", "unpo.org", "||unstable.icu", ".untraceable.us", "|http://untraceable.us", "||uocn.org", "tor.updatestar.com", "||upghsbc.com", ".upholdjustice.org", ".upload4u.info", "uploaded.net/file", "|http://uploaded.net/file", "|http://uploaded.to/file", ".uploadstation.com/file", ".upmedia.mg", "||upmedia.mg", ".upornia.com", "|http://upornia.com", "||uproxy.org", "||uptodown.com", ".upwill.org", "ur7s.com", "||urbandictionary.com", "||urbansurvival.com", "myshare.url.com.tw/", "||urlborg.com", "||urlparser.com", "us.to", "||usacn.com", ".usaip.eu", "||usaip.eu", "dalailama.usc.edu", "||usma.edu", ".usocctn.com", "||ustibetcommittee.org", ".ustream.tv", "||ustream.tv", ".usunitednews.com", "|http://usunitednews.com", "usus.cc", ".utopianpal.com", "||utopianpal.com", ".uu-gg.com", ".uvwxyz.xyz", "||uvwxyz.xyz", ".uwants.com", ".uwants.net", "uyghur.co.uk", "|http://uyghur-j.org", "||uyghuramerican.org", "||uyghurbiz.org", ".uyghurcanadiansociety.org", ".uyghurensemble.co.uk", "||uyghurcongress.org", ".uyghurpen.org", ".uyghurpress.com", "|https://uyghurpress.com", ".uyghurstudies.org", "|http://uyghurstudies.org", "uygur.org", "|http://uymaarip.com/", "||v2fly.org", ".v2ray.com", "||v2ray.com", "||v2raycn.com", "||v2raytech.com", "||valeursactuelles.com", ".van001.com", ".van698.com", ".vanemu.cn", ".vanilla-jp.com", ".vanpeople.com", "vansky.com", "||vaticannews.va", "||vcf-online.org", "||vcfbuilder.org", ".vegasred.com", ".velkaepocha.sk", ".venbbs.com", ".venchina.com", ".venetianmacao.com", "||venetianmacao.com", "veoh.com", "mysite.verizon.net", "vermonttibet.org", ".versavpn.com", "||versavpn.com", "||verybs.com", ".vft.com.tw", ".viber.com", "||viber.com", ".vica.info", ".victimsofcommunism.org", "|http://victimsofcommunism.org", "||vid.me", "||vidble.com", "videobam.com", "||videobam.com", ".videodetective.com", ".videomega.tv", "||videomega.tv", ".videomo.com", "videopediaworld.com", ".videopress.com", ".vidinfo.org/video", "vietdaikynguyen.com", ".vijayatemple.org", "||vilavpn.com", "vimeo.com", "||vimeo.com", "||vimperator.org", "||vincnd.com", "||vinniev.com", "|http://www.lib.virginia.edu/area-studies/Tibet/tibet.html", ".virtualrealporn.com", "||virtualrealporn.com", "visibletweets.com", "|http://ny.visiontimes.com", ".vital247.org", "||viu.com", ".vivahentai4u.net", ".vivatube.com", ".vivthomas.com", "||vivthomas.com", ".vjav.com", "||vjav.com", ".vjmedia.com.hk", ".vllcs.org", "|http://vllcs.org", "||vmixcore.com", "||vnet.link", ".vocativ.com", "vocn.tv", "||vocus.cc", "||voicettank.org", ".vot.org", "||vot.org", ".vovo2000.com", "|http://vovo2000.com", ".voxer.com", "||voxer.com", ".voy.com", "||vpn.ac", ".vpn4all.com", "||vpn4all.com", ".vpnaccount.org", "|http://vpnaccount.org", ".vpnaccounts.com", "||vpnaccounts.com", ".vpncomparison.org", ".vpncup.com", "||vpncup.com", "vpnbook.com", ".vpncoupons.com", "|http://vpncoupons.com", ".vpndada.com", "||vpndada.com", ".vpnfan.com", "vpnfire.com", ".vpnfires.biz", ".vpnforgame.net", "||vpnforgame.net", "||vpngate.jp", ".vpngate.net", "||vpngate.net", ".vpngratis.net", "vpnhq.com", "||vpnhub.com", ".vpnmaster.com", "||vpnmaster.com", ".vpnmentor.com", "||vpnmentor.com", ".vpninja.net", "||vpninja.net", ".vpnintouch.com", "||vpnintouch.net", "vpnjack.com", "||vpnjack.com", ".vpnpick.com", "||vpnpick.com", "||vpnpop.com", "||vpnpronet.com", ".vpnreactor.com", "||vpnreactor.com", "||vpnreviewz.com", ".vpnsecure.me", "||vpnsecure.me", ".vpnshazam.com", "||vpnshazam.com", ".vpnshieldapp.com", "||vpnshieldapp.com", ".vpnsp.com", ".vpntraffic.com", ".vpntunnel.com", "||vpntunnel.com", ".vpnuk.info", "||vpnuk.info", "||vpnunlimitedapp.com", ".vpnvip.com", "||vpnvip.com", ".vpnworldwide.com", ".vporn.com", "||vporn.com", ".vpser.net", "@@||vpser.net", "vraiesagesse.net", ".vrmtr.com", "||vtunnel.com", "||vuku.cc", "lists.w3.org/archives/public", "||w3schools.com", "||waffle1999.com", ".wahas.com", ".waigaobu.com", "waikeung.org/php_wind", ".wailaike.net", ".waiwaier.com", "|http://waiwaier.com", "||wallmama.com", "wallornot.org", "||wallpapercasa.com", ".wallproxy.com", "@@||wallproxy.com.cn", "||wallsttv.com", "||waltermartin.com", "||waltermartin.org", "||www.wan-press.org", "||wanderinghorse.net", "||wangafu.net", "||wangjinbo.org", ".wangjinbo.org", "wanglixiong.com", ".wango.org", "||wango.org", "wangruoshui.net", "www.wangruowang.org", "||want-daily.com", "wapedia.mobi/zhsimp", "||warroom.org", "||waselpro.com", ".watchinese.com", "||watchout.tw", ".wattpad.com", "||wattpad.com", ".makzhou.warehouse333.com", "washeng.net", ".watch8x.com", "||watchmygf.net", "||wav.tv", ".wdf5.com", ".wearehairy.com", ".wearn.com", "||wearn.com", "|http://hkcoc.weather.com.hk", "||hudatoriq.web.id", "||web2project.net", "webbang.net", ".webevader.org", ".webfreer.com", "weblagu.com", ".webjb.org", ".webrush.net", "webs-tv.net", ".websitepulse.com/help/testtools.china-test", "|http://www.websnapr.com", ".webwarper.net", "|http://webwarper.net", "webworkerdaily.com", "||wechatlawsuit.com", ".weekmag.info", "||wefightcensorship.org", ".wefong.com", "weiboleak.com", ".weihuo.org", "weijingsheng.org", ".weiming.info", "||weiming.info", "weiquanwang.org", "|http://weisuo.ws", ".welovecock.com", "||welt.de", ".wemigrate.org", "|http://wemigrate.org", "wengewang.com", "||wengewang.org", ".wenhui.ch", "|http://trans.wenweipo.com/gb/", ".wenxuecity.com", "||wenxuecity.com", ".wenyunchao.com", "||wenyunchao.com", ".westca.com", "||westca.com", "||westernwolves.com", ".westkit.net", "||westpoint.edu", ".westernshugdensociety.org", "wetpussygames.com", ".wetplace.com", "wexiaobo.org", "||wexiaobo.org", "wezhiyong.org", "||wezone.net", ".wforum.com", "||wforum.com/", ".whatblocked.com", "||whatblocked.com", ".wheatseeds.org", "||wheelockslatin.com", ".whippedass.com", ".whoer.net", "||whoer.net", "whotalking.com", "whylover.com", "||whyx.org", "||wikileaks.ch", "||wikileaks.com", "||wikileaks.de", "||wikileaks.eu", "||wikileaks.lu", ".wikileaks.org", "||wikileaks.org", "||wikileaks.pl", ".wikileaks-forum.com", "wildammo.com", ".williamhill.com", "||collateralmurder.com", "||collateralmurder.org", "wikilivres.info/wiki/%E9%9B%B6%E5%85%AB%E5%AE%AA%E7%AB%A0", "||wikimapia.org", ".wikiwand.com", "||wikiwand.com", "||wikiwiki.jp", "||casino.williamhill.com", "||sports.williamhill.com", "||vegas.williamhill.com", "||willw.net", "||windowsphoneme.com", ".windscribe.com", "||windscribe.com", "||community.windy.com", "||wingy.site", ".winning11.com", "winwhispers.info", "||wionews.com", "||wiredbytes.com", "||wiredpen.com", "||wireguard.com", ".wisdompubs.org", ".wisevid.com", "||wisevid.com", "||whispersystems.org", ".witnessleeteaching.com", ".witopia.net", ".wjbk.org", "||wjbk.org", "|http://wn.com", ".wnacg.com", ".wnacg.org", ".wo.tc", "||woeser.com", "|http://woesermiddle-way.net/", ".wokar.org", "|http://wokar.org", "wolfax.com", "||wolfax.com", "||wombo.ai", "||woolyss.com", "woopie.jp", "||woopie.jp", "woopie.tv", "||woopie.tv", "||workatruna.com", ".workerdemo.org.hk", ".workerempowerment.org", "||workersthebig.net", ".worldcat.org", "worldjournal.com", ".worldvpn.net", "||worldvpn.net", "||videopress.com", ".wordpress.com", "|http://*.wordpress.com", "||chenshan20042005.wordpress.com", "||chinaview.wordpress.com", "||cnbbnews.wordpress.com", "||freedominfonetweb.wordpress.com", "||hka8964.wordpress.com", "||hkanews.wordpress.com", "||hqsbnet.wordpress.com", "||hqsbonline.wordpress.com", "||investigating.wordpress.com", "||jobnewera.wordpress.com", "||matthewdgreen.wordpress.com", "||minghuiyw.wordpress.com", "||wo3ttt.wordpress.com", "||sujiatun.wordpress.com", "||xijie.wordpress.com", "||wp.com", ".wow.com", ".wow-life.net", "||wowlegacy.ml", "||wowporn.com", "||wowgirls.com", ".wowrk.com", "woxinghuiguo.com", ".woyaolian.org", "|http://woyaolian.org", ".wpoforum.com", "||wpoforum.com", ".wqyd.org", "||wqyd.org", "wrchina.org", "wretch.cc", ".wsj.com", "||wsj.com", ".wsj.net", "||wsj.net", ".wsjhk.com", ".wtbn.org", ".wtfpeople.com", "wuerkaixi.com", "||wufafangwen.com", "wufi.org.tw", "||wuguoguang.com", "wujie.net", "wujieliulan.com", "||wujieliulan.com", "wukangrui.net", "||wuw.red", "||wuyanblog.com", ".wwitv.com", "||wwitv.com", "wzyboy.im/post/160", ".x-berry.com", "||x-berry.com", "||x-art.com", "||x-wall.org", "x1949x.com", "x365x.com", "xanga.com", "||xbabe.com", ".xbookcn.com", "||xbookcn.com", "||xcafe.in", "||xcity.jp", ".xcritic.com", "|http://cdn*.xda-developers.com", ".xerotica.com", "destiny.xfiles.to/ubbthreads", ".xfm.pp.ru", ".xgmyd.com", "||xgmyd.com", "xhamster.com", "||xhamster.com", ".xianba.net", ".xianchawang.net", ".xianjian.tw", "|http://xianjian.tw", ".xianqiao.net", ".xiaobaiwu.com", ".xiaochuncnjp.com", ".xiaod.in", ".xiaohexie.com", "||xiaolan.me", "||xiaoma.org", "||xiaohexie.com", "||xiaxiaoqiang.net", "xiezhua.com", ".xihua.es", "forum.xinbao.de/forum", ".xing.com", "|http://xing.com", ".xinmiao.com.hk", "||xinmiao.com.hk", "xinsheng.net", "xinshijue.com", "xinhuanet.org", "|http://xinyubbs.net", ".xiongpian.com", ".xiuren.org", "||xixicui.icu", "xizang-zhiye.org", "xjp.cc", "||xjp.cc", "||xjtravelguide.com", "xlfmtalk.com", "||xlfmwz.info", "||xml-training-guide.com", "xmovies.com", "||xnxx.com", "xpdo.net", "||xpud.org", ".xrentdvd.com", ".xskywalker.net", "||xtube.com", "blog.xuite.net", "vlog.xuite.net", "xuzhiyong.net", "||xuchao.org", "xuchao.net", "||xuchao.net", "xvideo.cc", ".xvideos.com", "||xvideos.com", "||xvideos-cdn.com", "||xvideos.es", "||xvbelink.com", "||xvinlink.com", ".xkiwi.tk/", "||xsden.info", ".xxbbx.com", ".xxlmovies.com", "||xxx.com", ".xxx.xxx", "|http://xxx.xxx", ".xxxfuckmom.com", "||xxxx.com.au", ".xxxymovies.com", "|http://xxxymovies.com", "xys.org", "xysblogs.org", "xyy69.com", "xyy69.info", "||y2mate.com", "||yakbutterblues.com", "||yam.com", "||yam.org.tw", "||yande.re", "||disk.yandex.com", ".yanghengjun.com", "yangjianli.com", ".yasni.co.uk", "||yasni.co.uk", ".yayabay.com/forum", "||news.ycombinator.com", ".ydy.com", ".yeahteentube.com", "||yeahteentube.com", "||yecl.net", "||yeelou.com", "||yeeyi.com", "yegle.net", "||yegle.net", ".yes.xxx", "||yes123.com.tw", "||yesasia.com", "||yesasia.com.hk", ".yes-news.com", "|http://yes-news.com", ".yespornplease.com", "||yespornplease.com", "|http://yeyeclub.com", "||yhcw.net", ".yibada.com", ".yibaochina.com", ".yidio.com", "||yidio.com", "yilubbs.com", "xa.yimg.com", ".yingsuoss.com", ".yipub.com", "||yipub.com", "yinlei.org/mt", "||yiyechat.com", ".yizhihongxing.com", ".yobt.com", ".yobt.tv", "||yobt.tv", ".yogichen.org", "||yogichen.org", ".yolasite.com", ".yomiuri.co.jp", "yong.hu", ".yorkbbs.ca", "||youxu.info", ".youjizz.com", "||youjizz.com", ".youmaker.com", "||youmaker.com", ".youngpornvideos.com", "youngspiration.hk", ".youpai.org", "||youpai.org", ".your-freedom.net", "||yourepeat.com", ".yourprivatevpn.com", "||yourprivatevpn.com", ".yousendit.com", "||yousendit.com", "||youthforfreechina.org", ".youthnetradio.org/tmit/forum", "blog.youthwant.com.tw", "me.youthwant.com.tw", "share.youthwant.com.tw", "topic.youthwant.com.tw", ".youporn.com", "||youporn.com", ".youporngay.com", "||youporngay.com", ".yourlisten.com", "|http://yourlisten.com", ".yourlust.com", "|http://yourlust.com", "youshun12.com", ".youtubecn.com", "youversion.com", "||youversion.com", "blog.youxu.info/2010/03/14/west-chamber", "ytht.net", "yuanming.net", ".yuanzhengtang.org", ".yulghun.com", "||yunchao.net", "||yuntipub.com", ".yuvutu.com", "||yvesgeleyn.com", ".ywpw.com/forums/history/post/A0/p0/html/227", "yx51.net", ".yyii.org", "||yyii.org", "||yyjlymb.xyz", ".yzzk.com", "||yzzk.com", "zacebook.com", ".zalmos.com", "||zalmos.com", "||zannel.com", ".zaobao.com", "||zaobao.com", "|http://zaobao.com.sg", "||zaobao.com.sg", ".zaozon.com", "||zdnet.com.tw", ".zello.com", "||zello.com", ".zengjinyan.org", ".zenmate.com", "||zenmate.com", "||zenmate.com.ru", "||zerohedge.com", "||zeronet.io", "||zeutch.com", ".zfreet.com", ".zgsddh.com", "zgzcjj.net", ".zhanbin.net", "||zhanbin.net", ".zhangboli.net", "||zhangtianliang.com", "||zhanlve.org", "zhenghui.org", ".zhengjian.org", "||zhengjian.org", "zhengwunet.org", "zhenlibu.info", "||zhenlibu.info", ".zhenlibu1984.com", "||zhenlibu1984.com", "|http://zhenxiang.biz", ".zhinengluyou.com", "zhongguo.ca", "|http://zhongguorenquan.org", "zhongguotese.net", "||zhongguotese.net", "||zhongmeng.org", ".zhoushuguang.com", "||zhreader.com", ".zhuangbi.me", "||zhuangbi.me", ".zhuanxing.cn", "||zhuatieba.com", "zhuichaguoji.org", "||zhuichaguoji.org", "||zi.media", "|http://book.zi5.me", ".ziddu.com/download", "||zillionk.com", ".zinio.com", "||zinio.com", ".ziporn.com", ".zippyshare.com", ".zkaip.com", "||zkaip.com", "realforum.zkiz.com", "||zmw.cn", ".zodgame.us", "zomobo.net", ".zonaeuropa.com", "||zonaeuropa.com", "||zonghexinwen.com", ".zonghexinwen.net", "||zoogvpn.com", "||zootool.com", ".zoozle.net", "||zophar.net", "writer.zoho.com", "||zorrovpn.com", "||zpn.im", "||zspeeder.me", ".zsrhao.com", ".zuo.la", "||zuo.la", "||zuobiao.me", ".zuola.com", "||zuola.com", "||zvereff.com", "||zyxel.com", ".zynaima.com", "zyzc9.com", ".zzcartoon.com", "64memo", "aHR0cHM6Ly95ZWNsLm5ldA", "freenet", ".google.*/falun", "phobos.apple.com*/video", "q=freedom", "q%3Dfreedom", "remembering_tiananmen_20_years", "search*safeweb", "q=triangle", "q%3DTriangle", "ultrareach", "ultrasurf", "@@||aliyun.com", "@@||baidu.com", "@@||chinaso.com", "@@||chinaz.com", "@@|http://nrch.culture.tw/", "@@||adservice.google.com", "@@||dl.google.com", "@@||kh.google.com", "@@||khm.google.com", "@@||khm0.google.com", "@@||khm1.google.com", "@@||khm2.google.com", "@@||khm3.google.com", "@@||khmdb.google.com", "@@||tools.google.com", "@@||clientservices.googleapis.com", "@@||fonts.googleapis.com", "@@||khm.googleapis.com", "@@||khm0.googleapis.com", "@@||khm1.googleapis.com", "@@||khm2.googleapis.com", "@@||khm3.googleapis.com", "@@||khmdb.googleapis.com", "@@||storage.googleapis.com", "@@||translate.googleapis.com", "@@||update.googleapis.com", "@@||safebrowsing.googleapis.com", "@@||cn.gravatar.com", "@@||connectivitycheck.gstatic.com", "@@||csi.gstatic.com", "@@||fonts.gstatic.com", "@@||ssl.gstatic.com", "@@||haosou.com", "@@||ip.cn", "@@||jike.com", "@@|http://translate.google.cn", "@@|http://www.google.cn/maps", "@@||http2.golang.org", "@@||gov.cn", "@@||qq.com", "@@||sina.cn", "@@||sina.com.cn", "@@||sogou.com", "@@||so.com", "@@||soso.com", "@@||uluai.com.cn", "@@||weibo.com", "@@||yahoo.cn", "@@||youdao.com", "@@||zhongsou.com", "@@|http://ime.baidu.jp" ]; /* * This file is part of Adblock Plus , * Copyright (C) 2006-2014 Eyeo GmbH * * Adblock Plus is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * Adblock Plus is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Adblock Plus. If not, see . */ function createDict() { var result = {}; result.__proto__ = null; return result; } function getOwnPropertyDescriptor(obj, key) { if (obj.hasOwnProperty(key)) { return obj[key]; } return null; } function extend(subclass, superclass, definition) { if (Object.__proto__) { definition.__proto__ = superclass.prototype; subclass.prototype = definition; } else { var tmpclass = function(){}, ret; tmpclass.prototype = superclass.prototype; subclass.prototype = new tmpclass(); subclass.prototype.constructor = superclass; for (var i in definition) { if (definition.hasOwnProperty(i)) { subclass.prototype[i] = definition[i]; } } } } function Filter(text) { this.text = text; this.subscriptions = []; } Filter.prototype = { text: null, subscriptions: null, toString: function() { return this.text; } }; Filter.knownFilters = createDict(); Filter.elemhideRegExp = /^([^\/\*\|\@"!]*?)#(\@)?(?:([\w\-]+|\*)((?:\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\))*)|#([^{}]+))$/; Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)?$/; Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/; Filter.fromText = function(text) { if (text in Filter.knownFilters) { return Filter.knownFilters[text]; } var ret; if (text.charAt(0) == "!") { ret = new CommentFilter(text); } else { ret = RegExpFilter.fromText(text); } Filter.knownFilters[ret.text] = ret; return ret; }; function InvalidFilter(text, reason) { Filter.call(this, text); this.reason = reason; } extend(InvalidFilter, Filter, { reason: null }); function CommentFilter(text) { Filter.call(this, text); } extend(CommentFilter, Filter, { }); function ActiveFilter(text, domains) { Filter.call(this, text); this.domainSource = domains; } extend(ActiveFilter, Filter, { domainSource: null, domainSeparator: null, ignoreTrailingDot: true, domainSourceIsUpperCase: false, getDomains: function() { var prop = getOwnPropertyDescriptor(this, "domains"); if (prop) { return prop; } var domains = null; if (this.domainSource) { var source = this.domainSource; if (!this.domainSourceIsUpperCase) { source = source.toUpperCase(); } var list = source.split(this.domainSeparator); if (list.length == 1 && (list[0]).charAt(0) != "~") { domains = createDict(); domains[""] = false; if (this.ignoreTrailingDot) { list[0] = list[0].replace(/\.+$/, ""); } domains[list[0]] = true; } else { var hasIncludes = false; for (var i = 0; i < list.length; i++) { var domain = list[i]; if (this.ignoreTrailingDot) { domain = domain.replace(/\.+$/, ""); } if (domain == "") { continue; } var include; if (domain.charAt(0) == "~") { include = false; domain = domain.substr(1); } else { include = true; hasIncludes = true; } if (!domains) { domains = createDict(); } domains[domain] = include; } domains[""] = !hasIncludes; } this.domainSource = null; } return this.domains; }, sitekeys: null, isActiveOnDomain: function(docDomain, sitekey) { if (this.getSitekeys() && (!sitekey || this.getSitekeys().indexOf(sitekey.toUpperCase()) < 0)) { return false; } if (!this.getDomains()) { return true; } if (!docDomain) { return this.getDomains()[""]; } if (this.ignoreTrailingDot) { docDomain = docDomain.replace(/\.+$/, ""); } docDomain = docDomain.toUpperCase(); while (true) { if (docDomain in this.getDomains()) { return this.domains[docDomain]; } var nextDot = docDomain.indexOf("."); if (nextDot < 0) { break; } docDomain = docDomain.substr(nextDot + 1); } return this.domains[""]; }, isActiveOnlyOnDomain: function(docDomain) { if (!docDomain || !this.getDomains() || this.getDomains()[""]) { return false; } if (this.ignoreTrailingDot) { docDomain = docDomain.replace(/\.+$/, ""); } docDomain = docDomain.toUpperCase(); for (var domain in this.getDomains()) { if (this.domains[domain] && domain != docDomain && (domain.length <= docDomain.length || domain.indexOf("." + docDomain) != domain.length - docDomain.length - 1)) { return false; } } return true; } }); function RegExpFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys) { ActiveFilter.call(this, text, domains, sitekeys); if (contentType != null) { this.contentType = contentType; } if (matchCase) { this.matchCase = matchCase; } if (thirdParty != null) { this.thirdParty = thirdParty; } if (sitekeys != null) { this.sitekeySource = sitekeys; } if (regexpSource.length >= 2 && regexpSource.charAt(0) == "/" && regexpSource.charAt(regexpSource.length - 1) == "/") { var regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), this.matchCase ? "" : "i"); this.regexp = regexp; } else { this.regexpSource = regexpSource; } } extend(RegExpFilter, ActiveFilter, { domainSourceIsUpperCase: true, length: 1, domainSeparator: "|", regexpSource: null, getRegexp: function() { var prop = getOwnPropertyDescriptor(this, "regexp"); if (prop) { return prop; } var source = this.regexpSource.replace(/\*+/g, "*").replace(/\^\|$/, "^").replace(/\W/g, "\\$&").replace(/\\\*/g, ".*").replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x60\\x7B-\\x7F]|$)").replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?").replace(/^\\\|/, "^").replace(/\\\|$/, "$").replace(/^(\.\*)/, "").replace(/(\.\*)$/, ""); var regexp = new RegExp(source, this.matchCase ? "" : "i"); this.regexp = regexp; return regexp; }, contentType: 2147483647, matchCase: false, thirdParty: null, sitekeySource: null, getSitekeys: function() { var prop = getOwnPropertyDescriptor(this, "sitekeys"); if (prop) { return prop; } var sitekeys = null; if (this.sitekeySource) { sitekeys = this.sitekeySource.split("|"); this.sitekeySource = null; } this.sitekeys = sitekeys; return this.sitekeys; }, matches: function(location, contentType, docDomain, thirdParty, sitekey) { if (this.getRegexp().test(location) && this.isActiveOnDomain(docDomain, sitekey)) { return true; } return false; } }); RegExpFilter.prototype["0"] = "#this"; RegExpFilter.fromText = function(text) { var blocking = true; var origText = text; if (text.indexOf("@@") == 0) { blocking = false; text = text.substr(2); } var contentType = null; var matchCase = null; var domains = null; var sitekeys = null; var thirdParty = null; var collapse = null; var options; var match = text.indexOf("$") >= 0 ? Filter.optionsRegExp.exec(text) : null; if (match) { options = match[1].toUpperCase().split(","); text = match.input.substr(0, match.index); for (var _loopIndex6 = 0; _loopIndex6 < options.length; ++_loopIndex6) { var option = options[_loopIndex6]; var value = null; var separatorIndex = option.indexOf("="); if (separatorIndex >= 0) { value = option.substr(separatorIndex + 1); option = option.substr(0, separatorIndex); } option = option.replace(/-/, "_"); if (option in RegExpFilter.typeMap) { if (contentType == null) { contentType = 0; } contentType |= RegExpFilter.typeMap[option]; } else if (option.charAt(0) == "~" && option.substr(1) in RegExpFilter.typeMap) { if (contentType == null) { contentType = RegExpFilter.prototype.contentType; } contentType &= ~RegExpFilter.typeMap[option.substr(1)]; } else if (option == "MATCH_CASE") { matchCase = true; } else if (option == "~MATCH_CASE") { matchCase = false; } else if (option == "DOMAIN" && typeof value != "undefined") { domains = value; } else if (option == "THIRD_PARTY") { thirdParty = true; } else if (option == "~THIRD_PARTY") { thirdParty = false; } else if (option == "COLLAPSE") { collapse = true; } else if (option == "~COLLAPSE") { collapse = false; } else if (option == "SITEKEY" && typeof value != "undefined") { sitekeys = value; } else { return new InvalidFilter(origText, "Unknown option " + option.toLowerCase()); } } } if (!blocking && (contentType == null || contentType & RegExpFilter.typeMap.DOCUMENT) && (!options || options.indexOf("DOCUMENT") < 0) && !/^\|?[\w\-]+:/.test(text)) { if (contentType == null) { contentType = RegExpFilter.prototype.contentType; } contentType &= ~RegExpFilter.typeMap.DOCUMENT; } try { if (blocking) { return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse); } else { return new WhitelistFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys); } } catch (e) { return new InvalidFilter(origText, e); } }; RegExpFilter.typeMap = { OTHER: 1, SCRIPT: 2, IMAGE: 4, STYLESHEET: 8, OBJECT: 16, SUBDOCUMENT: 32, DOCUMENT: 64, XBL: 1, PING: 1, XMLHTTPREQUEST: 2048, OBJECT_SUBREQUEST: 4096, DTD: 1, MEDIA: 16384, FONT: 32768, BACKGROUND: 4, POPUP: 268435456, ELEMHIDE: 1073741824 }; RegExpFilter.prototype.contentType &= ~ (RegExpFilter.typeMap.ELEMHIDE | RegExpFilter.typeMap.POPUP); function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys, collapse) { RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys); this.collapse = collapse; } extend(BlockingFilter, RegExpFilter, { collapse: null }); function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys) { RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys); } extend(WhitelistFilter, RegExpFilter, { }); function Matcher() { this.clear(); } Matcher.prototype = { filterByKeyword: null, keywordByFilter: null, clear: function() { this.filterByKeyword = createDict(); this.keywordByFilter = createDict(); }, add: function(filter) { if (filter.text in this.keywordByFilter) { return; } var keyword = this.findKeyword(filter); var oldEntry = this.filterByKeyword[keyword]; if (typeof oldEntry == "undefined") { this.filterByKeyword[keyword] = filter; } else if (oldEntry.length == 1) { this.filterByKeyword[keyword] = [oldEntry, filter]; } else { oldEntry.push(filter); } this.keywordByFilter[filter.text] = keyword; }, remove: function(filter) { if (!(filter.text in this.keywordByFilter)) { return; } var keyword = this.keywordByFilter[filter.text]; var list = this.filterByKeyword[keyword]; if (list.length <= 1) { delete this.filterByKeyword[keyword]; } else { var index = list.indexOf(filter); if (index >= 0) { list.splice(index, 1); if (list.length == 1) { this.filterByKeyword[keyword] = list[0]; } } } delete this.keywordByFilter[filter.text]; }, findKeyword: function(filter) { var result = ""; var text = filter.text; if (Filter.regexpRegExp.test(text)) { return result; } var match = Filter.optionsRegExp.exec(text); if (match) { text = match.input.substr(0, match.index); } if (text.substr(0, 2) == "@@") { text = text.substr(2); } var candidates = text.toLowerCase().match(/[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/g); if (!candidates) { return result; } var hash = this.filterByKeyword; var resultCount = 16777215; var resultLength = 0; for (var i = 0, l = candidates.length; i < l; i++) { var candidate = candidates[i].substr(1); var count = candidate in hash ? hash[candidate].length : 0; if (count < resultCount || count == resultCount && candidate.length > resultLength) { result = candidate; resultCount = count; resultLength = candidate.length; } } return result; }, hasFilter: function(filter) { return filter.text in this.keywordByFilter; }, getKeywordForFilter: function(filter) { if (filter.text in this.keywordByFilter) { return this.keywordByFilter[filter.text]; } else { return null; } }, _checkEntryMatch: function(keyword, location, contentType, docDomain, thirdParty, sitekey) { var list = this.filterByKeyword[keyword]; for (var i = 0; i < list.length; i++) { var filter = list[i]; if (filter == "#this") { filter = list; } if (filter.matches(location, contentType, docDomain, thirdParty, sitekey)) { return filter; } } return null; }, matchesAny: function(location, contentType, docDomain, thirdParty, sitekey) { var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); if (candidates === null) { candidates = []; } candidates.push(""); for (var i = 0, l = candidates.length; i < l; i++) { var substr = candidates[i]; if (substr in this.filterByKeyword) { var result = this._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey); if (result) { return result; } } } return null; } }; function CombinedMatcher() { this.blacklist = new Matcher(); this.whitelist = new Matcher(); this.resultCache = createDict(); } CombinedMatcher.maxCacheEntries = 1000; CombinedMatcher.prototype = { blacklist: null, whitelist: null, resultCache: null, cacheEntries: 0, clear: function() { this.blacklist.clear(); this.whitelist.clear(); this.resultCache = createDict(); this.cacheEntries = 0; }, add: function(filter) { if (filter instanceof WhitelistFilter) { this.whitelist.add(filter); } else { this.blacklist.add(filter); } if (this.cacheEntries > 0) { this.resultCache = createDict(); this.cacheEntries = 0; } }, remove: function(filter) { if (filter instanceof WhitelistFilter) { this.whitelist.remove(filter); } else { this.blacklist.remove(filter); } if (this.cacheEntries > 0) { this.resultCache = createDict(); this.cacheEntries = 0; } }, findKeyword: function(filter) { if (filter instanceof WhitelistFilter) { return this.whitelist.findKeyword(filter); } else { return this.blacklist.findKeyword(filter); } }, hasFilter: function(filter) { if (filter instanceof WhitelistFilter) { return this.whitelist.hasFilter(filter); } else { return this.blacklist.hasFilter(filter); } }, getKeywordForFilter: function(filter) { if (filter instanceof WhitelistFilter) { return this.whitelist.getKeywordForFilter(filter); } else { return this.blacklist.getKeywordForFilter(filter); } }, isSlowFilter: function(filter) { var matcher = filter instanceof WhitelistFilter ? this.whitelist : this.blacklist; if (matcher.hasFilter(filter)) { return !matcher.getKeywordForFilter(filter); } else { return !matcher.findKeyword(filter); } }, matchesAnyInternal: function(location, contentType, docDomain, thirdParty, sitekey) { var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); if (candidates === null) { candidates = []; } candidates.push(""); var blacklistHit = null; for (var i = 0, l = candidates.length; i < l; i++) { var substr = candidates[i]; if (substr in this.whitelist.filterByKeyword) { var result = this.whitelist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey); if (result) { return result; } } if (substr in this.blacklist.filterByKeyword && blacklistHit === null) { blacklistHit = this.blacklist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey); } } return blacklistHit; }, matchesAny: function(location, docDomain) { var key = location + " " + docDomain + " "; if (key in this.resultCache) { return this.resultCache[key]; } var result = this.matchesAnyInternal(location, 0, docDomain, null, null); if (this.cacheEntries >= CombinedMatcher.maxCacheEntries) { this.resultCache = createDict(); this.cacheEntries = 0; } this.resultCache[key] = result; this.cacheEntries++; return result; } }; var userrulesMatcher = new CombinedMatcher(); var defaultMatcher = new CombinedMatcher(); for (var i = 0; i < userrules.length; i++) { userrulesMatcher.add(Filter.fromText(userrules[i])); } for (var i = 0; i < rules.length; i++) { defaultMatcher.add(Filter.fromText(rules[i])); } var subnetIpRangeList = [ 0,16777216, //0.0.0.0/8 167772160,184549376, //10.0.0.0/8 1681915904,1686110208, //100.64.0.0/10 2130706432,2147483648, //127.0.0.0/8 2851995648,2852061184, //169.254.0.0/16 2886729728,2887778304, //172.16.0.0/12 3221225472,3221225728, //192.0.0.0/24 3221225984,3221226240, //192.0.2.0/24 3227017984,3227018240, //192.88.99.0/24 3232235520,3232301056, //192.168.0.0/16 3323068416,3323199488, //198.18.0.0/15 3325256704,3325256960, //198.51.100.0/24 3405803776,3405804032, //203.0.113.0/24 3758096384,4026531840 //224.0.0.0/4 ]; function convertAddress(ipchars) { var bytes = ipchars.split('.'); var result = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | (bytes[3]); return result >>> 0; } function check_ipv4(host) { var re_ipv4 = /^\d+\.\d+\.\d+\.\d+$/g; if (re_ipv4.test(host)) { return true; } } function check_ipv6(host) { var re_ipv6 = /^\[?([a-fA-F0-9]{0,4}\:){1,7}[a-fA-F0-9]{0,4}\]?$/g; if (re_ipv6.test(host)) { return true; } } function check_ipv6_dns(dnsstr) { var re_ipv6 = /([a-fA-F0-9]{0,4}\:){1,7}[a-fA-F0-9]{0,4}(%[0-9]+)?/g; if (re_ipv6.test(dnsstr)) { return true; } } function isInSubnetRange(ipRange, intIp) { for ( var i = 0; i < 28; i += 2 ) { if ( ipRange[i] <= intIp && intIp < ipRange[i+1] ) return true; } } function getProxyFromIP(strIp) { var intIp = convertAddress(strIp); if ( isInSubnetRange(subnetIpRangeList, intIp) ) { return direct; } return ip_proxy(); } function FindProxyForURL(url, host) { if ( isPlainHostName(host) === true ) { return direct; } if (userrulesMatcher.matchesAny(url, host) instanceof BlockingFilter) { return wall_proxy(); } if (userrulesMatcher.matchesAny(url, host) instanceof WhitelistFilter) { return direct; } if (defaultMatcher.matchesAny(url, host) instanceof BlockingFilter) { return wall_proxy(); } if ( check_ipv4(host) === true ) { return getProxyFromIP(host); } return direct; } ================================================ FILE: shadowsocks-csharp/Data/user-rule.txt ================================================ ! Put user rules line by line in this file. ! See https://adblockplus.org/en/filter-cheatsheet ================================================ FILE: shadowsocks-csharp/Encryption/CircularBuffer/ByteCircularBuffer.cs ================================================ #region Original License //New BSD License(BSD) // //Copyright(c) 2014-2015 Cyotek Ltd //Copyright(c) 2012, Alex Regueiro //All rights reserved. // //Redistribution and use in source and binary forms, with or without //modification, are permitted provided that the following conditions are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of Cyotek nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND //ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE //DISCLAIMED.IN NO EVENT SHALL BE LIABLE FOR ANY //DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND //ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; namespace Shadowsocks.Encryption.CircularBuffer { /// /// Represents a first-in, first-out collection of objects using a fixed buffer. /// /// /// The capacity of a is the number of elements the can hold. /// ByteCircularBuffer accepts null as a valid value for reference types and allows duplicate elements. /// The methods will remove the items that are returned from the ByteCircularBuffer. To view the contents of the ByteCircularBuffer without removing items, use the or methods. /// public class ByteCircularBuffer { // based on http://circularbuffer.codeplex.com/ // http://en.wikipedia.org/wiki/Circular_buffer // modified from https://github.com/cyotek/Cyotek.Collections.Generic.CircularBuffer // some code taken from https://github.com/xorxornop/RingBuffer // and https://github.com/xorxornop/PerfCopy #region Instance Fields private byte[] _buffer; private int _capacity; #endregion #region Public Constructors /// /// Initializes a new instance of the class that is empty and has the specified initial capacity. /// /// The maximum capcity of the buffer. /// Thown if the is less than zero. public ByteCircularBuffer(int capacity) { if (capacity < 0) { throw new ArgumentException(@"The buffer capacity must be greater than or equal to zero.", nameof(capacity)); } _buffer = new byte[capacity]; this.Capacity = capacity; this.Size = 0; this.Head = 0; this.Tail = 0; } #endregion #region Public Properties /// /// Gets or sets the total number of elements the internal data structure can hold. /// /// The total number of elements that the can contain. /// Thrown if the specified new capacity is smaller than the current contents of the buffer. public int Capacity { get { return _capacity; } set { if (value != _capacity) { if (value < this.Size) { throw new ArgumentOutOfRangeException(nameof(value), value, @"The new capacity must be greater than or equal to the buffer size."); } var newBuffer = new byte[value]; if (this.Size > 0) { this.CopyTo(newBuffer); } _buffer = newBuffer; _capacity = value; } } } /// /// Gets the index of the beginning of the buffer data. /// /// The index of the first element in the buffer. public int Head { get; protected set; } /// /// Gets a value indicating whether the buffer is empty. /// /// true if buffer is empty; otherwise, false. public virtual bool IsEmpty => this.Size == 0; /// /// Gets a value indicating whether the buffer is full. /// /// true if the buffer is full; otherwise, false. /// The property always returns false if the property is set to true. public virtual bool IsFull => this.Size == this.Capacity; /// /// Gets the number of elements contained in the . /// /// The number of elements contained in the . public int Size { get; protected set; } /// /// Gets the index of the end of the buffer data. /// /// The index of the last element in the buffer. public int Tail { get; protected set; } #endregion #region Public Members /// /// Removes all items from the . /// public void Clear() { this.Size = 0; this.Head = 0; this.Tail = 0; _buffer = new byte[this.Capacity]; } /// /// Determines whether the contains a specific value. /// /// The object to locate in the . /// true if is found in the ; otherwise, false. public bool Contains(byte item) { var bufferIndex = this.Head; var comparer = EqualityComparer.Default; var result = false; for (int i = 0; i < this.Size; i++, bufferIndex++) { if (bufferIndex == this.Capacity) { bufferIndex = 0; } if (comparer.Equals(_buffer[bufferIndex], item)) { result = true; break; } } return result; } /// /// Copies the entire to a compatible one-dimensional array, starting at the beginning of the target array. /// /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. public void CopyTo(byte[] array) { this.CopyTo(array, 0); } /// /// Copies the entire to a compatible one-dimensional array, starting at the specified index of the target array. /// /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. /// The zero-based index in at which copying begins. public void CopyTo(byte[] array, int arrayIndex) { this.CopyTo(this.Head, array, arrayIndex, Math.Min(this.Size, array.Length - arrayIndex)); } /// /// Copies a range of elements from the to a compatible one-dimensional array, starting at the specified index of the target array. /// /// The zero-based index in the source at which copying begins. /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. /// The zero-based index in at which copying begins. /// The number of elements to copy. public virtual void CopyTo(int index, byte[] array, int arrayIndex, int count) { if (count > this.Size) { throw new ArgumentOutOfRangeException(nameof(count), count, @"The read count cannot be greater than the buffer size."); } var startAnchor = index; var dstIndex = arrayIndex; while (count > 0) { int chunk = Math.Min(Capacity - startAnchor, count); Buffer.BlockCopy(_buffer, startAnchor, array, dstIndex, chunk); startAnchor = (startAnchor + chunk == Capacity) ? 0 : startAnchor + chunk; dstIndex += chunk; count -= chunk; } } /// /// Removes and returns the specified number of objects from the beginning of the . /// /// The number of elements to remove and return from the . /// The objects that are removed from the beginning of the . public byte[] Get(int count) { if (count <= 0) { throw new ArgumentOutOfRangeException(nameof(count)); } var result = new byte[count]; this.Get(result); return result; } /// /// Copies and removes the specified number elements from the to a compatible one-dimensional array, starting at the beginning of the target array. /// /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. /// The actual number of elements copied into . public int Get(byte[] array) { if (array.Length <= 0) { throw new ArgumentOutOfRangeException(nameof(array)); } return this.Get(array, 0, array.Length); } /// /// Copies and removes the specified number elements from the to a compatible one-dimensional array, starting at the specified index of the target array. /// /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. /// The zero-based index in at which copying begins. /// The number of elements to copy. /// The actual number of elements copied into . public virtual int Get(byte[] array, int arrayIndex, int count) { if (arrayIndex < 0) { throw new ArgumentOutOfRangeException(nameof(arrayIndex), @"Negative offset specified. Offsets must be positive."); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count), @"Negative count specified. Count must be positive."); } if (count > this.Size) { throw new ArgumentException(@"Ringbuffer contents insufficient for take/read operation.", nameof(count)); } if (array.Length < arrayIndex + count) { throw new ArgumentException("Destination array too small for requested output."); } var bytesCopied = 0; var dstIndex = arrayIndex; while (count > 0) { int chunk = Math.Min(Capacity - this.Head, count); Buffer.BlockCopy(_buffer, this.Head, array, dstIndex, chunk); this.Head = (this.Head + chunk == Capacity) ? 0 : this.Head + chunk; this.Size -= chunk; dstIndex += chunk; bytesCopied += chunk; count -= chunk; } return bytesCopied; } /// /// Removes and returns the object at the beginning of the . /// /// The object that is removed from the beginning of the . /// Thrown if the buffer is empty. /// This method is similar to the method, but Peek does not modify the . public virtual byte Get() { if (this.IsEmpty) { throw new InvalidOperationException("The buffer is empty."); } var item = _buffer[this.Head]; if (++this.Head == this.Capacity) { this.Head = 0; } this.Size--; return item; } /// /// Returns the object at the beginning of the without removing it. /// /// The object at the beginning of the . /// Thrown if the buffer is empty. public virtual byte Peek() { if (this.IsEmpty) { throw new InvalidOperationException("The buffer is empty."); } var item = _buffer[this.Head]; return item; } /// /// Returns the specified number of objects from the beginning of the . /// /// The number of elements to return from the . /// The objects that from the beginning of the . /// Thrown if the buffer is empty. public virtual byte[] Peek(int count) { if (this.IsEmpty) { throw new InvalidOperationException("The buffer is empty."); } var items = new byte[count]; this.CopyTo(items); return items; } /// /// Returns the object at the end of the without removing it. /// /// The object at the end of the . /// Thrown if the buffer is empty. public virtual byte PeekLast() { int bufferIndex; if (this.IsEmpty) { throw new InvalidOperationException("The buffer is empty."); } if (this.Tail == 0) { bufferIndex = this.Size - 1; } else { bufferIndex = this.Tail - 1; } var item = _buffer[bufferIndex]; return item; } /// /// Copies an entire compatible one-dimensional array to the . /// /// The one-dimensional that is the source of the elements copied to . The must have zero-based indexing. /// Thrown if buffer does not have sufficient capacity to put in new items. /// If plus the size of exceeds the capacity of the and the property is true, the oldest items in the are overwritten with . public int Put(byte[] array) { return this.Put(array, 0, array.Length); } /// /// Copies a range of elements from a compatible one-dimensional array to the . /// /// The one-dimensional that is the source of the elements copied to . The must have zero-based indexing. /// The zero-based index in at which copying begins. /// The number of elements to copy. /// Thrown if buffer does not have sufficient capacity to put in new items. /// If plus exceeds the capacity of the and the property is true, the oldest items in the are overwritten with . public virtual int Put(byte[] array, int arrayIndex, int count) { if (count <= 0) { throw new ArgumentOutOfRangeException(nameof(count), @"Count must be positive."); } if (this.Size + count > this.Capacity) { throw new InvalidOperationException("The buffer does not have sufficient capacity to put new items."); } if (array.Length < arrayIndex + count) { throw new ArgumentException("Source array too small for requested input."); } var srcIndex = arrayIndex; var bytesToProcess = count; while (bytesToProcess > 0) { int chunk = Math.Min(Capacity - Tail, bytesToProcess); Buffer.BlockCopy(array, srcIndex, _buffer, Tail, chunk); Tail = (Tail + chunk == Capacity) ? 0 : Tail + chunk; this.Size += chunk; srcIndex += chunk; bytesToProcess -= chunk; } return count; } /// /// Adds a byte to the end of the . /// /// The byte to add to the . /// Thrown if buffer does not have sufficient capacity to put in new items. public virtual void Put(byte item) { if (IsFull) { throw new InvalidOperationException("The buffer does not have sufficient capacity to put new items."); } _buffer[this.Tail] = item; this.Tail++; if (this.Size == this.Capacity) { this.Head++; if (this.Head >= this.Capacity) { this.Head -= this.Capacity; } } if (this.Tail == this.Capacity) { this.Tail = 0; } if (this.Size != this.Capacity) { this.Size++; } } /// /// Increments the starting index of the data buffer in the . /// /// The number of elements to increment the data buffer start index by. public void Skip(int count) { if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count), @"Negative count specified. Count must be positive."); } if (count > this.Size) { throw new ArgumentException(@"Ringbuffer contents insufficient for operation.", nameof(count)); } // Modular division gives new offset position this.Head = (this.Head + count) % Capacity; this.Size -= count; } /// /// Copies the elements to a new array. /// /// A new array containing elements copied from the . /// The is not modified. The order of the elements in the new array is the same as the order of the elements from the beginning of the to its end. public byte[] ToArray() { var result = new byte[this.Size]; this.CopyTo(result); return result; } #endregion } } ================================================ FILE: shadowsocks-csharp/Encryption/CryptoUtils.cs ================================================ using CryptoBase.Abstractions.Digests; using CryptoBase.Digests; using CryptoBase.SymmetricCryptos.BlockCryptos.AES; using Shadowsocks.Crypto; using System; using System.Buffers; namespace Shadowsocks.Encryption { public static class CryptoUtils { public static void SsAes128(string password, ReadOnlySpan source, Span destination) { var buffer = ArrayPool.Shared.Rent(16); try { buffer.AsSpan(0, 16).SsDeriveKey(password); using var aes = AESUtils.CreateECB(buffer); aes.Encrypt(source, destination); } finally { ArrayPool.Shared.Return(buffer); } } public static byte[] MD5(ReadOnlySpan input) { var output = new byte[HashConstants.Md5Length]; using var hash = DigestUtils.Create(DigestType.Md5); hash.UpdateFinal(input, output); return output; } public static byte[] SHA1(ReadOnlySpan input) { var output = new byte[HashConstants.Sha1Length]; using var hash = DigestUtils.Create(DigestType.Sha1); hash.UpdateFinal(input, output); return output; } } } ================================================ FILE: shadowsocks-csharp/Encryption/EncryptorBase.cs ================================================ namespace Shadowsocks.Encryption { public abstract class EncryptorBase : IEncryptor { public const int MAX_INPUT_SIZE = 32768; public const int MD5_LEN = 16; public const int ADDR_PORT_LEN = 2; public const int ADDR_ATYP_LEN = 1; public const int ATYP_IPv4 = 0x01; public const int ATYP_DOMAIN = 0x03; public const int ATYP_IPv6 = 0x04; protected EncryptorBase(string method, string password) { Method = method; Password = password; } protected string Method; protected string Password; public abstract void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength); public abstract void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength); public abstract void ResetEncrypt(); public abstract void ResetDecrypt(); public abstract void Dispose(); public abstract byte[] getIV(); public abstract byte[] getKey(); public abstract EncryptorInfo getInfo(); } } ================================================ FILE: shadowsocks-csharp/Encryption/EncryptorFactory.cs ================================================ using Shadowsocks.Encryption.Stream; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Shadowsocks.Encryption { public static class EncryptorFactory { public static readonly Dictionary RegisteredEncryptors = new(); private static readonly Type[] ConstructorTypes = { typeof(string), typeof(string) }; static EncryptorFactory() { foreach (var method in NoneEncryptor.SupportedCiphers().Where(method => !RegisteredEncryptors.ContainsKey(method))) { RegisteredEncryptors.Add(method, typeof(NoneEncryptor)); } foreach (var method in StreamOpenSSLEncryptor.SupportedCiphers().Where(method => !RegisteredEncryptors.ContainsKey(method))) { RegisteredEncryptors.Add(method, typeof(StreamOpenSSLEncryptor)); } foreach (var method in StreamSodiumEncryptor.SupportedCiphers().Where(method => !RegisteredEncryptors.ContainsKey(method))) { RegisteredEncryptors.Add(method, typeof(StreamSodiumEncryptor)); } var allEncryptor = new StringBuilder(Environment.NewLine); allEncryptor.AppendLine(@"============================"); allEncryptor.AppendLine(@"Registered Encryptor Info"); foreach (var encryptor in RegisteredEncryptors) { allEncryptor.AppendLine($@"{encryptor.Key}=>{encryptor.Value.Name}"); } allEncryptor.AppendLine(@"============================"); Console.WriteLine(allEncryptor); } public static IEncryptor GetEncryptor(string method, string password) { if (string.IsNullOrEmpty(method)) { method = @"aes-256-cfb"; } method = method.ToLowerInvariant(); var t = RegisteredEncryptors[method]; var c = t.GetConstructor(ConstructorTypes); if (c == null) { throw new System.Exception("Invalid ctor"); } var result = (IEncryptor)c.Invoke(new object[] { method, password }); return result; } public static EncryptorInfo GetEncryptorInfo(string method) { if (string.IsNullOrEmpty(method)) { method = @"aes-256-cfb"; } method = method.ToLowerInvariant(); var t = RegisteredEncryptors[method]; var c = t.GetConstructor(ConstructorTypes); if (c == null) { throw new System.Exception("Invalid ctor"); } var result = (IEncryptor)c.Invoke(new object[] { method, "0" }); var info = result.getInfo(); result.Dispose(); return info; } } } ================================================ FILE: shadowsocks-csharp/Encryption/EncryptorInfo.cs ================================================ namespace Shadowsocks.Encryption { public class EncryptorInfo { public int KeySize; public int IvSize; public bool Display; public int Type; public string InnerLibName; public EncryptorInfo(int key, int iv, int type, string innerLibName = @"", bool display = true) { KeySize = key; IvSize = iv; Display = display; Type = type; InnerLibName = innerLibName; } } } ================================================ FILE: shadowsocks-csharp/Encryption/Exception/CryptoException.cs ================================================ namespace Shadowsocks.Encryption.Exception { public class CryptoErrorException : System.Exception { public CryptoErrorException() { } public CryptoErrorException(string msg) : base(msg) { } public CryptoErrorException(string message, System.Exception innerException) : base(message, innerException) { } } } ================================================ FILE: shadowsocks-csharp/Encryption/IEncryptor.cs ================================================ using System; namespace Shadowsocks.Encryption { public interface IEncryptor : IDisposable { void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength); void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength); void ResetEncrypt(); void ResetDecrypt(); byte[] getIV(); byte[] getKey(); EncryptorInfo getInfo(); } } ================================================ FILE: shadowsocks-csharp/Encryption/OpenSSL.cs ================================================ using Shadowsocks.Controller; using Shadowsocks.Properties; using Shadowsocks.Util; using System; using System.IO; using System.Runtime.InteropServices; using System.Security; using System.Text; namespace Shadowsocks.Encryption { public static class OpenSSL { private const string DLLNAME = @"libsscrypto.dll"; public const int OPENSSL_ENCRYPT = 1; public const int OPENSSL_DECRYPT = 0; static OpenSSL() { var dllPath = Utils.GetTempPath(DLLNAME); try { FileManager.DecompressFile(dllPath, Environment.Is64BitProcess ? Resources.libsscrypto64_dll : Resources.libsscrypto_dll); LoadLibrary(dllPath); } catch (IOException) { } catch (System.Exception e) { Logging.LogUsefulException(e); } } public static IntPtr GetCipherInfo(string cipherName) { var name = Encoding.ASCII.GetBytes(cipherName); Array.Resize(ref name, name.Length + 1); return EVP_get_cipherbyname(name); } [DllImport(@"Kernel32.dll")] private static extern IntPtr LoadLibrary(string path); [SuppressUnmanagedCodeSecurity] [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr EVP_get_cipherbyname(byte[] name); [SuppressUnmanagedCodeSecurity] [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr EVP_CIPHER_CTX_new(); [SuppressUnmanagedCodeSecurity] [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern void EVP_CIPHER_CTX_free(IntPtr ctx); [SuppressUnmanagedCodeSecurity] [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern int EVP_CipherInit_ex(IntPtr ctx, IntPtr type, IntPtr impl, byte[] key, byte[] iv, int enc); [SuppressUnmanagedCodeSecurity] [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern int EVP_CipherUpdate(IntPtr ctx, byte[] outb, out int outl, byte[] inb, int inl); [SuppressUnmanagedCodeSecurity] [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern int EVP_CIPHER_CTX_set_padding(IntPtr x, int padding); [SuppressUnmanagedCodeSecurity] [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern int EVP_CIPHER_CTX_set_key_length(IntPtr x, int keylen); } } ================================================ FILE: shadowsocks-csharp/Encryption/Sodium.cs ================================================ using Shadowsocks.Controller; using Shadowsocks.Properties; using Shadowsocks.Util; using System; using System.IO; using System.Runtime.InteropServices; namespace Shadowsocks.Encryption { public static class Sodium { private const string DLLNAME = @"libsscrypto.dll"; private static readonly bool _initialized; private static readonly object _initLock = new(); static Sodium() { var dllPath = Utils.GetTempPath(DLLNAME); try { FileManager.DecompressFile(dllPath, Environment.Is64BitProcess ? Resources.libsscrypto64_dll : Resources.libsscrypto_dll); LoadLibrary(dllPath); } catch (IOException) { } catch (System.Exception e) { Logging.LogUsefulException(e); } lock (_initLock) { if (!_initialized) { if (sodium_init() == -1) { throw new System.Exception(@"Failed to initialize sodium"); } _initialized = true; } } } [DllImport(@"Kernel32.dll")] private static extern IntPtr LoadLibrary(string path); [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] private static extern int sodium_init(); #region Stream [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern int crypto_stream_salsa20_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k); [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern int crypto_stream_xsalsa20_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k); [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern int crypto_stream_chacha20_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k); [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern int crypto_stream_xchacha20_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k); [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)] public static extern int crypto_stream_chacha20_ietf_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, uint ic, byte[] k); #endregion } } ================================================ FILE: shadowsocks-csharp/Encryption/Stream/NoneEncryptor.cs ================================================ using System; using System.Collections.Generic; namespace Shadowsocks.Encryption.Stream { public sealed class NoneEncryptor : StreamEncryptor { public NoneEncryptor(string method, string password) : base(method, password) { } private static Dictionary _ciphers = new() { { @"none", new EncryptorInfo(16, 0, 1) } }; public static List SupportedCiphers() { return new(_ciphers.Keys); } protected override Dictionary getCiphers() { return _ciphers; } protected override void CipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf) { if (_disposed) { throw new ObjectDisposedException(ToString()); } Array.Copy(buf, outbuf, length); } #region IDisposable private bool _disposed; public override void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~NoneEncryptor() { Dispose(false); } private void Dispose(bool disposing) { lock (this) { if (_disposed) { return; } _disposed = true; if (disposing) { // free managed objects } // free unmanaged objects } } #endregion } } ================================================ FILE: shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs ================================================ using Shadowsocks.Crypto; using Shadowsocks.Encryption.CircularBuffer; using Shadowsocks.Proxy; using Shadowsocks.Util; using System; using System.Collections.Generic; namespace Shadowsocks.Encryption.Stream { public abstract class StreamEncryptor : EncryptorBase { // every connection should create its own buffer private readonly ByteCircularBuffer _encCircularBuffer = new(ProxyAuthHandler.BufferSize * 2); private readonly ByteCircularBuffer _decCircularBuffer = new(ProxyAuthHandler.BufferSize * 2); protected Dictionary ciphers; protected byte[] _encryptIV; protected byte[] _decryptIV; // Is first packet protected bool _decryptIVReceived; protected bool _encryptIVSent; protected string _method; protected int _cipher; // internal name in the crypto library protected string _innerLibName; protected EncryptorInfo CipherInfo; // long-time master key protected byte[] _key; protected int keyLen; protected byte[] _iv; protected int ivLen; protected StreamEncryptor(string method, string password) : base(method, password) { InitEncryptorInfo(method); InitKey(password); } protected abstract Dictionary getCiphers(); public bool SetIV(byte[] iv) { if (iv != null && iv.Length == ivLen) { iv.CopyTo(_iv, 0); _encryptIVSent = true; InitCipher(iv, true); return true; } return false; } public override byte[] getIV() { return _iv; } public override byte[] getKey() { var key = (byte[])_key.Clone(); Array.Resize(ref key, keyLen); return key; } public override EncryptorInfo getInfo() { return CipherInfo; } private void InitEncryptorInfo(string method) { method = method.ToLower(); _method = method; ciphers = getCiphers(); CipherInfo = ciphers[_method]; _innerLibName = string.IsNullOrWhiteSpace(CipherInfo.InnerLibName) ? method : CipherInfo.InnerLibName; _cipher = CipherInfo.Type; if (_cipher == 0) { throw new System.Exception("method not found"); } keyLen = CipherInfo.KeySize; ivLen = CipherInfo.IvSize; } private void InitKey(string password) { _key = new byte[keyLen]; _key.AsSpan(0, keyLen).SsDeriveKey(password); Array.Resize(ref _iv, ivLen); Rng.RandBytes(_iv, ivLen); } protected virtual void InitCipher(byte[] iv, bool isCipher) { if (isCipher) { _encryptIV = new byte[ivLen]; Array.Copy(iv, _encryptIV, ivLen); } else { _decryptIV = new byte[ivLen]; Array.Copy(iv, _decryptIV, ivLen); } } protected abstract void CipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf); public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength) { //none rc4 if (length == 0) { outlength = 0; return; } var cipherOffset = 0; _encCircularBuffer.Put(buf, 0, length); if (!_encryptIVSent) { InitCipher(_iv, true); Array.Copy(_iv, 0, outbuf, 0, ivLen); cipherOffset = ivLen; _encryptIVSent = true; } var size = _encCircularBuffer.Size; var plain = _encCircularBuffer.Get(size); var cipher = new byte[size]; CipherUpdate(true, size, plain, cipher); Buffer.BlockCopy(cipher, 0, outbuf, cipherOffset, size); outlength = size + cipherOffset; } public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength) { _decCircularBuffer.Put(buf, 0, length); if (!_decryptIVReceived) { if (_decCircularBuffer.Size <= ivLen) { // we need more data outlength = 0; return; } // start decryption _decryptIVReceived = true; var iv = ivLen == 0 ? new byte[0] : _decCircularBuffer.Get(ivLen); //none rc4 InitCipher(iv, false); } var cipher = _decCircularBuffer.ToArray(); CipherUpdate(false, cipher.Length, cipher, outbuf); // move pointer only _decCircularBuffer.Skip(_decCircularBuffer.Size); outlength = cipher.Length; // done the decryption } public override void ResetEncrypt() { _encryptIVSent = false; Rng.RandBytes(_iv, ivLen); } public override void ResetDecrypt() { _decryptIVReceived = false; } } } ================================================ FILE: shadowsocks-csharp/Encryption/Stream/StreamOpenSSLEncryptor.cs ================================================ using Shadowsocks.Encryption.Exception; using System; using System.Collections.Generic; using System.Diagnostics; namespace Shadowsocks.Encryption.Stream { public sealed class StreamOpenSSLEncryptor : StreamEncryptor { const int CIPHER_AES = 1; const int CIPHER_RC4 = 2; const int CIPHER_CAMELLIA = 3; const int CIPHER_OTHER_CFB = 4; private IntPtr _encryptCtx = IntPtr.Zero; private IntPtr _decryptCtx = IntPtr.Zero; public StreamOpenSSLEncryptor(string method, string password) : base(method, password) { } private static readonly Dictionary _ciphers = new() { { @"aes-128-ctr", new EncryptorInfo(16, 16, CIPHER_AES) }, { @"aes-192-ctr", new EncryptorInfo(24, 16, CIPHER_AES) }, { @"aes-256-ctr", new EncryptorInfo(32, 16, CIPHER_AES) }, { @"aes-128-cfb", new EncryptorInfo(16, 16, CIPHER_AES) }, { @"aes-192-cfb", new EncryptorInfo(24, 16, CIPHER_AES) }, { @"aes-256-cfb", new EncryptorInfo(32, 16, CIPHER_AES) }, { @"aes-128-cfb8", new EncryptorInfo(16, 16, CIPHER_AES) }, { @"aes-192-cfb8", new EncryptorInfo(24, 16, CIPHER_AES) }, { @"aes-256-cfb8", new EncryptorInfo(32, 16, CIPHER_AES) }, { @"aes-128-cfb1", new EncryptorInfo(16, 16, CIPHER_AES, @"", false) }, { @"aes-192-cfb1", new EncryptorInfo(24, 16, CIPHER_AES, @"", false) }, { @"aes-256-cfb1", new EncryptorInfo(32, 16, CIPHER_AES, @"", false) }, { @"camellia-128-cfb", new EncryptorInfo(16, 16, CIPHER_CAMELLIA, @"", false) }, { @"camellia-192-cfb", new EncryptorInfo(24, 16, CIPHER_CAMELLIA, @"", false) }, { @"camellia-256-cfb", new EncryptorInfo(32, 16, CIPHER_CAMELLIA, @"", false) }, { @"bf-cfb", new EncryptorInfo(16, 8, CIPHER_OTHER_CFB, @"", false) }, { @"cast5-cfb", new EncryptorInfo(16, 8, CIPHER_OTHER_CFB, @"", false) }, { @"idea-cfb", new EncryptorInfo(16, 8, CIPHER_OTHER_CFB, @"", false) }, { @"rc2-cfb", new EncryptorInfo(16, 8, CIPHER_OTHER_CFB, @"", false) }, { @"rc4", new EncryptorInfo(16, 0, CIPHER_RC4) }, // weak { @"rc4-md5", new EncryptorInfo(16, 16, CIPHER_RC4, @"RC4") }, // weak { @"rc4-md5-6", new EncryptorInfo(16, 6, CIPHER_RC4, @"RC4") }, // weak { @"seed-cfb", new EncryptorInfo(16, 16, CIPHER_OTHER_CFB, @"", false) } }; public static List SupportedCiphers() { return new(_ciphers.Keys); } protected override Dictionary getCiphers() { return _ciphers; } protected override void InitCipher(byte[] iv, bool isEncrypt) { base.InitCipher(iv, isEncrypt); var cipherInfo = OpenSSL.GetCipherInfo(_innerLibName); if (cipherInfo == IntPtr.Zero) { throw new System.Exception("openssl: cipher not found"); } var ctx = OpenSSL.EVP_CIPHER_CTX_new(); if (ctx == IntPtr.Zero) { throw new System.Exception("fail to create ctx"); } if (isEncrypt) { _encryptCtx = ctx; } else { _decryptCtx = ctx; } byte[] realKey; if (_method.StartsWith(@"rc4-")) { var temp = new byte[keyLen + ivLen]; Array.Copy(_key, 0, temp, 0, keyLen); Array.Copy(iv, 0, temp, keyLen, ivLen); realKey = CryptoUtils.MD5(temp); } else { realKey = _key; } var ret = OpenSSL.EVP_CipherInit_ex(ctx, cipherInfo, IntPtr.Zero, null, null, isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT); if (ret != 1) { throw new System.Exception("openssl: fail to set key length"); } ret = OpenSSL.EVP_CIPHER_CTX_set_key_length(ctx, keyLen); if (ret != 1) { throw new System.Exception("openssl: fail to set key length"); } ret = OpenSSL.EVP_CipherInit_ex(ctx, IntPtr.Zero, IntPtr.Zero, realKey, _method.StartsWith(@"rc4-") ? null : iv, isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT); if (ret != 1) { throw new System.Exception("openssl: cannot set key and iv"); } OpenSSL.EVP_CIPHER_CTX_set_padding(ctx, 0); } protected override void CipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf) { if (_disposed) { throw new ObjectDisposedException(ToString()); } var ret = OpenSSL.EVP_CipherUpdate(isCipher ? _encryptCtx : _decryptCtx, outbuf, out var outlen, buf, length); if (ret != 1) { throw new CryptoErrorException($@"ret is {ret}"); } Debug.Assert(outlen == length); } #region IDisposable private bool _disposed; // instance based lock private readonly object _lock = new(); public override void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~StreamOpenSSLEncryptor() { Dispose(false); } private void Dispose(bool disposing) { lock (_lock) { if (_disposed) { return; } _disposed = true; } if (disposing) { // free managed objects } // free unmanaged objects if (_encryptCtx != IntPtr.Zero) { OpenSSL.EVP_CIPHER_CTX_free(_encryptCtx); _encryptCtx = IntPtr.Zero; } if (_decryptCtx != IntPtr.Zero) { OpenSSL.EVP_CIPHER_CTX_free(_decryptCtx); _decryptCtx = IntPtr.Zero; } } #endregion } } ================================================ FILE: shadowsocks-csharp/Encryption/Stream/StreamSodiumEncryptor.cs ================================================ using Shadowsocks.Encryption.Exception; using System; using System.Collections.Generic; namespace Shadowsocks.Encryption.Stream { public class StreamSodiumEncryptor : StreamEncryptor { private const int CIPHER_SALSA20 = 1; private const int CIPHER_CHACHA20 = 2; private const int CIPHER_CHACHA20_IETF = 3; private const int CIPHER_XSALSA20 = 4 + 1; private const int CIPHER_XCHACHA20 = 4 + 2; private const int SODIUM_BLOCK_SIZE = 64; protected int _encryptBytesRemaining; protected int _decryptBytesRemaining; protected ulong _encryptIC; protected ulong _decryptIC; protected byte[] _encryptBuf; protected byte[] _decryptBuf; private delegate int CryptoStream(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k); private readonly CryptoStream _encryptorDelegate; public StreamSodiumEncryptor(string method, string password) : base(method, password) { _encryptBuf = new byte[MAX_INPUT_SIZE + SODIUM_BLOCK_SIZE]; _decryptBuf = new byte[MAX_INPUT_SIZE + SODIUM_BLOCK_SIZE]; _encryptorDelegate = _cipher switch { CIPHER_SALSA20 => Sodium.crypto_stream_salsa20_xor_ic, CIPHER_CHACHA20 => Sodium.crypto_stream_chacha20_xor_ic, CIPHER_XSALSA20 => Sodium.crypto_stream_xsalsa20_xor_ic, CIPHER_XCHACHA20 => Sodium.crypto_stream_xchacha20_xor_ic, CIPHER_CHACHA20_IETF => crypto_stream_chacha20_ietf_xor_ic, _ => _encryptorDelegate }; } private static Dictionary _ciphers = new() { { @"salsa20", new EncryptorInfo(32, 8, CIPHER_SALSA20) }, { @"chacha20", new EncryptorInfo(32, 8, CIPHER_CHACHA20) }, { @"xsalsa20", new EncryptorInfo(32, 24, CIPHER_XSALSA20) }, { @"xchacha20", new EncryptorInfo(32, 24, CIPHER_XCHACHA20) }, { @"chacha20-ietf", new EncryptorInfo(32, 12, CIPHER_CHACHA20_IETF) } }; protected override Dictionary getCiphers() { return _ciphers; } public static List SupportedCiphers() { return new(_ciphers.Keys); } protected override void CipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf) { int bytesRemaining; ulong ic; byte[] sodiumBuf; byte[] iv; if (isCipher) { bytesRemaining = _encryptBytesRemaining; ic = _encryptIC; sodiumBuf = _encryptBuf; iv = _encryptIV; } else { bytesRemaining = _decryptBytesRemaining; ic = _decryptIC; sodiumBuf = _decryptBuf; iv = _decryptIV; } var padding = bytesRemaining; Buffer.BlockCopy(buf, 0, sodiumBuf, padding, length); var ret = _encryptorDelegate(sodiumBuf, sodiumBuf, (ulong)(padding + length), iv, ic, _key); if (ret != 0) { throw new CryptoErrorException(); } Buffer.BlockCopy(sodiumBuf, padding, outbuf, 0, length); padding += length; ic += (ulong)padding / SODIUM_BLOCK_SIZE; bytesRemaining = padding % SODIUM_BLOCK_SIZE; if (isCipher) { _encryptBytesRemaining = bytesRemaining; _encryptIC = ic; } else { _decryptBytesRemaining = bytesRemaining; _decryptIC = ic; } } public override void ResetEncrypt() { _encryptIVSent = false; _encryptIC = 0; _encryptBytesRemaining = 0; } public override void ResetDecrypt() { _decryptIVReceived = false; _decryptIC = 0; _decryptBytesRemaining = 0; } private int crypto_stream_chacha20_ietf_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic, byte[] k) { return Sodium.crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, n, (uint)ic, k); } public override void Dispose() { } } } ================================================ FILE: shadowsocks-csharp/Enums/BalanceType.cs ================================================ namespace Shadowsocks.Enums { public enum BalanceType { OneByOne, Random, FastDownloadSpeed, LowLatency, LowException, SelectedFirst, Timer, } } ================================================ FILE: shadowsocks-csharp/Enums/DnsType.cs ================================================ namespace Shadowsocks.Enums { public enum DnsType { Default, DnsOverTls } } ================================================ FILE: shadowsocks-csharp/Enums/HttpRequestProxyType.cs ================================================ namespace Shadowsocks.Enums { public enum HttpRequestProxyType { Auto, Direct, Proxy, SystemSetting } } ================================================ FILE: shadowsocks-csharp/Enums/LogLevel.cs ================================================ namespace Shadowsocks.Enums { public enum LogLevel { Debug = 0, Info, Warn, Error, Assert } } ================================================ FILE: shadowsocks-csharp/Enums/PacType.cs ================================================ namespace Shadowsocks.Enums { public enum PacType { GfwList, Online, } } ================================================ FILE: shadowsocks-csharp/Enums/PortMapType.cs ================================================ namespace Shadowsocks.Enums { public enum PortMapType { Forward = 0, ForceProxy, RuleProxy } } ================================================ FILE: shadowsocks-csharp/Enums/ProxyMode.cs ================================================ namespace Shadowsocks.Enums { public enum ProxyMode { NoModify, Direct, Pac, Global } } ================================================ FILE: shadowsocks-csharp/Enums/ProxyRuleMode.cs ================================================ namespace Shadowsocks.Enums { public enum ProxyRuleMode { Disable = 0, BypassLan, BypassLanAndChina, BypassLanAndNotChina, UserCustom = 16 } } ================================================ FILE: shadowsocks-csharp/Enums/ProxyType.cs ================================================ namespace Shadowsocks.Enums { public enum ProxyType { Socks5, Http, TcpPortTunnel } } ================================================ FILE: shadowsocks-csharp/Enums/ServerTreeViewType.cs ================================================ namespace Shadowsocks.Enums { public enum ServerTreeViewType { Subtag, Group, Server } } ================================================ FILE: shadowsocks-csharp/I18N/App.en-US.xaml ================================================ en-US Mode Disable PAC Global No modify Update PAC Lan IP list Chn Domain list Chn Domain and IP list Chn IP list GFWList Chn Only list Copy PAC URL Edit local PAC file... Edit user rule for GFWList... Proxy setting Proxy rule Bypass LAN Bypass LAN && China Bypass LAN && not China User custom Disable bypass Servers Edit servers... Scan QRCode from screen... Import links from clipboard... Import servers from file... Load balance Same host for same address Server statistic... Disconnect current Subscription Setting Update Show logs... Update available More Global settings... DNS settings... Port settings... Open wiki... Feedback... Gen custom QRCode... Update... Check update Auto check update Include prerelease version Quit No newer version was found {0} {1} Update Found Click menu to download New version {0} {1} available Check for update failure Unexpected error, ShadowsocksR will exit. Find Shadowsocks icon in your notify tray. If you want to start multiple Shadowsocks, make a copy in another directory. ShadowsocksR is already running New server Port {0} already in use Port {0} is reserved by system Port out of range ShadowsocksR Error: {0} : OneByOne Random FastDownloadSpeed LowLatency LowException SelectedFirst Timer Balance in group AutoBan Running: Port {0} Failed to update PAC file GFWList PAC updated PAC updated No updates found. Please report to GFWList if you have problems with it. No updates found. Success Error Update subscribe {0} success Update subscribe {0} failure No QRCode found. Try to zoom in or move it to the center of the screen. [Empty subscription remarks] [Empty group name] Import servers failed Default configuration detected Tap ‘Yes’ to open config window or ‘No’ to open subscription window Socks5(support UDP) Http tunnel TCP Port tunnel ================================================ FILE: shadowsocks-csharp/I18N/App.zh-CN.xaml ================================================ zh-CN 系统代理 直连 PAC 全局 不修改 更新 PAC 绕过局域网 IP 绕过大陆域名 绕过大陆域名和 IP 绕过大陆 IP GFWList 仅大陆常见域名(回国) 复制 PAC URL 编辑本地 PAC 文件 编辑 GFWList 的用户规则 规则设置 代理规则 绕过局域网 绕过局域网和大陆 绕过局域网和非大陆 用户自定义 全局 服务器 编辑服务器 扫描二维码 从链接导入 从文件导入 负载均衡 同址优先 连接统计 强制断开连接 订阅 设置 更新 日志 更新可用 更多 选项设置 DNS 设置 端口设置 帮助文档 问题反馈 二维码生成器 更新 检查更新 自动检查更新 包括测试版更新 退出 没有找到新版本 {0} {1} 更新 点击菜单项下载 【点击下载新版本 {0} {1}】 检查更新失败 Unexpected error, ShadowsocksR will exit. 请在任务栏里寻找 ShadowsocksR 图标 如果想启动多份,可以另外复制一份到别的目录 ShadowsocksR 已经在运行 未配置的服务器 端口 {0} 已被占用 端口 {0} 是系统保留端口 端口超出范围 ShadowsocksR Error: {0} 按次序 随机 下载速度优先 低延迟优先 低错误优先 选中优先 定时切换 所选组切换 自动禁用出错服务器 正在运行:端口 {0} 更新 PAC 文件失败 更新 GFWList PAC 成功 更新 PAC 成功 未发现更新。如有问题请提交给 GFWList 未发现更新 成功 错误 服务器订阅 {0} 更新成功 服务器订阅 {0} 更新失败 未发现二维码,尝试把它放大或移动到靠近屏幕中间的位置 【不属于任何订阅】 【空群组名】 导入服务器失败 检测到是默认服务器 “是”打开服务器设置,“否”打开订阅设置 Socks5(支持UDP) HTTP 隧道 TCP 端口转发 ================================================ FILE: shadowsocks-csharp/I18N/App.zh-TW.xaml ================================================ zh-TW 代理模式 直連 PAC 全域 不修改 更新 PAC 繞過區域網路IP 繞過大陸域名 繞過大陸域名和IP 繞過大陸IP GFWList 僅大陸常見域名(國外訪問大陸) 複製 PAC URL 編輯本地 PAC 檔... 編輯 GFWList 的使用者規則... 代理設定 代理規則 繞過區域網路 繞過區域網路和大陸 繞過區域網路和非大陸 使用者自訂 全域 伺服器 編輯伺服器... QR 碼掃描... 剪貼板批量匯入連結... 自檔案匯入伺服器... 伺服器負載均衡 優先相同節點連接同一位址 伺服器連接統計... 斷開當前所有連接 訂閱 設定 更新 顯示日誌... 可用更新 更多 選項設定... DNS 設定... 通訊埠設定... 打開Wiki文件... 問題回饋... 自訂產生 QR 碼 更新... 檢查更新 自動檢查更新 包括測試版更新 退出 沒有找到新版本 {0} {1} 更新 點選選單項下載 【點選下載新版本 {0} {1}】 檢查更新失敗 Unexpected error, ShadowsocksR will exit. 請在工作列裡尋找 ShadowsocksR 圖示。 如果想啟動多份,可以另外複製一份到別的目錄。 ShadowsocksR 已經在執行 未配置的伺服器 通訊埠 {0} 已被使用 通訊埠 {0} 由系統保留 通訊埠超出範圍 ShadowsocksR Error: {0} 按次序 隨機 下載速度優先 低延遲優先 低錯誤優先 選中優先 定時切換 所選組切換 自動禁用出錯伺服器 正在執行:通訊埠 {0} 更新 PAC 檔失敗 更新 GFWList PAC 成功 更新 PAC 成功 未發現更新。如有問題請提交給 GFWList 未發現更新 成功 錯誤 伺服器訂閱 {0} 更新成功 伺服器訂閱 {0} 更新失敗 未發現 QR 碼,嘗試把它放大或移動到靠近螢幕中間的位置 【不屬於任何訂閱】 【空群組名】 匯入伺服器失敗 檢測到是默認伺服器 「是」開啟伺服器設定,「否」開啟訂閱設定 Socks5(支援UDP) Http隧道 TCP通訊埠轉發 ================================================ FILE: shadowsocks-csharp/I18N/ConfigWindow.en-US.xaml ================================================  en-US Add Delete Expand Collapse Edit Servers Any Local Version Server Server IP Server Port Password Encryption Protocol Protocol param Obfs Obfs param Remarks Group SSR Link Adv. Setting NOT all server support belows UDP Port UDP over TCP UDP over TCP if not checked OK Cancel Apply Please add at least one server Please select a group or server ================================================ FILE: shadowsocks-csharp/I18N/ConfigWindow.zh-CN.xaml ================================================  zh-CN 添加 删除 展开 折叠 编辑服务器 任意地址 本机地址 版本 服务器 服务器 IP 服务器端口 密码 加密 协议 协议参数 混淆 混淆参数 备注 群组名 SSR 链接 高级选项 以下选项不是所有服务端都支持 UDP 端口 UDP over TCP 不打钩使用原生 UDP 确定 取消 应用 请添加至少一个服务器 请先选择一个群组或服务器 ================================================ FILE: shadowsocks-csharp/I18N/ConfigWindow.zh-TW.xaml ================================================  zh-TW 新增 刪除 展開 折疊 編輯伺服器 任意位址 本機位址 版本 伺服器 伺服器 IP 伺服器通訊埠 密碼 加密 協議 協議參數 混淆 混淆參數 備註 群組名 SSR連結 高級選項 以下選項不是所有伺服器都支援 UDP通訊埠 UDP over TCP 不打勾使用原生 UDP 確定 取消 套用 請添加至少一個伺服器 請選擇一個群組或伺服器 ================================================ FILE: shadowsocks-csharp/I18N/DnsSettingWindow.en-US.xaml ================================================  en-US DNS Setting   OK   Cancel Apply Add Delete Enable Default DNS over TLS IPv6 first TCP UDP Address Port Timeout EDNS IP Source netmask Scope netmask Test Domain ================================================ FILE: shadowsocks-csharp/I18N/DnsSettingWindow.zh-CN.xaml ================================================  zh-CN DNS 设置 确定 取消 应用 添加 删除 启用 默认 DNS over TLS IPv6 优先 TCP UDP 服务器 端口 超时 EDNS IP Source netmask Scope netmask 测试 域名 ================================================ FILE: shadowsocks-csharp/I18N/DnsSettingWindow.zh-TW.xaml ================================================  zh-TW DNS 設定 確定 取消 套用 新增 刪除 啟用 預設 DNS over TLS IPv6 優先 TCP UDP 伺服器 連接埠 連接逾時 EDNS IP Source netmask Scope netmask 測試 網域 ================================================ FILE: shadowsocks-csharp/I18N/LogWindow.en-US.xaml ================================================  en-US Log Viewer _File Clear _log Show in _Explorer _Close _View _Font _Wrap Text _Always on top ================================================ FILE: shadowsocks-csharp/I18N/LogWindow.zh-CN.xaml ================================================  zh-CN 日志查看器 文件(_F) 清空日志(_L) 在资源管理器中显示(_E) 关闭(_C) 视图(_V) 字体设置(_F) 自动换行(_W) 置于顶层(_A) ================================================ FILE: shadowsocks-csharp/I18N/LogWindow.zh-TW.xaml ================================================  zh-TW Log Viewer 檔案(_F) 清空日誌(_L) 在檔案總管中顯示(_E) 關閉(_C) 視圖(_V) 字型設定(_F) 自動換行(_W) 置於頂層(_A) ================================================ FILE: shadowsocks-csharp/I18N/PortSettingsWindow.en-US.xaml ================================================  en-US Port Settings Port Forward Force Proxy Proxy With Rule Map Setting Enable Type Server ID Local Port Target Addr Target Port Remarks Add Delete OK Cancel Apply ================================================ FILE: shadowsocks-csharp/I18N/PortSettingsWindow.zh-CN.xaml ================================================  zh-CN 端口设置 端口转发 强制代理 规则代理 映射设置 开关 类型 服务器 ID 本地端口 目标地址 目标端口 备注 添加 删除 确定 取消 应用 ================================================ FILE: shadowsocks-csharp/I18N/PortSettingsWindow.zh-TW.xaml ================================================  zh-TW 通訊埠設定 通訊埠轉發 強制代理 規則代理 映射設定 開關 類型 伺服器 ID 本地通訊埠 目標位址 目標通訊埠 備註 新增 刪除 確定 取消 套用 ================================================ FILE: shadowsocks-csharp/I18N/ServerLogWindow.en-US.xaml ================================================  en-US ServerLog Any Local Version _Control _Disconnect direct connections Disconnect _All Clear _MaxSpeed _Clear Clear _Selected Total Clear _Total Port _out Copy current link Copy current group links Copy all enable links Copy all links _Window Auto _size Always On _Top Id Group Server Connecting Latency Avg DSpeed Max DSpeed Avg UpSpeed Max UpSpeed Dload Upload DloadRaw Error Timeout Empty Response Continuous Error Percent ================================================ FILE: shadowsocks-csharp/I18N/ServerLogWindow.zh-CN.xaml ================================================  zh-CN 服务器记录 任意地址 本机地址 版本 操作(_C) 断开直连连接(_D) 断开当前所有连接(_A) 重置历史最高(_M) 清空(_C) 清空选中节点历史流量(_S) 清空所有历史流量(_T) 导出(_O) 复制选中链接 复制选中组链接 复制所有开启节点链接 复制所有节点链接 窗口(_W) 自动调整大小(_S) 窗口置顶(_T) 序号 群组名 服务器 连接 延迟 平均下载速度 最高下载速度 平均上传速度 最高上传速度 总下载 总上传 实下载 错误 超时 空连 连错 出错比例 ================================================ FILE: shadowsocks-csharp/I18N/ServerLogWindow.zh-TW.xaml ================================================  zh-TW 伺服器記錄 任意位址 本機位址 版本 操作(_C) 斷開直連連接(_D) 斷開當前所有連接(_A) 重置歷史最高(_M) 清空(_C) 清空選中節點歷史流量(_S) 清空所有歷史流量(_T) 匯出(_O) 複製選中連結 複製選中組連結 複製所有開啟節點連結 複製所有節點連結 視窗(_W) 自動調整大小(_S) 視窗置頂(_T) Id 群組名 伺服器 連接 延遲 平均下載速度 最高下載速度 平均上傳速度 最高上傳速度 總下載 總上傳 實下載 錯誤 超時 空連 連錯 出錯比例 ================================================ FILE: shadowsocks-csharp/I18N/SettingsWindow.en-US.xaml ================================================  en-US Global Settings Any Local Version   OK   Cancel Apply Failed to update registry Restart required Remote proxy Proxy On PAC "direct" return this proxy Server IP Server Port Username Password User Agent Local proxy Allow Clients from LAN Local Port Misc Balance Logging Language Start on Boot Switch auto close TCP links Load balance Balance in group AutoBan Enable Log Set Default Reconnect Times Connect Timeout TTL ================================================ FILE: shadowsocks-csharp/I18N/SettingsWindow.zh-CN.xaml ================================================  zh-CN 选项设置 任意地址 本机地址 版本 确定 取消 应用 无法修改注册表 需要重启 二级(前置)代理 开启代理 PAC “直连” 使用二级代理 服务器 IP 服务器端口 用户名 密码 用户代理 本地代理 允许来自局域网的连接 本地端口 杂项 负载均衡 日志记录 选择语言 开机启动 切换服务器前断开所有连接 服务器负载均衡 所选组切换 自动禁用出错服务器 开启日志 重置默认值 重连次数 连接超时 空闲断开秒数 ================================================ FILE: shadowsocks-csharp/I18N/SettingsWindow.zh-TW.xaml ================================================  zh-TW 選項設定 任意位址 本機位址 版本 確定 取消 套用 無法修改登錄檔 請重新啟動應用程式 二級(前置)代理 開啟代理 PAC「直接連接」使用二級代理 伺服器 IP 伺服器通訊埠 使用者名稱 密碼 使用者代理 本地代理 允許來自區域網路的連接 本地通訊埠 雜項 負載均衡 日誌記錄 語言 開機啟動 切換伺服器前斷開所有連結 伺服器負載均衡 所選組切換 自動禁用出錯伺服器 開啟日誌 重置預設值 重連次數 連接逾時 空閒斷開秒數 ================================================ FILE: shadowsocks-csharp/I18N/SubscribeWindow.en-US.xaml ================================================  en-US Subscribe Settings Confirm & update Cancel Apply Add Delete URL Subscription remark Last Update Auto update Update current subscription Subscription remarks cannot have the same Proxy type Auto Direct Proxy System Setting Some subscription servers that are not on the subscription list were found. Do you want to delete these servers? ================================================ FILE: shadowsocks-csharp/I18N/SubscribeWindow.zh-CN.xaml ================================================  zh-CN 订阅设置 确定并更新 取消 应用 添加 删除 订阅地址 订阅备注 最近更新 自动更新 更新当前订阅 订阅备注不能一样 更新订阅使用的代理类型 自动 直连 代理 系统设置 发现不在订阅列表的订阅服务器 是否删除? ================================================ FILE: shadowsocks-csharp/I18N/SubscribeWindow.zh-TW.xaml ================================================  zh-TW 訂閱設定 確定並更新 取消 套用 新增 刪除 網址 訂閱備註 最近更新 自動更新 更新當前訂閱 訂閱備註不能一樣 更新訂閱使用的代理類型 自動 直接連線 代理 系統設定 發現不在訂閱列表的訂閱服務器 是否刪除? ================================================ FILE: shadowsocks-csharp/Model/Configuration.cs ================================================ using Shadowsocks.Enums; using Shadowsocks.ViewModel; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text.Json.Serialization; namespace Shadowsocks.Model { [Serializable] public class Configuration : ViewModelBase { #region private private List _configs; private int _index; private bool _random; private ProxyMode _sysProxyMode; private bool _shareOverLan; private int _localPort; private int _reconnectTimes; private BalanceType _balanceType; private bool _randomInGroup; private int _ttl; private int _connectTimeout; private ProxyRuleMode _proxyRuleMode; private bool _proxyEnable; private bool _pacDirectGoProxy; private ProxyType _proxyType; private string _proxyHost; private int _proxyPort; private string _proxyAuthUser; private string _proxyAuthPass; private string _proxyUserAgent; private string _authUser; private string _authPass; private bool _autoBan; private bool _checkSwitchAutoCloseAll; private bool _logEnable; private bool _sameHostForSameTarget; private bool _isPreRelease; private bool _autoCheckUpdate; private string _langName; private List _dnsClients; private List _serverSubscribes; private Dictionary _portMap; #endregion #region Public /// /// 服务器列表 /// public List Configs { get => _configs; set => SetField(ref _configs, value); } /// /// 选中的服务器在列表的位置 /// public int Index { get => _index; set => SetField(ref _index, value); } /// /// 是否启用负载均衡 /// public bool Random { get => _random; set => SetField(ref _random, value); } /// /// 系统代理模式 /// public ProxyMode SysProxyMode { get => _sysProxyMode; set => SetField(ref _sysProxyMode, value); } /// /// 是否监听所有网卡 /// public bool ShareOverLan { get => _shareOverLan; set => SetField(ref _shareOverLan, value); } /// /// 监听端口 /// public int LocalPort { get => _localPort; set => SetField(ref _localPort, value); } /// /// 重连次数 /// public int ReconnectTimes { get => _reconnectTimes; set => SetField(ref _reconnectTimes, value); } /// /// 负载均衡使用的算法 /// public BalanceType BalanceType { get => _balanceType; set => SetField(ref _balanceType, value); } /// /// 负载均衡是否只在所选组切换 /// public bool RandomInGroup { get => _randomInGroup; set => SetField(ref _randomInGroup, value); } /// /// 空闲断开间隔(单位:秒) /// public int Ttl { get => _ttl; set => SetField(ref _ttl, value); } /// /// 连接超时(单位:秒) /// public int ConnectTimeout { get => _connectTimeout; set => SetField(ref _connectTimeout, value); } /// /// 代理规则模式 /// public ProxyRuleMode ProxyRuleMode { get => _proxyRuleMode; set => SetField(ref _proxyRuleMode, value); } /// /// 是否开启二级代理 /// public bool ProxyEnable { get => _proxyEnable; set => SetField(ref _proxyEnable, value); } /// /// PAC 的直连使用二级代理 /// public bool PacDirectGoProxy { get => _pacDirectGoProxy; set => SetField(ref _pacDirectGoProxy, value); } /// /// 二级代理类型 /// public ProxyType ProxyType { get => _proxyType; set => SetField(ref _proxyType, value); } /// /// 二级代理服务器地址 /// public string ProxyHost { get => _proxyHost; set => SetField(ref _proxyHost, value); } /// /// 二级代理服务器端口 /// public int ProxyPort { get => _proxyPort; set => SetField(ref _proxyPort, value); } /// /// 二级代理用户名 /// public string ProxyAuthUser { get => _proxyAuthUser; set => SetField(ref _proxyAuthUser, value); } /// /// 二级代理密码 /// public string ProxyAuthPass { get => _proxyAuthPass; set => SetField(ref _proxyAuthPass, value); } /// /// Http 请求所用的 UserAgent /// public string ProxyUserAgent { get => _proxyUserAgent; set => SetField(ref _proxyUserAgent, value); } /// /// 本地代理的用户名 /// public string AuthUser { get => _authUser; set => SetField(ref _authUser, value); } /// /// 本地代理的密码 /// public string AuthPass { get => _authPass; set => SetField(ref _authPass, value); } /// /// 自动禁用出错服务器 /// public bool AutoBan { get => _autoBan; set => SetField(ref _autoBan, value); } /// /// 切换服务器前断开所有连接 /// public bool CheckSwitchAutoCloseAll { get => _checkSwitchAutoCloseAll; set => SetField(ref _checkSwitchAutoCloseAll, value); } /// /// 是否开启日志 /// public bool LogEnable { get => _logEnable; set => SetField(ref _logEnable, value); } /// /// 负载均衡优先使用同一个服务器访问同一地址 /// public bool SameHostForSameTarget { get => _sameHostForSameTarget; set => SetField(ref _sameHostForSameTarget, value); } /// /// 检查更新是否包括测试版更新 /// public bool IsPreRelease { get => _isPreRelease; set => SetField(ref _isPreRelease, value); } /// /// 自动检查更新 /// public bool AutoCheckUpdate { get => _autoCheckUpdate; set => SetField(ref _autoCheckUpdate, value); } /// /// 所选的语言 /// public string LangName { get => _langName; set => SetField(ref _langName, value); } /// /// 自定义的 DNS /// public List DnsClients { get => _dnsClients; set => SetField(ref _dnsClients, value); } /// /// 订阅列表 /// public List ServerSubscribes { get => _serverSubscribes; set => SetField(ref _serverSubscribes, value); } /// /// 端口设置列表 /// public Dictionary PortMap { get => _portMap; set => SetField(ref _portMap, value); } #endregion #region NotConfig private const int KeepVisitTime = 1800; private readonly Dictionary _serverStrategyMap = new(); [JsonIgnore] public Dictionary PortMapCache { get; private set; } = new(); private readonly LRUCache _uriCache = new(180); #endregion public bool KeepCurrentServer(int port, string targetAddr, string id) { if (SameHostForSameTarget && targetAddr != null) { lock (_serverStrategyMap) { if (!_serverStrategyMap.ContainsKey(port)) { _serverStrategyMap[port] = new ServerSelectStrategy(); } if (_uriCache.ContainsKey(targetAddr)) { var visit = _uriCache.Get(targetAddr); var j = -1; for (var i = 0; i < Configs.Count; ++i) { if (Configs[i].Id == id) { j = i; break; } } if (j >= 0 && visit.index == j && Configs[j].Enable) { _uriCache.Del(targetAddr); return true; } } } } return false; } public Server GetCurrentServer(int port, ServerSelectStrategy.FilterFunc filter, string targetAddr = null, bool cfgRandom = false, bool usingRandom = false, bool forceRandom = false) { lock (_serverStrategyMap) { if (!_serverStrategyMap.ContainsKey(port)) { _serverStrategyMap[port] = new ServerSelectStrategy(); } var serverStrategy = _serverStrategyMap[port]; _uriCache.SetTimeout(KeepVisitTime); _uriCache.Sweep(); if (SameHostForSameTarget && !forceRandom && targetAddr != null && _uriCache.ContainsKey(targetAddr)) { var visit = _uriCache.Get(targetAddr); if (visit.index < Configs.Count && Configs[visit.index].Enable && Configs[visit.index].SpeedLog.ErrorContinuousTimes == 0) { _uriCache.Del(targetAddr); return Configs[visit.index]; } } if (forceRandom) { int i; if (filter == null && RandomInGroup) { i = serverStrategy.Select(Configs, Index, BalanceType, delegate (Server server, Server selServer) { if (selServer != null) { return selServer.Group == server.Group; } return false; }, true); } else { i = serverStrategy.Select(Configs, Index, BalanceType, filter, true); } return i == -1 ? GetErrorServer() : Configs[i]; } if (usingRandom && cfgRandom) { int i; if (filter == null && RandomInGroup) { i = serverStrategy.Select(Configs, Index, BalanceType, delegate (Server server, Server selServer) { if (selServer != null) { return selServer.Group == server.Group; } return false; }); } else { i = serverStrategy.Select(Configs, Index, BalanceType, filter); } if (i == -1) { return GetErrorServer(); } if (targetAddr != null) { var visit = new UriVisitTime { uri = targetAddr, index = i, visitTime = DateTime.Now }; _uriCache.Set(targetAddr, visit); } return Configs[i]; } if (Index >= 0 && Index < Configs.Count) { var selIndex = Index; if (usingRandom) { foreach (var unused in Configs) { if (Configs[selIndex].Enable) { break; } selIndex = (selIndex + 1) % Configs.Count; } } if (targetAddr != null) { var visit = new UriVisitTime { uri = targetAddr, index = selIndex, visitTime = DateTime.Now }; _uriCache.Set(targetAddr, visit); } return Configs[selIndex]; } return GetErrorServer(); } } public void FlushPortMapCache() { PortMapCache = new Dictionary(); var id2server = new Dictionary(); var server_group = new Dictionary(); foreach (var s in Configs) { id2server[s.Id] = s; if (!string.IsNullOrEmpty(s.Group)) { server_group[s.Group] = 1; } } foreach (var pair in PortMap) { int key; var pm = pair.Value; if (!pm.Enable) { continue; } if (id2server.ContainsKey(pm.Id) || server_group.ContainsKey(pm.Id) || pm.Id == null || pm.Id.Length == 0) { } else { continue; } try { key = int.Parse(pair.Key); } catch (FormatException) { continue; } PortMapCache[key] = new PortMapConfigCache { type = pm.Type, id = pm.Id, server = id2server.ContainsKey(pm.Id) ? id2server[pm.Id] : null, server_addr = pm.Server_addr, server_port = pm.Server_port }; } lock (_serverStrategyMap) { var remove_ports = new List(); foreach (var pair in _serverStrategyMap) { if (PortMapCache.ContainsKey(pair.Key)) { continue; } remove_ports.Add(pair.Key); } foreach (var port in remove_ports) { _serverStrategyMap.Remove(port); } if (!PortMapCache.ContainsKey(LocalPort)) { _serverStrategyMap.Remove(LocalPort); } } _uriCache.Clear(); } public Configuration() { Configs = new List(); Index = 0; Random = false; SysProxyMode = ProxyMode.NoModify; ShareOverLan = false; LocalPort = 1080; ReconnectTimes = 2; BalanceType = BalanceType.LowException; RandomInGroup = true; Ttl = 60; ConnectTimeout = 5; ProxyRuleMode = ProxyRuleMode.Disable; ProxyEnable = false; PacDirectGoProxy = false; ProxyType = ProxyType.Socks5; ProxyHost = string.Empty; ProxyPort = 1; ProxyAuthUser = string.Empty; ProxyAuthPass = string.Empty; ProxyUserAgent = string.Empty; AuthUser = string.Empty; AuthPass = string.Empty; AutoBan = false; CheckSwitchAutoCloseAll = true; LogEnable = true; SameHostForSameTarget = true; IsPreRelease = false; AutoCheckUpdate = true; LangName = string.Empty; DnsClients = new List { new(DnsType.DnsOverTls) { DnsServer = @"208.67.222.222" }, new(DnsType.DnsOverTls) { DnsServer = @"208.67.220.220" }, new(DnsType.DnsOverTls) { DnsServer = @"1.1.1.1" }, new(DnsType.DnsOverTls) { DnsServer = @"1.0.0.1" }, new(DnsType.DnsOverTls) { DnsServer = @"1.12.12.12" }, }; ServerSubscribes = new List(); PortMap = new Dictionary(); } public void CopyFrom(Configuration config) { Configs = config.Configs; Index = config.Index; Random = config.Random; SysProxyMode = config.SysProxyMode; ShareOverLan = config.ShareOverLan; LocalPort = config.LocalPort; ReconnectTimes = config.ReconnectTimes; BalanceType = config.BalanceType; RandomInGroup = config.RandomInGroup; Ttl = config.Ttl; ConnectTimeout = config.ConnectTimeout; ProxyRuleMode = config.ProxyRuleMode; ProxyEnable = config.ProxyEnable; PacDirectGoProxy = config.PacDirectGoProxy; ProxyType = config.ProxyType; ProxyHost = config.ProxyHost; ProxyPort = config.ProxyPort; ProxyAuthUser = config.ProxyAuthUser; ProxyAuthPass = config.ProxyAuthPass; ProxyUserAgent = config.ProxyUserAgent; AuthUser = config.AuthUser; AuthPass = config.AuthPass; AutoBan = config.AutoBan; CheckSwitchAutoCloseAll = config.CheckSwitchAutoCloseAll; LogEnable = config.LogEnable; SameHostForSameTarget = config.SameHostForSameTarget; IsPreRelease = config.IsPreRelease; AutoCheckUpdate = config.AutoCheckUpdate; LangName = config.LangName; DnsClients = config.DnsClients; ServerSubscribes = config.ServerSubscribes; //PortMap = config.PortMap; } public void FixConfiguration() { if (!IsPort(LocalPort)) { LocalPort = 1080; } if (PortMap == null) { PortMap = new Dictionary(); } if (ConnectTimeout == 0) { ConnectTimeout = 5; ReconnectTimes = 2; Ttl = 60; } if (Index < 0 || Index >= Configs.Count) { Index = 0; } if (Configs.Count == 0) { Configs.Add(new Server()); } var id = new HashSet(); foreach (var server in Configs) { while (id.Contains(server.Id)) { server.Id = Guid.NewGuid().ToString(@"N"); } id.Add(server.Id); } } public bool IsDefaultConfig() { return Configs.All(server => server.server == new Server().server); } private static Server GetErrorServer() { var server = new Server { server = @"invalid" }; return server; } private static bool IsPort(int port) { return port is > IPEndPoint.MinPort and <= IPEndPoint.MaxPort; } } } ================================================ FILE: shadowsocks-csharp/Model/ConfigurationException.cs ================================================ using System; namespace Shadowsocks.Model { [Serializable] internal class ConfigurationException : Exception { public ConfigurationException() { } public ConfigurationException(string message) : base(message) { } public ConfigurationException(string message, Exception inner) : base(message, inner) { } protected ConfigurationException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } } } ================================================ FILE: shadowsocks-csharp/Model/Connections.cs ================================================ using Shadowsocks.Proxy; using System.Collections.Generic; namespace Shadowsocks.Model { public class Connections { private readonly Dictionary sockets = new(); public bool AddRef(IHandler socket) { lock (this) { if (sockets.ContainsKey(socket)) { sockets[socket] += 1; } else { sockets[socket] = 1; } return true; } } public bool DecRef(IHandler socket) { lock (this) { if (sockets.ContainsKey(socket)) { sockets[socket] -= 1; if (sockets[socket] == 0) { sockets.Remove(socket); } } else { return false; } return true; } } public void CloseAll() { IHandler[] s; lock (this) { s = new IHandler[sockets.Count]; sockets.Keys.CopyTo(s, 0); } foreach (var handler in s) { try { handler.Shutdown(); } catch { // ignored } } } } } ================================================ FILE: shadowsocks-csharp/Model/DnsBuffer.cs ================================================ using System; using System.Net; namespace Shadowsocks.Model { public class DnsBuffer { public IPAddress Ip; public DateTime updateTime; public string Host; public bool force_expired; public bool IsExpired(string host) { if (Host != host) { return true; } if (force_expired && (DateTime.Now - updateTime).TotalMinutes > 1) { return true; } return (DateTime.Now - updateTime).TotalMinutes > 30; } public void UpdateDns(string host, IPAddress ip) { updateTime = DateTime.Now; Ip = new IPAddress(ip.GetAddressBytes()); Host = host; force_expired = false; } } } ================================================ FILE: shadowsocks-csharp/Model/DnsClient.cs ================================================ using ARSoft.Tools.Net; using ARSoft.Tools.Net.Dns; using Shadowsocks.Enums; using Shadowsocks.ViewModel; using System; using System.Linq; using System.Net; using System.Net.Sockets; using System.Security.Authentication; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; #nullable enable namespace Shadowsocks.Model; [Serializable] public class DnsClient : ViewModelBase { #region private private bool _enable; private DnsType _dnsType; private bool _ipv6First; private string _dnsServer; private ushort _port; private int _timeout; private bool _isEDnsEnabled; private string _ecsIp; private byte _ecsSourceNetmask; private byte _ecsScopeNetmask; private bool _isTcpEnabled; private bool _isUdpEnabled; #endregion #region public public bool Enable { get => _enable; set => SetField(ref _enable, value); } public DnsType DnsType { get => _dnsType; set => SetField(ref _dnsType, value); } public bool Ipv6First { get => _ipv6First; set => SetField(ref _ipv6First, value); } public string DnsServer { get => IsValidDns(_dnsServer) ? _dnsServer : DefaultDnsServer; set { if (IsValidDns(value)) { SetField(ref _dnsServer, value); _ip = null; } } } public ushort Port { get => _port; set => SetField(ref _port, value); } public int Timeout { get => _timeout; set => SetField(ref _timeout, value); } public bool IsEDnsEnabled { get => _isEDnsEnabled; set => SetField(ref _isEDnsEnabled, value); } public string EcsIp { get => IsIp(_ecsIp) ? _ecsIp : DefaultDnsServer; set { if (IsIp(value)) { SetField(ref _ecsIp, value); } } } public byte EcsSourceNetmask { get => _ecsSourceNetmask; set => SetField(ref _ecsSourceNetmask, value); } public byte EcsScopeNetmask { get => _ecsScopeNetmask; set => SetField(ref _ecsScopeNetmask, value); } public bool IsTcpEnabled { get => _isTcpEnabled; set => SetField(ref _isTcpEnabled, value); } public bool IsUdpEnabled { get => _isUdpEnabled; set => SetField(ref _isUdpEnabled, value); } #endregion #region Ignore private IPAddress? _ip; public const string DefaultDnsServer = @"208.67.222.222"; public const ushort DefaultPort = 53; public const string DefaultTlsDnsServer = @"208.67.222.222"; public const ushort DefaultTlsPort = 853; #endregion #region 构造函数 [JsonConstructor] public DnsClient() { _ip = null; _enable = true; _dnsType = DnsType.Default; _ipv6First = false; _dnsServer = DefaultDnsServer; _port = DefaultPort; _timeout = 10000; _isEDnsEnabled = false; _ecsIp = DefaultDnsServer; _ecsSourceNetmask = 32; _ecsScopeNetmask = 0; _isTcpEnabled = true; _isUdpEnabled = true; } public DnsClient(DnsType type) : this() { _dnsType = type; switch (type) { case DnsType.Default: { _dnsServer = DefaultDnsServer; _port = DefaultPort; break; } case DnsType.DnsOverTls: { _dnsServer = DefaultTlsDnsServer; _port = DefaultTlsPort; break; } } } #endregion #region Private Method private static bool IsIp(string? str) { return IPAddress.TryParse(str, out var ip) && ip.ToString() == str; } private bool IsValidDns(string? dns) { return DnsType == DnsType.DnsOverTls || IsIp(dns); } private static async Task QueryBaseAAsync(ARSoft.Tools.Net.Dns.DnsClient client, DomainName domain, DnsQueryOptions options, CancellationToken ct) { DnsMessage? message = null; try { message = await client.ResolveAsync(domain, RecordType.A, RecordClass.INet, options, ct); } catch { // ignored } return message?.AnswerRecords?.OfType().Select(answerRecord => answerRecord.Address).FirstOrDefault(); } private static async Task QueryBaseAaaaAsync(ARSoft.Tools.Net.Dns.DnsClient client, DomainName domain, DnsQueryOptions options, CancellationToken ct) { DnsMessage? message = null; try { message = await client.ResolveAsync(domain, RecordType.Aaaa, RecordClass.INet, options, ct); } catch { // ignored } return message?.AnswerRecords?.OfType().Select(answerRecord => answerRecord.Address).FirstOrDefault(); } private static async Task QueryBaseAsync(ARSoft.Tools.Net.Dns.DnsClient client, DomainName domain, DnsQueryOptions options, bool ipv6First, CancellationToken ct) { var res = await Task.WhenAll( QueryBaseAaaaAsync(client, domain, options, ct), QueryBaseAAsync(client, domain, options, ct)); if (ipv6First) { return res[0] ?? res[1]; } return res[1] ?? res[0]; } private static async Task QueryBaseTlsAAsync(DnsOverTlsClient client, DomainName domain, DnsQueryOptions options, CancellationToken ct) { DnsMessage? message = null; try { message = await client.ResolveAsync(domain, RecordType.A, RecordClass.INet, options, ct); } catch { // ignored } return message?.AnswerRecords?.OfType().Select(answerRecord => answerRecord.Address).FirstOrDefault(); } private static async Task QueryBaseTlsAaaaAsync(DnsOverTlsClient client, DomainName domain, DnsQueryOptions options, CancellationToken ct) { DnsMessage? message = null; try { message = await client.ResolveAsync(domain, RecordType.Aaaa, RecordClass.INet, options, ct); } catch { // ignored } return message?.AnswerRecords?.OfType().Select(answerRecord => answerRecord.Address).FirstOrDefault(); } private static async Task QueryBaseTlsAsync(DnsOverTlsClient client, DomainName domain, DnsQueryOptions options, bool ipv6First, CancellationToken ct) { if (ipv6First) { var res = await Task.WhenAll(QueryBaseTlsAaaaAsync(client, domain, options, ct), QueryBaseTlsAAsync(client, domain, options, ct)); return res[0] ?? res[1]; } else { var res = await Task.WhenAll(QueryBaseTlsAAsync(client, domain, options, ct)); return res[0]; } } #endregion public static async Task QueryIpAddressDefaultAsync(string host, bool ipv6First, CancellationToken ct) { IPAddress[] ips = await Dns.GetHostAddressesAsync(host, ct); if (ipv6First) { foreach (var ip in ips) { if (ip.AddressFamily is AddressFamily.InterNetworkV6) { return ip; } } } return ips.FirstOrDefault(); } public async Task QueryIpAddressAsync(string host, CancellationToken ct) { var domain = DomainName.Parse(host); var options = new DnsQueryOptions { IsEDnsEnabled = IsEDnsEnabled, IsRecursionDesired = true, }; if (options.IsEDnsEnabled) { options.EDnsOptions = new OptRecord { Options = { new ClientSubnetOption(EcsSourceNetmask, EcsScopeNetmask, IPAddress.Parse(EcsIp)) } }; } switch (DnsType) { case DnsType.Default: { var dnsClient = new ARSoft.Tools.Net.Dns.DnsClient(IPAddress.Parse(DnsServer), Timeout, Port) { IsTcpEnabled = IsTcpEnabled, IsUdpEnabled = IsUdpEnabled }; return await QueryBaseAsync(dnsClient, domain, options, Ipv6First, ct); } case DnsType.DnsOverTls: { _ip ??= await QueryIpAddressDefaultAsync(DnsServer, Ipv6First, ct); if (_ip is null) { return null; } var tlsServer = new TlsUpstreamServer { IPAddress = _ip, AuthName = DnsServer, SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12 }; var dnsClient = new DnsOverTlsClient(tlsServer, Timeout, Port); var res = await QueryBaseTlsAsync(dnsClient, domain, options, Ipv6First, ct); if (res is null) { _ip = null; } return res; } default: return null; } } } ================================================ FILE: shadowsocks-csharp/Model/ErrorLog.cs ================================================ using System; namespace Shadowsocks.Model { public class ErrorLog { public int errno; public DateTime time; public ErrorLog(int no) { errno = no; time = DateTime.Now; } } } ================================================ FILE: shadowsocks-csharp/Model/Global.cs ================================================ using Shadowsocks.Controller; using Shadowsocks.Controller.HttpRequest; using Shadowsocks.Controller.Service; using Shadowsocks.Util; using System; using System.IO; using System.Net; using System.Net.Sockets; using System.Text.Json; namespace Shadowsocks.Model { public static class Global { private const string ConfigFile = @"gui-config.json"; public static bool OSSupportsLocalIPv6 => Socket.OSSupportsIPv6; public static string LocalHost => OSSupportsLocalIPv6 ? $@"[{IPAddress.IPv6Loopback}]" : $@"{IPAddress.Loopback}"; public static string AnyHost => OSSupportsLocalIPv6 ? $@"[{IPAddress.IPv6Any}]" : $@"{IPAddress.Any}"; public static IPAddress IpLocal => OSSupportsLocalIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback; public static IPAddress IpAny => OSSupportsLocalIPv6 ? IPAddress.IPv6Any : IPAddress.Any; public static Configuration GuiConfig; public static MainController Controller; public static MenuViewController ViewController; public static UpdateNode UpdateNodeChecker; public static UpdateSubscribeManager UpdateSubscribeManager; public static Configuration LoadFile(string filename) { Configuration config; try { if (File.Exists(filename)) { var configContent = File.ReadAllText(filename); config = Load(configContent); if (config != null) { return config; } } } catch (Exception e) { Console.WriteLine(e); } config = new Configuration(); config.FixConfiguration(); return config; } public static Configuration Load() { return LoadFile(ConfigFile); } private static Configuration Load(string configStr) { try { var config = JsonSerializer.Deserialize(configStr); if (config is not null) { config.FixConfiguration(); return config; } } catch { // ignored } return null; } public static void LoadConfig() { GuiConfig = Load(); } public static void SaveConfig() { if (GuiConfig.Index >= GuiConfig.Configs.Count) { GuiConfig.Index = GuiConfig.Configs.Count - 1; } else if (GuiConfig.Index < 0) { GuiConfig.Index = 0; } try { var jsonString = JsonUtils.Serialize(GuiConfig, true); File.WriteAllText(ConfigFile, jsonString); } catch (IOException e) { Console.Error.WriteLine(e); } } } } ================================================ FILE: shadowsocks-csharp/Model/HostNode.cs ================================================ using System.Collections.Generic; namespace Shadowsocks.Model { internal class HostNode { public readonly bool IncludeSub; public readonly string Addr; public Dictionary SubNode; public HostNode() { IncludeSub = false; Addr = string.Empty; SubNode = new Dictionary(); } public HostNode(bool sub, string addr) { IncludeSub = sub; Addr = addr; SubNode = null; } } } ================================================ FILE: shadowsocks-csharp/Model/IPRangeSet.cs ================================================ using RouteMatcher.Abstractions; using RouteMatcher.IPMatchers; using Shadowsocks.Enums; using Shadowsocks.Properties; using Shadowsocks.Util; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net; using System.Text; #nullable enable namespace Shadowsocks.Model { public class IPRangeSet { public const string ChnFilename = @"chn_ip.txt"; private static bool IsReverse => Global.GuiConfig.ProxyRuleMode == ProxyRuleMode.BypassLanAndNotChina; private IIPAddressMatcher _ipMatcher; public IPRangeSet() { Reset(); } [MemberNotNull(nameof(_ipMatcher))] private void Reset() { _ipMatcher = new IPMatcherTrie(); } public bool IsInIPRange(IPAddress ip) { if (!IsReverse) { return _ipMatcher.Match(ip) == Rule.Direct; } return _ipMatcher.Match(ip) == default; } private bool LoadChn(IEnumerable lines) { try { var hasRule = false; foreach (var line in lines) { if (line is null) { continue; } var strings = line.Split('/', 2, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); if (strings.Length != 2 || !IPAddress.TryParse(strings[0], out var ip) || !byte.TryParse(strings[1], out var mask)) { continue; } _ipMatcher.Update(ip, mask, Rule.Direct); hasRule = true; } return hasRule; } catch { return false; } } public void LoadChn() { var absFilePath = Path.Combine(Directory.GetCurrentDirectory(), ChnFilename); if (File.Exists(absFilePath)) { if (!LoadChn(File.ReadLines(absFilePath, Encoding.UTF8))) { Reset(); } } else { LoadChn(Resources.chn_ip.GetLines()); } } } } ================================================ FILE: shadowsocks-csharp/Model/IPSegment.cs ================================================ using System; using System.Collections; using System.Net; namespace Shadowsocks.Model { public class IPAddressCmp : IPAddress, IComparable { public IPAddressCmp(IPAddress ip) : base(ip.GetAddressBytes()) { } public IPAddressCmp(byte[] ip) : base(ip) { } public IPAddressCmp(string ip) : base(FromString(ip).GetAddressBytes()) { } public static IPAddress FromString(string ip) { TryParse(ip, out var addr); return addr; } public int CompareTo(object obj) { var b1 = GetAddressBytes(); var b2 = ((IPAddressCmp)obj).GetAddressBytes(); for (var i = 0; i < b1.Length; ++i) { if (b1[i] < b2[i]) { return -1; } if (b1[i] > b2[i]) { return 1; } } if (b1.Length < b2.Length) { return -1; } if (b1.Length > b2.Length) { return 1; } return 0; } public IPAddressCmp ToIPv6() { if (AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) { return this; } var b1 = GetAddressBytes(); var br = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0 }; b1.CopyTo(br, 12); return new IPAddressCmp(br); } public IPAddressCmp Inc() { var b = GetAddressBytes(); var i = b.Length - 1; for (; i >= 0; --i) { if (b[i] == 0xff) { b[i] = 0; } else { b[i]++; break; } } if (i < 0) { return new IPAddressCmp(GetAddressBytes()); } return new IPAddressCmp(b); } } public class IPSegment { protected SortedList list = new(); public IPSegment(object val = null) { list.Add(new IPAddressCmp(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }), val); } public bool insert(IPAddressCmp ipStart, IPAddressCmp ipEnd, object val) { var s = ipStart.ToIPv6(); var e = ipEnd.ToIPv6().Inc(); object ed_val = null; if (list.Contains(s)) { ed_val = list[s]; list[s] = val; } else { list[s] = val; var index = list.IndexOfKey(s) - 1; if (index >= 0) { ed_val = list.GetByIndex(index); } } { var index = list.IndexOfKey(s); while (index > 0) { if (val.Equals(list.GetByIndex(index - 1))) { list.RemoveAt(index); --index; } else { break; } } ++index; var keep = false; while (index < list.Count) { var cmp = ((IPAddressCmp)list.GetKey(index)).CompareTo(e); if (cmp >= 0) { if (cmp == 0) { keep = true; } break; } ed_val = list.GetByIndex(index); list.RemoveAt(index); } if (!keep) { list[e] = ed_val; index = list.IndexOfKey(e); while (index > 0) { if (ed_val != null && ed_val.Equals(list.GetByIndex(index - 1))) { list.RemoveAt(index); --index; } else { break; } } while (index + 1 < list.Count) { if (ed_val != null && ed_val.Equals(list.GetByIndex(index + 1))) { list.RemoveAt(index); } else { break; } } } } return true; } public object Get(IPAddressCmp ip) { var ip_addr = ip.ToIPv6(); int l = 0, r = list.Count - 1; while (l < r) { var m = (l + r + 1) / 2; if (list.GetKey(m) is IPAddressCmp v) { var cmp = v.CompareTo(ip_addr); if (cmp > 0) { r = m - 1; } else if (cmp < 0) { l = m; } else if (cmp == 0) { return list.GetByIndex(m); } } } return list.GetByIndex(l); } } } ================================================ FILE: shadowsocks-csharp/Model/LRUCache.cs ================================================ using Shadowsocks.Controller; using System; using System.Collections.Generic; namespace Shadowsocks.Model { public class LRUCache { protected Dictionary _store = new(); protected Dictionary _key_2_time = new(); protected Dictionary _time_2_key = new(); protected object _lock = new(); protected int _sweep_time; public LRUCache(int sweep_time = 60 * 60) { _sweep_time = sweep_time; } public void SetTimeout(int time) { _sweep_time = time; } public void Clear() { lock (_lock) { _store.Clear(); _key_2_time.Clear(); _time_2_key.Clear(); } } public bool isTimeout(K key) { lock (_lock) { if ((DateTime.Now - _key_2_time[key]).TotalSeconds > _sweep_time) { return true; } return false; } } public bool ContainsKey(K key) { lock (_lock) { return _store.ContainsKey(key); } } public V Get(K key) { lock (_lock) { if (_store.ContainsKey(key)) { var t = _key_2_time[key]; _key_2_time.Remove(key); _time_2_key.Remove(t); t = DateTime.Now; while (_time_2_key.ContainsKey(t)) { t = t.AddTicks(1); } _time_2_key[t] = key; _key_2_time[key] = t; return _store[key]; } return default; } } public V Set(K key, V val) { lock (_lock) { DateTime t; if (_store.ContainsKey(key)) { t = _key_2_time[key]; _key_2_time.Remove(key); _time_2_key.Remove(t); } t = DateTime.Now; while (_time_2_key.ContainsKey(t)) { t = t.AddTicks(1); } _time_2_key[t] = key; _key_2_time[key] = t; _store[key] = val; return val; } } public void Del(K key) { lock (_lock) { DateTime t; if (_store.ContainsKey(key)) { t = _key_2_time[key]; _key_2_time.Remove(key); _time_2_key.Remove(t); _store.Remove(key); } } } public void Sweep() { lock (_lock) { var now = DateTime.Now; var sweep = 0; for (var i = 0; i < 100; ++i) { var finish = false; foreach (var p in _time_2_key) { if ((now - p.Key).TotalSeconds < _sweep_time) { finish = true; break; } _key_2_time.Remove(p.Value); _time_2_key.Remove(p.Key); _store.Remove(p.Value); Logging.Debug("sweep [" + p.Key + "]: " + p.Value); sweep += 1; break; } if (finish) { break; } } if (sweep > 0) { Logging.Debug("sweep " + sweep + " items"); } } } } } ================================================ FILE: shadowsocks-csharp/Model/MinSearchTree.cs ================================================ using System; using System.Collections.Generic; namespace Shadowsocks.Model { public struct MinSearchTreeNode { public int range_min; public int range_max; public int count; public long min; } public class MinSearchTree { protected int _count; protected int _size; protected int _level; protected MinSearchTreeNode[] _tree; public MinSearchTree(int size) { _level = GetLevel(size); _size = size; _count = size + (1 << _level); _tree = new MinSearchTreeNode[2 << _level]; } public int Size => _size; protected int GetLevel(int size) { var ret = 0; for (var s = size; s > 1; s >>= 1) { ret++; } if (size != 1 << ret) { ++ret; } return ret; } protected void _Init(int index, int level, int range_min, int range_max) { _tree[index].range_min = range_min; _tree[index].range_max = range_max; _tree[index].min = 0; _tree[index].count = range_max - range_min; if (level >= 0) { var l = index * 2; var r = l + 1; _Init(l, level - 1, range_min, range_min + (1 << level)); _Init(r, level - 1, range_min + (1 << level), range_max); } } public void Init() { _Init(1, _level - 1, 0, _size); for (var i = _count; i < 2 << _level; ++i) { _tree[i].min = long.MaxValue; } var offset = 1 << _level; for (var i = _count >> 1; i < offset; ++i) { Maintain(i); } } public MinSearchTree Clone() { var tree = new MinSearchTree(_size); for (var i = 0; i < 2 << _level; ++i) { tree._tree[i] = _tree[i]; } return tree; } public void Update(int[] add_list) { var offset = 1 << _level; for (var i = 0; i < add_list.Length; ++i) { if (add_list[i] > 0) { _tree[offset + i].min += add_list[i]; add_list[i] = 0; Maintain((offset + i) >> 1); } } } public void Update(Dictionary add_map) { var offset = 1 << _level; foreach (var pair in add_map) { _tree[offset + pair.Key].min += pair.Value; Maintain((offset + pair.Key) >> 1); } add_map.Clear(); if (_tree[1].min > int.MaxValue) { for (var i = 1; i < _tree.Length; ++i) { _tree[i].min -= int.MaxValue; } } } protected void Maintain(int index) { for (; index > 0; index >>= 1) { var l = index * 2; var r = l + 1; var min = Math.Min(_tree[l].min, _tree[r].min); var count = 0; if (min == _tree[l].min) { count += _tree[l].count; } if (min == _tree[r].min) { count += _tree[r].count; } if (_tree[index].min == min && _tree[index].count == count) { return; } _tree[index].min = min; _tree[index].count = count; } } public void Update(int index, int add = 1) { index = (1 << _level) + index; _tree[index].min += add; Maintain(index >> 1); } public int FindMinCount(int index, int range_min, int range_max, out long min_val) { if (range_min == _tree[index].range_min && range_max == _tree[index].range_max) { min_val = _tree[index].min; return _tree[index].count; } var l = index * 2; var r = l + 1; var count = 0; var sub_min_val = long.MaxValue; if (_tree[l].range_max > range_min) { var cnt = FindMinCount(l, range_min, Math.Min(range_max, _tree[l].range_max), out var out_val); if (out_val < sub_min_val) { sub_min_val = out_val; count = cnt; } else if (out_val == sub_min_val) { count += cnt; } } if (_tree[r].range_min < range_max) { var cnt = FindMinCount(r, Math.Max(range_min, _tree[r].range_min), range_max, out var out_val); if (out_val < sub_min_val) { sub_min_val = out_val; count = cnt; } else if (out_val == sub_min_val) { count += cnt; } } min_val = sub_min_val; return count; } public int FindNthMin(int index, int range_min, int range_max, int nth, long val) { if (_tree[index].range_min + 1 == _tree[index].range_max) { return index - (1 << _level); } var l = index * 2; var r = l + 1; if (_tree[l].range_max > range_min) { if (_tree[r].range_min < range_max) { var cnt = FindMinCount(l, range_min, _tree[l].range_max, out var out_val); if (out_val != val) { cnt = 0; } if (cnt > nth) { return FindNthMin(l, range_min, _tree[l].range_max, nth, val); } return FindNthMin(r, _tree[r].range_min, range_max, nth - cnt, val); } return FindNthMin(l, Math.Max(range_min, _tree[l].range_min), range_max, nth, val); } return FindNthMin(r, range_min, Math.Min(range_max, _tree[r].range_max), nth, val); } public int FindMinCount2(int index, int range_min, int range_max, out long min_val) { var offset = 1 << _level; var min = long.MaxValue; var cnt = 0; for (var i = range_min; i < range_max; ++i) { if (_tree[offset + i].min < min) { min = _tree[offset + i].min; } } for (var i = range_min; i < range_max; ++i) { if (_tree[offset + i].min == min) { ++cnt; } } min_val = min; return cnt; } public int FindNthMin2(int range_min, int range_max, int nth) { var offset = 1 << _level; var min = long.MaxValue; var cnt = 0; for (var i = range_min; i < range_max; ++i) { if (_tree[offset + i].min < min) { min = _tree[offset + i].min; } } for (var i = range_min; i < range_max; ++i) { if (_tree[offset + i].min == min) { if (cnt == nth) { return i; } ++cnt; } } return -1; } public int RandomFindIndex(int range_min, int range_max, Random random) { var count = FindMinCount(1, range_min, range_max, out var out_val); var nth = random.Next(count); var index = FindNthMin(1, range_min, range_max, nth, out_val); return index; } public long GetMin(int range_min, int range_max) { FindMinCount(1, range_min, range_max, out var ret); return ret; } } } ================================================ FILE: shadowsocks-csharp/Model/PortMapConfig.cs ================================================ using Shadowsocks.Enums; using Shadowsocks.ViewModel; using System; namespace Shadowsocks.Model { [Serializable] public class PortMapConfig : ViewModelBase { #region private private bool _enable; private PortMapType _type; private string _id; private string _serverAddr; private int _serverPort; private string _remarks; #endregion #region public public bool Enable { get => _enable; set => SetField(ref _enable, value); } public PortMapType Type { get => _type; set => SetField(ref _type, value); } public string Id { get => _id; set => SetField(ref _id, value); } public string Server_addr { get => _serverAddr; set => SetField(ref _serverAddr, value); } public int Server_port { get => _serverPort; set => SetField(ref _serverPort, value); } public string Remarks { get => _remarks; set => SetField(ref _remarks, value); } #endregion } } ================================================ FILE: shadowsocks-csharp/Model/PortMapConfigCache.cs ================================================ using Shadowsocks.Enums; namespace Shadowsocks.Model { public class PortMapConfigCache { public PortMapType type; public string id; public Server server; public string server_addr; public int server_port; } } ================================================ FILE: shadowsocks-csharp/Model/Rule.cs ================================================ namespace Shadowsocks.Model { public enum Rule : byte { Unknown, Block, Direct, Proxy } } ================================================ FILE: shadowsocks-csharp/Model/Server.cs ================================================ using Shadowsocks.Model.Transfer; using Shadowsocks.Util; using Shadowsocks.ViewModel; using System; using System.Collections.Generic; using System.Text; using System.Text.Json.Serialization; using System.Text.RegularExpressions; namespace Shadowsocks.Model { [Serializable] public class Server : ViewModelBase, ICloneable { #region private private string _id; private string _server; private ushort _serverPort; private ushort _serverUdpPort; private string _password; private string _method; private string _protocol; private string _protocolParam; private string _obfs; private string _obfsParam; private string _remarksBase64; private string _group; private string _subTag; private bool _enable; private bool _udpOverTcp; #endregion #region Public public string Id { get => _id; set => SetField(ref _id, value); } public string server { get => _server; set { if (SetField(ref _server, value)) { OnPropertyChanged(nameof(FriendlyName)); } } } public ushort Server_Port { get => _serverPort; set { if (SetField(ref _serverPort, value)) { OnPropertyChanged(nameof(FriendlyName)); } } } public ushort Server_Udp_Port { get => _serverUdpPort; set { if (SetField(ref _serverUdpPort, value)) { OnPropertyChanged(nameof(FriendlyName)); } } } public string Password { get => _password; set => SetField(ref _password, value); } public string Method { get => string.IsNullOrWhiteSpace(_method) ? @"aes-256-cfb" : _method; set => SetField(ref _method, value); } public string Protocol { get => string.IsNullOrWhiteSpace(_protocol) ? @"origin" : _protocol; set => SetField(ref _protocol, value); } public string ProtocolParam { get => _protocolParam ?? string.Empty; set => SetField(ref _protocolParam, value); } public string obfs { get => string.IsNullOrWhiteSpace(_obfs) ? @"plain" : _obfs; set => SetField(ref _obfs, value); } public string ObfsParam { get => _obfsParam ?? string.Empty; set => SetField(ref _obfsParam, value); } public string Remarks_Base64 { get => _remarksBase64; set { if (SetField(ref _remarksBase64, value)) { OnPropertyChanged(nameof(Remarks)); OnPropertyChanged(nameof(FriendlyName)); } } } public string Group { get => _group; set { if (SetField(ref _group, value)) { OnPropertyChanged(nameof(GroupName)); } } } public string SubTag { get => _subTag; set => SetField(ref _subTag, value); } public bool Enable { get => _enable; set => SetField(ref _enable, value); } public bool UdpOverTcp { get => _udpOverTcp; set { if (SetField(ref _udpOverTcp, value)) { OnPropertyChanged(nameof(ShowAdvSetting)); } } } #endregion #region NotConfig private int _index; private bool _isSelected; private ServerSpeedLog _serverSpeedLog; [JsonIgnore] public int Index { get => _index; set => SetField(ref _index, value); } [JsonIgnore] public bool IsSelected { get => _isSelected; set => SetField(ref _isSelected, value); } [JsonIgnore] public string GroupName => string.IsNullOrEmpty(Group) ? I18NUtil.GetAppStringValue(@"EmptyGroup") : Group; [JsonIgnore] public string Remarks { get { if (Remarks_Base64.Length == 0) { return string.Empty; } try { return Base64.DecodeUrlSafeBase64(Remarks_Base64); } catch (FormatException) { var old = Remarks_Base64; Remarks = Remarks_Base64; return old; } } set { var newValue = Base64.EncodeUrlSafeBase64(value); if (newValue != Remarks_Base64) { Remarks_Base64 = newValue; } } } [JsonIgnore] public string FriendlyName { get { if (string.IsNullOrEmpty(server)) { return I18NUtil.GetAppStringValue(@"NewServer"); } if (string.IsNullOrEmpty(Remarks)) { if (server.IndexOf(':') >= 0) { return $@"[{server}]:{Server_Port}"; } return $@"{server}:{Server_Port}"; } return $@"{Remarks}"; } } [JsonIgnore] public string SsLink { get { var parts = $@"{Method}:{Password}@{server}:{Server_Port}"; var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(parts)).Replace(@"=", string.Empty); return $@"ss://{base64}"; } } [JsonIgnore] public string SsrLink { get { var mainPart = $@"{server}:{Server_Port}:{Protocol}:{Method}:{obfs}:{Base64.EncodeUrlSafeBase64(Password)}"; var paramStr = $@"obfsparam={Base64.EncodeUrlSafeBase64(ObfsParam)}"; if (!string.IsNullOrEmpty(ProtocolParam)) { paramStr += $@"&protoparam={Base64.EncodeUrlSafeBase64(ProtocolParam)}"; } if (!string.IsNullOrEmpty(Remarks)) { paramStr += $@"&remarks={Base64.EncodeUrlSafeBase64(Remarks)}"; } if (!string.IsNullOrEmpty(Group)) { paramStr += $@"&group={Base64.EncodeUrlSafeBase64(Group)}"; } if (UdpOverTcp) { paramStr += @"&uot=1"; } if (Server_Udp_Port > 0) { paramStr += $@"&udpport={Server_Udp_Port}"; } var base64 = Base64.EncodeUrlSafeBase64($@"{mainPart}/?{paramStr}"); return $@"ssr://{base64}"; } } [JsonIgnore] public bool ShowAdvSetting => UdpOverTcp || Server_Udp_Port != 0; [JsonIgnore] public object ProtocolData { get; set; } [JsonIgnore] public object ObfsData { get; set; } [JsonIgnore] public ServerSpeedLog SpeedLog { get => _serverSpeedLog; set => SetField(ref _serverSpeedLog, value); } [JsonIgnore] public Connections Connections { get; private set; } = new(); [JsonIgnore] public DnsBuffer DnsBuffer { get; private set; } = new(); [JsonIgnore] public static Server ForwardServer { get; } = new(); #endregion public void CopyServer(Server oldServer) { ProtocolData = oldServer.ProtocolData; ObfsData = oldServer.ObfsData; SpeedLog = oldServer.SpeedLog; DnsBuffer = oldServer.DnsBuffer; Connections = oldServer.Connections; Enable = oldServer.Enable; } public object Clone() { return new Server { server = server, Server_Port = Server_Port, Password = Password, Method = Method, Protocol = Protocol, obfs = obfs, ObfsParam = ObfsParam, Remarks_Base64 = Remarks_Base64, Group = Group, Enable = Enable, UdpOverTcp = UdpOverTcp, Id = Id, ProtocolData = ProtocolData, ObfsData = ObfsData }; } public static Server Clone(Server serverObject) { return new() { server = serverObject.server, Server_Port = serverObject.Server_Port, Server_Udp_Port = serverObject.Server_Udp_Port, Password = serverObject.Password, Method = serverObject.Method, Protocol = serverObject.Protocol, ProtocolParam = serverObject.ProtocolParam, obfs = serverObject.obfs, ObfsParam = serverObject.ObfsParam, Remarks = serverObject.Remarks, Group = serverObject.Group, UdpOverTcp = serverObject.UdpOverTcp }; } public Server() { server = @"server host"; Server_Port = 8388; Method = @"aes-256-cfb"; Protocol = @"origin"; ProtocolParam = @""; obfs = @"plain"; ObfsParam = @""; Password = @"0"; Remarks_Base64 = @""; Group = @"Default Group"; SubTag = @""; UdpOverTcp = false; Enable = true; Id = Guid.NewGuid().ToString(@"N"); SpeedLog = new ServerSpeedLog(); Index = 0; IsSelected = false; } public Server(string ssUrl, string forceGroup) : this() { if (ssUrl.StartsWith(@"ss://", StringComparison.OrdinalIgnoreCase)) { ServerFromSs(ssUrl, forceGroup); } else if (ssUrl.StartsWith(@"ssr://", StringComparison.OrdinalIgnoreCase)) { ServerFromSsr(ssUrl, forceGroup); } else { throw new FormatException(); } } private static Dictionary ParseParam(string paramStr) { var paramsDict = new Dictionary(); var obfsParams = paramStr.Split('&'); foreach (var p in obfsParams) { if (p.IndexOf('=') > 0) { var index = p.IndexOf('='); var key = p.Substring(0, index); var val = p.Substring(index + 1); paramsDict[key] = val; } } return paramsDict; } public void ServerFromSsr(string ssrUrl, string forceGroup) { // ssr://host:port:protocol:method:obfs:base64pass/?obfsparam=base64&remarks=base64&group=base64&udpport=0&uot=1 var ssr = Regex.Match(ssrUrl, "ssr://([A-Za-z0-9+/=_-]+)", RegexOptions.IgnoreCase); if (!ssr.Success) { throw new FormatException(); } var data = Base64.DecodeUrlSafeBase64(ssr.Groups[1].Value); var params_dict = new Dictionary(); var param_start_pos = data.IndexOf("?", StringComparison.Ordinal); if (param_start_pos > 0) { params_dict = ParseParam(data.Substring(param_start_pos + 1)); data = data.Substring(0, param_start_pos); } if (data.IndexOf("/", StringComparison.Ordinal) >= 0) { data = data.Substring(0, data.LastIndexOf("/", StringComparison.Ordinal)); } var UrlFinder = new Regex("^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)"); var match = UrlFinder.Match(data); if (match == null || !match.Success) { throw new FormatException(); } server = match.Groups[1].Value; Server_Port = ushort.Parse(match.Groups[2].Value); Protocol = match.Groups[3].Value.Length == 0 ? "origin" : match.Groups[3].Value; Protocol = Protocol.Replace("_compatible", ""); Method = match.Groups[4].Value; obfs = match.Groups[5].Value.Length == 0 ? "plain" : match.Groups[5].Value; obfs = obfs.Replace("_compatible", ""); Password = Base64.DecodeUrlSafeBase64(match.Groups[6].Value); if (params_dict.ContainsKey("protoparam")) { ProtocolParam = Base64.DecodeUrlSafeBase64(params_dict["protoparam"]); } if (params_dict.ContainsKey("obfsparam")) { ObfsParam = Base64.DecodeUrlSafeBase64(params_dict["obfsparam"]); } if (params_dict.ContainsKey("remarks")) { Remarks = Base64.DecodeUrlSafeBase64(params_dict["remarks"]); } Group = params_dict.ContainsKey("group") ? Base64.DecodeUrlSafeBase64(params_dict["group"]) : string.Empty; if (params_dict.ContainsKey("uot")) { UdpOverTcp = int.Parse(params_dict["uot"]) != 0; } if (params_dict.ContainsKey("udpport")) { Server_Udp_Port = ushort.Parse(params_dict["udpport"]); } if (!string.IsNullOrEmpty(forceGroup)) { SubTag = forceGroup; } } private void ServerFromSs(string ssUrl, string forceGroup) { Regex UrlFinder = new("^(?i)ss://([A-Za-z0-9+-/=_]+)(#(.+))?", RegexOptions.IgnoreCase), DetailsParser = new("^((?.+):(?.*)@(?.+?)" + ":(?\\d+?))$", RegexOptions.IgnoreCase); var match = UrlFinder.Match(ssUrl); if (!match.Success) { throw new FormatException(); } var base64 = match.Groups[1].Value; match = DetailsParser.Match(Encoding.UTF8.GetString(Convert.FromBase64String( base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '=')))); Protocol = "origin"; Method = match.Groups["method"].Value; Password = match.Groups["password"].Value; server = match.Groups["hostname"].Value; Server_Port = ushort.Parse(match.Groups["port"].Value); SubTag = !string.IsNullOrEmpty(forceGroup) ? forceGroup : string.Empty; } public bool IsMatchServer(Server serverObject) { return server == serverObject.server && Server_Port == serverObject.Server_Port && Server_Udp_Port == serverObject.Server_Udp_Port && Method == serverObject.Method && Protocol == serverObject.Protocol && ProtocolParam == serverObject.ProtocolParam && obfs == serverObject.obfs && ObfsParam == serverObject.ObfsParam && Password == serverObject.Password && UdpOverTcp == serverObject.UdpOverTcp && Remarks == serverObject.Remarks && Group == serverObject.Group; } public event EventHandler ServerChanged; protected override bool SetField(ref T field, T value, string propertyName = @"") { if (base.SetField(ref field, value, propertyName)) { OnPropertyChanged(nameof(SsLink)); OnPropertyChanged(nameof(SsrLink)); ServerChanged?.Invoke(this, EventArgs.Empty); return true; } return false; } } } ================================================ FILE: shadowsocks-csharp/Model/ServerSelectStrategy.cs ================================================ using Shadowsocks.Enums; using Shadowsocks.Model.Transfer; using System; using System.Collections.Generic; namespace Shadowsocks.Model { public class ServerSelectStrategy { public delegate bool FilterFunc(Server server, Server selServer); // return true if select the server private Random randomGennarator; private int lastSelectIndex; private string lastSelectID; private DateTime lastSelectTime; private int lastUserSelectIndex; private const int MAX_CHANCE = 10000; private const int ERROR_PENALTY = MAX_CHANCE / 20; private const int CONNECTION_PENALTY = MAX_CHANCE / 100; private const int MIN_CHANCE = 10; private struct ServerIndex { public int index; public Server server; public ServerIndex(int i, Server s) { index = i; server = s; } } private int lowerBound(List data, double target) { var left = 0; var right = data.Count - 1; while (left < right) { var mid = (left + right) / 2; if (data[mid] >= target) { right = mid; } else if (data[mid] < target) { left = mid + 1; } } return left; } private double Algorithm2(ServerSpeedLog serverSpeedLog) // perfer less delay { if (serverSpeedLog.ErrorContinuousTimes >= 20) { return 1; } if (serverSpeedLog.ErrorContinuousTimes >= 10) { return MIN_CHANCE; } if (serverSpeedLog.AvgConnectTime < 0 && serverSpeedLog.TotalConnectTimes >= 3) { return MIN_CHANCE; } if (serverSpeedLog.TotalConnectTimes < 1) { return MAX_CHANCE; } long avgConnectTime = serverSpeedLog.AvgConnectTime <= 0 ? 1 : serverSpeedLog.AvgConnectTime; if (serverSpeedLog.TotalConnectTimes >= 1 && serverSpeedLog.AvgConnectTime < 0) { avgConnectTime = 5000; } var connections = serverSpeedLog.TotalConnectTimes - serverSpeedLog.TotalDisconnectTimes; var chance = MAX_CHANCE * 10.0 / avgConnectTime - connections * CONNECTION_PENALTY; if (chance > MAX_CHANCE) { chance = MAX_CHANCE; } chance -= serverSpeedLog.ErrorContinuousTimes * ERROR_PENALTY; if (chance < MIN_CHANCE) { chance = MIN_CHANCE; } return chance; } private double Algorithm3(ServerSpeedLog serverSpeedLog) // perfer less error { if (serverSpeedLog.ErrorContinuousTimes >= 20) { return 1; } if (serverSpeedLog.ErrorContinuousTimes >= 10) { return MIN_CHANCE; } if (serverSpeedLog.AvgConnectTime < 0 && serverSpeedLog.TotalConnectTimes >= 3) { return MIN_CHANCE; } if (serverSpeedLog.TotalConnectTimes < 1) { return MAX_CHANCE; } long avgConnectTime = serverSpeedLog.AvgConnectTime <= 0 ? 1 : serverSpeedLog.AvgConnectTime / 1000 * 1000; if (serverSpeedLog.TotalConnectTimes >= 1 && serverSpeedLog.AvgConnectTime < 0) { avgConnectTime = 5000; } var connections = serverSpeedLog.TotalConnectTimes - serverSpeedLog.TotalDisconnectTimes; var chance = MAX_CHANCE * 1.0 / (avgConnectTime / 500 + 1) - connections * CONNECTION_PENALTY; if (chance > MAX_CHANCE) { chance = MAX_CHANCE; } chance -= serverSpeedLog.ErrorContinuousTimes * ERROR_PENALTY; if (chance < MIN_CHANCE) { chance = MIN_CHANCE; } return chance; } private double Algorithm4(ServerSpeedLog serverSpeedLog, long avg_speed, double zero_chance) // perfer fast speed { if (serverSpeedLog.ErrorContinuousTimes >= 20) { return 1; } if (serverSpeedLog.ErrorContinuousTimes >= 10) { return MIN_CHANCE; } if (serverSpeedLog.AvgConnectTime < 0 && serverSpeedLog.TotalConnectTimes >= 3) { return MIN_CHANCE; } if (serverSpeedLog.TotalConnectTimes < 1) { return MAX_CHANCE; } long avgConnectTime = serverSpeedLog.AvgConnectTime <= 0 ? 1 : serverSpeedLog.AvgConnectTime / 2000 * 2000; serverSpeedLog.GetTransSpeed(out _, out var speed_d); if (serverSpeedLog.TotalConnectTimes >= 1 && serverSpeedLog.AvgConnectTime < 0) { avgConnectTime = 5000; } var speed_mul = speed_d > avg_speed ? 1.0 : speed_d == 0 ? zero_chance : speed_d < avg_speed / 2 ? 0.001 : 0.005; var connections = serverSpeedLog.TotalConnectTimes - serverSpeedLog.TotalDisconnectTimes; var chance = MAX_CHANCE * speed_mul / (avgConnectTime / 500 + 1) - connections * CONNECTION_PENALTY; if (chance > MAX_CHANCE) { chance = MAX_CHANCE; } chance -= serverSpeedLog.ErrorContinuousTimes * ERROR_PENALTY; if (chance < MIN_CHANCE) { chance = MIN_CHANCE; } return chance; } protected int SubSelect(IList configs, int curIndex, BalanceType algorithm, FilterFunc filter, bool forceChange) { if (randomGennarator == null) { randomGennarator = new Random(); lastSelectIndex = -1; } if (configs.Count <= lastSelectIndex || lastSelectIndex < 0) { lastSelectIndex = -1; lastSelectTime = DateTime.Now; lastUserSelectIndex = -1; } else { if (configs[lastSelectIndex].Id != lastSelectID) { if (lastSelectID != null) { for (var i = 0; i < configs.Count; ++i) { if (configs[i].Id == lastSelectID) { lastSelectIndex = i; break; } } } if (configs[lastSelectIndex].Id != lastSelectID) { lastSelectIndex = -1; lastSelectTime = DateTime.Now; lastUserSelectIndex = -1; } } } if (lastUserSelectIndex != curIndex) { if (configs.Count > curIndex && curIndex >= 0 && algorithm != BalanceType.Timer) { lastSelectIndex = curIndex; } lastUserSelectIndex = curIndex; } if (lastSelectIndex == -1) { if (configs.Count > curIndex && curIndex >= 0) { lastSelectIndex = curIndex; } } if (configs.Count > 0) { var serverList = new List(); for (var i = 0; i < configs.Count; ++i) { if (configs[i].Enable) { if (filter != null) { if (!filter(configs[i], lastSelectIndex < 0 ? null : configs[lastSelectIndex])) { continue; } } serverList.Add(new ServerIndex(i, configs[i])); } } if (serverList.Count == 0 && filter != null) { for (var i = 0; i < configs.Count; ++i) { if (!filter(configs[i], lastSelectIndex < 0 ? null : configs[lastSelectIndex])) { continue; } serverList.Add(new ServerIndex(i, configs[i])); } } if (forceChange && serverList.Count > 1 && algorithm != BalanceType.OneByOne) { for (var i = 0; i < serverList.Count; ++i) { if (serverList[i].index == lastSelectIndex) { serverList.RemoveAt(i); break; } } } if (serverList.Count == 0) { var i = lastSelectIndex; if (i >= 0 && i < configs.Count && configs[i].Enable) { serverList.Add(new ServerIndex(i, configs[i])); } } var serverListIndex = -1; if (serverList.Count > 0) { if (algorithm == BalanceType.OneByOne) { var selIndex = -1; for (var i = 0; i < serverList.Count; ++i) { if (serverList[i].index == lastSelectIndex) { selIndex = i; break; } } serverListIndex = serverList[(selIndex + 1) % serverList.Count].index; } else if (algorithm == BalanceType.Random) { serverListIndex = randomGennarator.Next(serverList.Count); serverListIndex = serverList[serverListIndex].index; } else if (algorithm is BalanceType.LowException or BalanceType.Timer or BalanceType.FastDownloadSpeed) { if (algorithm == BalanceType.Timer) { if ((DateTime.Now - lastSelectTime).TotalSeconds > 60 * 5) { lastSelectTime = DateTime.Now; } else { if (configs.Count > lastSelectIndex && lastSelectIndex >= 0 && configs[lastSelectIndex].Enable && !forceChange) { return lastSelectIndex; } } } var chances = new List(); double lastBeginVal = 0; if (algorithm == BalanceType.FastDownloadSpeed) { long avg_speed = 1024 * 64; long sum_speed = 0; var sum_cnt = 0; var zero_cnt = 0; foreach (var s in serverList) { s.server.SpeedLog.GetTransSpeed(out _, out var speed_d); if (speed_d == 0) { ++zero_cnt; } else { sum_speed += speed_d; ++sum_cnt; } } var zero_chance = 0.5; if (sum_cnt > 0) { avg_speed = sum_speed / sum_cnt; if (zero_cnt + sum_cnt > 0) { zero_chance = 0.1 * sum_cnt / (zero_cnt + sum_cnt); } } foreach (var s in serverList) { var chance = Algorithm4(s.server.SpeedLog, avg_speed, zero_chance); if (chance > 0) { chances.Add(lastBeginVal + chance); lastBeginVal += chance; } } } else { foreach (var s in serverList) { var chance = Algorithm3(s.server.SpeedLog); if (chance > 0) { chances.Add(lastBeginVal + chance); lastBeginVal += chance; } } } { var target = randomGennarator.NextDouble() * lastBeginVal; serverListIndex = lowerBound(chances, target); serverListIndex = serverList[serverListIndex].index; return serverListIndex; } } else //if (algorithm == (int)SelectAlgorithm.LowLatency || algorithm == (int)SelectAlgorithm.SelectedFirst) { var chances = new List(); double lastBeginVal = 0; foreach (var s in serverList) { var chance = Algorithm2(s.server.SpeedLog); if (chance > 0) { chances.Add(lastBeginVal + chance); lastBeginVal += chance; } } if (algorithm == BalanceType.SelectedFirst && randomGennarator.Next(3) == 0 && configs[curIndex].Enable) { for (var i = 0; i < serverList.Count; ++i) { if (curIndex == serverList[i].index) { return curIndex; } } } { var target = randomGennarator.NextDouble() * lastBeginVal; serverListIndex = lowerBound(chances, target); serverListIndex = serverList[serverListIndex].index; return serverListIndex; } } } return serverListIndex; } return -1; } public int Select(IList configs, int curIndex, BalanceType algorithm, FilterFunc filter, bool forceChange = false) { lastSelectIndex = SubSelect(configs, curIndex, algorithm, filter, forceChange); if (lastSelectIndex >= 0 && lastSelectIndex < configs.Count) { lastSelectID = configs[lastSelectIndex].Id; } else { lastSelectID = null; } return lastSelectIndex; } } } ================================================ FILE: shadowsocks-csharp/Model/ServerSubscribe.cs ================================================ using Shadowsocks.Controller.HttpRequest; using Shadowsocks.Encryption; using Shadowsocks.Enums; using Shadowsocks.ViewModel; using System; using System.Text; using System.Text.Json.Serialization; namespace Shadowsocks.Model { [Serializable] public class ServerSubscribe : ViewModelBase { private string _url; private string _tag; private long _lastUpdateTime; private bool _autoCheckUpdate; private HttpRequestProxyType _proxyType; public ServerSubscribe() { _url = UpdateNode.DefaultUpdateUrl; _autoCheckUpdate = true; _proxyType = HttpRequestProxyType.Auto; } public string Url { get => _url; set { if (SetField(ref _url, value)) { SubscribeChanged?.Invoke(this, EventArgs.Empty); } } } [JsonIgnore] public string OriginTag => _tag; [JsonIgnore] public string UrlMd5 => BitConverter.ToString(CryptoUtils.MD5(Encoding.UTF8.GetBytes(Url))).Replace(@"-", string.Empty); public string Tag { get => string.IsNullOrWhiteSpace(_tag) ? UrlMd5 : _tag; set { if (UrlMd5 == value) { value = string.Empty; } if (SetField(ref _tag, value)) { SubscribeChanged?.Invoke(this, EventArgs.Empty); } } } public long LastUpdateTime { get => _lastUpdateTime; set { if (SetField(ref _lastUpdateTime, value)) { SubscribeChanged?.Invoke(this, EventArgs.Empty); } } } public bool AutoCheckUpdate { get => _autoCheckUpdate; set { if (SetField(ref _autoCheckUpdate, value)) { SubscribeChanged?.Invoke(this, EventArgs.Empty); } } } public HttpRequestProxyType ProxyType { get => _proxyType; set { if (SetField(ref _proxyType, value)) { SubscribeChanged?.Invoke(this, EventArgs.Empty); } } } public event EventHandler SubscribeChanged; } } ================================================ FILE: shadowsocks-csharp/Model/ServerTreeViewModel.cs ================================================ using Shadowsocks.Enums; using Shadowsocks.Util; using Shadowsocks.ViewModel; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; namespace Shadowsocks.Model { public class ServerTreeViewModel : ViewModelBase { public ServerTreeViewModel() { _nodes = new ObservableCollection(); _name = string.Empty; _server = null; _type = ServerTreeViewType.Subtag; } private string _name; public string Name { get { switch (Type) { case ServerTreeViewType.Subtag: if (string.IsNullOrEmpty(_name)) { return I18NUtil.GetAppStringValue(@"EmptySubtag"); } break; case ServerTreeViewType.Group: if (string.IsNullOrEmpty(_name)) { return I18NUtil.GetAppStringValue(@"EmptyGroup"); } break; case ServerTreeViewType.Server: if (Server != null) { return Server.FriendlyName; } break; default: throw new ArgumentOutOfRangeException(nameof(Type)); } return _name; } set => SetField(ref _name, value); } private ObservableCollection _nodes; public ObservableCollection Nodes { get => _nodes; set => SetField(ref _nodes, value); } private ServerTreeViewType _type; public ServerTreeViewType Type { get => _type; set => SetField(ref _type, value); } private Server _server; public Server Server { get => _server; set { if (SetField(ref _server, value)) { _server.ServerChanged += Server_ServerChanged; OnPropertyChanged(nameof(Name)); } } } private void Server_ServerChanged(object sender, EventArgs e) { OnPropertyChanged(nameof(Name)); } #region Static Method public static void Remove(ObservableCollection root, ServerTreeViewModel st) { if (root.Remove(st)) { return; } foreach (var serverTreeViewModel in root) { Remove(serverTreeViewModel.Nodes, st); } } public static ServerTreeViewModel FindParentNode(Collection root, ServerTreeViewModel st) { var res = root.Where(serverTreeViewModel => serverTreeViewModel.Nodes != null) .FirstOrDefault(serverTreeViewModel => serverTreeViewModel.Nodes.Contains(st)); if (res != null) { return res; } foreach (var serverTreeViewModel in root) { res = FindParentNode(serverTreeViewModel.Nodes, st); if (res != null) { return res; } } return null; } public static ServerTreeViewModel FindNode(Collection root, string serverId) { var res = root.FirstOrDefault(serverTreeViewModel => serverTreeViewModel.Server?.Id == serverId); if (res != null) { return res; } foreach (var serverTreeViewModel in root) { res = FindNode(serverTreeViewModel.Nodes, serverId); if (res != null) { return res; } } return null; } #endregion } } ================================================ FILE: shadowsocks-csharp/Model/Transfer/ServerSpeedLog.cs ================================================ using Shadowsocks.Util; using Shadowsocks.ViewModel; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; // ReSharper disable MemberCanBePrivate.Global namespace Shadowsocks.Model.Transfer { public class ServerSpeedLog : ViewModelBase { private long _totalConnectTimes; private long _totalDisconnectTimes; private long _errorConnectTimes; private long _errorTimeoutTimes; private long _errorDecodeTimes; private long _errorEmptyTimes; private long _errorContinuousTimes; private long _transUpload; private long _transDownload; private long _transDownloadRaw; private readonly List _downTransLog = new(); private readonly List _upTransLog = new(); private long _maxTransDownload; private long _maxTransUpload; private long _avgConnectTime = -1; private readonly ConcurrentQueue _errList = new(); private const int AvgTime = 5; public ServerSpeedLog() { } public ServerSpeedLog(long upload, long download) { Interlocked.Exchange(ref _transUpload, upload); Interlocked.Exchange(ref _transDownload, download); } public void GetTransSpeed(out long upload, out long download) { upload = MaxUpSpeed; download = MaxDownSpeed; } /// /// 总连接数 /// public long TotalConnectTimes => Interlocked.Read(ref _totalConnectTimes); public long TotalDisconnectTimes => Interlocked.Read(ref _totalDisconnectTimes); /// /// 连接数 /// public long Connecting => TotalConnectTimes - TotalDisconnectTimes; #region 下载速度 public long AvgDownloadBytes { get { List transLog; lock (this) { transLog = _downTransLog.ToList(); } double totalTime = 0; if (transLog.Count == 0 || transLog.Count > 0 && DateTime.Now > transLog.Last().recvTime.AddSeconds(AvgTime)) { return 0; } var totalBytes = transLog.Aggregate(0, (current, t) => current + t.size); totalBytes -= transLog[0].firstsize; if (transLog.Count > 1) { totalTime = (transLog.Last().endTime - transLog[0].recvTime).TotalSeconds; } if (totalTime > 0.2) { var ret = (long)(totalBytes / totalTime); return ret; } return 0; } } public string AvgDownloadBytesText => $@"{Utils.FormatBytes(AvgDownloadBytes)}/s"; #endregion #region 上传速度 public long AvgUploadBytes { get { List transLog; lock (this) { transLog = _upTransLog.ToList(); } double totalTime = 0; if (transLog.Count == 0 || transLog.Count > 0 && DateTime.Now > transLog.Last().recvTime.AddSeconds(AvgTime)) { return 0; } var totalBytes = transLog.Aggregate(0, (current, t) => current + t.size); totalBytes -= transLog[0].firstsize; if (transLog.Count > 1) { totalTime = (transLog.Last().endTime - transLog[0].recvTime).TotalSeconds; } if (totalTime > 0.2) { var ret = (long)(totalBytes / totalTime); return ret; } return 0; } } public string AvgUploadBytesText => $@"{Utils.FormatBytes(AvgUploadBytes)}/s"; #endregion #region 最大下载速度 public long MaxDownSpeed => Interlocked.Read(ref _maxTransDownload); public string MaxDownSpeedText => $@"{Utils.FormatBytes(MaxDownSpeed)}/s"; #endregion #region 最大上传速度 public long MaxUpSpeed => Interlocked.Read(ref _maxTransUpload); public string MaxUpSpeedText => $@"{Utils.FormatBytes(MaxUpSpeed)}/s"; #endregion #region 延迟 public long AvgConnectTime => Interlocked.Read(ref _avgConnectTime); public long AvgConnectTimeText { get { if (AvgConnectTime > 0) { return AvgConnectTime / 1000; } return 0; } } #endregion #region 总上传 public long TotalUploadBytes => Interlocked.Read(ref _transUpload); public string TotalUploadBytesText => Utils.FormatBytes(TotalUploadBytes); #endregion #region 总下载 public long TotalDownloadBytes => Interlocked.Read(ref _transDownload); public string TotalDownloadBytesText => Utils.FormatBytes(TotalDownloadBytes); #endregion #region 实下载 public long TotalDownloadRawBytes => Interlocked.Read(ref _transDownloadRaw); public string TotalDownloadRawBytesText => Utils.FormatBytes(TotalDownloadRawBytes); #endregion /// /// 错误 /// public long ConnectError => ErrorConnectTimes + ErrorDecodeTimes; public long ErrorConnectTimes => Interlocked.Read(ref _errorConnectTimes); public long ErrorDecodeTimes => Interlocked.Read(ref _errorDecodeTimes); /// /// 连错 /// public long ErrorContinuousTimes => Interlocked.Read(ref _errorContinuousTimes); /// /// 超时 /// public long ErrorTimeoutTimes => Interlocked.Read(ref _errorTimeoutTimes); /// /// 空连 /// public long ErrorEmptyTimes => Interlocked.Read(ref _errorEmptyTimes); #region 出错比例 public double? ErrorPercent { get { var errorLogTimes = _errList.Count; var m = errorLogTimes + Connecting; if (m > 0) { return (ConnectError + ErrorTimeoutTimes) * 100.0 / m; } return null; } } #endregion public void ClearTrans() { Interlocked.Exchange(ref _transUpload, 0); Interlocked.Exchange(ref _transDownload, 0); OnPropertyChanged(nameof(TotalUploadBytes)); OnPropertyChanged(nameof(TotalUploadBytesText)); OnPropertyChanged(nameof(TotalDownloadBytes)); OnPropertyChanged(nameof(TotalDownloadBytesText)); } public void ClearError() { var value = Connecting; if (value > 0) { Interlocked.Exchange(ref _totalConnectTimes, value); } else { Interlocked.Exchange(ref _totalConnectTimes, 0); } Interlocked.Exchange(ref _totalDisconnectTimes, 0); Interlocked.Exchange(ref _errorConnectTimes, 0); Interlocked.Exchange(ref _errorTimeoutTimes, 0); Interlocked.Exchange(ref _errorDecodeTimes, 0); Interlocked.Exchange(ref _errorEmptyTimes, 0); Interlocked.Exchange(ref _errorContinuousTimes, 0); _errList.Clear(); OnPropertyChanged(nameof(Connecting)); OnPropertyChanged(nameof(TotalConnectTimes)); OnPropertyChanged(nameof(TotalDisconnectTimes)); OnPropertyChanged(nameof(ConnectError)); OnPropertyChanged(nameof(ErrorConnectTimes)); OnPropertyChanged(nameof(ErrorTimeoutTimes)); OnPropertyChanged(nameof(ErrorDecodeTimes)); OnPropertyChanged(nameof(ErrorEmptyTimes)); OnPropertyChanged(nameof(ErrorContinuousTimes)); OnPropertyChanged(nameof(ErrorPercent)); } public void ClearMaxSpeed() { Interlocked.Exchange(ref _maxTransDownload, 0); Interlocked.Exchange(ref _maxTransUpload, 0); OnPropertyChanged(nameof(MaxDownSpeed)); OnPropertyChanged(nameof(MaxDownSpeedText)); OnPropertyChanged(nameof(MaxUpSpeed)); OnPropertyChanged(nameof(MaxUpSpeedText)); } public void Clear() { ResetConnectTime(); ClearError(); ClearMaxSpeed(); ClearTrans(); Interlocked.Exchange(ref _transDownloadRaw, 0); OnPropertyChanged(nameof(TotalDownloadRawBytes)); OnPropertyChanged(nameof(TotalDownloadRawBytesText)); } public void AddConnectTimes() { Interlocked.Increment(ref _totalConnectTimes); OnPropertyChanged(nameof(TotalConnectTimes)); OnPropertyChanged(nameof(Connecting)); OnPropertyChanged(nameof(ErrorPercent)); } public void AddDisconnectTimes() { Interlocked.Increment(ref _totalDisconnectTimes); OnPropertyChanged(nameof(TotalDisconnectTimes)); OnPropertyChanged(nameof(Connecting)); OnPropertyChanged(nameof(ErrorPercent)); } private void Sweep() { while (_errList.TryPeek(out var first)) { if ((DateTime.Now - first.time).TotalMinutes < 30 && _errList.Count < 100) { break; } _errList.TryDequeue(out first); switch (first.errno) { case 1: { if (ErrorConnectTimes > 0) { Interlocked.Decrement(ref _errorConnectTimes); OnPropertyChanged(nameof(ErrorConnectTimes)); OnPropertyChanged(nameof(ConnectError)); } break; } case 2: { if (ErrorTimeoutTimes > 0) { Interlocked.Decrement(ref _errorTimeoutTimes); OnPropertyChanged(nameof(ErrorTimeoutTimes)); } break; } case 3: { if (ErrorDecodeTimes > 0) { Interlocked.Decrement(ref _errorDecodeTimes); OnPropertyChanged(nameof(ErrorDecodeTimes)); OnPropertyChanged(nameof(ConnectError)); } break; } case 4: { if (ErrorEmptyTimes > 0) { Interlocked.Decrement(ref _errorEmptyTimes); OnPropertyChanged(nameof(ErrorEmptyTimes)); } break; } } OnPropertyChanged(nameof(ErrorPercent)); } } public void AddNoErrorTimes() { _errList.Enqueue(new ErrorLog(0)); Sweep(); Interlocked.Exchange(ref _errorEmptyTimes, 0); OnPropertyChanged(nameof(ErrorEmptyTimes)); } public void AddErrorTimes() { Interlocked.Increment(ref _errorConnectTimes); Interlocked.Add(ref _errorContinuousTimes, 2); _errList.Enqueue(new ErrorLog(1)); Sweep(); OnPropertyChanged(nameof(ErrorConnectTimes)); OnPropertyChanged(nameof(ErrorContinuousTimes)); OnPropertyChanged(nameof(ConnectError)); } public void AddTimeoutTimes() { Interlocked.Increment(ref _errorTimeoutTimes); Interlocked.Increment(ref _errorContinuousTimes); _errList.Enqueue(new ErrorLog(2)); Sweep(); OnPropertyChanged(nameof(ErrorTimeoutTimes)); OnPropertyChanged(nameof(ErrorContinuousTimes)); OnPropertyChanged(nameof(ConnectError)); } public void AddErrorDecodeTimes() { Interlocked.Increment(ref _errorDecodeTimes); Interlocked.Add(ref _errorContinuousTimes, 10); _errList.Enqueue(new ErrorLog(3)); Sweep(); OnPropertyChanged(nameof(ErrorDecodeTimes)); OnPropertyChanged(nameof(ErrorContinuousTimes)); OnPropertyChanged(nameof(ConnectError)); } public void AddErrorEmptyTimes() { Interlocked.Increment(ref _errorEmptyTimes); Interlocked.Increment(ref _errorContinuousTimes); _errList.Enqueue(new ErrorLog(0)); Sweep(); OnPropertyChanged(nameof(ErrorEmptyTimes)); OnPropertyChanged(nameof(ErrorContinuousTimes)); OnPropertyChanged(nameof(ConnectError)); } private static void UpdateTransLog(IList transLog, int bytes, DateTime now, ref long maxTrans, bool updateMaxTrans) { if (transLog.Count > 0) { const int baseTimeDiff = 100; const int maxTimeDiff = 3 * baseTimeDiff; var timeDiff = (int)(now - transLog.Last().recvTime).TotalMilliseconds; if (timeDiff < 0) { transLog.Clear(); transLog.Add(new TransLog(bytes, now)); return; } if (timeDiff < baseTimeDiff) { transLog.Last().times++; transLog.Last().size += bytes; if (transLog.Last().endTime < now) { transLog.Last().endTime = now; } } else { transLog.Add(new TransLog(bytes, now)); var baseTimes = 1 + (maxTrans > 1024 * 512 ? 1 : 0); var lastIndex = transLog.Count - 1 - 2; if (updateMaxTrans && transLog.Count >= 6 && transLog[lastIndex].times > baseTimes) { var beginIndex = lastIndex - 1; for (; beginIndex > 0; --beginIndex) { if ((transLog[beginIndex + 1].recvTime - transLog[beginIndex].endTime).TotalMilliseconds > maxTimeDiff || transLog[beginIndex].times <= baseTimes ) { break; } } if (beginIndex <= lastIndex - 4) { beginIndex++; var t = new TransLog(transLog[beginIndex].firstsize, transLog[beginIndex].recvTime) { endTime = transLog[lastIndex].endTime, size = 0 }; for (var i = beginIndex; i <= lastIndex; ++i) { t.size += transLog[i].size; } if (maxTrans == 0) { maxTrans = (long)((t.size - t.firstsize) / (t.endTime - t.recvTime).TotalSeconds * 0.7); } else { const double a = 2.0 / (1 + 32); maxTrans = (long)(0.5 + maxTrans * (1 - a) + a * ((t.size - t.firstsize) / (t.endTime - t.recvTime).TotalSeconds)); } } } } while (transLog.Count > 0 && now > transLog[0].recvTime.AddSeconds(AvgTime)) { transLog.RemoveAt(0); } } else { transLog.Add(new TransLog(bytes, now)); } } public void AddUploadBytes(int bytes, DateTime now, bool updateMaxTrans) { Interlocked.Add(ref _transUpload, bytes); OnPropertyChanged(nameof(TotalUploadBytes)); OnPropertyChanged(nameof(TotalUploadBytesText)); lock (this) { UpdateTransLog(_upTransLog, bytes, now, ref _maxTransUpload, updateMaxTrans); } OnPropertyChanged(nameof(AvgUploadBytes)); OnPropertyChanged(nameof(AvgUploadBytesText)); OnPropertyChanged(nameof(MaxUpSpeed)); OnPropertyChanged(nameof(MaxUpSpeedText)); } public void AddDownloadBytes(int bytes, DateTime now, bool updateMaxTrans) { Interlocked.Add(ref _transDownload, bytes); OnPropertyChanged(nameof(TotalDownloadBytes)); OnPropertyChanged(nameof(TotalDownloadBytesText)); lock (this) { UpdateTransLog(_downTransLog, bytes, now, ref _maxTransDownload, updateMaxTrans); } OnPropertyChanged(nameof(AvgDownloadBytes)); OnPropertyChanged(nameof(AvgDownloadBytesText)); OnPropertyChanged(nameof(MaxDownSpeed)); OnPropertyChanged(nameof(MaxDownSpeedText)); } public void AddDownloadRawBytes(long bytes) { Interlocked.Add(ref _transDownloadRaw, bytes); OnPropertyChanged(nameof(TotalDownloadRawBytes)); OnPropertyChanged(nameof(TotalDownloadRawBytesText)); } public void ResetErrorDecodeTimes() { Interlocked.Exchange(ref _errorDecodeTimes, 0); Interlocked.Exchange(ref _errorEmptyTimes, 0); Interlocked.Exchange(ref _errorContinuousTimes, 0); OnPropertyChanged(nameof(ErrorDecodeTimes)); OnPropertyChanged(nameof(ErrorEmptyTimes)); OnPropertyChanged(nameof(ErrorContinuousTimes)); OnPropertyChanged(nameof(ConnectError)); OnPropertyChanged(nameof(ErrorPercent)); } public void ResetContinuousTimes() { Interlocked.Exchange(ref _errorEmptyTimes, 0); Interlocked.Exchange(ref _errorContinuousTimes, 0); OnPropertyChanged(nameof(ErrorEmptyTimes)); OnPropertyChanged(nameof(ErrorContinuousTimes)); } public void ResetEmptyTimes() { Interlocked.Exchange(ref _errorEmptyTimes, 0); OnPropertyChanged(nameof(ErrorEmptyTimes)); } public void ResetConnectTime() { Interlocked.Exchange(ref _avgConnectTime, -1); OnPropertyChanged(nameof(AvgConnectTimeText)); } public void AddConnectTime(long millisecond) { if (millisecond == 0) { millisecond = 10; } else { millisecond *= 1000; } var oldValue = AvgConnectTime; if (oldValue == -1) { Interlocked.Exchange(ref _avgConnectTime, millisecond); } else { const double a = 2.0 / (1 + 16); Interlocked.Exchange(ref _avgConnectTime, Convert.ToInt64(0.5 + oldValue * (1 - a) + a * millisecond)); } OnPropertyChanged(nameof(AvgConnectTimeText)); } } } ================================================ FILE: shadowsocks-csharp/Model/Transfer/ServerTrans.cs ================================================ using System; namespace Shadowsocks.Model.Transfer { [Serializable] public class ServerTrans { public long TotalUploadBytes { get; set; } public long TotalDownloadBytes { get; set; } } } ================================================ FILE: shadowsocks-csharp/Model/Transfer/ServerTransferTotal.cs ================================================ using Shadowsocks.Util; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; namespace Shadowsocks.Model.Transfer { [Serializable] public class ServerTransferTotal { private const string LogFile = @"transfer_log.json"; public Dictionary Servers = new(); private int _saveCounter; private DateTime _saveTime; private static readonly TimeSpan MinInterval = TimeSpan.FromMinutes(10); private const int MaxSaveCounter = 256; public static ServerTransferTotal Load() { try { ServerTransferTotal config; if (File.Exists(LogFile)) { config = new ServerTransferTotal { Servers = JsonSerializer.Deserialize>(File.ReadAllText(LogFile)) }; } else { config = new ServerTransferTotal(); } config.Init(); return config; } catch (FileNotFoundException) { // ignored } catch (Exception e) { Console.WriteLine(e); } return new ServerTransferTotal(); } private void Init() { _saveCounter = MaxSaveCounter; _saveTime = DateTime.Now; if (Servers == null) { Servers = new Dictionary(); } } public static void Save(ServerTransferTotal config, List servers = null) { try { if (servers != null) { config.Servers = config.Servers .Where(pair => servers.Exists(server => server.Id == pair.Key)) .ToDictionary(pair => pair.Key, pair => pair.Value); } var jsonString = JsonUtils.Serialize(config.Servers, true); File.WriteAllTextAsync(LogFile, jsonString); } catch (IOException e) { Console.Error.WriteLine(e); } } public void Clear(string serverId) { lock (Servers) { if (Servers.TryGetValue(serverId, out var trans)) { trans.TotalUploadBytes = 0; trans.TotalDownloadBytes = 0; } } } public void AddUpload(string serverId, long size) { lock (Servers) { if (Servers.TryGetValue(serverId, out var trans)) { trans.TotalUploadBytes += size; } else { Servers.Add(serverId, new ServerTrans()); } } if (--_saveCounter <= 0) { _saveCounter = MaxSaveCounter; if (DateTime.Now - _saveTime > MinInterval) { lock (Servers) { Save(this); _saveTime = DateTime.Now; } } } } public void AddDownload(string server, long size) { lock (Servers) { if (Servers.TryGetValue(server, out var trans)) { trans.TotalDownloadBytes += size; } else { Servers.Add(server, new ServerTrans()); } } if (--_saveCounter <= 0) { _saveCounter = MaxSaveCounter; if (DateTime.Now - _saveTime > MinInterval) { lock (Servers) { Save(this); _saveTime = DateTime.Now; } } } } } } ================================================ FILE: shadowsocks-csharp/Model/Transfer/TransLog.cs ================================================ using System; namespace Shadowsocks.Model.Transfer { public class TransLog { public int size; public int firstsize; public int times; public DateTime recvTime; public DateTime endTime; public TransLog(int s, DateTime t) { firstsize = s; size = s; recvTime = t; endTime = t; times = 1; } } } ================================================ FILE: shadowsocks-csharp/Model/UriVisitTime.cs ================================================ using System; namespace Shadowsocks.Model { public class UriVisitTime : IComparable { public DateTime visitTime; public string uri; public int index; public int CompareTo(object other) { if (other is not UriVisitTime) { throw new InvalidOperationException("CompareTo: Not a UriVisitTime"); } return Equals(other) ? 0 : visitTime.CompareTo(((UriVisitTime)other).visitTime); } } } ================================================ FILE: shadowsocks-csharp/Model/WindowStatus.cs ================================================ using Shadowsocks.Util; using System.Windows; namespace Shadowsocks.Model { public class WindowStatus { public double Width; public double Height; public double Left; public double Top; public WindowState State; public WindowStatus() { Width = 0.0; Height = 0.0; Left = 0.0; Top = 0.0; State = WindowState.Normal; } public WindowStatus(Window window) { Width = window.Width; Height = window.Height; Left = window.Left; Top = window.Top; State = window.WindowState; } public void SetStatus(Window window) { window.Width = Width; window.Height = Height; window.Left = Left; window.Top = Top; window.WindowState = State; window.WindowStartupLocation = ViewUtils.IsOnScreen(window) ? WindowStartupLocation.Manual : WindowStartupLocation.CenterScreen; } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthAES128SHA1.cs ================================================ using CryptoBase.Abstractions; using CryptoBase.Abstractions.Digests; using CryptoBase.Digests; using CryptoBase.Macs.Hmac; using Shadowsocks.Controller; using Shadowsocks.Encryption; using Shadowsocks.Enums; using System; using System.Collections.Generic; using System.Security.Cryptography; namespace Shadowsocks.Obfs { public class AuthAES128SHA1 : VerifySimpleBase { protected delegate byte[] hash_func(ReadOnlySpan input); protected class AuthDataAes128 : AuthData { public Model.MinSearchTree tree; } public AuthAES128SHA1(string method) : base(method) { has_sent_header = false; has_recv_header = false; pack_id = 1; recv_id = 1; SALT = method; if (method == "auth_aes128_md5") { hash = CryptoUtils.MD5; } else { hash = CryptoUtils.SHA1; } random = new Random(RandomNumberGenerator.GetInt32(int.MaxValue)); } private static Dictionary _obfs = new() { { "auth_aes128_md5", new[] { 1, 0, 1 } }, { "auth_aes128_sha1", new[] { 1, 0, 1 } } }; protected bool has_sent_header; protected bool has_recv_header; protected string SALT; protected uint pack_id; protected uint recv_id; protected byte[] user_key; protected byte[] user_id; protected hash_func hash; protected byte[] send_buffer; protected int last_datalength; protected const int overhead = 9; // 2(length) + 2(len-MAC) + 4(data-MAC) + 1(padding) //protected int[] packet_cnt; protected Dictionary packet_cnt = new(); //protected int[] packet_mul; protected Model.MinSearchTree tree; protected const int tree_offset = 9; protected DateTime lastSendTime; public static List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } public override object InitData() { return new AuthDataAes128(); } public override bool isKeepAlive() { return true; } public override bool isAlwaysSendback() { return true; } public override int GetOverhead() { return overhead; } protected IMac CreateHMAC(byte[] key) { return Method switch { @"auth_aes128_md5" => HmacUtils.Create(DigestType.Md5, key), @"auth_aes128_sha1" => HmacUtils.Create(DigestType.Sha1, key), _ => null }; } protected void Sync() { #if PROTOCOL_STATISTICS if (Server.data is not null and AuthDataAes128 authData) { lock (authData) { if (authData.tree != null && packet_cnt != null) { authData.tree.Update(packet_cnt); tree = authData.tree.Clone(); } } } #endif } // return final size, include dataLengthMax protected int RandomInMin(int dataLengthMin, int dataLengthMax) { dataLengthMin -= tree_offset; dataLengthMax -= tree_offset; var len = tree.RandomFindIndex(dataLengthMin - 1, dataLengthMax, random); tree.Update(len); return len + tree_offset + 1; } // real packet size. mapping: 1 => 0 protected void AddPacket(int length) { #if PROTOCOL_STATISTICS if (length > tree_offset) { length -= 1 + tree_offset; if (length >= tree.Size) { length = tree.Size - 1; } lock (Server.data) { if (packet_cnt.ContainsKey(length)) { packet_cnt[length] += 1; } else { packet_cnt[length] = 1; } } } else { throw new ObfsException("AddPacket size uncorrect"); } #endif } protected void StatisticsInit(AuthDataAes128 authData) { #if PROTOCOL_STATISTICS if (authData.tree == null) { authData.tree = new Model.MinSearchTree(Server.tcp_mss - tree_offset); authData.tree.Init(); } tree = authData.tree.Clone(); #endif } protected int GetRandLen(int datalength, int fulldatalength, bool nopadding) { if (nopadding || fulldatalength >= Server.buffer_size) { return 0; } var rev_len = Server.tcp_mss - datalength - overhead; if (rev_len <= 0) { return 0; } if (datalength > 1100) { return LinearRandomInt(rev_len); } return TrapezoidRandomInt(rev_len, -0.3); } #if PROTOCOL_STATISTICS // packetlength + padding = real_packetlength // return size of padding, at least 1 protected int GenRandLenFull(int packetlength, int fulldatalength, bool nopadding) { if (nopadding || fulldatalength >= Server.buffer_size) { return packetlength; } if (packetlength >= Server.tcp_mss) { if (packetlength > Server.tcp_mss && packetlength < Server.tcp_mss * 2) { return packetlength + TrapezoidRandomInt(Server.tcp_mss * 2 - packetlength, -0.3); } return packetlength + TrapezoidRandomInt(32, -0.3); } return RandomInMin(packetlength, Server.tcp_mss - 1); } protected int GenRandLen(int packetlength, int maxpacketlength) { return RandomInMin(packetlength, maxpacketlength); } #endif public void PackData(byte[] data, int datalength, int fulldatalength, byte[] outdata, out int outlength, bool nopadding = false) { #if !PROTOCOL_STATISTICS int rand_len = GetRandLen(datalength, fulldatalength, nopadding) + 1; #else const int overHead = 8; var rand_len = GenRandLenFull((datalength == 0 ? 1 : datalength) + overHead + 1, fulldatalength, nopadding) - datalength - overHead; #endif outlength = rand_len + datalength + 8; if (datalength > 0) { Array.Copy(data, 0, outdata, rand_len + 4, datalength); } outdata[0] = (byte)outlength; outdata[1] = (byte)(outlength >> 8); var key = new byte[user_key.Length + 4]; user_key.CopyTo(key, 0); BitConverter.GetBytes(pack_id).CopyTo(key, key.Length - 4); { var rnd_data = new byte[rand_len]; random.NextBytes(rnd_data); rnd_data.CopyTo(outdata, 4); } using var sha1 = CreateHMAC(key); { sha1.Update(outdata.AsSpan(0, 2)); Span span = stackalloc byte[sha1.Length]; sha1.GetMac(span); span[..2].CopyTo(outdata.AsSpan(2, 2)); } if (rand_len < 128) { outdata[4] = (byte)rand_len; } else { outdata[4] = 0xFF; outdata[5] = (byte)rand_len; outdata[6] = (byte)(rand_len >> 8); } ++pack_id; { sha1.Update(outdata.AsSpan(0, outlength - 4)); Span span = stackalloc byte[sha1.Length]; sha1.GetMac(span); span[..4].CopyTo(outdata.AsSpan(outlength - 4, 4)); } } public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength) { const int authHeadLen = 7 + 4 + 16 + 4; const int overHead = authHeadLen + 4; var encrypt = new byte[24]; if (Server.data is AuthDataAes128 authData) { lock (authData) { if (authData.connectionID > 0xFF000000) { authData.clientID = null; } if (authData.clientID == null) { authData.clientID = RandomNumberGenerator.GetBytes(4); authData.connectionID = (uint)BitConverter.ToInt32(authData.clientID, 0) % 0xFFFFFD; } authData.connectionID += 1; Array.Copy(authData.clientID, 0, encrypt, 4, 4); Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, encrypt, 8, 4); StatisticsInit(authData); } } #if !PROTOCOL_STATISTICS int rand_len = TrapezoidRandomInt(Server.tcp_mss - datalength - overhead + 1, -0.3); //(datalength > 400 ? LinearRandomInt(512) : LinearRandomInt(1024)); #else var rand_len = GenRandLenFull(datalength + overHead, datalength, false) - datalength - overHead; #endif var data_offset = rand_len + authHeadLen; outlength = data_offset + datalength + 4; var encrypt_data = new byte[32]; var key = new byte[Server.Iv.Length + Server.key.Length]; Server.Iv.CopyTo(key, 0); Server.key.CopyTo(key, Server.Iv.Length); { var rnd_data = new byte[rand_len]; random.NextBytes(rnd_data); rnd_data.CopyTo(outdata, data_offset - rand_len); } var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); var utc_time = (uint)utc_time_second; Array.Copy(BitConverter.GetBytes(utc_time), 0, encrypt, 0, 4); encrypt[12] = (byte)outlength; encrypt[13] = (byte)(outlength >> 8); encrypt[14] = (byte)rand_len; encrypt[15] = (byte)(rand_len >> 8); { var uid = new byte[4]; var index_of_split = Server.param.IndexOf(':'); if (index_of_split > 0) { try { var user = uint.Parse(Server.param.Substring(0, index_of_split)); user_key = hash(System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1))); BitConverter.GetBytes(user).CopyTo(uid, 0); } catch (Exception ex) { Logging.Log(LogLevel.Warn, $"Faild to parse auth param, fallback to basic mode. {ex}"); } } if (user_key == null) { random.NextBytes(uid); user_key = Server.key; } var encrypt_key = user_key; CryptoUtils.SsAes128(Convert.ToBase64String(encrypt_key) + SALT, encrypt.AsSpan(0, 16), encrypt_data.AsSpan(0, 16)); Array.Copy(encrypt_data, 0, encrypt, 4, 16); uid.CopyTo(encrypt, 0); } { using var sha1 = CreateHMAC(key); sha1.Update(encrypt.AsSpan(0, 20)); Span span = stackalloc byte[sha1.Length]; sha1.GetMac(span); span[..4].CopyTo(encrypt.AsSpan(20, 4)); var rnd = new byte[1]; random.NextBytes(rnd); rnd.CopyTo(outdata, 0); sha1.Update(rnd); sha1.GetMac(span); span[..(7 - rnd.Length)].CopyTo(outdata.AsSpan(rnd.Length, 7 - rnd.Length)); } encrypt.CopyTo(outdata, 7); Array.Copy(data, 0, outdata, data_offset, datalength); { using var sha1 = CreateHMAC(user_key); sha1.Update(outdata.AsSpan(0, outlength - 4)); Span span = stackalloc byte[sha1.Length]; sha1.GetMac(span); span[..4].CopyTo(outdata.AsSpan(outlength - 4, 4)); } } // plaindata == null try send buffer data, return null if empty buffer // datalength == 0 sendback, return 0 // datalength == -1 keepalive public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength) { var last = lastSendTime; var now = DateTime.Now; lastSendTime = now; var outdata = new byte[datalength + datalength / 10 + 32]; var packdata = new byte[9000]; var data = plaindata == null ? send_buffer : plaindata; outlength = 0; if (data == null) { return null; } if (data == send_buffer) { datalength = send_buffer.Length; send_buffer = null; Sync(); last = now; } else if (send_buffer != null) { if (datalength <= 0) { return outdata; } Array.Resize(ref send_buffer, send_buffer.Length + datalength); Array.Copy(data, 0, send_buffer, send_buffer.Length - datalength, datalength); data = send_buffer; datalength = send_buffer.Length; send_buffer = null; } const int unit_len = 8100; var ogn_datalength = datalength; if (datalength < 0 || (now - last).TotalSeconds > 3) { Sync(); } if (!has_sent_header) { var _datalength = Math.Min(1200, datalength); PackAuthData(data, _datalength, packdata, out var outlen); has_sent_header = true; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= _datalength; var newdata = new byte[datalength]; Array.Copy(data, _datalength, newdata, 0, newdata.Length); data = newdata; send_buffer = data.Length > 0 ? data : null; AddPacket(outlength); return outdata; } var nopadding = false; #if !PROTOCOL_STATISTICS if (datalength > 120 * 4 && pack_id < 32) { { int send_len = LinearRandomInt(120 * 16); if (send_len < datalength) { send_len = TrapezoidRandomInt(Math.Min(datalength - 1, Server.tcp_mss - overhead) - 1, -0.3) + 1; // must less than datalength #else if (datalength > 120 * 4 && pack_id < 64) { var send_len = LinearRandomInt(datalength + 120 * 4); if (send_len < datalength) { //long min_0 = tree.GetMin(0, 512); //long min_512 = tree.GetMin(512, tree.Size); //if (min_0 < min_512) { var max_packet_size = Math.Min(datalength - 1 + overhead, Server.tcp_mss); // must less than datalength + overhead var len = GenRandLen(overhead + 1, max_packet_size) - overhead; // at least 1 byte data send_len = len; #endif send_len = datalength - send_len; if (send_len > 0) { send_buffer = new byte[send_len]; Array.Copy(data, datalength - send_len, send_buffer, 0, send_len); datalength -= send_len; } nopadding = true; } } } while (datalength > unit_len) { PackData(data, unit_len, ogn_datalength, packdata, out var outlen, nopadding); Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= unit_len; var newdata = new byte[datalength]; Array.Copy(data, unit_len, newdata, 0, newdata.Length); data = newdata; } if (datalength > 0 || ogn_datalength == -1) { if (ogn_datalength == -1) { datalength = 0; } PackData(data, datalength, ogn_datalength, packdata, out var outlen, nopadding); Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; } last_datalength = ogn_datalength; if (outlength > 0) { AddPacket(outlength); } return outdata; } public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[recv_buf_len + datalength]; Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength); recv_buf_len += datalength; outlength = 0; var key = new byte[user_key.Length + 4]; user_key.CopyTo(key, 0); Span span = stackalloc byte[HashConstants.Sha1Length]; while (recv_buf_len > 4) { BitConverter.GetBytes(recv_id).CopyTo(key, key.Length - 4); using var sha1 = CreateHMAC(key); { sha1.Update(recv_buf.AsSpan(0, 2)); sha1.GetMac(span); if (span[0] != recv_buf[2] || span[1] != recv_buf[3]) { throw new ObfsException("ClientPostDecrypt data error"); } } var len = (recv_buf[1] << 8) + recv_buf[0]; if (len is >= 8192 or < 8) { throw new ObfsException("ClientPostDecrypt data error"); } if (len > recv_buf_len) { break; } sha1.Update(recv_buf.AsSpan(0, len - 4)); sha1.GetMac(span); if (!span[..4].SequenceEqual(recv_buf.AsSpan(len - 4, 4))) { throw new ObfsException("ClientPostDecrypt data uncorrect checksum"); } { ++recv_id; int pos = recv_buf[4]; if (pos < 255) { pos += 4; } else { pos = ((recv_buf[6] << 8) | recv_buf[5]) + 4; } var outlen = len - pos - 4; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(recv_buf, pos, outdata, outlength, outlen); outlength += outlen; recv_buf_len -= len; Array.Copy(recv_buf, len, recv_buf, 0, recv_buf_len); } } return outdata; } public override byte[] ClientUdpPreEncrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[datalength + 8]; if (user_key == null) { user_id = new byte[4]; var index_of_split = Server.param.IndexOf(':'); if (index_of_split > 0) { try { var user = uint.Parse(Server.param.Substring(0, index_of_split)); user_key = hash(System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1))); BitConverter.GetBytes(user).CopyTo(user_id, 0); } catch (Exception ex) { Logging.Log(LogLevel.Warn, $"Faild to parse auth param, fallback to basic mode. {ex}"); } } if (user_key == null) { random.NextBytes(user_id); user_key = Server.key; } } outlength = datalength + 8; Array.Copy(plaindata, 0, outdata, 0, datalength); user_id.CopyTo(outdata, datalength); { using var sha1 = CreateHMAC(user_key); sha1.Update(outdata.AsSpan(0, outlength - 4)); Span span = stackalloc byte[sha1.Length]; sha1.GetMac(span); span[..4].CopyTo(outdata.AsSpan(outlength - 4, 4)); } return outdata; } public override byte[] ClientUdpPostDecrypt(byte[] plaindata, int datalength, out int outlength) { if (datalength <= 4) { outlength = 0; return plaindata; } using var sha1 = CreateHMAC(Server.key); sha1.Update(plaindata.AsSpan(0, datalength - 4)); Span span = stackalloc byte[sha1.Length]; sha1.GetMac(span); if (span[..4].SequenceEqual(plaindata.AsSpan(datalength - 4, 4))) { outlength = datalength - 4; return plaindata; } outlength = 0; return plaindata; } protected override void Dispose(bool disposing) { #if PROTOCOL_STATISTICS if (disposing) { if (Server != null && Server.data != null && packet_cnt != null) { var authData = Server.data as AuthDataAes128; if (authData != null && authData.tree != null) { lock (authData) { authData.tree.Update(packet_cnt); } } } } #endif } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthAkarin.cs ================================================ using CryptoBase.Abstractions; using CryptoBase.Digests; using CryptoBase.Macs.Hmac; using Shadowsocks.Controller; using Shadowsocks.Encryption; using Shadowsocks.Encryption.Stream; using Shadowsocks.Enums; using System; using System.Collections.Generic; using System.Security.Cryptography; namespace Shadowsocks.Obfs { internal class AuthAkarin : VerifySimpleBase { protected class AuthDataAesChain : AuthData { } public AuthAkarin(string method) : base(method) { has_sent_header = false; has_recv_header = false; pack_id = 1; recv_id = 1; SALT = method; random = new Random(RandomNumberGenerator.GetInt32(int.MaxValue)); } private static Dictionary _obfs = new() { { "auth_akarin_rand", new[] { 1, 0, 1 } } }; protected bool has_sent_header; protected bool has_recv_header; protected string SALT; protected uint pack_id; protected uint recv_id; protected byte[] user_key; protected byte[] user_id; protected byte[] send_buffer; protected int last_datalength; protected byte[] last_client_hash; protected byte[] last_server_hash; protected xorshift128plus random_client = new(0); protected xorshift128plus random_server = new(0); protected StreamEncryptor encryptor; protected int send_tcp_mss = 2000; protected int recv_tcp_mss = 2000; protected List send_back_cmd = new(); protected const int overhead = 4; public static List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } protected override void Disposing() { if (encryptor != null) { encryptor.Dispose(); encryptor = null; } } public override object InitData() { return new AuthDataAesChain(); } public override bool isKeepAlive() { return true; } public override bool isAlwaysSendback() { return true; } public override int GetOverhead() { return overhead; } protected IMac CreateHMAC(byte[] key) { return HmacUtils.Create(DigestType.Md5, key); } protected virtual int GetSendRandLen(int datalength, xorshift128plus rd, byte[] last_hash) { if (datalength + Server.overhead > send_tcp_mss) { rd.init_from_bin(last_hash, datalength); return (int)(rd.next() % 521); } if (datalength >= 1440 || datalength + Server.overhead == recv_tcp_mss) { return 0; } rd.init_from_bin(last_hash, datalength); if (datalength > 1300) { return (int)(rd.next() % 31); } if (datalength > 900) { return (int)(rd.next() % 127); } if (datalength > 400) { return (int)(rd.next() % 521); } return (int)(rd.next() % (ulong)(send_tcp_mss - datalength - Server.overhead)); //return (int)(random.next() % 1021); } protected virtual int GetRecvRandLen(int datalength, xorshift128plus rd, byte[] last_hash) { if (datalength + Server.overhead > recv_tcp_mss) { rd.init_from_bin(last_hash, datalength); return (int)(rd.next() % 521); } if (datalength >= 1440 || datalength + Server.overhead == recv_tcp_mss) { return 0; } rd.init_from_bin(last_hash, datalength); if (datalength > 1300) { return (int)(rd.next() % 31); } if (datalength > 900) { return (int)(rd.next() % 127); } if (datalength > 400) { return (int)(rd.next() % 521); } return (int)(rd.next() % (ulong)(recv_tcp_mss - datalength - Server.overhead)); //return (int)(random.next() % 1021); } protected int UdpGetRandLen(xorshift128plus rd, byte[] last_hash) { rd.init_from_bin(last_hash); return (int)(rd.next() % 127); } protected int GetSendRandLen(int datalength) { return GetSendRandLen(datalength, random_client, last_client_hash); } public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength) { var cmdlen = 0; int rand_len; var start_pos = 2; if (send_back_cmd.Count > 0) { cmdlen += 2; send_tcp_mss = recv_tcp_mss; rand_len = GetSendRandLen(datalength + cmdlen); outlength = rand_len + datalength + cmdlen + 2; start_pos += cmdlen; outdata[0] = (byte)(send_back_cmd[0] ^ last_client_hash[14]); outdata[1] = (byte)((send_back_cmd[0] >> 8) ^ last_client_hash[15]); outdata[2] = (byte)(datalength ^ last_client_hash[12]); outdata[3] = (byte)((datalength >> 8) ^ last_client_hash[13]); send_back_cmd.Clear(); } else { rand_len = GetSendRandLen(datalength); outlength = rand_len + datalength + 2; outdata[0] = (byte)(datalength ^ last_client_hash[14]); outdata[1] = (byte)((datalength >> 8) ^ last_client_hash[15]); } { var rnd_data = new byte[rand_len]; random.NextBytes(rnd_data); if (datalength > 0) { encryptor.Encrypt(data, datalength, data, out datalength); Array.Copy(data, 0, outdata, start_pos, datalength); if (rand_len > 0) { rnd_data.CopyTo(outdata, start_pos + datalength); } } else { rnd_data.CopyTo(outdata, start_pos); } } var key = new byte[user_key.Length + 4]; user_key.CopyTo(key, 0); BitConverter.GetBytes(pack_id).CopyTo(key, key.Length - 4); using var md5 = CreateHMAC(key); ++pack_id; { md5.Update(outdata.AsSpan(0, outlength)); var md5data = new byte[md5.Length]; md5.GetMac(md5data); last_client_hash = md5data; md5data[..2].CopyTo(outdata.AsSpan(outlength, 2)); outlength += 2; } } public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength) { const int authhead_len = 4 + 8 + 4 + 16 + 4; var encrypt = new byte[24]; if (Server.data is AuthDataAesChain authData) { lock (authData) { if (authData.connectionID > 0xFF000000) { authData.clientID = null; } if (authData.clientID == null) { authData.clientID = RandomNumberGenerator.GetBytes(4); authData.connectionID = (uint)BitConverter.ToInt32(authData.clientID, 0) % 0xFFFFFD; } authData.connectionID += 1; Array.Copy(authData.clientID, 0, encrypt, 4, 4); Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, encrypt, 8, 4); } } outlength = authhead_len; var encrypt_data = new byte[32]; var key = new byte[Server.Iv.Length + Server.key.Length]; Server.Iv.CopyTo(key, 0); Server.key.CopyTo(key, Server.Iv.Length); var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); var utc_time = (uint)utc_time_second; Array.Copy(BitConverter.GetBytes(utc_time), 0, encrypt, 0, 4); encrypt[12] = (byte)Server.overhead; encrypt[13] = (byte)(Server.overhead >> 8); send_tcp_mss = 1024; //random.Next(1024) + 400; recv_tcp_mss = send_tcp_mss; encrypt[14] = (byte)send_tcp_mss; encrypt[15] = (byte)(send_tcp_mss >> 8); // first 12 bytes { Span rnd = stackalloc byte[4]; RandomNumberGenerator.Fill(rnd); rnd.CopyTo(outdata); using var md5 = CreateHMAC(key); md5.Update(rnd); var md5data = new byte[md5.Length]; md5.GetMac(md5data); last_client_hash = md5data; md5data[..8].CopyTo(outdata.AsSpan(rnd.Length, 8)); } // uid & 16 bytes auth data { var uid = new byte[4]; var index_of_split = Server.param.IndexOf(':'); if (index_of_split > 0) { try { var user = uint.Parse(Server.param.Substring(0, index_of_split)); user_key = System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1)); BitConverter.GetBytes(user).CopyTo(uid, 0); } catch (Exception ex) { Logging.Log(LogLevel.Warn, $"Faild to parse auth param, fallback to basic mode. {ex}"); } } if (user_key == null) { random.NextBytes(uid); user_key = Server.key; } for (var i = 0; i < 4; ++i) { uid[i] ^= last_client_hash[8 + i]; } var encrypt_key = user_key; CryptoUtils.SsAes128(Convert.ToBase64String(encrypt_key) + SALT, encrypt.AsSpan(0, 16), encrypt_data.AsSpan(0, 16)); Array.Copy(encrypt_data, 0, encrypt, 4, 16); uid.CopyTo(encrypt, 0); } // final HMAC { using var md5 = CreateHMAC(user_key); md5.Update(encrypt.AsSpan(0, 20)); var md5data = new byte[md5.Length]; md5.GetMac(md5data); last_server_hash = md5data; md5data[..4].CopyTo(encrypt.AsSpan(20, 4)); } encrypt.CopyTo(outdata, 12); encryptor = (StreamEncryptor)EncryptorFactory.GetEncryptor("chacha20", Convert.ToBase64String(user_key) + Convert.ToBase64String(last_client_hash, 0, 16)); { var iv = new byte[8]; Array.Copy(last_client_hash, iv, 8); encryptor.SetIV(iv); } { encryptor.Decrypt(last_server_hash, 8, outdata, out _); } // combine first chunk { var pack_outdata = new byte[outdata.Length]; PackData(data, datalength, pack_outdata, out var pack_outlength); Array.Copy(pack_outdata, 0, outdata, outlength, pack_outlength); outlength += pack_outlength; } } // plaindata == null try send buffer data, return null if empty buffer // datalength == 0 sendback, return 0 // datalength == -1 keepalive public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[datalength + datalength / 10 + 32]; var packdata = new byte[9000]; var data = plaindata == null ? send_buffer : plaindata; outlength = 0; if (data == null) { return null; } if (data == send_buffer) { datalength = send_buffer.Length; send_buffer = null; } else if (send_buffer != null) { if (datalength <= 0) { return outdata; } Array.Resize(ref send_buffer, send_buffer.Length + datalength); Array.Copy(data, 0, send_buffer, send_buffer.Length - datalength, datalength); data = send_buffer; datalength = send_buffer.Length; send_buffer = null; } var unit_len = Server.tcp_mss - Server.overhead; var ogn_datalength = datalength; if (!has_sent_header) { var _datalength = Math.Min(1200, datalength); PackAuthData(data, _datalength, packdata, out var outlen); has_sent_header = true; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= _datalength; var newdata = new byte[datalength]; Array.Copy(data, _datalength, newdata, 0, newdata.Length); data = newdata; send_buffer = data.Length > 0 ? data : null; return outdata; } if (datalength > 120 * 4 && pack_id < 32) { var send_len = LinearRandomInt(120 * 16); if (send_len < datalength) { send_len = TrapezoidRandomInt(Math.Min(datalength - 1, Server.tcp_mss - overhead) - 1, -0.3) + 1; // must less than datalength send_len = datalength - send_len; if (send_len > 0) { send_buffer = new byte[send_len]; Array.Copy(data, datalength - send_len, send_buffer, 0, send_len); datalength -= send_len; } } } while (datalength > unit_len) { PackData(data, unit_len, packdata, out var outlen); Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= unit_len; var newdata = new byte[datalength]; Array.Copy(data, unit_len, newdata, 0, newdata.Length); data = newdata; } if (datalength > 0 || ogn_datalength == -1) { if (ogn_datalength == -1) { datalength = 0; } PackData(data, datalength, packdata, out var outlen); Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; } last_datalength = ogn_datalength; return outdata; } public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[recv_buf_len + datalength]; Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength); recv_buf_len += datalength; outlength = 0; var key = new byte[user_key.Length + 4]; user_key.CopyTo(key, 0); while (recv_buf_len > 4) { BitConverter.GetBytes(recv_id).CopyTo(key, key.Length - 4); using var md5 = CreateHMAC(key); var data_len = ((recv_buf[1] ^ last_server_hash[15]) << 8) + (recv_buf[0] ^ last_server_hash[14]); var rand_len = GetRecvRandLen(data_len, random_server, last_server_hash); var len = rand_len + data_len; if (len >= 4096) { throw new ObfsException("ClientPostDecrypt data error"); } if (len + 4 > recv_buf_len) { break; } md5.Update(recv_buf.AsSpan(0, len + 2)); var md5data = new byte[md5.Length]; md5.GetMac(md5data); if (md5data[0] != recv_buf[len + 2] || md5data[1] != recv_buf[len + 3] ) { throw new ObfsException("ClientPostDecrypt data uncorrect checksum"); } { var pos = 2; var outlen = data_len; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); var data = new byte[outlen]; Array.Copy(recv_buf, pos, data, 0, outlen); encryptor.Decrypt(data, outlen, data, out outlen); last_server_hash = md5data; if (recv_id == 1) { Server.tcp_mss = recv_tcp_mss = data[0] | (data[1] << 8); pos = 2; outlen -= 2; send_back_cmd.Add(0xff00); } else { pos = 0; } Array.Copy(data, pos, outdata, outlength, outlen); outlength += outlen; recv_buf_len -= len + 4; Array.Copy(recv_buf, len + 4, recv_buf, 0, recv_buf_len); ++recv_id; } } return outdata; } public override byte[] ClientUdpPreEncrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[datalength + 1024]; if (user_key == null) { user_id = new byte[4]; var index_of_split = Server.param.IndexOf(':'); if (index_of_split > 0) { try { var user = uint.Parse(Server.param.Substring(0, index_of_split)); user_key = System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1)); BitConverter.GetBytes(user).CopyTo(user_id, 0); } catch (Exception ex) { Logging.Log(LogLevel.Warn, $"Faild to parse auth param, fallback to basic mode. {ex}"); } } if (user_key == null) { random.NextBytes(user_id); user_key = Server.key; } } var auth_data = new byte[3]; random.NextBytes(auth_data); using var md5 = CreateHMAC(Server.key); md5.Update(auth_data); var md5data = new byte[md5.Length]; md5.GetMac(md5data); var rand_len = UdpGetRandLen(random_client, md5data); var rand_data = new byte[rand_len]; random.NextBytes(rand_data); outlength = datalength + rand_len + 8; encryptor = (StreamEncryptor)EncryptorFactory.GetEncryptor("chacha20", Convert.ToBase64String(user_key) + Convert.ToBase64String(md5data, 0, 16)); { var iv = new byte[8]; Array.Copy(Server.key, iv, 8); encryptor.SetIV(iv); } encryptor.Encrypt(plaindata, datalength, outdata, out datalength); rand_data.CopyTo(outdata, datalength); auth_data.CopyTo(outdata, outlength - 8); var uid = new byte[4]; for (var i = 0; i < 4; ++i) { uid[i] = (byte)(user_id[i] ^ md5data[i]); } uid.CopyTo(outdata, outlength - 5); { using var userMd5 = CreateHMAC(user_key); userMd5.Update(outdata.AsSpan(0, outlength - 1)); Span span = stackalloc byte[userMd5.Length]; userMd5.GetMac(span); outdata[outlength - 1] = span[0]; } return outdata; } public override byte[] ClientUdpPostDecrypt(byte[] plaindata, int datalength, out int outlength) { if (datalength <= 8) { outlength = 0; return plaindata; } using var md5 = CreateHMAC(user_key); md5.Update(plaindata.AsSpan(0, datalength - 1)); var md5data = new byte[md5.Length]; md5.GetMac(md5data); if (md5data[0] != plaindata[datalength - 1]) { outlength = 0; return plaindata; } using var serverMd5 = CreateHMAC(Server.key); serverMd5.Update(plaindata.AsSpan(datalength - 8, 7)); serverMd5.GetMac(md5data); var rand_len = UdpGetRandLen(random_server, md5data); outlength = datalength - rand_len - 8; encryptor = (StreamEncryptor)EncryptorFactory.GetEncryptor("chacha20", Convert.ToBase64String(user_key) + Convert.ToBase64String(md5data, 0, 16)); { var iv = new byte[8]; Array.Copy(Server.key, iv, 8); encryptor.Decrypt(iv, 8, plaindata, out _); } encryptor.Decrypt(plaindata, outlength, plaindata, out outlength); return plaindata; } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthAkarin_spec_a.cs ================================================ using System.Collections.Generic; namespace Shadowsocks.Obfs { class AuthAkarin_spec_a : AuthAkarin { public AuthAkarin_spec_a(string method) : base(method) { } private static Dictionary _obfs = new() { { "auth_akarin_spec_a", new[] { 1, 0, 1 } } }; protected int[] data_size_list; protected int[] data_size_list2; public static new List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } protected void InitDataSizeList() { var rd = new xorshift128plus(0); rd.init_from_bin(Server.key); var len = (int)(rd.next() % 8 + 4); var data_list = new List(); for (var i = 0; i < len; ++i) { data_list.Add((int)(rd.next() % 2340 % 2040 % 1440)); } data_list.Sort(); data_size_list = data_list.ToArray(); len = (int)(rd.next() % 16 + 8); data_list.Clear(); for (var i = 0; i < len; ++i) { data_list.Add((int)(rd.next() % 2340 % 2040 % 1440)); } data_list.Sort(); data_size_list2 = data_list.ToArray(); } public override void SetServerInfo(ServerInfo serverInfo) { Server = serverInfo; InitDataSizeList(); } protected int FindPos(int[] arr, int key) { var low = 0; var high = arr.Length - 1; if (key > arr[high]) { return arr.Length; } while (low < high) { var middle = (low + high) / 2; if (key > arr[middle]) { low = middle + 1; } else if (key <= arr[middle]) { high = middle; } } return low; } protected override int GetSendRandLen(int datalength, xorshift128plus rd, byte[] last_hash) { if (datalength + Server.overhead > send_tcp_mss) { rd.init_from_bin(last_hash, datalength); return (int)(rd.next() % 521); } if (datalength >= 1440 || datalength + Server.overhead == recv_tcp_mss) { return 0; } rd.init_from_bin(last_hash, datalength); var pos = FindPos(data_size_list, datalength + Server.overhead); var final_pos = pos + (int)(rd.next() % (ulong)data_size_list.Length); if (final_pos < data_size_list.Length) { return data_size_list[final_pos] - datalength - Server.overhead; } pos = FindPos(data_size_list2, datalength + Server.overhead); final_pos = pos + (int)(rd.next() % (ulong)data_size_list2.Length); if (final_pos < data_size_list2.Length) { return data_size_list2[final_pos] - datalength - Server.overhead; } if (final_pos < pos + data_size_list2.Length - 1) { return 0; } if (datalength > 1300) { return (int)(rd.next() % 31); } if (datalength > 900) { return (int)(rd.next() % 127); } if (datalength > 400) { return (int)(rd.next() % 521); } return (int)(rd.next() % 1021); } protected override int GetRecvRandLen(int datalength, xorshift128plus rd, byte[] last_hash) { if (datalength + Server.overhead > recv_tcp_mss) { rd.init_from_bin(last_hash, datalength); return (int)(rd.next() % 521); } if (datalength >= 1440 || datalength + Server.overhead == recv_tcp_mss) { return 0; } rd.init_from_bin(last_hash, datalength); var pos = FindPos(data_size_list, datalength + Server.overhead); var final_pos = pos + (int)(rd.next() % (ulong)data_size_list.Length); if (final_pos < data_size_list.Length) { return data_size_list[final_pos] - datalength - Server.overhead; } pos = FindPos(data_size_list2, datalength + Server.overhead); final_pos = pos + (int)(rd.next() % (ulong)data_size_list2.Length); if (final_pos < data_size_list2.Length) { return data_size_list2[final_pos] - datalength - Server.overhead; } if (final_pos < pos + data_size_list2.Length - 1) { return 0; } if (datalength > 1300) { return (int)(rd.next() % 31); } if (datalength > 900) { return (int)(rd.next() % 127); } if (datalength > 400) { return (int)(rd.next() % 521); } return (int)(rd.next() % 1021); } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthChain_a.cs ================================================ using CryptoBase.Abstractions; using CryptoBase.Digests; using CryptoBase.Macs.Hmac; using Shadowsocks.Controller; using Shadowsocks.Encryption; using Shadowsocks.Enums; using System; using System.Collections.Generic; using System.Security.Cryptography; namespace Shadowsocks.Obfs { class AuthChain_a : VerifySimpleBase { protected class AuthDataAesChain : AuthData { } public AuthChain_a(string method) : base(method) { has_sent_header = false; has_recv_header = false; pack_id = 1; recv_id = 1; SALT = method; random = new Random(RandomNumberGenerator.GetInt32(int.MaxValue)); } private static Dictionary _obfs = new() { { "auth_chain_a", new[] { 1, 0, 1 } } }; protected bool has_sent_header; protected bool has_recv_header; protected string SALT; protected uint pack_id; protected uint recv_id; protected byte[] user_key; protected byte[] user_id; protected byte[] send_buffer; protected int last_datalength; protected byte[] last_client_hash; protected byte[] last_server_hash; protected xorshift128plus random_client = new(); protected xorshift128plus random_server = new(); protected IEncryptor encryptor; protected const int overhead = 4; public static List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } protected override void Disposing() { if (encryptor != null) { encryptor.Dispose(); encryptor = null; } } public override object InitData() { return new AuthDataAesChain(); } public override bool isKeepAlive() { return true; } public override bool isAlwaysSendback() { return true; } public override int GetOverhead() { return overhead; } protected IMac CreateHMAC(byte[] key) { return HmacUtils.Create(DigestType.Md5, key); } protected virtual int GetRandLen(int datalength, xorshift128plus rd, byte[] last_hash) { if (datalength > 1440) { return 0; } rd.init_from_bin(last_hash, datalength); if (datalength > 1300) { return (int)(rd.next() % 31); } if (datalength > 900) { return (int)(rd.next() % 127); } if (datalength > 400) { return (int)(rd.next() % 521); } return (int)(rd.next() % 1021); } protected int UdpGetRandLen(xorshift128plus rd, byte[] last_hash) { rd.init_from_bin(last_hash); return (int)(rd.next() % 127); } protected int GetRandStartPos(int rand_len, xorshift128plus rd) { if (rand_len > 0) { return (int)(rd.next() % 8589934609 % (ulong)rand_len); } return 0; } protected int GetRandLen(int datalength) { return GetRandLen(datalength, random_client, last_client_hash); } public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength) { var rand_len = GetRandLen(datalength); outlength = rand_len + datalength + 2; outdata[0] = (byte)(datalength ^ last_client_hash[14]); outdata[1] = (byte)((datalength >> 8) ^ last_client_hash[15]); { var rnd_data = new byte[rand_len]; random.NextBytes(rnd_data); encryptor.Encrypt(data, datalength, data, out datalength); if (datalength > 0) { if (rand_len > 0) { var start_pos = GetRandStartPos(rand_len, random_client); Array.Copy(data, 0, outdata, 2 + start_pos, datalength); Array.Copy(rnd_data, 0, outdata, 2, start_pos); Array.Copy(rnd_data, start_pos, outdata, 2 + start_pos + datalength, rand_len - start_pos); } else { Array.Copy(data, 0, outdata, 2, datalength); } } else { rnd_data.CopyTo(outdata, 2); } } var key = new byte[user_key.Length + 4]; user_key.CopyTo(key, 0); BitConverter.GetBytes(pack_id).CopyTo(key, key.Length - 4); using var md5 = CreateHMAC(key); ++pack_id; { md5.Update(outdata.AsSpan(0, outlength)); var md5data = new byte[md5.Length]; md5.GetMac(md5data); last_client_hash = md5data; md5data[..2].CopyTo(outdata.AsSpan(outlength, 2)); outlength += 2; } } public virtual void OnInitAuthData(ulong unixTimestamp) { } public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength) { const int authhead_len = 4 + 8 + 4 + 16 + 4; var encrypt = new byte[24]; if (Server.data is AuthDataAesChain authData) { lock (authData) { if (authData.connectionID > 0xFF000000) { authData.clientID = null; } if (authData.clientID == null) { authData.clientID = RandomNumberGenerator.GetBytes(4); authData.connectionID = (uint)BitConverter.ToInt32(authData.clientID, 0) % 0xFFFFFD; } authData.connectionID += 1; Array.Copy(authData.clientID, 0, encrypt, 4, 4); Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, encrypt, 8, 4); } } outlength = authhead_len; var encrypt_data = new byte[32]; var key = new byte[Server.Iv.Length + Server.key.Length]; Server.Iv.CopyTo(key, 0); Server.key.CopyTo(key, Server.Iv.Length); var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); var utc_time = (uint)utc_time_second; Array.Copy(BitConverter.GetBytes(utc_time), 0, encrypt, 0, 4); OnInitAuthData(utc_time_second); encrypt[12] = (byte)Server.overhead; encrypt[13] = (byte)(Server.overhead >> 8); // first 12 bytes { Span rnd = stackalloc byte[4]; RandomNumberGenerator.Fill(rnd); rnd.CopyTo(outdata); using var md5 = CreateHMAC(key); md5.Update(rnd); var md5data = new byte[md5.Length]; md5.GetMac(md5data); last_client_hash = md5data; md5data[..8].CopyTo(outdata.AsSpan(rnd.Length, 8)); } // uid & 16 bytes auth data { var uid = new byte[4]; var index_of_split = Server.param.IndexOf(':'); if (index_of_split > 0) { try { var user = uint.Parse(Server.param.Substring(0, index_of_split)); user_key = System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1)); BitConverter.GetBytes(user).CopyTo(uid, 0); } catch (Exception ex) { Logging.Log(LogLevel.Warn, $"Faild to parse auth param, fallback to basic mode. {ex}"); } } if (user_key == null) { random.NextBytes(uid); user_key = Server.key; } for (var i = 0; i < 4; ++i) { uid[i] ^= last_client_hash[8 + i]; } var encrypt_key = user_key; CryptoUtils.SsAes128(Convert.ToBase64String(encrypt_key) + SALT, encrypt.AsSpan(0, 16), encrypt_data.AsSpan(0, 16)); Array.Copy(encrypt_data, 0, encrypt, 4, 16); uid.CopyTo(encrypt, 0); } // final HMAC { using var md5 = CreateHMAC(user_key); md5.Update(encrypt.AsSpan(0, 20)); var md5data = new byte[md5.Length]; md5.GetMac(md5data); last_server_hash = md5data; md5data[..4].CopyTo(encrypt.AsSpan(20, 4)); } encrypt.CopyTo(outdata, 12); encryptor = EncryptorFactory.GetEncryptor("rc4", Convert.ToBase64String(user_key) + Convert.ToBase64String(last_client_hash, 0, 16)); // combine first chunk { var pack_outdata = new byte[outdata.Length]; PackData(data, datalength, pack_outdata, out var pack_outlength); Array.Copy(pack_outdata, 0, outdata, outlength, pack_outlength); outlength += pack_outlength; } } // plaindata == null try send buffer data, return null if empty buffer // datalength == 0 sendback, return 0 // datalength == -1 keepalive public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[datalength + datalength / 10 + 32]; var packdata = new byte[9000]; var data = plaindata == null ? send_buffer : plaindata; outlength = 0; if (data == null) { return null; } if (data == send_buffer) { datalength = send_buffer.Length; send_buffer = null; } else if (send_buffer != null) { if (datalength <= 0) { return outdata; } Array.Resize(ref send_buffer, send_buffer.Length + datalength); Array.Copy(data, 0, send_buffer, send_buffer.Length - datalength, datalength); data = send_buffer; datalength = send_buffer.Length; send_buffer = null; } var unit_len = Server.tcp_mss - Server.overhead; var ogn_datalength = datalength; if (!has_sent_header) { var _datalength = Math.Min(1200, datalength); PackAuthData(data, _datalength, packdata, out var outlen); has_sent_header = true; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= _datalength; var newdata = new byte[datalength]; Array.Copy(data, _datalength, newdata, 0, newdata.Length); data = newdata; send_buffer = data.Length > 0 ? data : null; return outdata; } if (datalength > 120 * 4 && pack_id < 32) { var send_len = LinearRandomInt(120 * 16); if (send_len < datalength) { send_len = TrapezoidRandomInt(Math.Min(datalength - 1, Server.tcp_mss - overhead) - 1, -0.3) + 1; // must less than datalength send_len = datalength - send_len; if (send_len > 0) { send_buffer = new byte[send_len]; Array.Copy(data, datalength - send_len, send_buffer, 0, send_len); datalength -= send_len; } } } while (datalength > unit_len) { PackData(data, unit_len, packdata, out var outlen); Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= unit_len; var newdata = new byte[datalength]; Array.Copy(data, unit_len, newdata, 0, newdata.Length); data = newdata; } if (datalength > 0 || ogn_datalength == -1) { if (ogn_datalength == -1) { datalength = 0; } PackData(data, datalength, packdata, out var outlen); Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; } last_datalength = ogn_datalength; return outdata; } public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[recv_buf_len + datalength]; Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength); recv_buf_len += datalength; outlength = 0; var key = new byte[user_key.Length + 4]; user_key.CopyTo(key, 0); while (recv_buf_len > 4) { BitConverter.GetBytes(recv_id).CopyTo(key, key.Length - 4); using var md5 = CreateHMAC(key); var data_len = ((recv_buf[1] ^ last_server_hash[15]) << 8) + (recv_buf[0] ^ last_server_hash[14]); var rand_len = GetRandLen(data_len, random_server, last_server_hash); var len = rand_len + data_len; if (len >= 4096) { throw new ObfsException("ClientPostDecrypt data error"); } if (len + 4 > recv_buf_len) { break; } md5.Update(recv_buf.AsSpan(0, len + 2)); var md5data = new byte[md5.Length]; md5.GetMac(md5data); if (md5data[0] != recv_buf[len + 2] || md5data[1] != recv_buf[len + 3] ) { throw new ObfsException("ClientPostDecrypt data uncorrect checksum"); } { int pos; if (data_len > 0 && rand_len > 0) { pos = 2 + GetRandStartPos(rand_len, random_server); } else { pos = 2; } var outlen = data_len; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); var data = new byte[outlen]; Array.Copy(recv_buf, pos, data, 0, outlen); encryptor.Decrypt(data, outlen, data, out outlen); last_server_hash = md5data; if (recv_id == 1) { Server.tcp_mss = data[0] | (data[1] << 8); pos = 2; outlen -= 2; } else { pos = 0; } Array.Copy(data, pos, outdata, outlength, outlen); outlength += outlen; recv_buf_len -= len + 4; Array.Copy(recv_buf, len + 4, recv_buf, 0, recv_buf_len); ++recv_id; } } return outdata; } public override byte[] ClientUdpPreEncrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[datalength + 1024]; if (user_key == null) { user_id = new byte[4]; var index_of_split = Server.param.IndexOf(':'); if (index_of_split > 0) { try { var user = uint.Parse(Server.param.Substring(0, index_of_split)); user_key = System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1)); BitConverter.GetBytes(user).CopyTo(user_id, 0); } catch (Exception ex) { Logging.Log(LogLevel.Warn, $"Faild to parse auth param, fallback to basic mode. {ex}"); } } if (user_key == null) { random.NextBytes(user_id); user_key = Server.key; } } var auth_data = new byte[3]; random.NextBytes(auth_data); using var md5 = CreateHMAC(Server.key); md5.Update(auth_data); var md5data = new byte[md5.Length]; md5.GetMac(md5data); var rand_len = UdpGetRandLen(random_client, md5data); var rand_data = new byte[rand_len]; random.NextBytes(rand_data); outlength = datalength + rand_len + 8; encryptor = EncryptorFactory.GetEncryptor("rc4", Convert.ToBase64String(user_key) + Convert.ToBase64String(md5data, 0, 16)); encryptor.Encrypt(plaindata, datalength, outdata, out datalength); rand_data.CopyTo(outdata, datalength); auth_data.CopyTo(outdata, outlength - 8); var uid = new byte[4]; for (var i = 0; i < 4; ++i) { uid[i] = (byte)(user_id[i] ^ md5data[i]); } uid.CopyTo(outdata, outlength - 5); { using var userMd5 = CreateHMAC(user_key); userMd5.Update(outdata.AsSpan(0, outlength - 1)); Span span = stackalloc byte[userMd5.Length]; userMd5.GetMac(span); outdata[outlength - 1] = span[0]; } return outdata; } public override byte[] ClientUdpPostDecrypt(byte[] plaindata, int datalength, out int outlength) { if (datalength <= 8) { outlength = 0; return plaindata; } using var md5 = CreateHMAC(user_key); md5.Update(plaindata.AsSpan(0, datalength - 1)); var md5data = new byte[md5.Length]; md5.GetMac(md5data); if (md5data[0] != plaindata[datalength - 1]) { outlength = 0; return plaindata; } using var serverMd5 = CreateHMAC(Server.key); serverMd5.Update(plaindata.AsSpan(datalength - 8, 7)); serverMd5.GetMac(md5data); var rand_len = UdpGetRandLen(random_server, md5data); outlength = datalength - rand_len - 8; encryptor = EncryptorFactory.GetEncryptor("rc4", Convert.ToBase64String(user_key) + Convert.ToBase64String(md5data, 0, 16)); encryptor.Decrypt(plaindata, outlength, plaindata, out outlength); return plaindata; } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthChain_b.cs ================================================ using System.Collections.Generic; namespace Shadowsocks.Obfs { class AuthChain_b : AuthChain_a { public AuthChain_b(string method) : base(method) { } private static Dictionary _obfs = new() { { "auth_chain_b", new[] { 1, 0, 1 } } }; protected int[] data_size_list; protected int[] data_size_list2; public static new List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } protected virtual void InitDataSizeList() { var rd = new xorshift128plus(); rd.init_from_bin(Server.key); var len = (int)(rd.next() % 8 + 4); var data_list = new List(); for (var i = 0; i < len; ++i) { data_list.Add((int)(rd.next() % 2340 % 2040 % 1440)); } data_list.Sort(); data_size_list = data_list.ToArray(); len = (int)(rd.next() % 16 + 8); data_list.Clear(); for (var i = 0; i < len; ++i) { data_list.Add((int)(rd.next() % 2340 % 2040 % 1440)); } data_list.Sort(); data_size_list2 = data_list.ToArray(); } public override void SetServerInfo(ServerInfo serverInfo) { Server = serverInfo; InitDataSizeList(); } protected int FindPos(int[] arr, int key) { var low = 0; var high = arr.Length - 1; if (key > arr[high]) { return arr.Length; } while (low < high) { var middle = (low + high) / 2; if (key > arr[middle]) { low = middle + 1; } else if (key <= arr[middle]) { high = middle; } } return low; } protected override int GetRandLen(int datalength, xorshift128plus rd, byte[] last_hash) { if (datalength >= 1440) { return 0; } rd.init_from_bin(last_hash, datalength); var pos = FindPos(data_size_list, datalength + Server.overhead); var final_pos = pos + (int)(rd.next() % (ulong)data_size_list.Length); if (final_pos < data_size_list.Length) { return data_size_list[final_pos] - datalength - Server.overhead; } pos = FindPos(data_size_list2, datalength + Server.overhead); final_pos = pos + (int)(rd.next() % (ulong)data_size_list2.Length); if (final_pos < data_size_list2.Length) { return data_size_list2[final_pos] - datalength - Server.overhead; } if (final_pos < pos + data_size_list2.Length - 1) { return 0; } if (datalength > 1300) { return (int)(rd.next() % 31); } if (datalength > 900) { return (int)(rd.next() % 127); } if (datalength > 400) { return (int)(rd.next() % 521); } return (int)(rd.next() % 1021); } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthChain_c.cs ================================================ using System.Collections.Generic; namespace Shadowsocks.Obfs { class AuthChain_c : AuthChain_b { public AuthChain_c(string method) : base(method) { } private static Dictionary _obfs = new() { { "auth_chain_c", new[] { 1, 0, 1 } } }; protected int[] data_size_list0; public static new List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } protected override void InitDataSizeList() { var rd = new xorshift128plus(); rd.init_from_bin(Server.key); var len = (int)(rd.next() % (8 + 16) + (4 + 8)); var data_list = new List(); for (var i = 0; i < len; ++i) { data_list.Add((int)(rd.next() % 2340 % 2040 % 1440)); } data_list.Sort(); data_size_list0 = data_list.ToArray(); } public override void SetServerInfo(ServerInfo serverInfo) { Server = serverInfo; InitDataSizeList(); } protected override int GetRandLen(int datalength, xorshift128plus rd, byte[] last_hash) { var other_data_size = datalength + Server.overhead; // 一定要在random使用前初始化,以保证服务器与客户端同步,保证包大小验证结果正确 rd.init_from_bin(last_hash, datalength); if (other_data_size >= data_size_list0[data_size_list0.Length - 1]) { if (datalength >= 1440) { return 0; } if (datalength > 1300) { return (int)(rd.next() % 31); } if (datalength > 900) { return (int)(rd.next() % 127); } if (datalength > 400) { return (int)(rd.next() % 521); } return (int)(rd.next() % 1021); } var pos = FindPos(data_size_list0, other_data_size); var final_pos = pos + (int)(rd.next() % (ulong)(data_size_list0.Length - pos)); return data_size_list0[final_pos] - other_data_size; } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthChain_d.cs ================================================ using System.Collections.Generic; namespace Shadowsocks.Obfs { class AuthChain_d : AuthChain_c { public AuthChain_d(string method) : base(method) { } private static Dictionary _obfs = new() { { "auth_chain_d", new[] { 1, 0, 1 } } }; public static new List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } protected void CheckAndPatchDataSize(List data_list, xorshift128plus rd) { if (data_list[data_list.Count - 1] < 1300 && data_list.Count < 64) { data_list.Add((int)(rd.next() % 2340 % 2040 % 1440)); CheckAndPatchDataSize(data_list, rd); } } protected override void InitDataSizeList() { var rd = new xorshift128plus(); rd.init_from_bin(Server.key); var len = (int)(rd.next() % (8 + 16) + (4 + 8)); var data_list = new List(); for (var i = 0; i < len; ++i) { data_list.Add((int)(rd.next() % 2340 % 2040 % 1440)); } data_list.Sort(); var old_len = data_list.Count; CheckAndPatchDataSize(data_list, rd); if (old_len != data_list.Count) { data_list.Sort(); } data_size_list0 = data_list.ToArray(); } public override void SetServerInfo(ServerInfo serverInfo) { Server = serverInfo; InitDataSizeList(); } protected override int GetRandLen(int datalength, xorshift128plus rd, byte[] last_hash) { var other_data_size = datalength + Server.overhead; if (other_data_size >= data_size_list0[data_size_list0.Length - 1]) { return 0; } rd.init_from_bin(last_hash, datalength); var pos = FindPos(data_size_list0, other_data_size); var final_pos = pos + (int)(rd.next() % (ulong)(data_size_list0.Length - pos)); return data_size_list0[final_pos] - other_data_size; } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthChain_e.cs ================================================ using System.Collections.Generic; namespace Shadowsocks.Obfs { class AuthChain_e : AuthChain_d { public AuthChain_e(string method) : base(method) { } private static Dictionary _obfs = new() { { "auth_chain_e", new[] { 1, 0, 1 } } }; public static new List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } protected override int GetRandLen(int datalength, xorshift128plus rd, byte[] last_hash) { rd.init_from_bin(last_hash, datalength); var other_data_size = datalength + Server.overhead; if (other_data_size >= data_size_list0[data_size_list0.Length - 1]) { return 0; } var pos = FindPos(data_size_list0, other_data_size); return data_size_list0[pos] - other_data_size; } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthChain_f.cs ================================================ using System; using System.Collections.Generic; namespace Shadowsocks.Obfs { class AuthChain_f : AuthChain_e { public AuthChain_f(string method) : base(method) { } private static Dictionary _obfs = new() { { "auth_chain_f", new[] { 1, 0, 1 } } }; public static new List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } protected ulong key_change_interval = 60 * 60 * 24; // a day by second protected ulong key_change_datetime_key; protected List key_change_datetime_key_bytes = new(); protected override void InitDataSizeList() { var rd = new xorshift128plus(); var newKey = new byte[Server.key.Length]; Server.key.CopyTo(newKey, 0); for (var i = 0; i < 8; i++) { newKey[i] ^= key_change_datetime_key_bytes[i]; } rd.init_from_bin(newKey); var len = (int)(rd.next() % (8 + 16) + (4 + 8)); var data_list = new List(); for (var i = 0; i < len; ++i) { data_list.Add((int)(rd.next() % 2340 % 2040 % 1440)); } data_list.Sort(); var old_len = data_list.Count; CheckAndPatchDataSize(data_list, rd); if (old_len != data_list.Count) { data_list.Sort(); } data_size_list0 = data_list.ToArray(); } public override void SetServerInfo(ServerInfo serverInfo) { Server = serverInfo; var protocalParams = serverInfo.param; if (protocalParams != "") { if (-1 != protocalParams.IndexOf("#", StringComparison.Ordinal)) { protocalParams = protocalParams.Split('#')[1]; } if (ulong.TryParse(protocalParams, out var interval)) { key_change_interval = interval; } } } public override void OnInitAuthData(ulong unixTimestamp) { key_change_datetime_key = unixTimestamp / key_change_interval; for (var i = 7; i > -1; --i) { var b = (byte)(key_change_datetime_key >> (8 * i) & 0xFF); key_change_datetime_key_bytes.Add(b); } InitDataSizeList(); } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthData.cs ================================================ namespace Shadowsocks.Obfs { public class AuthData : VerifyData { public byte[] clientID; public uint connectionID; } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthSHA1.cs ================================================ using CryptoBase.Digests; using CryptoBase.Macs.Hmac; using System; using System.Collections.Generic; using System.Security.Cryptography; namespace Shadowsocks.Obfs { public class AuthSHA1 : VerifySimpleBase { public AuthSHA1(string method) : base(method) { has_sent_header = false; has_recv_header = false; } private static Dictionary _obfs = new() { { "auth_sha1", new[] { 1, 0, 1 } } }; protected bool has_sent_header; protected bool has_recv_header; public static List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } public override object InitData() { return new AuthData(); } public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength) { var rand_len = datalength > 1300 ? 1 : LinearRandomInt(64) + 1; outlength = rand_len + datalength + 6; if (datalength > 0) { Array.Copy(data, 0, outdata, rand_len + 2, datalength); } outdata[0] = (byte)(outlength >> 8); outdata[1] = (byte)outlength; outdata[2] = (byte)rand_len; var adler = Util.Adler32.CalcAdler32(outdata, outlength - 4); BitConverter.GetBytes((uint)adler).CopyTo(outdata, outlength - 4); } public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength) { var rand_len = LinearRandomInt(250) + 1; var data_offset = rand_len + 4 + 2; outlength = data_offset + datalength + 12 + 10; var authData = (AuthData)Server.data; lock (authData) { if (authData.connectionID > 0xFF000000) { authData.clientID = null; } if (authData.clientID == null) { authData.clientID = RandomNumberGenerator.GetBytes(4); authData.connectionID = (uint)LinearRandomInt(0x1000000); } authData.connectionID += 1; Array.Copy(authData.clientID, 0, outdata, data_offset + 4, 4); Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, outdata, data_offset + 8, 4); } var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); var utc_time = (uint)utc_time_second; Array.Copy(BitConverter.GetBytes(utc_time), 0, outdata, data_offset, 4); Array.Copy(data, 0, outdata, data_offset + 12, datalength); outdata[4] = (byte)(outlength >> 8); outdata[5] = (byte)outlength; outdata[6] = (byte)rand_len; var crc32 = Util.CRC32.CalcCRC32(Server.key, Server.key.Length); BitConverter.GetBytes((uint)crc32).CopyTo(outdata, 0); Span key = new byte[Server.Iv.Length + Server.key.Length]; Server.Iv.AsSpan().CopyTo(key); Server.key.AsSpan().CopyTo(key[Server.Iv.Length..]); using var hmac = HmacUtils.Create(DigestType.Sha1, key); hmac.Update(outdata.AsSpan(0, outlength - 10)); Span hash = stackalloc byte[hmac.Length]; hmac.GetMac(hash); hash[..10].CopyTo(outdata.AsSpan(outlength - 10, 10)); } public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength) { if (plaindata == null) { outlength = 0; return null; } var outdata = new byte[datalength + datalength / 10 + 32]; var packdata = new byte[9000]; var data = plaindata; outlength = 0; const int unit_len = 8100; if (!has_sent_header) { var headsize = GetHeadSize(plaindata, 30); var _datalength = Math.Min(LinearRandomInt(32) + headsize, datalength); PackAuthData(data, _datalength, packdata, out var outlen); has_sent_header = true; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= _datalength; var newdata = new byte[datalength]; Array.Copy(data, _datalength, newdata, 0, newdata.Length); data = newdata; } while (datalength > unit_len) { PackData(data, unit_len, packdata, out var outlen); Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= unit_len; var newdata = new byte[datalength]; Array.Copy(data, unit_len, newdata, 0, newdata.Length); data = newdata; } if (datalength > 0) { PackData(data, datalength, packdata, out var outlen); Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; } return outdata; } public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[recv_buf_len + datalength]; Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength); recv_buf_len += datalength; outlength = 0; while (recv_buf_len > 2) { var len = (recv_buf[0] << 8) + recv_buf[1]; if (len is >= 8192 or < 7) { throw new ObfsException("ClientPostDecrypt data error"); } if (len > recv_buf_len) { break; } if (Util.Adler32.CheckAdler32(recv_buf, len)) { var pos = recv_buf[2] + 2; var outlen = len - pos - 4; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(recv_buf, pos, outdata, outlength, outlen); outlength += outlen; recv_buf_len -= len; Array.Copy(recv_buf, len, recv_buf, 0, recv_buf_len); } else { throw new ObfsException("ClientPostDecrypt data uncorrect checksum"); } } return outdata; } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthSHA1V2.cs ================================================ using CryptoBase.Digests; using CryptoBase.Macs.Hmac; using System; using System.Collections.Generic; using System.Security.Cryptography; namespace Shadowsocks.Obfs { public class AuthSHA1V2 : VerifySimpleBase { public AuthSHA1V2(string method) : base(method) { has_sent_header = false; has_recv_header = false; } private static Dictionary _obfs = new() { { "auth_sha1_v2", new[] { 1, 0, 1 } } }; protected bool has_sent_header; protected bool has_recv_header; public static List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } public override object InitData() { return new AuthData(); } public override bool isKeepAlive() { return true; } public override bool isAlwaysSendback() { return true; } public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength) { var rand_len = (datalength >= 1300 ? 0 : datalength > 400 ? LinearRandomInt(128) : LinearRandomInt(1024)) + 1; outlength = rand_len + datalength + 6; if (datalength > 0) { Array.Copy(data, 0, outdata, rand_len + 2, datalength); } outdata[0] = (byte)(outlength >> 8); outdata[1] = (byte)outlength; { var rnd_data = new byte[rand_len]; random.NextBytes(rnd_data); rnd_data.CopyTo(outdata, 2); } if (rand_len < 128) { outdata[2] = (byte)rand_len; } else { outdata[2] = 0xFF; outdata[3] = (byte)(rand_len >> 8); outdata[4] = (byte)rand_len; } var adler = Util.Adler32.CalcAdler32(outdata, outlength - 4); BitConverter.GetBytes((uint)adler).CopyTo(outdata, outlength - 4); } public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength) { var rand_len = (datalength > 400 ? LinearRandomInt(128) : LinearRandomInt(1024)) + 1; var data_offset = rand_len + 4 + 2; outlength = data_offset + datalength + 12 + 10; var authData = (AuthData)Server.data; { var rnd_data = new byte[rand_len]; random.NextBytes(rnd_data); rnd_data.CopyTo(outdata, data_offset - rand_len); } lock (authData) { if (authData.connectionID > 0xFF000000) { authData.clientID = null; } if (authData.clientID == null) { authData.clientID = RandomNumberGenerator.GetBytes(8); authData.connectionID = (uint)BitConverter.ToInt64(authData.clientID, 0) % 0xFFFFFD; } authData.connectionID += 1; Array.Copy(authData.clientID, 0, outdata, data_offset, 8); Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, outdata, data_offset + 8, 4); } Array.Copy(data, 0, outdata, data_offset + 12, datalength); outdata[4] = (byte)(outlength >> 8); outdata[5] = (byte)outlength; if (rand_len < 128) { outdata[6] = (byte)rand_len; } else { outdata[6] = 0xFF; outdata[7] = (byte)(rand_len >> 8); outdata[8] = (byte)rand_len; } var salt = System.Text.Encoding.UTF8.GetBytes("auth_sha1_v2"); var crcdata = new byte[salt.Length + Server.key.Length]; salt.CopyTo(crcdata, 0); Server.key.CopyTo(crcdata, salt.Length); var crc32 = Util.CRC32.CalcCRC32(crcdata, crcdata.Length); BitConverter.GetBytes((uint)crc32).CopyTo(outdata, 0); Span key = new byte[Server.Iv.Length + Server.key.Length]; Server.Iv.AsSpan().CopyTo(key); Server.key.AsSpan().CopyTo(key[Server.Iv.Length..]); using var hmac = HmacUtils.Create(DigestType.Sha1, key); hmac.Update(outdata.AsSpan(0, outlength - 10)); Span hash = stackalloc byte[hmac.Length]; hmac.GetMac(hash); hash[..10].CopyTo(outdata.AsSpan(outlength - 10, 10)); } public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength) { if (plaindata == null) { outlength = 0; return null; } var outdata = new byte[datalength + datalength / 10 + 32]; var packdata = new byte[9000]; var data = plaindata; outlength = 0; const int unit_len = 8100; var ogn_datalength = datalength; if (!has_sent_header) { var headsize = GetHeadSize(plaindata, 30); var _datalength = Math.Min(LinearRandomInt(32) + headsize, datalength); PackAuthData(data, _datalength, packdata, out var outlen); has_sent_header = true; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= _datalength; var newdata = new byte[datalength]; Array.Copy(data, _datalength, newdata, 0, newdata.Length); data = newdata; } while (datalength > unit_len) { PackData(data, unit_len, packdata, out var outlen); Util.Utils.SetArrayMinSize(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= unit_len; var newdata = new byte[datalength]; Array.Copy(data, unit_len, newdata, 0, newdata.Length); data = newdata; } if (datalength > 0 || ogn_datalength == -1) { if (ogn_datalength == -1) { datalength = 0; } PackData(data, datalength, packdata, out var outlen); Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; } return outdata; } public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[recv_buf_len + datalength]; Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength); recv_buf_len += datalength; outlength = 0; while (recv_buf_len > 2) { var len = (recv_buf[0] << 8) + recv_buf[1]; if (len is >= 8192 or < 8) { throw new ObfsException("ClientPostDecrypt data error"); } if (len > recv_buf_len) { break; } if (Util.Adler32.CheckAdler32(recv_buf, len)) { int pos = recv_buf[2]; if (pos < 255) { pos += 2; } else { pos = ((recv_buf[3] << 8) | recv_buf[4]) + 2; } var outlen = len - pos - 4; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(recv_buf, pos, outdata, outlength, outlen); outlength += outlen; recv_buf_len -= len; Array.Copy(recv_buf, len, recv_buf, 0, recv_buf_len); } else { throw new ObfsException("ClientPostDecrypt data uncorrect checksum"); } } return outdata; } } } ================================================ FILE: shadowsocks-csharp/Obfs/AuthSHA1V4.cs ================================================ using CryptoBase.Digests; using CryptoBase.Macs.Hmac; using System; using System.Collections.Generic; using System.Security.Cryptography; namespace Shadowsocks.Obfs { public class AuthSHA1V4 : VerifySimpleBase { public AuthSHA1V4(string method) : base(method) { has_sent_header = false; has_recv_header = false; } private static Dictionary _obfs = new() { { "auth_sha1_v4", new[] { 1, 0, 1 } } }; protected bool has_sent_header; protected bool has_recv_header; protected const string SALT = "auth_sha1_v4"; protected const int overhead = 9; public static List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } public override object InitData() { return new AuthData(); } public override bool isKeepAlive() { return true; } public override bool isAlwaysSendback() { return true; } public override int GetOverhead() { return overhead; } public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength) { var rand_len = (datalength > 1200 ? 0 : datalength > 400 ? LinearRandomInt(256) : LinearRandomInt(512)) + 1; outlength = rand_len + datalength + 8; if (datalength > 0) { Array.Copy(data, 0, outdata, rand_len + 4, datalength); } outdata[0] = (byte)(outlength >> 8); outdata[1] = (byte)outlength; var crc32 = Util.CRC32.CalcCRC32(outdata, 2); BitConverter.GetBytes((ushort)crc32).CopyTo(outdata, 2); { var rnd_data = new byte[rand_len]; random.NextBytes(rnd_data); rnd_data.CopyTo(outdata, 4); } if (rand_len < 128) { outdata[4] = (byte)rand_len; } else { outdata[4] = 0xFF; outdata[5] = (byte)(rand_len >> 8); outdata[6] = (byte)rand_len; } var adler = Util.Adler32.CalcAdler32(outdata, outlength - 4); BitConverter.GetBytes((uint)adler).CopyTo(outdata, outlength - 4); } public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength) { var rand_len = (datalength > 400 ? LinearRandomInt(128) : LinearRandomInt(1024)) + 1; var data_offset = rand_len + 4 + 2; outlength = data_offset + datalength + 12 + 10; var authData = (AuthData)Server.data; { var rnd_data = new byte[rand_len]; random.NextBytes(rnd_data); rnd_data.CopyTo(outdata, data_offset - rand_len); } lock (authData) { if (authData.connectionID > 0xFF000000) { authData.clientID = null; } if (authData.clientID == null) { authData.clientID = RandomNumberGenerator.GetBytes(4); authData.connectionID = (uint)BitConverter.ToInt32(authData.clientID, 0) % 0xFFFFFD; } authData.connectionID += 1; Array.Copy(authData.clientID, 0, outdata, data_offset + 4, 4); Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, outdata, data_offset + 8, 4); } var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); var utc_time = (uint)utc_time_second; Array.Copy(BitConverter.GetBytes(utc_time), 0, outdata, data_offset, 4); Array.Copy(data, 0, outdata, data_offset + 12, datalength); outdata[0] = (byte)(outlength >> 8); outdata[1] = (byte)outlength; if (rand_len < 128) { outdata[6] = (byte)rand_len; } else { outdata[6] = 0xFF; outdata[7] = (byte)(rand_len >> 8); outdata[8] = (byte)rand_len; } var salt = System.Text.Encoding.UTF8.GetBytes(SALT); var crcdata = new byte[salt.Length + Server.key.Length + 2]; salt.CopyTo(crcdata, 2); Server.key.CopyTo(crcdata, salt.Length + 2); crcdata[0] = outdata[0]; crcdata[1] = outdata[1]; var crc32 = Util.CRC32.CalcCRC32(crcdata, crcdata.Length); BitConverter.GetBytes((uint)crc32).CopyTo(outdata, 2); Span key = new byte[Server.Iv.Length + Server.key.Length]; Server.Iv.AsSpan().CopyTo(key); Server.key.AsSpan().CopyTo(key[Server.Iv.Length..]); using var hmac = HmacUtils.Create(DigestType.Sha1, key); hmac.Update(outdata.AsSpan(0, outlength - 10)); Span hash = stackalloc byte[hmac.Length]; hmac.GetMac(hash); hash[..10].CopyTo(outdata.AsSpan(outlength - 10, 10)); } public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength) { if (plaindata == null) { outlength = 0; return null; } var outdata = new byte[datalength + datalength / 10 + 32]; var packdata = new byte[9000]; var data = plaindata; outlength = 0; const int unit_len = 8100; var ogn_datalength = datalength; if (!has_sent_header) { var headsize = GetHeadSize(plaindata, 30); var _datalength = Math.Min(LinearRandomInt(32) + headsize, datalength); PackAuthData(data, _datalength, packdata, out var outlen); has_sent_header = true; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= _datalength; var newdata = new byte[datalength]; Array.Copy(data, _datalength, newdata, 0, newdata.Length); data = newdata; } while (datalength > unit_len) { PackData(data, unit_len, packdata, out var outlen); Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= unit_len; var newdata = new byte[datalength]; Array.Copy(data, unit_len, newdata, 0, newdata.Length); data = newdata; } if (datalength > 0 || ogn_datalength == -1) { if (ogn_datalength == -1) { datalength = 0; } PackData(data, datalength, packdata, out var outlen); Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; } return outdata; } public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[recv_buf_len + datalength]; Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength); recv_buf_len += datalength; outlength = 0; while (recv_buf_len > 4) { var crc32 = Util.CRC32.CalcCRC32(recv_buf, 2); if ((uint)((recv_buf[3] << 8) | recv_buf[2]) != ((uint)crc32 & 0xffff)) { throw new ObfsException("ClientPostDecrypt data error"); } var len = (recv_buf[0] << 8) + recv_buf[1]; if (len is >= 8192 or < 8) { throw new ObfsException("ClientPostDecrypt data error"); } if (len > recv_buf_len) { break; } if (Util.Adler32.CheckAdler32(recv_buf, len)) { int pos = recv_buf[4]; if (pos < 255) { pos += 4; } else { pos = ((recv_buf[5] << 8) | recv_buf[6]) + 4; } var outlen = len - pos - 4; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(recv_buf, pos, outdata, outlength, outlen); outlength += outlen; recv_buf_len -= len; Array.Copy(recv_buf, len, recv_buf, 0, recv_buf_len); } else { throw new ObfsException("ClientPostDecrypt data uncorrect checksum"); } } return outdata; } } } ================================================ FILE: shadowsocks-csharp/Obfs/HttpSimpleObfs.cs ================================================ using System; using System.Collections.Generic; namespace Shadowsocks.Obfs { class HttpSimpleObfs : ObfsBase { public HttpSimpleObfs(string method) : base(method) { has_sent_header = false; //has_recv_header = false; raw_trans_sent = false; raw_trans_recv = false; } private static Dictionary _obfs = new() { //modify original protocol, wrap protocol, obfs param { "http_simple", new[] { 0, 1, 1 } }, { "http_post", new[] { 0, 1, 1 } }, { "random_head", new[] { 0, 1, 0 } } }; private static string[] _request_path = { "", "", "login.php?redir=", "", "register.php?code=", "", "?keyword=", "", "search?src=typd&q=", "&lang=en", "s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&ch=&bar=&wd=", "&rn=", "post.php?id=", "&goto=view.php" }; private static string[] _request_useragent = { "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0", "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/44.0", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/27.0.1453.93 Chrome/27.0.1453.93 Safari/537.36", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:35.0) Gecko/20100101 Firefox/35.0", "Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; Trident/7.0; .NET4.0E; .NET4.0C)", "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko", "Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/BuildID) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36", "Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3", "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3" }; private static int _useragent_index = new Random().Next(_request_useragent.Length); private bool has_sent_header; //private bool has_recv_header; private bool raw_trans_sent; private bool raw_trans_recv; private List data_buffer = new(); private Random random = new(); public static List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } private string data2urlencode(byte[] encryptdata, int datalength) { var ret = ""; for (var i = 0; i < datalength; ++i) { ret += "%" + encryptdata[i].ToString("x2"); } return ret; } private string boundary() { var set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; var ret = ""; for (var i = 0; i < 32; ++i) { ret += set[random.Next(set.Length)]; } return ret; } public override byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength) { if (raw_trans_sent) { SentLength += datalength; outlength = datalength; return encryptdata; } var outdata = new byte[datalength + 4096]; byte[] headdata; if (Method == "random_head") { if (has_sent_header) { outlength = 0; if (datalength > 0) { var data = new byte[datalength]; Array.Copy(encryptdata, 0, data, 0, datalength); data_buffer.Add(data); } else { foreach (var data in data_buffer) { Array.Copy(data, 0, outdata, outlength, data.Length); SentLength += data.Length; outlength += data.Length; } data_buffer.Clear(); raw_trans_sent = true; } } else { var size = random.Next(96) + 8; var rnd = new byte[size]; random.NextBytes(rnd); Util.CRC32.SetCRC32(rnd); rnd.CopyTo(outdata, 0); outlength = rnd.Length; var data = new byte[datalength]; Array.Copy(encryptdata, 0, data, 0, datalength); data_buffer.Add(data); } } else if (Method is "http_simple" or "http_post") { var headsize = Server.Iv.Length + Server.head_len; if (datalength - headsize > 64) { headdata = new byte[headsize + random.Next(0, 64)]; } else { headdata = new byte[datalength]; } Array.Copy(encryptdata, 0, headdata, 0, headdata.Length); var request_path_index = new Random().Next(_request_path.Length / 2) * 2; var host = Server.host; var custom_head = ""; if (Server.param.Length > 0) { var custom_heads = Server.param.Split(new[] { '#' }, 2); var param = Server.param; if (custom_heads.Length > 1) { custom_head = custom_heads[1]; param = custom_heads[0]; } var hosts = param.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (hosts.Length > 0) { host = hosts[random.Next(hosts.Length)]; host = host.Trim(' '); } } var http_buf = (Method == "http_post" ? "POST /" : "GET /") + _request_path[request_path_index] + data2urlencode(headdata, headdata.Length) + _request_path[request_path_index + 1] + " HTTP/1.1\r\n" + "Host: " + host + (Server.port == 80 ? "" : ":" + Server.port) + "\r\n"; if (custom_head.Length > 0) { http_buf += custom_head.Replace("\\n", "\r\n") + "\r\n\r\n"; } else { http_buf += "User-Agent: " + _request_useragent[_useragent_index] + "\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" + "Accept-Language: en-US,en;q=0.8\r\n" + "Accept-Encoding: gzip, deflate\r\n" + (Method == "http_post" ? "Content-Type: multipart/form-data; boundary=" + boundary() + "\r\n" : "") + "DNT: 1\r\n" + "Connection: keep-alive\r\n" + "\r\n"; } for (var i = 0; i < http_buf.Length; ++i) { outdata[i] = (byte)http_buf[i]; } if (headdata.Length < datalength) { Array.Copy(encryptdata, headdata.Length, outdata, http_buf.Length, datalength - headdata.Length); } SentLength += headdata.Length; outlength = http_buf.Length + datalength - headdata.Length; raw_trans_sent = true; } else { outlength = 0; } has_sent_header = true; return outdata; } private int FindSubArray(byte[] array, int length, byte[] subArray) { for (var pos = 0; pos < length; ++pos) { var offset = 0; for (; offset < subArray.Length; ++offset) { if (array[pos + offset] != subArray[offset]) { break; } } if (offset == subArray.Length) { return pos; } } return -1; } public override byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback) { if (raw_trans_recv) { outlength = datalength; needsendback = false; return encryptdata; } var outdata = new byte[datalength]; if (Method == "random_head") { outlength = 0; raw_trans_recv = true; needsendback = true; return encryptdata; } var pos = FindSubArray(encryptdata, datalength, new[] { (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }); if (pos > 0) { outlength = datalength - (pos + 4); Array.Copy(encryptdata, pos + 4, outdata, 0, outlength); raw_trans_recv = true; } else { outlength = 0; } needsendback = false; return outdata; } } } ================================================ FILE: shadowsocks-csharp/Obfs/IObfs.cs ================================================ using System; namespace Shadowsocks.Obfs { public interface IObfs : IDisposable { string Name(); bool isKeepAlive(); bool isAlwaysSendback(); byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength); byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength); byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback); byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength); byte[] ClientUdpPreEncrypt(byte[] plaindata, int datalength, out int outlength); byte[] ClientUdpPostDecrypt(byte[] plaindata, int datalength, out int outlength); object InitData(); void SetServerInfo(ServerInfo serverInfo); void SetServerInfoIV(byte[] iv); long GetSentLength(); int GetOverhead(); int GetTcpMSS(); } } ================================================ FILE: shadowsocks-csharp/Obfs/ObfsBase.cs ================================================ using System; using System.Collections.Generic; namespace Shadowsocks.Obfs { public abstract class ObfsBase : IObfs { protected ObfsBase(string method) { Method = method; } protected string Method; protected ServerInfo Server; protected long SentLength; public abstract Dictionary GetObfs(); public string Name() { return Method; } public virtual bool isKeepAlive() { return false; } public virtual bool isAlwaysSendback() { return false; } public virtual byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength) { outlength = datalength; return plaindata; } public abstract byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength); public abstract byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback); public virtual byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength) { outlength = datalength; return plaindata; } public virtual byte[] ClientUdpPreEncrypt(byte[] plaindata, int datalength, out int outlength) { outlength = datalength; return plaindata; } public virtual byte[] ClientUdpPostDecrypt(byte[] plaindata, int datalength, out int outlength) { outlength = datalength; return plaindata; } public virtual object InitData() { return null; } public virtual void SetServerInfo(ServerInfo serverInfo) { Server = serverInfo; } public virtual void SetServerInfoIV(byte[] iv) { Server.SetIV(iv); } public static int GetHeadSize(byte[] plaindata, int defaultValue) { if (plaindata == null || plaindata.Length < 2) { return defaultValue; } var head_type = plaindata[0] & 0x7; if (head_type == 1) { return 7; } if (head_type == 4) { return 19; } if (head_type == 3) { return 4 + plaindata[1]; } if (head_type == 2) { return 4 + plaindata[1]; } return defaultValue; } public long GetSentLength() { return SentLength; } public virtual int GetOverhead() { return 0; } public int GetTcpMSS() { return Server.tcp_mss; } #region IDisposable protected bool _disposed; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { lock (this) { if (_disposed) { return; } _disposed = true; Disposing(); } } protected virtual void Disposing() { } #endregion } } ================================================ FILE: shadowsocks-csharp/Obfs/ObfsException.cs ================================================ using System; namespace Shadowsocks.Obfs { public class ObfsException : Exception { public ObfsException(string info) : base(info) { } } } ================================================ FILE: shadowsocks-csharp/Obfs/ObfsFactory.cs ================================================ using System; using System.Collections.Generic; namespace Shadowsocks.Obfs { public static class ObfsFactory { private static Dictionary _registeredObfs; private static Type[] _constructorTypes = { typeof(string) }; static ObfsFactory() { _registeredObfs = new Dictionary(); foreach (var method in Plain.SupportedObfs()) { _registeredObfs.Add(method, typeof(Plain)); } foreach (var method in HttpSimpleObfs.SupportedObfs()) { _registeredObfs.Add(method, typeof(HttpSimpleObfs)); } foreach (var method in TlsTicketAuthObfs.SupportedObfs()) { _registeredObfs.Add(method, typeof(TlsTicketAuthObfs)); } foreach (var method in VerifyDeflateObfs.SupportedObfs()) { _registeredObfs.Add(method, typeof(VerifyDeflateObfs)); } #if DEBUG foreach (var method in AuthSHA1.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthSHA1)); } foreach (var method in AuthSHA1V2.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthSHA1V2)); } #endif foreach (var method in AuthSHA1V4.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthSHA1V4)); } foreach (var method in AuthAES128SHA1.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthAES128SHA1)); } foreach (var method in AuthChain_a.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthChain_a)); } foreach (var method in AuthChain_b.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthChain_b)); } foreach (var method in AuthChain_c.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthChain_c)); } foreach (var method in AuthChain_d.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthChain_d)); } foreach (var method in AuthChain_e.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthChain_e)); } foreach (var method in AuthChain_f.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthChain_f)); } foreach (var method in AuthAkarin.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthAkarin)); } foreach (var method in AuthAkarin_spec_a.SupportedObfs()) { _registeredObfs.Add(method, typeof(AuthAkarin_spec_a)); } } public static IObfs GetObfs(string method) { if (string.IsNullOrEmpty(method)) { method = "plain"; } method = method.ToLowerInvariant(); var t = _registeredObfs[method]; var c = t.GetConstructor(_constructorTypes); var result = (IObfs)c?.Invoke(new object[] { method }); return result; } } } ================================================ FILE: shadowsocks-csharp/Obfs/Plain.cs ================================================ using System.Collections.Generic; namespace Shadowsocks.Obfs { public class Plain : ObfsBase { public Plain(string method) : base(method) { } private static Dictionary _obfs = new() { { "plain", new[] { 0, 0, 0 } }, { "origin", new[] { 0, 0, 0 } } }; public static List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } public override byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength) { outlength = datalength; SentLength += outlength; return encryptdata; } public override byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback) { outlength = datalength; needsendback = false; return encryptdata; } } } ================================================ FILE: shadowsocks-csharp/Obfs/ProtocolException.cs ================================================ using System; namespace Shadowsocks.Obfs { public class ProtocolException : Exception { public ProtocolException(string info) : base(info) { } } } ================================================ FILE: shadowsocks-csharp/Obfs/ServerInfo.cs ================================================ namespace Shadowsocks.Obfs { public class ServerInfo { public string host; public int port; public string param; public object data; public int tcp_mss; public int overhead; public int buffer_size; public byte[] Iv; public byte[] key; public string key_str; public int head_len; public ServerInfo(string host, int port, string param, object data, byte[] iv, string key_str, byte[] key, int head_len, int tcp_mss, int overhead, int buffer_size) { this.host = host; this.port = port; this.param = param; this.data = data; this.Iv = iv; this.key = key; this.key_str = key_str; this.head_len = head_len; this.tcp_mss = tcp_mss; this.overhead = overhead; this.buffer_size = buffer_size; } public void SetIV(byte[] iv) { this.Iv = iv; } } } ================================================ FILE: shadowsocks-csharp/Obfs/TlsAuthData.cs ================================================ using System.Collections.Generic; namespace Shadowsocks.Obfs { public class TlsAuthData { public byte[] clientID; public Dictionary ticket_buf; } } ================================================ FILE: shadowsocks-csharp/Obfs/TlsTicketAuthObfs.cs ================================================ using CryptoBase.Digests; using CryptoBase.Macs.Hmac; using System; using System.Collections.Generic; using System.Security.Cryptography; namespace Shadowsocks.Obfs { class TlsTicketAuthObfs : ObfsBase { public TlsTicketAuthObfs(string method) : base(method) { handshake_status = 0; if (method == "tls1.2_ticket_fastauth") { fastauth = true; } } private static Dictionary _obfs = new() { { "tls1.2_ticket_auth", new[] { 0, 1, 1 } }, { "tls1.2_ticket_fastauth", new[] { 0, 1, 1 } } }; private int handshake_status; private List data_sent_buffer = new(); private byte[] data_recv_buffer = new byte[0]; private uint send_id; private bool fastauth; protected Random random = new(); protected const int overhead = 5; public static List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } public override object InitData() { return new TlsAuthData(); } public override bool isAlwaysSendback() { return true; } public override int GetOverhead() { return overhead; } protected byte[] sni(string url) { if (url == null) { url = ""; } var b_url = System.Text.Encoding.UTF8.GetBytes(url); var len = b_url.Length; var ret = new byte[len + 9]; Array.Copy(b_url, 0, ret, 9, len); ret[7] = (byte)(len >> 8); ret[8] = (byte)len; len += 3; ret[4] = (byte)(len >> 8); ret[5] = (byte)len; len += 2; ret[2] = (byte)(len >> 8); ret[3] = (byte)len; return ret; } protected byte to_val(char c) { if (c > '9') { return (byte)(c - 'a' + 10); } return (byte)(c - '0'); } protected byte[] to_bin(string str) { var ret = new byte[str.Length / 2]; for (var i = 0; i < str.Length; i += 2) { ret[i / 2] = (byte)((to_val(str[i]) << 4) | to_val(str[i + 1])); } return ret; } protected void hmac_sha1(byte[] data, int length) { Span key = new byte[Server.key.Length + 32]; Server.key.AsSpan().CopyTo(key); ((TlsAuthData)Server.data).clientID.AsSpan().CopyTo(key[Server.key.Length..]); using var hmac = HmacUtils.Create(DigestType.Sha1, key); hmac.Update(data.AsSpan(0, length - 10)); Span hash = stackalloc byte[hmac.Length]; hmac.GetMac(hash); hash[..10].CopyTo(data.AsSpan(length - 10, 10)); } public void PackAuthData(byte[] outdata) { var authData = (TlsAuthData)Server.data; var outlength = 32; { var randomdata = new byte[18]; lock (authData) { RandomNumberGenerator.Fill(randomdata); } randomdata.CopyTo(outdata, 4); } lock (authData) { authData.clientID ??= RandomNumberGenerator.GetBytes(32); } var utc_time_second = (ulong)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); var utc_time = (uint)utc_time_second; var time_bytes = BitConverter.GetBytes(utc_time); Array.Reverse(time_bytes); Array.Copy(time_bytes, 0, outdata, 0, 4); hmac_sha1(outdata, outlength); } protected void PackData(byte[] data, ref int start, int len, byte[] outdata, ref int outlength) { outdata[outlength] = 0x17; outdata[outlength + 1] = 0x3; outdata[outlength + 2] = 0x3; outdata[outlength + 3] = (byte)(len >> 8); outdata[outlength + 4] = (byte)len; Array.Copy(data, start, outdata, outlength + 5, len); start += len; outlength += len + 5; ++send_id; } public override byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength) { if (handshake_status == -1) { SentLength += datalength; outlength = datalength; return encryptdata; } var outdata = new byte[datalength + 4096]; if ((handshake_status & 4) == 4) { var start = 0; outlength = 0; while (send_id <= 4 && datalength - start > 256) { var len = random.Next(512) + 64; if (len > datalength - start) { len = datalength - start; } PackData(encryptdata, ref start, len, outdata, ref outlength); } while (datalength - start > 2048) { var len = random.Next(4096) + 100; if (len > datalength - start) { len = datalength - start; } PackData(encryptdata, ref start, len, outdata, ref outlength); } if (datalength - start > 0) { PackData(encryptdata, ref start, datalength - start, outdata, ref outlength); } return outdata; } if (datalength > 0) { var data = new byte[datalength + 5]; data[0] = 0x17; data[1] = 0x3; data[2] = 0x3; data[3] = (byte)(datalength >> 8); data[4] = (byte)datalength; Array.Copy(encryptdata, 0, data, 5, datalength); data_sent_buffer.Add(data); } if ((handshake_status & 3) != 0) { outlength = 0; if ((handshake_status & 2) == 0) { int[] finish_len_set = { 32 }; //, 40, 64 var finish_len = finish_len_set[random.Next(finish_len_set.Length)]; var hmac_data = new byte[11 + finish_len]; var rnd = new byte[finish_len - 10]; random.NextBytes(rnd); var handshake_finish = System.Text.Encoding.ASCII.GetBytes("\x14\x03\x03\x00\x01\x01" + "\x16\x03\x03\x00\x20"); handshake_finish[handshake_finish.Length - 1] = (byte)finish_len; handshake_finish.CopyTo(hmac_data, 0); rnd.CopyTo(hmac_data, handshake_finish.Length); hmac_sha1(hmac_data, hmac_data.Length); data_sent_buffer.Insert(0, hmac_data); SentLength -= hmac_data.Length; handshake_status |= 2; } if (datalength == 0 || fastauth) { foreach (var data in data_sent_buffer) { Util.Utils.SetArrayMinSize2(ref outdata, outlength + data.Length); Array.Copy(data, 0, outdata, outlength, data.Length); SentLength += data.Length; outlength += data.Length; } data_sent_buffer.Clear(); } if (datalength == 0) { handshake_status |= 4; } } else { var rnd = new byte[32]; PackAuthData(rnd); var ssl_buf = new List(); var ext_buf = new List(); var str_buf = "001cc02bc02fcca9cca8cc14cc13c00ac014c009c013009c0035002f000a0100"; ssl_buf.AddRange(rnd); ssl_buf.Add(32); ssl_buf.AddRange(((TlsAuthData)Server.data).clientID); ssl_buf.AddRange(to_bin(str_buf)); str_buf = "ff01000100"; ext_buf.AddRange(to_bin(str_buf)); var host = Server.host; if (Server.param.Length > 0) { var hosts = Server.param.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (hosts.Length > 0) { host = hosts[random.Next(hosts.Length)]; host = host.Trim(' '); } } if (!string.IsNullOrEmpty(host) && host[host.Length - 1] >= '0' && host[host.Length - 1] <= '9' && Server.param.Length == 0) { host = ""; } ext_buf.AddRange(sni(host)); var str_buf2 = "001700000023"; ext_buf.AddRange(to_bin(str_buf2)); { var authData = (TlsAuthData)Server.data; byte[] ticket; lock (authData) { if (authData.ticket_buf == null) { authData.ticket_buf = new Dictionary(); } if (!authData.ticket_buf.ContainsKey(host ?? throw new InvalidOperationException()) || random.Next(16) == 0) { var ticketSize = random.Next(32, 196) * 2; ticket = RandomNumberGenerator.GetBytes(ticketSize); authData.ticket_buf[host] = ticket; } else { ticket = authData.ticket_buf[host]; } } ext_buf.Add((byte)(ticket.Length >> 8)); ext_buf.Add((byte)(ticket.Length & 0xff)); ext_buf.AddRange(ticket); } var str_buf3 = "000d0016001406010603050105030401040303010303020102030005000501000000000012000075500000000b00020100000a0006000400170018"; str_buf3 += "00150066000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; ext_buf.AddRange(to_bin(str_buf3)); ext_buf.Insert(0, (byte)(ext_buf.Count % 256)); ext_buf.Insert(0, (byte)((ext_buf.Count - 1) / 256)); ssl_buf.AddRange(ext_buf); // client version ssl_buf.Insert(0, 3); // version ssl_buf.Insert(0, 3); // length ssl_buf.Insert(0, (byte)(ssl_buf.Count % 256)); ssl_buf.Insert(0, (byte)((ssl_buf.Count - 1) / 256)); ssl_buf.Insert(0, 0); ssl_buf.Insert(0, 1); // client hello // length ssl_buf.Insert(0, (byte)(ssl_buf.Count % 256)); ssl_buf.Insert(0, (byte)((ssl_buf.Count - 1) / 256)); // ssl_buf.Insert(0, 0x1); // version ssl_buf.Insert(0, 0x3); ssl_buf.Insert(0, 0x16); for (var i = 0; i < ssl_buf.Count; ++i) { outdata[i] = ssl_buf[i]; } outlength = ssl_buf.Count; handshake_status = 1; } return outdata; } public override byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback) { if (handshake_status == -1) { outlength = datalength; needsendback = false; return encryptdata; } if ((handshake_status & 8) == 8) { Array.Resize(ref data_recv_buffer, data_recv_buffer.Length + datalength); Array.Copy(encryptdata, 0, data_recv_buffer, data_recv_buffer.Length - datalength, datalength); needsendback = false; var outdata = new byte[65536]; outlength = 0; while (data_recv_buffer.Length > 5) { if (data_recv_buffer[0] != 0x17) { throw new ObfsException("ClientDecode appdata error"); } var len = (data_recv_buffer[3] << 8) + data_recv_buffer[4]; var pack_len = len + 5; if (pack_len > data_recv_buffer.Length) { break; } Array.Copy(data_recv_buffer, 5, outdata, outlength, len); outlength += len; var buffer = new byte[data_recv_buffer.Length - pack_len]; Array.Copy(data_recv_buffer, pack_len, buffer, 0, buffer.Length); data_recv_buffer = buffer; } return outdata; } else { Array.Resize(ref data_recv_buffer, data_recv_buffer.Length + datalength); Array.Copy(encryptdata, 0, data_recv_buffer, data_recv_buffer.Length - datalength, datalength); outlength = 0; needsendback = false; if (data_recv_buffer.Length >= 11 + 32 + 1 + 32) { var data = new byte[32]; Array.Copy(data_recv_buffer, 11, data, 0, 22); hmac_sha1(data, data.Length); if (!data_recv_buffer.AsSpan(11 + 22, 10).SequenceEqual(data.AsSpan(22, 10))) { throw new ObfsException("ClientDecode data error: wrong sha1"); } var headerlength = data_recv_buffer.Length; data = new byte[headerlength]; Array.Copy(data_recv_buffer, 0, data, 0, headerlength - 10); hmac_sha1(data, headerlength); if (!data_recv_buffer.AsSpan(headerlength - 10, 10).SequenceEqual(data.AsSpan(headerlength - 10, 10))) { headerlength = 0; while (headerlength < data_recv_buffer.Length && (data_recv_buffer[headerlength] == 0x14 || data_recv_buffer[headerlength] == 0x16)) { headerlength += 5; if (headerlength >= data_recv_buffer.Length) { return encryptdata; } headerlength += (data_recv_buffer[headerlength - 2] << 8) | data_recv_buffer[headerlength - 1]; if (headerlength > data_recv_buffer.Length) { return encryptdata; } } data = new byte[headerlength]; Array.Copy(data_recv_buffer, 0, data, 0, headerlength - 10); hmac_sha1(data, headerlength); if (!data_recv_buffer.AsSpan(headerlength - 10, 10).SequenceEqual(data.AsSpan(headerlength - 10, 10))) { throw new ObfsException("ClientDecode data error: wrong sha1"); } } var buffer = new byte[data_recv_buffer.Length - headerlength]; Array.Copy(data_recv_buffer, headerlength, buffer, 0, buffer.Length); data_recv_buffer = buffer; handshake_status |= 8; var ret = ClientDecode(encryptdata, 0, out outlength, out needsendback); needsendback = true; return ret; } return encryptdata; } } } } ================================================ FILE: shadowsocks-csharp/Obfs/VerifyData.cs ================================================ namespace Shadowsocks.Obfs { public class VerifyData { } } ================================================ FILE: shadowsocks-csharp/Obfs/VerifyDeflateObfs.cs ================================================ using Shadowsocks.Controller; using Shadowsocks.Util; using System; using System.Collections.Generic; namespace Shadowsocks.Obfs { public class VerifyDeflateObfs : VerifySimpleBase { public VerifyDeflateObfs(string method) : base(method) { } private static Dictionary _obfs = new() { { "verify_deflate", new[] { 1, 0, 1 } } }; public static List SupportedObfs() { return new(_obfs.Keys); } public override Dictionary GetObfs() { return _obfs; } public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength) { var comdata = FileManager.DeflateCompress(data, 0, datalength, out var outlen); outlength = outlen + 2 + 4; outdata[0] = (byte)(outlength >> 8); outdata[1] = (byte)outlength; Array.Copy(comdata, 0, outdata, 2, outlen); var adler = Adler32.CalcAdler32(data, datalength); outdata[outlength - 4] = (byte)(adler >> 24); outdata[outlength - 3] = (byte)(adler >> 16); outdata[outlength - 2] = (byte)(adler >> 8); outdata[outlength - 1] = (byte)adler; } public override byte[] ClientPreEncrypt(byte[] plaindata, int datalength, out int outlength) { if (plaindata == null) { outlength = 0; return null; } var outdata = new byte[datalength + datalength / 10 + 32]; var packdata = new byte[32768]; var data = plaindata; outlength = 0; const int unit_len = 32700; while (datalength > unit_len) { PackData(data, unit_len, packdata, out var outlen); Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; datalength -= unit_len; var newdata = new byte[datalength]; Array.Copy(data, unit_len, newdata, 0, newdata.Length); data = newdata; } if (datalength > 0) { PackData(data, datalength, packdata, out var outlen); Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(packdata, 0, outdata, outlength, outlen); outlength += outlen; } return outdata; } public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength) { var outdata = new byte[recv_buf_len + datalength * 2 + 16]; Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength); recv_buf_len += datalength; outlength = 0; while (recv_buf_len > 2) { var len = (recv_buf[0] << 8) + recv_buf[1]; if (len is >= 32768 or < 6) { throw new ObfsException("ClientPostDecrypt data error"); } if (len > recv_buf_len) { break; } var buf = FileManager.DeflateDecompress(recv_buf, 2, len - 6, out var outlen); if (buf != null) { var alder = Adler32.CalcAdler32(buf, outlen); if (recv_buf[len - 4] == (byte)(alder >> 24) && recv_buf[len - 3] == (byte)(alder >> 16) && recv_buf[len - 2] == (byte)(alder >> 8) && recv_buf[len - 1] == (byte)alder) { //pass } else { throw new ObfsException("ClientPostDecrypt data decompress ERROR"); } Utils.SetArrayMinSize2(ref outdata, outlength + outlen); Array.Copy(buf, 0, outdata, outlength, outlen); outlength += outlen; recv_buf_len -= len; Array.Copy(recv_buf, len, recv_buf, 0, recv_buf_len); } else { throw new ObfsException("ClientPostDecrypt data decompress ERROR"); } } return outdata; } } } ================================================ FILE: shadowsocks-csharp/Obfs/VerifySimpleBase.cs ================================================ using System; namespace Shadowsocks.Obfs { public abstract class VerifySimpleBase : ObfsBase { public VerifySimpleBase(string method) : base(method) { } protected const int RecvBufferSize = 65536 * 2; protected byte[] recv_buf = new byte[RecvBufferSize]; protected int recv_buf_len; protected Random random = new(); public override object InitData() { return new VerifyData(); } public int LinearRandomInt(int max) { return random.Next(max); } public int NonLinearRandomInt(int max) { int r1, r2; if ((max & 1) == 1) { var mid = (max + 1) >> 1; r1 = random.Next(mid); r2 = random.Next(mid + 1); var r = r1 + r2; if (r == max) { return mid - 1; } if (r < mid) { return mid - r - 1; } return max - r + mid - 1; } else { var mid = max >> 1; r1 = random.Next(mid); r2 = random.Next(mid + 1); var r = r1 + r2; if (r < mid) { return mid - r - 1; } return max - r + mid - 1; } } public double TrapezoidRandomFloat(double d) // -1 <= d <= 1 { if (Math.Abs(d) < 0.000001) { return random.NextDouble(); } var s = random.NextDouble(); //(2dx + 2(1 - d))x/2 = s //dx^2 + (1-d)x - s = 0 var a = 1 - d; //dx^2 + ax - s = 0 //[-a + sqrt(a^2 + 4ds)] / 2d return (Math.Sqrt(a * a + 4 * d * s) - a) / (2 * d); } public int TrapezoidRandomInt(int max, double d) { var v = TrapezoidRandomFloat(d); return (int)(v * max); } public override byte[] ClientEncode(byte[] encryptdata, int datalength, out int outlength) { outlength = datalength; return encryptdata; } public override byte[] ClientDecode(byte[] encryptdata, int datalength, out int outlength, out bool needsendback) { outlength = datalength; needsendback = false; return encryptdata; } } } ================================================ FILE: shadowsocks-csharp/Obfs/xorshift128plus.cs ================================================ using System; namespace Shadowsocks.Obfs { class xorshift128plus { protected ulong v0, v1; protected int init_loop; public xorshift128plus(int init_loop_ = 4) { v0 = v1 = 0; init_loop = init_loop_; } public ulong next() { var x = v0; var y = v1; v0 = y; x ^= x << 23; x ^= y ^ (x >> 17) ^ (y >> 26); v1 = x; return x + y; } public void init_from_bin(byte[] bytes) { var fill_bytes = new byte[16]; Array.Copy(bytes, fill_bytes, 16); v0 = BitConverter.ToUInt64(fill_bytes, 0); v1 = BitConverter.ToUInt64(fill_bytes, 8); } public void init_from_bin(byte[] bytes, int datalength) { var fill_bytes = new byte[16]; Array.Copy(bytes, fill_bytes, 16); BitConverter.GetBytes((ushort)datalength).CopyTo(fill_bytes, 0); v0 = BitConverter.ToUInt64(fill_bytes, 0); v1 = BitConverter.ToUInt64(fill_bytes, 8); for (var i = 0; i < init_loop; ++i) { next(); } } } } ================================================ FILE: shadowsocks-csharp/Program.cs ================================================ using CryptoBase; using Microsoft.Win32; using Shadowsocks.Controller; using Shadowsocks.Enums; using Shadowsocks.Model; using Shadowsocks.Util; using SingleInstance; using System; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows; using Utils = Shadowsocks.Util.Utils; namespace Shadowsocks { internal static class Program { [STAThread] private static void Main(string[] args) { Directory.SetCurrentDirectory(Path.GetDirectoryName(Utils.GetExecutablePath()) ?? throw new InvalidOperationException()); var identifier = $@"Global\{Controller.HttpRequest.UpdateChecker.Name}_{Directory.GetCurrentDirectory().GetClassicHashCode()}"; using var singleInstance = new SingleInstanceService(identifier); if (!singleInstance.TryStartSingleInstance()) { SendCommand(singleInstance, args.Length <= 0 ? Constants.ParameterMultiplyInstance : string.Join(' ', args)); return; } using var d = singleInstance.Received.Subscribe(ArgumentsReceived); var app = new Application { ShutdownMode = ShutdownMode.OnExplicitShutdown }; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; app.Exit += App_Exit; Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(@"##SyncfusionLicense##"); Global.LoadConfig(); I18NUtil.SetLanguage(Global.GuiConfig.LangName); ViewUtils.SetResource(app.Resources, @"../View/NotifyIconResources.xaml", 1); Global.Controller = new MainController(); // Logging Logging.DefaultOut = Console.Out; Logging.DefaultError = Console.Error; Utils.SetTls(); Global.ViewController = new MenuViewController(Global.Controller); SystemEvents.SessionEnding += Global.ViewController.Quit_Click; Global.Controller.Reload(); if (Global.GuiConfig.IsDefaultConfig()) { var res = MessageBox.Show( $@"{I18NUtil.GetAppStringValue(@"DefaultConfigMessage")}{Environment.NewLine}{I18NUtil.GetAppStringValue(@"DefaultConfigQuestion")}", Controller.HttpRequest.UpdateChecker.Name, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.OK); switch (res) { case MessageBoxResult.Yes: { Global.Controller.ShowConfigForm(); break; } case MessageBoxResult.No: { Global.Controller.ShowSubscribeWindow(); break; } default: { StopController(); return; } } } Reg.SetUrlProtocol(@"ssr"); Reg.SetUrlProtocol(@"sub"); singleInstance.StartListenServer(); app.Run(); } private static void StopController() { Global.ViewController?.Quit_Click(default, default); Global.Controller?.Stop(); Global.Controller = null; } private static void App_Exit(object sender, ExitEventArgs e) { Reg.RemoveUrlProtocol(@"ssr"); Reg.RemoveUrlProtocol(@"sub"); StopController(); } private static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) { switch (e.Mode) { case PowerModes.Resume: { Logging.Info("os wake up"); if (Global.Controller != null) { Task.Run(() => { Thread.Sleep(10 * 1000); try { Global.Controller.Reload(); Logging.Info("controller started"); } catch (Exception ex) { Logging.LogUsefulException(ex); } }); } break; } case PowerModes.Suspend: { if (Global.Controller != null) { Global.Controller.Stop(); Logging.Info("controller stopped"); } Logging.Info("os suspend"); break; } } } private static int _exited; private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { if (Interlocked.Increment(ref _exited) == 1) { Logging.Log(LogLevel.Error, $@"{e.ExceptionObject}"); MessageBox.Show( $@"{I18NUtil.GetAppStringValue(@"UnexpectedError")}{Environment.NewLine}{e.ExceptionObject}", Controller.HttpRequest.UpdateChecker.Name, MessageBoxButton.OK, MessageBoxImage.Error); Environment.Exit(1); } } private static void SendCommand(ISingleInstanceService service, string command) { try { service.SendMessageToFirstInstanceAsync(command).GetAwaiter().GetResult(); } catch { // ignored } } private static void ArgumentsReceived((string, Action) receive) { var (message, endFunc) = receive; var args = message .Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .ToHashSet(); if (args.Contains(Constants.ParameterMultiplyInstance)) { MessageBox.Show(I18NUtil.GetAppStringValue(@"SuccessiveInstancesMessage1") + Environment.NewLine + I18NUtil.GetAppStringValue(@"SuccessiveInstancesMessage2"), I18NUtil.GetAppStringValue(@"SuccessiveInstancesCaption"), MessageBoxButton.OK, MessageBoxImage.Information); } Application.Current.Dispatcher?.InvokeAsync(() => { Global.ViewController.ImportAddress(string.Join(Environment.NewLine, args)); }); endFunc(string.Empty); } } } ================================================ FILE: shadowsocks-csharp/Properties/AssemblyInfo.cs ================================================ using System.Reflection; [assembly: AssemblyTitle(Shadowsocks.Controller.HttpRequest.UpdateChecker.Name)] [assembly: AssemblyProduct(Shadowsocks.Controller.HttpRequest.UpdateChecker.Name)] [assembly: AssemblyCopyright(Shadowsocks.Controller.HttpRequest.UpdateChecker.Copyright)] [assembly: AssemblyVersion(Shadowsocks.Controller.HttpRequest.UpdateChecker.Version)] [assembly: AssemblyFileVersion(Shadowsocks.Controller.HttpRequest.UpdateChecker.Version)] [assembly: AssemblyInformationalVersion(Shadowsocks.Controller.HttpRequest.UpdateChecker.FullVersion)] ================================================ FILE: shadowsocks-csharp/Properties/Resources.Designer.cs ================================================ //------------------------------------------------------------------------------ // // 此代码由工具生成。 // 运行时版本:4.0.30319.42000 // // 对此文件的更改可能会导致不正确的行为,并且如果 // 重新生成代码,这些更改将会丢失。 // //------------------------------------------------------------------------------ namespace Shadowsocks.Properties { using System; /// /// 一个强类型的资源类,用于查找本地化的字符串等。 /// // 此类是由 StronglyTypedResourceBuilder // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen // (以 /str 作为命令选项),或重新生成 VS 项目。 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } /// /// 返回此类使用的缓存的 ResourceManager 实例。 /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Shadowsocks.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } /// /// 重写当前线程的 CurrentUICulture 属性,对 /// 使用此强类型资源类的所有资源查找执行重写。 /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } /// /// 查找类似 var direct = "__DIRECT__"; ///if (direct == "__DIR" + "ECT__") direct = "DIRECT;"; /// ///var wall_proxy = function(){ return "__PROXY__"; }; ///var wall_v6_proxy = function(){ return "__PROXY__"; }; /// ///var nowall_proxy = function(){ return direct; }; ///var ip_proxy = function(){ return nowall_proxy(); }; ///var ipv6_proxy = function(){ return nowall_proxy(); }; /// ///var userrules = __USERRULES__; ///var rules = __RULES__; /// ////* ///* This file is part of Adblock Plus <http://adblockplus.org/>, ///* Copyright (C) 2006-2014 Eye [字符串的其余部分被截断]"; 的本地化字符串。 /// internal static string abp { get { return ResourceManager.GetString("abp", resourceCulture); } } /// /// 查找类似 1.0.1.0/24 ///1.0.2.0/23 ///1.0.8.0/21 ///1.0.32.0/19 ///1.1.0.0/24 ///1.1.2.0/23 ///1.1.4.0/22 ///1.1.8.0/21 ///1.1.16.0/20 ///1.1.32.0/19 ///1.2.0.0/23 ///1.2.2.0/24 ///1.2.4.0/22 ///1.2.8.0/21 ///1.2.16.0/20 ///1.2.32.0/19 ///1.2.64.0/18 ///1.3.0.0/16 ///1.4.1.0/24 ///1.4.2.0/23 ///1.4.4.0/22 ///1.4.8.0/21 ///1.4.16.0/20 ///1.4.32.0/19 ///1.4.64.0/18 ///1.8.0.0/16 ///1.10.0.0/21 ///1.10.8.0/23 ///1.10.11.0/24 ///1.10.12.0/22 ///1.10.16.0/20 ///1.10.32.0/19 ///1.10.64.0/18 ///1.12.16.0/20 ///1.12.32.0/23 ///1.12.36.0/22 ///1.12.40.0/21 ///1.12.48.0/20 ///1.12.64.0/18 ///1.12.128.0/17 ///1.13.0.0/16 ///1.14.0.0/15 ///1.18.128.0/2 [字符串的其余部分被截断]"; 的本地化字符串。 /// internal static string chn_ip { get { return ResourceManager.GetString("chn_ip", resourceCulture); } } /// /// 查找 System.Byte[] 类型的本地化资源。 /// internal static byte[] libsscrypto_dll { get { object obj = ResourceManager.GetObject("libsscrypto_dll", resourceCulture); return ((byte[])(obj)); } } /// /// 查找 System.Byte[] 类型的本地化资源。 /// internal static byte[] libsscrypto64_dll { get { object obj = ResourceManager.GetObject("libsscrypto64_dll", resourceCulture); return ((byte[])(obj)); } } /// /// 查找类似 var direct = "__DIRECT__"; ///if (direct == "__DIR" + "ECT__") direct = "DIRECT;"; /// ///var wall_proxy = function(){ return "__PROXY__"; }; ///var wall_v6_proxy = function(){ return "__PROXY__"; }; /// ///var nowall_proxy = function(){ return direct; }; ///var ip_proxy = function(){ return nowall_proxy(); }; ///var ipv6_proxy = function(){ return nowall_proxy(); }; /// ///var userrules = []; ///var rules = [ /// "|http://85.17.73.31/", /// "||afreecatv.com", /// "||agnesb.fr", /// "||akiba-web.com", /// "||altrec.com", /// "||angela-merkel.de", /// "| [字符串的其余部分被截断]"; 的本地化字符串。 /// internal static string proxy_pac { get { return ResourceManager.GetString("proxy_pac", resourceCulture); } } /// /// 查找 System.Drawing.Bitmap 类型的本地化资源。 /// internal static System.Drawing.Bitmap ss128 { get { object obj = ResourceManager.GetObject("ss128", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } /// /// 查找类似 ! Put user rules line by line in this file. ///! See https://adblockplus.org/en/filter-cheatsheet /// 的本地化字符串。 /// internal static string user_rule { get { return ResourceManager.GetString("user_rule", resourceCulture); } } } } ================================================ FILE: shadowsocks-csharp/Properties/Resources.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ..\Data\abp.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312 ..\Data\chn_ip.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312 ..\Data\libsscrypto64.dll.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ..\data\libsscrypto.dll.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ..\Data\proxy.pac.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312 ..\Resources\ss128.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\data\user-rule.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 ================================================ FILE: shadowsocks-csharp/Proxy/CallbackState.cs ================================================ namespace Shadowsocks.Proxy { public class CallbackState { public byte[] buffer; public int size; public int protocol_size; public object state; } } ================================================ FILE: shadowsocks-csharp/Proxy/CallbackStatus.cs ================================================ namespace Shadowsocks.Proxy { class CallbackStatus { protected int status; public CallbackStatus() { status = 0; } public void SetIfEqu(int newStatus, int oldStatus) { lock (this) { if (status == oldStatus) { status = newStatus; } } } public int Status { get { lock (this) { return status; } } set { lock (this) { status = value; } } } } } ================================================ FILE: shadowsocks-csharp/Proxy/Handler.cs ================================================ using Shadowsocks.Controller; using Shadowsocks.Controller.Service; using Shadowsocks.Enums; using Shadowsocks.Model; using Shadowsocks.Model.Transfer; using Shadowsocks.Obfs; using Shadowsocks.Util; using Shadowsocks.Util.NetUtils; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using System.Timers; using static Shadowsocks.Encryption.EncryptorBase; using Timer = System.Timers.Timer; namespace Shadowsocks.Proxy { internal class Handler : IHandler { public delegate Server GetCurrentServer(int localPort, ServerSelectStrategy.FilterFunc filter, string targetURI = null, bool cfgRandom = false, bool usingRandom = false, bool forceRandom = false); public delegate void KeepCurrentServer(int localPort, string targetURI, string id); public GetCurrentServer getCurrentServer; public KeepCurrentServer keepCurrentServer; public Server server; public ServerSelectStrategy.FilterFunc select_server; public HandlerConfig cfg = new(); // Connection socket public ProxySocketTunLocal connection; public Socket connectionUDP; protected IPEndPoint connectionUDPEndPoint; protected int localPort; protected ProtocolResponseDetector detector = new(); // remote socket. //protected Socket remote; protected ProxyEncryptSocket remote; protected ProxyEncryptSocket remoteUDP; // Size of receive buffer. protected const int RecvSize = ProxyEncryptSocket.MSS * 4; protected const int BufferSize = ProxyEncryptSocket.MSS * 16; // remote header send buffer protected byte[] remoteHeaderSendBuffer; // connection send buffer protected List connectionSendBufferList = new(); protected DateTime lastKeepTime; private int _totalRecvSize; protected byte[] remoteUDPRecvBuffer = new byte[BufferSize]; protected int remoteUDPRecvBufferLength; protected object recvUDPoverTCPLock = new(); protected bool closed; protected bool local_error; protected bool is_protocol_sendback; protected bool is_obfs_sendback; protected bool connectionTCPIdle, connectionUDPIdle, remoteTCPIdle, remoteUDPIdle; protected SpeedTester speedTester = new(); protected int lastErrCode; protected Timer timer; protected object timerLock = new(); protected DateTime lastTimerSetTime; enum ConnectState { END = -1, READY = 0, HANDSHAKE = 1, CONNECTING = 2, CONNECTED = 3 } private ConnectState state = ConnectState.READY; private ConnectState State { get => state; set { lock (this) { state = value; } } } private void ResetTimeout(double time, bool reset_keep_alive = true) { if (time <= 0 && timer == null) { return; } if (reset_keep_alive) { cfg.TryKeepAlive = 0; } if (time <= 0) { if (timer != null) { lock (timerLock) { if (timer != null) { timer.Enabled = false; timer.Elapsed -= timer_Elapsed; timer.Dispose(); timer = null; } } } } else if (!closed) { if ((DateTime.Now - lastTimerSetTime).TotalMilliseconds > 500) { lock (timerLock) { if (timer == null) { timer = new Timer(time * 1000.0); timer.Elapsed += timer_Elapsed; } else { timer.Interval = time * 1000.0; timer.Stop(); } timer.Start(); lastTimerSetTime = DateTime.Now; } } } } private void timer_Elapsed(object sender, ElapsedEventArgs e) { if (closed) { return; } var stop = false; try { if (cfg.TryKeepAlive <= 0 && State == ConnectState.CONNECTED && remote != null && remoteUDP == null && remote.CanSendKeepAlive) { cfg.TryKeepAlive++; RemoteSend(remoteUDPRecvBuffer, -1); } else { if (connection != null) { var s = server; if (remote != null && cfg.ReconnectTimesRemain > 0 //&& obfs != null && obfs.getSentLength() == 0 && connectionSendBufferList != null && (State == ConnectState.CONNECTED || State == ConnectState.CONNECTING)) { if (lastErrCode == 0) { if (State == ConnectState.CONNECTING && cfg.Socks5RemotePort > 0) { } else { lastErrCode = 8; s.SpeedLog.AddTimeoutTimes(); } } //remote.Shutdown(SocketShutdown.Both); stop = true; } else { if (s != null && connectionSendBufferList != null ) { if (lastErrCode == 0) { lastErrCode = 8; s.SpeedLog.AddTimeoutTimes(); } } //connection.Shutdown(SocketShutdown.Both); stop = true; local_error = true; } } } } catch (Exception) { // } if (stop) { //Thread.Sleep(200); Close(); } } public void setServerTransferTotal(ServerTransferTotal transfer) { speedTester.Transfer = transfer; } public int LogSocketException(Exception e) { // just log useful exceptions, not all of them var s = server; if (e is ObfsException) { if (lastErrCode == 0) { if (s != null) { lastErrCode = 16; s.SpeedLog.AddErrorDecodeTimes(); } } return 16; // ObfsException(decrypt error) } if (e is ProtocolException) { if (lastErrCode == 0) { if (s != null) { lastErrCode = 16; s.SpeedLog.AddErrorDecodeTimes(); } } return 16; // ObfsException(decrypt error) } if (e is SocketException se) { switch (se.SocketErrorCode) { case SocketError.ConnectionAborted: case SocketError.ConnectionReset: case SocketError.NotConnected: case SocketError.Interrupted: case SocketError.Shutdown: // closed by browser when sending // normally happens when download is canceled or a tab is closed before page is loaded break; case SocketError.NoData: { if (lastErrCode == 0) { if (s != null) { lastErrCode = 1; s.SpeedLog.AddErrorTimes(); } } return 1; // proxy DNS error } case SocketError.HostNotFound: { if (lastErrCode == 0) { if (s != null) { lastErrCode = 2; s.SpeedLog.AddErrorTimes(); } } return 2; // ip not exist } case SocketError.ConnectionRefused: { if (lastErrCode == 0) { if (s != null) { lastErrCode = 1; if (cfg != null && cfg.Socks5RemotePort == 0) { s.SpeedLog.AddErrorTimes(); } } } return 2; // proxy ip/port error } case SocketError.NetworkUnreachable: { if (lastErrCode == 0 && s != null) { lastErrCode = 3; s.SpeedLog.AddErrorTimes(); } return 3; // proxy ip/port error } case SocketError.TimedOut: { if (lastErrCode == 0 && s != null) { lastErrCode = 8; s.SpeedLog.AddTimeoutTimes(); } return 8; // proxy server no response too slow } default: { if (lastErrCode == 0) { lastErrCode = -1; s?.SpeedLog.AddNoErrorTimes(); //? } return -1; } } } return 0; } public bool ReConnect() { Logging.Debug("Reconnect " + cfg.TargetHost + ":" + cfg.TargetPort + " " + connection.GetSocket().Handle); { var handler = new Handler(); handler.getCurrentServer = getCurrentServer; handler.keepCurrentServer = keepCurrentServer; handler.select_server = select_server; handler.connection = connection; handler.connectionUDP = connectionUDP; if (cfg.Clone() is HandlerConfig config) { handler.cfg = config; handler.cfg.ReconnectTimesRemain = cfg.ReconnectTimesRemain - 1; handler.cfg.ReconnectTimes = cfg.ReconnectTimes + 1; } handler.speedTester.Transfer = speedTester.Transfer; var total_len = 0; var newFirstPacket = remoteHeaderSendBuffer; if (connectionSendBufferList != null && connectionSendBufferList.Count > 0) { foreach (var data in connectionSendBufferList) { total_len += data.Length; } newFirstPacket = new byte[total_len]; total_len = 0; foreach (var data in connectionSendBufferList) { Buffer.BlockCopy(data, 0, newFirstPacket, total_len, data.Length); total_len += data.Length; } } handler.Start(newFirstPacket, newFirstPacket.Length, connection.local_sendback_protocol); } return true; } public void Start(byte[] firstPacket, int length, string rsp_protocol) { connection.local_sendback_protocol = rsp_protocol; if (cfg.Socks5RemotePort > 0) { cfg.AutoSwitchOff = false; } ResetTimeout(cfg.Ttl); if (State == ConnectState.READY) { State = ConnectState.HANDSHAKE; remoteHeaderSendBuffer = firstPacket; detector.OnSend(remoteHeaderSendBuffer, length); var data = new byte[length]; Array.Copy(remoteHeaderSendBuffer, data, data.Length); connectionSendBufferList.Add(data); remoteHeaderSendBuffer = data; if (cfg.ReconnectTimes > 0) { Task.Run(Connect); } else { Connect(); } } else { Close(); } } private void BeginConnect(IPAddress ipAddress, int serverPort) { var remoteEP = new IPEndPoint(ipAddress, serverPort); if (cfg.Socks5RemotePort != 0 || connectionUDP == null || connectionUDP != null && server.UdpOverTcp) { remote = new ProxyEncryptSocket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); remote.GetSocket().NoDelay = true; try { remote.CreateEncryptor(server.Method, server.Password); } catch { // ignored } remote.SetProtocol(ObfsFactory.GetObfs(server.Protocol)); remote.SetObfs(ObfsFactory.GetObfs(server.obfs)); } if (connectionUDP != null && !server.UdpOverTcp) { try { remoteUDP = new ProxyEncryptSocket(ipAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp); remoteUDP.GetSocket().Bind(new IPEndPoint(ipAddress.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0)); remoteUDP.CreateEncryptor(server.Method, server.Password); remoteUDP.SetProtocol(ObfsFactory.GetObfs(server.Protocol)); remoteUDP.SetObfs(ObfsFactory.GetObfs(server.obfs)); if (server.Server_Udp_Port == 0 || cfg.Socks5RemotePort != 0) { var _remoteEP = new IPEndPoint(ipAddress, serverPort); remoteUDP.SetUdpEndPoint(_remoteEP); } else { var _remoteEP = new IPEndPoint(ipAddress, server.Server_Udp_Port); remoteUDP.SetUdpEndPoint(_remoteEP); } } catch (SocketException) { remoteUDP = null; } } ResetTimeout(cfg.Ttl); // Connect to the remote endpoint. if (cfg.Socks5RemotePort == 0 && connectionUDP != null && !server.UdpOverTcp) { var _state = State; if (_state == ConnectState.CONNECTING) { StartPipe(); } } else { speedTester.BeginConnect(); var result = remote.BeginConnect(remoteEP, ConnectCallback, new CallbackStatus()); var t = cfg.ConnectTimeout <= 0 ? 30 : cfg.ConnectTimeout; var success = result.AsyncWaitHandle.WaitOne((int)(t * 1000), true); if (!success) { ((CallbackStatus)result.AsyncState).SetIfEqu(-1, 0); if (((CallbackStatus)result.AsyncState).Status == -1) { if (lastErrCode == 0) { lastErrCode = 8; server.SpeedLog.AddTimeoutTimes(); } CloseSocket(ref remote); Close(); } } } } public bool TryReconnect() { if (local_error) { return false; } if (cfg.ReconnectTimesRemain > 0) { if (State == ConnectState.CONNECTING) { return ReConnect(); } if (State == ConnectState.CONNECTED && lastErrCode == 8) { if (connectionSendBufferList != null) { return ReConnect(); } } } return false; } private void CloseSocket(ref Socket sock) { lock (this) { if (sock != null) { var s = sock; sock = null; try { s.Shutdown(SocketShutdown.Both); } catch { // ignored } try { s.Close(); } catch { // ignored } } } } private void CloseSocket(ref ProxySocketTunLocal sock) { lock (this) { if (sock != null) { var s = sock; sock = null; try { s.Shutdown(SocketShutdown.Both); } catch { // ignored } try { s.Close(); } catch { // ignored } } } } private void CloseSocket(ref ProxyEncryptSocket sock) { lock (this) { if (sock != null) { var s = sock; sock = null; try { s.Shutdown(SocketShutdown.Both); } catch { // ignored } try { s.Close(); } catch { // ignored } } } } public override void Shutdown() { Task.Run(Close); } public void Close() { lock (this) { if (closed) { return; } closed = true; } Thread.Sleep(200); CloseSocket(ref remote); CloseSocket(ref remoteUDP); if (connection != null && cfg != null && connection.GetSocket() != null) { if (cfg.TargetHost is not null) { Logging.Debug($@"Close {cfg.TargetHost}:{cfg.TargetPort} {connection.GetSocket().Handle}"); } } if (lastErrCode == 0 && server != null && speedTester != null) { if (!local_error && speedTester.SizeProtocolRecv == 0 && speedTester.SizeUpload > 0) { if (is_protocol_sendback || is_obfs_sendback && speedTester.SizeDownload == 0) { lastErrCode = 16; server.SpeedLog.AddErrorDecodeTimes(); } else { server.SpeedLog.AddErrorEmptyTimes(); } } else { server.SpeedLog.AddNoErrorTimes(); } } if (lastErrCode == 0 && server != null && cfg != null) { keepCurrentServer?.Invoke(localPort, cfg.TargetHost, server.Id); } ResetTimeout(0); try { var reconnect = TryReconnect(); //lock (this) { if (State != ConnectState.END) { if (State != ConnectState.READY && State != ConnectState.HANDSHAKE && server != null) { if (server.Connections.DecRef(this)) { server.SpeedLog.AddDisconnectTimes(); } } State = ConnectState.END; } } if (!reconnect) { if (cfg.TargetHost is not null) { Logging.Info($@"Disconnect {cfg.TargetHost}:{cfg.TargetPort}"); } CloseSocket(ref connection); CloseSocket(ref connectionUDP); if (cfg.TargetHost is not null) { Logging.Debug($@"Transfer {cfg.TargetHost}:{cfg.TargetPort + speedTester.TransferLog()}"); } } else { connection = null; connectionUDP = null; } if (cfg != null && cfg.AutoSwitchOff && server != null) { if (server.SpeedLog.ErrorPercent.HasValue && server.SpeedLog.ErrorPercent >= 100 && (server.SpeedLog.ConnectError >= 3 || server.SpeedLog.ErrorContinuousTimes >= 3 || server.SpeedLog.ErrorTimeoutTimes >= 3 || server.SpeedLog.ErrorEmptyTimes >= 3)) { server.Enable = false; } } } catch (Exception e) { Logging.LogUsefulException(e); } getCurrentServer = null; keepCurrentServer = null; detector = null; speedTester = null; remoteUDPRecvBuffer = null; server = null; select_server = null; cfg = null; } private bool ConnectProxyServer(string strRemoteHost, int iRemotePort) { if (cfg.ProxyType == ProxyType.Socks5) { var ret = remote.ConnectSocks5ProxyServer(strRemoteHost, iRemotePort, connectionUDP != null && !server.UdpOverTcp, cfg.Socks5RemoteUsername, cfg.Socks5RemotePassword); remote.SetTcpServer(server.server, server.Server_Port); remote.SetUdpServer(server.server, server.Server_Udp_Port == 0 ? server.Server_Port : server.Server_Udp_Port); if (remoteUDP != null) { remoteUDP.GoS5Proxy = true; remoteUDP.SetUdpServer(server.server, server.Server_Udp_Port == 0 ? server.Server_Port : server.Server_Udp_Port); remoteUDP.SetUdpEndPoint(remote.GetProxyUdpEndPoint()); } return ret; } if (cfg.ProxyType == ProxyType.Http) { var ret = remote.ConnectHttpProxyServer(strRemoteHost, iRemotePort, cfg.Socks5RemoteUsername, cfg.Socks5RemotePassword, cfg.ProxyUserAgent); remote.SetTcpServer(server.server, server.Server_Port); return ret; } return true; } private void Connect() { remote = null; remoteUDP = null; localPort = ((IPEndPoint)connection.GetSocket().LocalEndPoint).Port; if (select_server == null) { if (cfg.TargetHost == null) { cfg.TargetHost = GetQueryString(); cfg.TargetPort = GetQueryPort(); server = getCurrentServer(localPort, null, cfg.TargetHost, cfg.Random, true); } else { server = getCurrentServer(localPort, null, cfg.TargetHost, cfg.Random, true, cfg.ForceRandom); } } else { if (cfg.TargetHost == null) { cfg.TargetHost = GetQueryString(); cfg.TargetPort = GetQueryPort(); server = getCurrentServer(localPort, select_server, cfg.TargetHost, true, true); } else { server = getCurrentServer(localPort, select_server, cfg.TargetHost, true, true, cfg.ForceRandom); } } speedTester.ServerId = server.Id; Logging.Info(cfg.TargetHost is null ? $@"Send udp via {server.server}:{server.Server_Port}" : $@"Connect {cfg.TargetHost}:{cfg.TargetPort} via {server.server}:{server.Server_Port}"); ResetTimeout(cfg.Ttl); if (Global.GuiConfig.ProxyRuleMode != ProxyRuleMode.Disable && cfg.TargetHost != null) { var host = cfg.TargetHost; if (!IPAddress.TryParse(host, out var ipAddress)) { ipAddress = DnsUtil.DnsBuffer.Get(host) ?? DnsUtil.QueryDns(host); if (ipAddress != null) { Logging.Info($@"DNS nolock query {host} answer {ipAddress}"); DnsUtil.DnsBuffer.Set(host, new IPAddress(ipAddress.GetAddressBytes())); DnsUtil.DnsBuffer.Sweep(); } else { Logging.Info($@"DNS nolock query {host} failed."); } } if (ipAddress != null) { cfg.TargetHost = ipAddress.ToString(); ResetTimeout(cfg.Ttl); } } lock (this) { server.SpeedLog.AddConnectTimes(); if (State == ConnectState.HANDSHAKE) { State = ConnectState.CONNECTING; } server.Connections.AddRef(this); } try { var serverHost = server.server; int serverPort = server.Server_Port; if (cfg.Socks5RemotePort > 0) { serverHost = cfg.Socks5RemoteHost; serverPort = cfg.Socks5RemotePort; } if (!IPAddress.TryParse(serverHost, out var ipAddress)) { if (server.SpeedLog.ErrorContinuousTimes > 10) { server.DnsBuffer.force_expired = true; } if (server.DnsBuffer.IsExpired(serverHost)) { var dnsOk = false; var buf = server.DnsBuffer; if (Monitor.TryEnter(buf, buf.Ip != null ? 100 : 1000000)) { if (buf.IsExpired(serverHost)) { ipAddress = DnsUtil.QueryDns(serverHost); if (ipAddress != null) { buf.UpdateDns(serverHost, ipAddress); dnsOk = true; } } else { ipAddress = buf.Ip; dnsOk = true; } Monitor.Exit(buf); } else { if (buf.Ip != null) { ipAddress = buf.Ip; dnsOk = true; } } if (!dnsOk) { if (server.DnsBuffer.Ip != null) { ipAddress = server.DnsBuffer.Ip; } else { lastErrCode = 8; server.SpeedLog.AddTimeoutTimes(); Close(); return; } } } else { ipAddress = server.DnsBuffer.Ip; } } BeginConnect(ipAddress, serverPort); } catch (Exception e) { LogException(e); Close(); } } private void ConnectCallback(IAsyncResult ar) { if (ar?.AsyncState != null) { ((CallbackStatus)ar.AsyncState).SetIfEqu(1, 0); if (((CallbackStatus)ar.AsyncState).Status != 1) { return; } } try { remote.EndConnect(ar); if (cfg.Socks5RemotePort > 0) { if (!ConnectProxyServer(server.server, server.Server_Port)) { throw new SocketException((int)SocketError.ConnectionReset); } } speedTester.EndConnect(); var _state = State; if (_state == ConnectState.CONNECTING) { StartPipe(); } } catch (Exception e) { LogExceptionAndClose(e); } } // do/end xxx tcp/udp Recv private void doConnectionTCPRecv() { if (connection != null && connectionTCPIdle) { connectionTCPIdle = false; var recv_size = remote == null ? RecvSize : remote.TcpMSS - remote.OverHead; var buffer = new byte[recv_size]; connection.BeginReceive(buffer, recv_size, SocketFlags.None, PipeConnectionReceiveCallback, null); } } private int endConnectionTCPRecv(IAsyncResult ar) { if (connection != null) { var bytesRead = connection.EndReceive(ar); connectionTCPIdle = true; return bytesRead; } return 0; } private void doConnectionUDPRecv() { if (connectionUDP != null && connectionUDPIdle) { connectionUDPIdle = false; const int bufferSize = 65536; var sender = new IPEndPoint(connectionUDP.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); EndPoint tempEP = sender; var buffer = new byte[bufferSize]; connectionUDP.BeginReceiveFrom(buffer, 0, bufferSize, SocketFlags.None, ref tempEP, PipeConnectionUDPReceiveCallback, buffer); } } private int endConnectionUDPRecv(IAsyncResult ar, ref EndPoint endPoint) { if (connectionUDP != null) { var bytesRead = connectionUDP.EndReceiveFrom(ar, ref endPoint); if (connectionUDPEndPoint == null) { connectionUDPEndPoint = (IPEndPoint)endPoint; } connectionUDPIdle = true; return bytesRead; } return 0; } private void doRemoteTCPRecv() { if (remote != null && remoteTCPIdle) { remoteTCPIdle = false; remote.BeginReceive(new byte[BufferSize], RecvSize, SocketFlags.None, PipeRemoteReceiveCallback, null); } } private int endRemoteTCPRecv(IAsyncResult ar) { if (remote != null) { var bytesRead = remote.EndReceive(ar, out var sendback); var bytesRecv = remote.GetAsyncResultSize(ar); server.SpeedLog.AddDownloadBytes(bytesRecv, DateTime.Now, speedTester.AddDownloadSize(bytesRecv)); if (sendback) { RemoteSend(remoteUDPRecvBuffer, 0); doConnectionRecv(); } remoteTCPIdle = true; return bytesRead; } return 0; } private void doRemoteUDPRecv() { if (remoteUDP != null && remoteUDPIdle) { remoteUDPIdle = false; const int bufferSize = 65536; var sender = new IPEndPoint(remoteUDP.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); EndPoint tempEp = sender; remoteUDP.BeginReceiveFrom(new byte[bufferSize], bufferSize, SocketFlags.None, ref tempEp, PipeRemoteUDPReceiveCallback, null); } } private int endRemoteUDPRecv(IAsyncResult ar, ref EndPoint endPoint) { if (remoteUDP != null) { var bytesRead = remoteUDP.EndReceiveFrom(ar, ref endPoint); remoteUDPIdle = true; return bytesRead; } return 0; } private void doConnectionRecv() { doConnectionTCPRecv(); doConnectionUDPRecv(); } private void SetObfsPlugin() { int headLen; if (connectionSendBufferList != null && connectionSendBufferList.Count > 0) { headLen = ObfsBase.GetHeadSize(connectionSendBufferList[0], 30); } else { headLen = ObfsBase.GetHeadSize(remoteHeaderSendBuffer, 30); } remote?.SetObfsPlugin(server, headLen); remoteUDP?.SetObfsPlugin(server, headLen); } private string GetQueryString() { if (remoteHeaderSendBuffer == null) { return null; } switch (remoteHeaderSendBuffer[0]) { case ATYP_IPv4: { if (remoteHeaderSendBuffer.Length > 4) { return new IPAddress(remoteHeaderSendBuffer.Skip(1).Take(4).ToArray()).ToString(); } return null; } case ATYP_IPv6: { if (remoteHeaderSendBuffer.Length > 16) { return new IPAddress(remoteHeaderSendBuffer.Skip(1).Take(16).ToArray()).ToString(); } return null; } case ATYP_DOMAIN when remoteHeaderSendBuffer.Length > 1: { if (remoteHeaderSendBuffer.Length > remoteHeaderSendBuffer[1] + 1) { return System.Text.Encoding.UTF8.GetString(remoteHeaderSendBuffer, 2, remoteHeaderSendBuffer[1]); } break; } } return null; } private int GetQueryPort() { if (remoteHeaderSendBuffer == null) { return 0; } switch (remoteHeaderSendBuffer[0]) { case ATYP_IPv4: { if (remoteHeaderSendBuffer.Length > 6) { return (remoteHeaderSendBuffer[5] << 8) | remoteHeaderSendBuffer[6]; } return 0; } case ATYP_IPv6: { if (remoteHeaderSendBuffer.Length > 18) { return (remoteHeaderSendBuffer[17] << 8) | remoteHeaderSendBuffer[18]; } return 0; } case ATYP_DOMAIN when remoteHeaderSendBuffer.Length > 1: { if (remoteHeaderSendBuffer.Length > remoteHeaderSendBuffer[1] + 2) { var len = remoteHeaderSendBuffer[1]; return (remoteHeaderSendBuffer[len + 2] << 8) | remoteHeaderSendBuffer[len + 3]; } break; } } return 0; } // 2 sides connection start private void StartPipe() { try { // set mark connectionTCPIdle = true; connectionUDPIdle = true; remoteTCPIdle = true; remoteUDPIdle = true; closed = false; remoteUDPRecvBufferLength = 0; SetObfsPlugin(); ResetTimeout(cfg.ConnectTimeout); speedTester.BeginUpload(); // remote ready if (connectionUDP == null) // TCP { if (cfg.ReconnectTimes > 0 || cfg.TargetPort != 0) { RemoteSend(remoteHeaderSendBuffer, remoteHeaderSendBuffer.Length); remoteHeaderSendBuffer = null; } is_protocol_sendback = remote.isProtocolSendback; is_obfs_sendback = remote.isObfsSendback; } else // UDP { if (!server.UdpOverTcp && remoteUDP != null) { if (cfg.Socks5RemotePort == 0) { CloseSocket(ref remote); } remoteHeaderSendBuffer = null; } else if (remoteHeaderSendBuffer != null) { RemoteSend(remoteHeaderSendBuffer, remoteHeaderSendBuffer.Length); remoteHeaderSendBuffer = null; } } State = ConnectState.CONNECTED; if (connection.local_sendback_protocol != null) { connection.Send(remoteUDPRecvBuffer, 0, SocketFlags.None); } // remote recv first doRemoteTCPRecv(); doRemoteUDPRecv(); doConnectionTCPRecv(); doConnectionUDPRecv(); } catch (Exception e) { LogExceptionAndClose(e); } } private void ConnectionSend(byte[] buffer, int bytesToSend) { if (connectionUDP == null) { connection.Send(buffer, bytesToSend, SocketFlags.None); doRemoteUDPRecv(); } else { connectionUDP.BeginSendTo(buffer, 0, bytesToSend, SocketFlags.None, connectionUDPEndPoint, PipeConnectionUDPSendCallback, null); } } private void UDPoverTCPConnectionSend(byte[] send_buffer, int bytesToSend) { var buffer_list = new List(); lock (recvUDPoverTCPLock) { Utils.SetArrayMinSize(ref remoteUDPRecvBuffer, bytesToSend + remoteUDPRecvBufferLength); Array.Copy(send_buffer, 0, remoteUDPRecvBuffer, remoteUDPRecvBufferLength, bytesToSend); remoteUDPRecvBufferLength += bytesToSend; while (remoteUDPRecvBufferLength > 6) { var len = (remoteUDPRecvBuffer[0] << 8) + remoteUDPRecvBuffer[1]; if (len > remoteUDPRecvBufferLength) { break; } var buffer = new byte[len]; Array.Copy(remoteUDPRecvBuffer, buffer, len); remoteUDPRecvBufferLength -= len; Array.Copy(remoteUDPRecvBuffer, len, remoteUDPRecvBuffer, 0, remoteUDPRecvBufferLength); buffer[0] = 0; buffer[1] = 0; buffer_list.Add(buffer); } } if (buffer_list.Count == 0) { doRemoteTCPRecv(); } else { foreach (var buffer in buffer_list) { if (buffer == buffer_list[buffer_list.Count - 1]) { connectionUDP.BeginSendTo(buffer, 0, buffer.Length, SocketFlags.None, connectionUDPEndPoint, PipeConnectionUDPSendCallback, null); } else { connectionUDP.BeginSendTo(buffer, 0, buffer.Length, SocketFlags.None, connectionUDPEndPoint, PipeConnectionUDPSendCallbackNoRecv, null); } } } } private void PipeRemoteReceiveCallback(IAsyncResult ar) { var final_close = false; try { if (closed) { return; } var bytesRead = endRemoteTCPRecv(ar); if (remote.IsClose) { final_close = true; } else { remote.GetAsyncResultSize(ar); if (speedTester.BeginDownload()) { var pingTime = Convert.ToInt64((speedTester.TimeBeginDownload - speedTester.TimeBeginUpload).TotalMilliseconds); if (pingTime >= 0) { server.SpeedLog.AddConnectTime(pingTime); } } ResetTimeout(cfg.Ttl); speedTester.AddProtocolRecvSize(remote.GetAsyncProtocolSize(ar)); if (bytesRead > 0) { var remoteSendBuffer = new byte[BufferSize]; Array.Copy(remote.GetAsyncResultBuffer(ar), remoteSendBuffer, bytesRead); if (connectionUDP == null) { if (detector.OnRecv(remoteSendBuffer, bytesRead) > 0) { server.SpeedLog.AddErrorTimes(); } if (detector.Pass) { server.SpeedLog.ResetErrorDecodeTimes(); } else { server.SpeedLog.ResetEmptyTimes(); } connection.Send(remoteSendBuffer, bytesRead, SocketFlags.None); } else { UDPoverTCPConnectionSend(remoteSendBuffer, bytesRead); } server.SpeedLog.AddDownloadRawBytes(bytesRead); speedTester.AddRecvSize(bytesRead); _totalRecvSize += bytesRead; } if (connectionUDP == null && _totalRecvSize > 1024 * 1024 * 2) { PipeRemoteReceiveLoop(); } else { doRemoteTCPRecv(); } } } catch (Exception e) { LogException(e); final_close = true; } finally { if (final_close) { Close(); } } } private void PipeRemoteReceiveLoop() { var final_close = false; var recv_buffer = new byte[BufferSize * 4]; var beforeReceive = DateTime.Now; while (!closed) { try { var bytesRead = remote.Receive(recv_buffer, RecvSize, SocketFlags.None, out var bytesRecv, out var protocolSize, out var sendback); var now = DateTime.Now; if (remote != null && remote.IsClose) { final_close = true; break; } if (closed) { break; } if (speedTester.BeginDownload()) { var pingTime = Convert.ToInt64((speedTester.TimeBeginDownload - speedTester.TimeBeginUpload).TotalMilliseconds); if (pingTime >= 0) { server.SpeedLog.AddConnectTime(pingTime); } } server.SpeedLog.AddDownloadBytes(bytesRecv, now, speedTester.AddDownloadSize(bytesRecv)); ResetTimeout(cfg.Ttl); if (sendback) { RemoteSend(remoteUDPRecvBuffer, 0); doConnectionRecv(); } if (bytesRead > 0) { var remoteSendBuffer = new byte[BufferSize]; Array.Copy(recv_buffer, remoteSendBuffer, bytesRead); if (connectionUDP == null) { if (detector.OnRecv(remoteSendBuffer, bytesRead) > 0) { server.SpeedLog.AddErrorTimes(); } if (detector.Pass) { server.SpeedLog.ResetErrorDecodeTimes(); } else { server.SpeedLog.ResetEmptyTimes(); } connection.Send(remoteSendBuffer, bytesRead, SocketFlags.None); } else { UDPoverTCPConnectionSend(remoteSendBuffer, bytesRead); } speedTester.AddProtocolRecvSize(protocolSize); server.SpeedLog.AddDownloadRawBytes(bytesRead); speedTester.AddRecvSize(bytesRead); } if ((now - beforeReceive).TotalSeconds > 5) { _totalRecvSize = 0; doRemoteTCPRecv(); return; } beforeReceive = now; } catch (Exception e) { LogException(e); final_close = true; break; } } if (final_close) { Close(); } } // end ReceiveCallback private void PipeRemoteUDPReceiveCallback(IAsyncResult ar) { var final_close = false; try { if (closed) { return; } var sender = new IPEndPoint(remoteUDP.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); EndPoint tempEP = sender; var bytesRead = endRemoteUDPRecv(ar, ref tempEP); if (remoteUDP.IsClose) { final_close = true; } else { var bytesRecv = remoteUDP.GetAsyncResultSize(ar); if (speedTester.BeginDownload()) { var pingTime = Convert.ToInt64((speedTester.TimeBeginDownload - speedTester.TimeBeginUpload).TotalMilliseconds); if (pingTime >= 0) { server.SpeedLog.AddConnectTime(pingTime); } } server.SpeedLog.AddDownloadBytes(bytesRecv, DateTime.Now, speedTester.AddDownloadSize(bytesRecv)); ResetTimeout(cfg.Ttl); if (bytesRead <= 0) { doRemoteUDPRecv(); } else //if (bytesRead > 0) { ConnectionSend(remoteUDP.GetAsyncResultBuffer(ar), bytesRead); speedTester.AddRecvSize(bytesRead); server.SpeedLog.AddDownloadRawBytes(bytesRead); } } } catch (Exception e) { LogException(e); final_close = true; } finally { if (final_close) { Close(); } } } private int RemoteSend(byte[] bytes, int length) { var total_len = 0; int send_len; send_len = remote.Send(bytes, length, SocketFlags.None); if (send_len > 0) { server.SpeedLog.AddUploadBytes(send_len, DateTime.Now, speedTester.AddUploadSize(send_len)); if (length >= 0) { ResetTimeout(cfg.Ttl); } else { ResetTimeout(cfg.ConnectTimeout <= 0 ? 30 : cfg.ConnectTimeout, false); } total_len += send_len; if ((DateTime.Now - lastKeepTime).TotalSeconds > 5) { keepCurrentServer?.Invoke(localPort, cfg.TargetHost, server.Id); lastKeepTime = DateTime.Now; } while (true) { send_len = remote.Send(null, 0, SocketFlags.None); if (send_len > 0) { server.SpeedLog.AddUploadBytes(send_len, DateTime.Now, speedTester.AddUploadSize(send_len)); total_len += send_len; } else { break; } } } return total_len; } private void RemoteSendto(byte[] bytes, int length) { int send_len; send_len = remoteUDP.BeginSendTo(bytes, length, SocketFlags.None, PipeRemoteUDPSendCallback, null); server.SpeedLog.AddUploadBytes(send_len, DateTime.Now, speedTester.AddUploadSize(send_len)); } private void PipeConnectionReceiveCallback(IAsyncResult ar) { var final_close = false; try { if (closed) { return; } var bytesRead = endConnectionTCPRecv(ar); if (bytesRead > 0) { if (connectionUDP != null) { doConnectionTCPRecv(); ResetTimeout(cfg.Ttl); return; } var connetionRecvBuffer = new byte[BufferSize]; Array.Copy(((CallbackState)ar.AsyncState).buffer, 0, connetionRecvBuffer, 0, bytesRead); if (connectionSendBufferList != null) { detector.OnSend(connetionRecvBuffer, bytesRead); var data = new byte[bytesRead]; Array.Copy(connetionRecvBuffer, data, data.Length); connectionSendBufferList.Add(data); } if (State == ConnectState.CONNECTED) { if (remoteHeaderSendBuffer != null) { Array.Copy(connetionRecvBuffer, 0, connetionRecvBuffer, remoteHeaderSendBuffer.Length, bytesRead); Array.Copy(remoteHeaderSendBuffer, 0, connetionRecvBuffer, 0, remoteHeaderSendBuffer.Length); bytesRead += remoteHeaderSendBuffer.Length; remoteHeaderSendBuffer = null; } else { Logging.LogBin(LogLevel.Debug, "remote send", connetionRecvBuffer, bytesRead); } } if (speedTester.SizeRecv > 0) { connectionSendBufferList = null; server.SpeedLog.ResetContinuousTimes(); } if (closed || State != ConnectState.CONNECTED) { return; } if (connectionSendBufferList != null) { ResetTimeout(cfg.ConnectTimeout); } else { ResetTimeout(cfg.Ttl); } var send_len = RemoteSend(connetionRecvBuffer, bytesRead); if (!(send_len == 0 && bytesRead > 0)) { Task.Run(() => { try { doConnectionRecv(); } catch (Exception ex) { local_error = true; LogException(ex); Close(); } }); } } else { local_error = true; final_close = true; } } catch (Exception e) { local_error = true; LogException(e); final_close = true; } finally { if (final_close) { Close(); } } } private void PipeConnectionUDPReceiveCallback(IAsyncResult ar) { var final_close = false; try { if (closed) { return; } var sender = new IPEndPoint(connectionUDP.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); EndPoint tempEP = sender; var bytesRead = endConnectionUDPRecv(ar, ref tempEP); if (bytesRead > 0) { var connetionSendBuffer = new byte[bytesRead]; Array.Copy((byte[])ar.AsyncState, connetionSendBuffer, bytesRead); if (!server.UdpOverTcp && remoteUDP != null) { RemoteSendto(connetionSendBuffer, bytesRead); } else { if (connetionSendBuffer[0] == 0 && connetionSendBuffer[1] == 0) { connetionSendBuffer[0] = (byte)(bytesRead >> 8); connetionSendBuffer[1] = (byte)bytesRead; RemoteSend(connetionSendBuffer, bytesRead); doConnectionRecv(); } } ResetTimeout(cfg.Ttl); } else { final_close = true; } } catch (Exception e) { LogException(e); final_close = true; } finally { if (final_close) { Close(); } } } private void PipeRemoteUDPSendCallback(IAsyncResult ar) { if (closed) { return; } try { remoteUDP.EndSendTo(ar); doConnectionRecv(); } catch (Exception e) { LogExceptionAndClose(e); } } private void PipeConnectionUDPSendCallbackNoRecv(IAsyncResult ar) { if (closed) { return; } try { connectionUDP.EndSendTo(ar); } catch (Exception e) { LogExceptionAndClose(e); } } private void PipeConnectionUDPSendCallback(IAsyncResult ar) { if (closed) { return; } try { connectionUDP.EndSendTo(ar); doRemoteTCPRecv(); doRemoteUDPRecv(); } catch (Exception e) { LogExceptionAndClose(e); } } protected string getServerUrl(out string remarks) { var s = server; if (s == null) { remarks = ""; return ""; } remarks = s.Remarks; return s.server; } private void LogException(Exception e) { var err = LogSocketException(e); var server_url = getServerUrl(out var remarks); if (err != 0 && !Logging.LogSocketException(remarks, server_url, e)) { Logging.LogUsefulException(e); } } private void LogExceptionAndClose(Exception e) { LogException(e); Close(); } } } ================================================ FILE: shadowsocks-csharp/Proxy/HandlerConfig.cs ================================================ using Shadowsocks.Enums; using System; namespace Shadowsocks.Proxy { class HandlerConfig : ICloneable { public string TargetHost; public int TargetPort; public double Ttl; // Second public double ConnectTimeout; public int TryKeepAlive; public bool ForceLocalDnsQuery; // Server proxy public ProxyType ProxyType; public string Socks5RemoteHost; public int Socks5RemotePort; public string Socks5RemoteUsername; public string Socks5RemotePassword; public string ProxyUserAgent; // auto ban public bool AutoSwitchOff = true; // Reconnect public int ReconnectTimesRemain; public int ReconnectTimes; public bool Random; public bool ForceRandom; public object Clone() { var obj = new HandlerConfig { TargetHost = TargetHost, TargetPort = TargetPort, Ttl = Ttl, ConnectTimeout = ConnectTimeout, TryKeepAlive = TryKeepAlive, ForceLocalDnsQuery = ForceLocalDnsQuery, ProxyType = ProxyType, Socks5RemoteHost = Socks5RemoteHost, Socks5RemotePort = Socks5RemotePort, Socks5RemoteUsername = Socks5RemoteUsername, Socks5RemotePassword = Socks5RemotePassword, ProxyUserAgent = ProxyUserAgent, AutoSwitchOff = AutoSwitchOff, ReconnectTimesRemain = ReconnectTimesRemain, ReconnectTimes = ReconnectTimes, Random = Random, ForceRandom = ForceRandom }; return obj; } } } ================================================ FILE: shadowsocks-csharp/Proxy/HttpParser.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; namespace Shadowsocks.Proxy { internal class HttpParser { public bool httpProxy; public byte[] httpRequestBuffer; public int httpContentLength; //public byte[] lastContentBuffer; public string httpAuthUser; public string httpAuthPass; protected string httpHost; protected int httpPort; private readonly bool _redir; public HttpParser(bool redir = false) { this._redir = redir; } private static string ParseHostAndPort(string str, ref int port) { string host; if (str.StartsWith("[")) { var pos = str.LastIndexOf(']'); if (pos > 0) { host = str.Substring(1, pos - 1); if (str.Length > pos + 1 && str[pos + 2] == ':') { port = Convert.ToInt32(str.Substring(pos + 2)); } } else { host = str; } } else { var pos = str.LastIndexOf(':'); if (pos > 0) { host = str.Substring(0, pos); port = Convert.ToInt32(str.Substring(pos + 1)); } else { host = str; } } return host; } protected string ParseURL(string url, string host, int port) { if (url.StartsWith("http://")) { url = url.Substring(7); } if (url.StartsWith("[")) { if (url.StartsWith("[" + host + "]")) { url = url.Substring(host.Length + 2); } } else if (url.StartsWith(host)) { url = url.Substring(host.Length); } if (url.StartsWith(":")) { if (url.StartsWith(":" + port)) { url = url.Substring((":" + port).Length); } } if (!url.StartsWith("/")) { var pos_slash = url.IndexOf('/'); var pos_space = url.IndexOf(' '); if (pos_slash > 0 && pos_slash < pos_space) { url = url.Substring(pos_slash); } } if (url.StartsWith(" ")) { url = "/" + url; } return url; } public void HostToHandshakeBuffer(string host, int port, ref byte[] remoteHeaderSendBuffer) { if (_redir) { remoteHeaderSendBuffer = new byte[0]; } else if (host.Length > 0) { var parsed = IPAddress.TryParse(host, out var ipAddress); if (!parsed) { remoteHeaderSendBuffer = new byte[2 + host.Length + 2]; remoteHeaderSendBuffer[0] = 3; remoteHeaderSendBuffer[1] = (byte)host.Length; Encoding.UTF8.GetBytes(host).CopyTo(remoteHeaderSendBuffer, 2); } else { if (ipAddress.AddressFamily == AddressFamily.InterNetwork) { remoteHeaderSendBuffer = new byte[7]; remoteHeaderSendBuffer[0] = 1; ipAddress.GetAddressBytes().CopyTo(remoteHeaderSendBuffer, 1); } else { remoteHeaderSendBuffer = new byte[19]; remoteHeaderSendBuffer[0] = 4; ipAddress.GetAddressBytes().CopyTo(remoteHeaderSendBuffer, 1); } } remoteHeaderSendBuffer[remoteHeaderSendBuffer.Length - 2] = (byte)(port >> 8); remoteHeaderSendBuffer[remoteHeaderSendBuffer.Length - 1] = (byte)(port & 0xff); } } protected int AppendRequest(ref byte[] Packet, ref int PacketLength) { if (httpContentLength > 0) { if (httpContentLength >= PacketLength) { httpContentLength -= PacketLength; PacketLength = 0; Packet = new byte[0]; return -1; } var len = PacketLength - httpContentLength; var nextbuffer = new byte[len]; Array.Copy(Packet, httpContentLength, nextbuffer, 0, len); Packet = nextbuffer; PacketLength -= httpContentLength; httpContentLength = 0; } byte[] block = { (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }; int pos; if (httpRequestBuffer == null) { httpRequestBuffer = new byte[PacketLength]; } else { Array.Resize(ref httpRequestBuffer, httpRequestBuffer.Length + PacketLength); } Array.Copy(Packet, 0, httpRequestBuffer, httpRequestBuffer.Length - PacketLength, PacketLength); pos = httpRequestBuffer.AsSpan().IndexOf(block); return pos; } protected Dictionary ParseHttpHeader(string header) { var header_dict = new Dictionary(); var lines = header.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); var cmdItems = lines[0].Split(new[] { ' ' }, 3); for (var index = 1; index < lines.Length; ++index) { var parts = lines[index].Split(new[] { ": " }, 2, StringSplitOptions.RemoveEmptyEntries); if (parts.Length > 1) { header_dict[parts[0]] = parts[1]; } } header_dict["@0"] = cmdItems[0]; header_dict["@1"] = cmdItems[1]; header_dict["@2"] = cmdItems[2]; return header_dict; } protected string HeaderDictToString(Dictionary dict) { var result = ""; var cmd = dict["@0"] + " " + dict["@1"] + " " + dict["@2"] + "\r\n"; dict.Remove("@0"); dict.Remove("@1"); dict.Remove("@2"); result += "Host" + ": " + dict["Host"] + "\r\n"; dict.Remove("Host"); result = dict.Aggregate(result, (current, it) => $"{current}{it.Key}: {it.Value}\r\n"); return cmd + result + "\r\n"; } public int HandshakeReceive(byte[] _firstPacket, int _firstPacketLength, out byte[] remoteHeaderSendBuffer) { remoteHeaderSendBuffer = null; var pos = AppendRequest(ref _firstPacket, ref _firstPacketLength); if (pos < 0) { return 1; } var data = Encoding.UTF8.GetString(httpRequestBuffer, 0, pos + 4); { var nextbuffer = new byte[httpRequestBuffer.Length - (pos + 4)]; Array.Copy(httpRequestBuffer, pos + 4, nextbuffer, 0, nextbuffer.Length); httpRequestBuffer = nextbuffer; } var header_dict = ParseHttpHeader(data); httpPort = 80; if (header_dict["@0"] == "CONNECT") { httpHost = ParseHostAndPort(header_dict["@1"], ref httpPort); } else if (header_dict.ContainsKey("Host")) { httpHost = ParseHostAndPort(header_dict["Host"], ref httpPort); } else { return 500; } if (header_dict.ContainsKey("Content-Length") && Convert.ToInt32(header_dict["Content-Length"]) > 0) { httpContentLength = Convert.ToInt32(header_dict["Content-Length"]) + 2; } HostToHandshakeBuffer(httpHost, httpPort, ref remoteHeaderSendBuffer); if (_redir) { if (header_dict.ContainsKey("Proxy-Connection")) { header_dict["Connection"] = header_dict["Proxy-Connection"]; header_dict.Remove("Proxy-Connection"); } var httpRequest = HeaderDictToString(header_dict); var len = remoteHeaderSendBuffer.Length; var httpData = Encoding.UTF8.GetBytes(httpRequest); Array.Resize(ref remoteHeaderSendBuffer, len + httpData.Length); httpData.CopyTo(remoteHeaderSendBuffer, len); httpProxy = true; } var authOk = string.IsNullOrEmpty(httpAuthUser); if (header_dict.ContainsKey("Proxy-Authorization")) { var authString = header_dict["Proxy-Authorization"].Substring("Basic ".Length); var authStr = httpAuthUser + ":" + (httpAuthPass ?? ""); var httpAuthString = Convert.ToBase64String(Encoding.UTF8.GetBytes(authStr)); if (httpAuthString == authString) { authOk = true; } header_dict.Remove("Proxy-Authorization"); } if (authOk && httpRequestBuffer.Length > 0) { var len = httpRequestBuffer.Length; var httpData = httpRequestBuffer; Array.Resize(ref remoteHeaderSendBuffer, len + remoteHeaderSendBuffer.Length); httpData.CopyTo(remoteHeaderSendBuffer, remoteHeaderSendBuffer.Length - len); httpRequestBuffer = new byte[0]; } if (authOk && httpContentLength > 0) { var len = Math.Min(httpRequestBuffer.Length, httpContentLength); Array.Resize(ref remoteHeaderSendBuffer, len + remoteHeaderSendBuffer.Length); Array.Copy(httpRequestBuffer, 0, remoteHeaderSendBuffer, remoteHeaderSendBuffer.Length - len, len); var nextbuffer = new byte[httpRequestBuffer.Length - len]; Array.Copy(httpRequestBuffer, len, nextbuffer, 0, nextbuffer.Length); httpRequestBuffer = nextbuffer; } else { httpContentLength = 0; httpRequestBuffer = new byte[0]; } if (remoteHeaderSendBuffer == null || !authOk) { return 2; } if (httpProxy) { return 3; } return 0; } public static string Http200() { return "HTTP/1.1 200 Connection Established\r\n\r\n"; } public static string Http407() { var header = "HTTP/1.1 407 Proxy Authentication Required\r\nProxy-Authenticate: Basic realm=\"RRR\"\r\n"; var content = "" + "" + " " + " Error" + " " + " " + "

407 Proxy Authentication Required.

" + "\r\n"; return header + "\r\n" + content + "\r\n"; } public static string Http500() { var header = "HTTP/1.1 500 Internal Server Error\r\n"; var content = "" + "" + " " + " Error" + " " + " " + "

500 Internal Server Error.

" + ""; return header + "\r\n" + content + "\r\n"; } } } ================================================ FILE: shadowsocks-csharp/Proxy/IHandler.cs ================================================ namespace Shadowsocks.Proxy { public abstract class IHandler { public abstract void Shutdown(); } } ================================================ FILE: shadowsocks-csharp/Proxy/ProxyAuthHandler.cs ================================================ using Shadowsocks.Controller; using Shadowsocks.Controller.Service; using Shadowsocks.Enums; using Shadowsocks.Model; using Shadowsocks.Model.Transfer; using Shadowsocks.Util.NetUtils; using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using static Shadowsocks.Encryption.EncryptorBase; namespace Shadowsocks.Proxy { class ProxyAuthHandler { private Configuration _config; private ServerTransferTotal _transfer; private IPRangeSet _IPRange; private byte[] _firstPacket; private int _firstPacketLength; private Socket _connection; private Socket _connectionUDP; private string local_sendback_protocol; protected const int RecvSize = 2048; public const int BufferSize = 18497; protected byte[] _connetionRecvBuffer = new byte[BufferSize]; private byte _command; protected byte[] _remoteHeaderSendBuffer; protected HttpParser httpProxyState; private const int CMD_CONNECT = 0x01; private const int CMD_UDP_ASSOC = 0x03; public ProxyAuthHandler(Configuration config, ServerTransferTotal transfer, IPRangeSet ipRange, byte[] firstPacket, int length, Socket socket) { var localPort = ((IPEndPoint)socket.LocalEndPoint).Port; _config = config; _transfer = transfer; _IPRange = ipRange; _firstPacket = firstPacket; _firstPacketLength = length; _connection = socket; socket.NoDelay = true; if (_config.PortMapCache.TryGetValue(localPort, out var portMap) && portMap.type == PortMapType.Forward) { Connect(); } else { HandshakeReceive(); } } private bool AuthConnection(string authUser, string authPass) { if (string.IsNullOrEmpty(_config.AuthUser)) { return true; } if (_config.AuthUser == authUser && _config.AuthPass == authPass) { return true; } return IPSubnet.IsLoopBack(((IPEndPoint)_connection.RemoteEndPoint).Address); } private void HandshakeReceive() { try { var bytesRead = _firstPacketLength; if (bytesRead > 1) { if (_firstPacket[0] == 4 && _firstPacketLength >= 9 && (!string.IsNullOrEmpty(_config.AuthUser) || IPSubnet.IsLoopBack(((IPEndPoint)_connection.RemoteEndPoint).Address))) { RspSocks4aHandshakeReceive(); } else if (_firstPacket[0] == 5 && _firstPacketLength >= 3) { RspSocks5HandshakeReceive(); } else { RspHttpHandshakeReceive(); } } else { Close(); } } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void RspSocks4aHandshakeReceive() { var firstPacket = new List(); for (var i = 0; i < _firstPacketLength; ++i) { firstPacket.Add(_firstPacket[i]); } var dataSockSend = firstPacket.GetRange(0, 4); dataSockSend[0] = 0; dataSockSend[1] = 90; var remoteDNS = _firstPacket[4] == 0 && _firstPacket[5] == 0 && _firstPacket[6] == 0 && _firstPacket[7] == 1; if (remoteDNS) { for (var i = 0; i < 4; ++i) { dataSockSend.Add(0); } var addrStartPos = firstPacket.IndexOf(0x0, 8); var addr = firstPacket.GetRange(addrStartPos + 1, firstPacket.Count - addrStartPos - 2); _remoteHeaderSendBuffer = new byte[2 + addr.Count + 2]; _remoteHeaderSendBuffer[0] = 3; _remoteHeaderSendBuffer[1] = (byte)addr.Count; Array.Copy(addr.ToArray(), 0, _remoteHeaderSendBuffer, 2, addr.Count); _remoteHeaderSendBuffer[2 + addr.Count] = dataSockSend[2]; _remoteHeaderSendBuffer[2 + addr.Count + 1] = dataSockSend[3]; } else { for (var i = 0; i < 4; ++i) { dataSockSend.Add(_firstPacket[4 + i]); } _remoteHeaderSendBuffer = new byte[1 + 4 + 2]; _remoteHeaderSendBuffer[0] = 1; Array.Copy(dataSockSend.ToArray(), 4, _remoteHeaderSendBuffer, 1, 4); _remoteHeaderSendBuffer[1 + 4] = dataSockSend[2]; _remoteHeaderSendBuffer[1 + 4 + 1] = dataSockSend[3]; } _command = 1; // Set TCP connect command _connection.Send(dataSockSend.ToArray()); Connect(); } private void RspSocks5HandshakeReceive() { byte[] response = { 5, 0 }; if (_firstPacket[0] != 5) { response = new byte[] { 0, 91 }; Console.WriteLine(@"socks 4/5 protocol error"); _connection.Send(response); Close(); return; } var auth = false; var hasMethod = false; for (var index = 0; index < _firstPacket[1]; ++index) { if (_firstPacket[2 + index] == 0) { hasMethod = true; } else if (_firstPacket[2 + index] == 2) { auth = true; hasMethod = true; } } if (!hasMethod) { Console.WriteLine(@"Socks5 no acceptable auth method"); Close(); return; } if (auth) { response[1] = 2; _connection.BeginSend(response, 0, response.Length, SocketFlags.None, HandshakeAuthSendCallback, null); } else if (string.IsNullOrEmpty(_config.AuthUser) || IPSubnet.IsLoopBack(((IPEndPoint)_connection.RemoteEndPoint).Address)) { _connection.BeginSend(response, 0, response.Length, SocketFlags.None, HandshakeSendCallback, null); } else { Console.WriteLine(@"Socks5 Auth failed"); Close(); } } private void HandshakeAuthSendCallback(IAsyncResult ar) { try { _connection.EndSend(ar); var bytesRead = _connection.Receive(_connetionRecvBuffer, 1024, 0); //_connection.EndReceive(ar); if (bytesRead >= 3) { var user_len = _connetionRecvBuffer[1]; var pass_len = _connetionRecvBuffer[user_len + 2]; byte[] response = { 1, 0 }; var user = Encoding.UTF8.GetString(_connetionRecvBuffer, 2, user_len); var pass = Encoding.UTF8.GetString(_connetionRecvBuffer, user_len + 3, pass_len); if (AuthConnection(user, pass)) { _connection.BeginSend(response, 0, response.Length, SocketFlags.None, HandshakeSendCallback, null); } } else { Console.WriteLine(@"failed to recv data in HandshakeAuthSendCallback"); Close(); } } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void HandshakeSendCallback(IAsyncResult ar) { try { _connection.EndSend(ar); // +-----+-----+-------+------+----------+----------+ // | VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | // +-----+-----+-------+------+----------+----------+ // | 1 | 1 | X'00' | 1 | Variable | 2 | // +-----+-----+-------+------+----------+----------+ // Skip first 3 bytes, and read 2 more bytes to analysis the address. // 2 more bytes is designed if address is domain then we don't need to read once more to get the addr length. // TODO validate _connection.BeginReceive(_connetionRecvBuffer, 0, 3 + ADDR_ATYP_LEN + 1, SocketFlags.None, HandshakeReceive2Callback, null); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void HandshakeReceive2Callback(IAsyncResult ar) { try { var bytesRead = _connection.EndReceive(ar); if (bytesRead >= 5) { _command = _connetionRecvBuffer[1]; _remoteHeaderSendBuffer = new byte[bytesRead - 3]; Array.Copy(_connetionRecvBuffer, 3, _remoteHeaderSendBuffer, 0, _remoteHeaderSendBuffer.Length); var size = _remoteHeaderSendBuffer[0] switch { ATYP_IPv4 => (4 - 1), ATYP_IPv6 => (16 - 1), ATYP_DOMAIN => _remoteHeaderSendBuffer[1], _ => 0 }; if (size == 0) { throw new Exception("Wrong socks5 addr type"); } HandshakeReceive3Callback(size + ADDR_PORT_LEN); // recv port } else { Console.WriteLine(@"failed to recv data in HandshakeReceive2Callback"); Close(); } } catch { // ignored } } private void HandshakeReceive3Callback(int bytesRemain) { try { var bytesRead = _connection.Receive(_connetionRecvBuffer, bytesRemain, SocketFlags.None); if (bytesRead > 0) { Array.Resize(ref _remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length + bytesRead); Array.Copy(_connetionRecvBuffer, 0, _remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length - bytesRead, bytesRead); switch (_command) { case CMD_UDP_ASSOC: RspSocks5UDPHeader(bytesRead); break; case CMD_CONNECT: local_sendback_protocol = @"socks5"; Connect(); break; default: Logging.Debug($@"Unsupported CMD={_command}"); Close(); break; } } else { Console.WriteLine(@"failed to recv data in HandshakeReceive3Callback"); Close(); } } catch (Exception e) { Logging.LogUsefulException(e); Close(); } } private void RspSocks5UDPHeader(int bytesRead) { var ipv6 = _connection.AddressFamily == AddressFamily.InterNetworkV6; var udpPort = 0; if (bytesRead >= 3 + 6) { ipv6 = _remoteHeaderSendBuffer[0] == 4; if (!ipv6) { udpPort = _remoteHeaderSendBuffer[5] * 0x100 + _remoteHeaderSendBuffer[6]; } else { udpPort = _remoteHeaderSendBuffer[17] * 0x100 + _remoteHeaderSendBuffer[18]; } } if (!ipv6) { _remoteHeaderSendBuffer = new byte[1 + 4 + 2]; _remoteHeaderSendBuffer[0] = 0x8 | 1; _remoteHeaderSendBuffer[5] = (byte)(udpPort / 0x100); _remoteHeaderSendBuffer[6] = (byte)(udpPort % 0x100); } else { _remoteHeaderSendBuffer = new byte[1 + 16 + 2]; _remoteHeaderSendBuffer[0] = 0x8 | 4; _remoteHeaderSendBuffer[17] = (byte)(udpPort / 0x100); _remoteHeaderSendBuffer[18] = (byte)(udpPort % 0x100); } var port = 0; var ip = ipv6 ? IPAddress.IPv6Any : IPAddress.Any; _connectionUDP = new Socket(ip.AddressFamily, SocketType.Dgram, ProtocolType.Udp); for (; port < 65536; ++port) { try { _connectionUDP.Bind(new IPEndPoint(ip, port)); break; } catch (Exception) { // } } port = ((IPEndPoint)_connectionUDP.LocalEndPoint).Port; if (!ipv6) { byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, (byte)(port / 0x100), (byte)(port % 0x100) }; var ip_bytes = ((IPEndPoint)_connection.LocalEndPoint).Address.GetAddressBytes(); Array.Copy(ip_bytes, 0, response, 4, 4); _connection.Send(response); Connect(); } else { byte[] response = { 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)(port / 0x100), (byte)(port % 0x100) }; var ip_bytes = ((IPEndPoint)_connection.LocalEndPoint).Address.GetAddressBytes(); Array.Copy(ip_bytes, 0, response, 4, 16); _connection.Send(response); Connect(); } } private void RspHttpHandshakeReceive() { _command = 1; // Set TCP connect command if (httpProxyState == null) { httpProxyState = new HttpParser(); } if (IPSubnet.IsLoopBack(((IPEndPoint)_connection.RemoteEndPoint).Address)) { httpProxyState.httpAuthUser = string.Empty; httpProxyState.httpAuthPass = string.Empty; } else { httpProxyState.httpAuthUser = _config.AuthUser; httpProxyState.httpAuthPass = _config.AuthPass; } for (var i = 1; ; ++i) { var err = httpProxyState.HandshakeReceive(_firstPacket, _firstPacketLength, out _remoteHeaderSendBuffer); if (err == 1) { if (HttpHandshakeRecv()) { break; } } else if (err == 2) { var dataSend = HttpParser.Http407(); var httpData = Encoding.UTF8.GetBytes(dataSend); _connection.Send(httpData); if (HttpHandshakeRecv()) { break; } } else if (err is 3 or 4) { Connect(); break; } else if (err == 0) { local_sendback_protocol = "http"; Connect(); break; } else if (err == 500) { var dataSend = HttpParser.Http500(); var httpData = Encoding.UTF8.GetBytes(dataSend); _connection.Send(httpData); if (HttpHandshakeRecv()) { break; } } if (i == 3) { Close(); break; } } } private bool HttpHandshakeRecv() { try { var bytesRead = _connection.Receive(_connetionRecvBuffer, _firstPacket.Length, 0); if (bytesRead > 0) { Array.Copy(_connetionRecvBuffer, _firstPacket, bytesRead); _firstPacketLength = bytesRead; return false; } Console.WriteLine(@"failed to recv data in HttpHandshakeRecv"); Close(); } catch (Exception e) { Logging.LogUsefulException(e); Close(); } return true; } private void Connect() { Server GetCurrentServer(int localPort, ServerSelectStrategy.FilterFunc filter, string targetURI, bool cfgRandom, bool usingRandom, bool forceRandom) => _config.GetCurrentServer(localPort, filter, targetURI, cfgRandom, usingRandom, forceRandom); void KeepCurrentServer(int localPort, string targetURI, string id) { _config.KeepCurrentServer(localPort, targetURI, id); } var local_port = ((IPEndPoint)_connection.LocalEndPoint).Port; var handler = new Handler { getCurrentServer = GetCurrentServer, keepCurrentServer = KeepCurrentServer, connection = new ProxySocketTunLocal(_connection), connectionUDP = _connectionUDP, cfg = { ReconnectTimesRemain = _config.ReconnectTimes, Random = _config.Random, ForceRandom = _config.Random } }; handler.setServerTransferTotal(_transfer); if (_config.ProxyEnable) { handler.cfg.ProxyType = _config.ProxyType; handler.cfg.Socks5RemoteHost = _config.ProxyHost; handler.cfg.Socks5RemotePort = _config.ProxyPort; handler.cfg.Socks5RemoteUsername = _config.ProxyAuthUser; handler.cfg.Socks5RemotePassword = _config.ProxyAuthPass; handler.cfg.ProxyUserAgent = _config.ProxyUserAgent; } handler.cfg.Ttl = _config.Ttl; handler.cfg.ConnectTimeout = _config.ConnectTimeout; handler.cfg.AutoSwitchOff = _config.AutoBan; if (_config.PortMapCache.ContainsKey(local_port)) { var cfg = _config.PortMapCache[local_port]; if (cfg.server == null || cfg.id == cfg.server.Id) { if (cfg.server != null) { handler.select_server = (server, selServer) => server.Id == cfg.server.Id; } else if (!string.IsNullOrEmpty(cfg.id)) { handler.select_server = (server, selServer) => server.Group == cfg.id; } if (cfg.type == PortMapType.Forward) // tunnel { var addr = Encoding.UTF8.GetBytes(cfg.server_addr); var newFirstPacket = new byte[_firstPacketLength + addr.Length + 4]; newFirstPacket[0] = 3; newFirstPacket[1] = (byte)addr.Length; Array.Copy(addr, 0, newFirstPacket, 2, addr.Length); newFirstPacket[addr.Length + 2] = (byte)(cfg.server_port / 256); newFirstPacket[addr.Length + 3] = (byte)(cfg.server_port % 256); Array.Copy(_firstPacket, 0, newFirstPacket, addr.Length + 4, _firstPacketLength); _remoteHeaderSendBuffer = newFirstPacket; handler.Start(_remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length, null); } else if (_connectionUDP == null && cfg.type == PortMapType.RuleProxy && new Socks5Forwarder(_config, _IPRange).Handle(_remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length, _connection, local_sendback_protocol)) { } else { handler.Start(_remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length, @"socks5"); } Dispose(); return; } } else { if (_connectionUDP != null || !new Socks5Forwarder(_config, _IPRange) .Handle(_remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length, _connection, local_sendback_protocol)) { handler.Start(_remoteHeaderSendBuffer, _remoteHeaderSendBuffer.Length, local_sendback_protocol); } Dispose(); return; } Dispose(); Close(); } private void CloseSocket(ref Socket sock) { lock (this) { if (sock == null) { return; } try { sock.Shutdown(SocketShutdown.Both); } catch { // ignored } try { sock.Close(); } catch { // ignored } finally { sock = null; } } } private void Close() { CloseSocket(ref _connection); CloseSocket(ref _connectionUDP); _config = null; } private void Dispose() { _transfer = null; _IPRange = null; _firstPacket = null; _connection = null; _connectionUDP = null; _connetionRecvBuffer = null; _remoteHeaderSendBuffer = null; httpProxyState = null; } } } ================================================ FILE: shadowsocks-csharp/Proxy/ProxyEncryptSocket.cs ================================================ using Shadowsocks.Encryption; using Shadowsocks.Model; using Shadowsocks.Obfs; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; namespace Shadowsocks.Proxy { class ProxyEncryptSocket { protected Socket _socket; protected EndPoint _socketEndPoint; protected IPEndPoint _remoteUDPEndPoint; protected IEncryptor _encryptor; protected object _encryptionLock = new(); protected object _decryptionLock = new(); protected string _method; protected string _password; public IObfs _protocol; public IObfs _obfs; protected bool _proxy; protected string _proxy_server; protected int _proxy_udp_port; public const int MTU = 1492; public const int MSS = MTU - 40; protected const int RecvSize = ProxyAuthHandler.BufferSize; public int TcpMSS = MSS; public int RecvBufferSize; public int OverHead; private byte[] SendEncryptBuffer = new byte[RecvSize]; private byte[] ReceiveDecryptBuffer = new byte[RecvSize]; protected bool _close; public ProxyEncryptSocket(AddressFamily af, SocketType type, ProtocolType protocol) { _socket = new Socket(af, type, protocol); } public Socket GetSocket() { return _socket; } public bool IsClose => _close; public bool GoS5Proxy { get => _proxy; set => _proxy = value; } public bool CanSendKeepAlive => _protocol.isKeepAlive(); public bool isProtocolSendback => _protocol.isAlwaysSendback(); public bool isObfsSendback => _obfs.isAlwaysSendback(); public AddressFamily AddressFamily => _socket.AddressFamily; public int Available => _socket.Available; public void Shutdown(SocketShutdown how) { _socket.Shutdown(how); } public void Close() { _socket.Close(); if (_protocol != null) { _protocol.Dispose(); _protocol = null; } if (_obfs != null) { _obfs.Dispose(); _obfs = null; } lock (_encryptionLock) { lock (_decryptionLock) { if (_encryptor != null) { _encryptor.Dispose(); _encryptor = null; } } } _socket = null; SendEncryptBuffer = null; ReceiveDecryptBuffer = null; } public IAsyncResult BeginConnect(EndPoint ep, AsyncCallback callback, object state) { _close = false; _socketEndPoint = ep; return _socket.BeginConnect(ep, callback, state); } public void EndConnect(IAsyncResult ar) { _socket.EndConnect(ar); } public void CreateEncryptor(string method, string password) { _encryptor = EncryptorFactory.GetEncryptor(method, password); _method = method; _password = password; } public void SetProtocol(IObfs protocol) { _protocol = protocol; } public void SetObfs(IObfs obfs) { _obfs = obfs; } public void SetObfsPlugin(Server server, int head_len) { lock (server) // need a server lock { if (server.ProtocolData == null) { server.ProtocolData = _protocol.InitData(); } if (server.ObfsData == null) { server.ObfsData = _obfs.InitData(); } } var mss = MSS; var server_addr = server.server; OverHead = _protocol.GetOverhead() + _obfs.GetOverhead(); RecvBufferSize = RecvSize - OverHead; if (_proxy_server != null) { server_addr = _proxy_server; } _protocol.SetServerInfo(new ServerInfo(server_addr, server.Server_Port, server.ProtocolParam, server.ProtocolData, _encryptor.getIV(), _password, _encryptor.getKey(), head_len, mss, OverHead, RecvBufferSize)); _obfs.SetServerInfo(new ServerInfo(server_addr, server.Server_Port, server.ObfsParam, server.ObfsData, _encryptor.getIV(), _password, _encryptor.getKey(), head_len, mss, OverHead, RecvBufferSize)); } public int Receive(byte[] recv_buffer, int size, SocketFlags flags, out int bytesRead, out int protocolSize, out bool sendback) { bytesRead = _socket.Receive(recv_buffer, size, flags); protocolSize = 0; if (bytesRead > 0) { lock (_decryptionLock) { var remoteRecvObfsBuffer = _obfs.ClientDecode(recv_buffer, bytesRead, out var obfsRecvSize, out sendback); if (obfsRecvSize > 0) { Util.Utils.SetArrayMinSize(ref ReceiveDecryptBuffer, obfsRecvSize); _encryptor.Decrypt(remoteRecvObfsBuffer, obfsRecvSize, ReceiveDecryptBuffer, out var bytesToSend); protocolSize = bytesToSend; var buffer = _protocol.ClientPostDecrypt(ReceiveDecryptBuffer, bytesToSend, out var outlength); TcpMSS = _protocol.GetTcpMSS(); //if (recv_buffer.Length < outlength) //ASSERT Array.Copy(buffer, 0, recv_buffer, 0, outlength); return outlength; } } return 0; } sendback = false; _close = true; return bytesRead; } public IAsyncResult BeginReceive(byte[] buffer, int size, SocketFlags flags, AsyncCallback callback, object state) { var st = new CallbackState(); st.buffer = buffer; st.size = size; st.state = state; return _socket.BeginReceive(buffer, 0, size, flags, callback, st); } public int EndReceive(IAsyncResult ar, out bool sendback) { var bytesRead = _socket.EndReceive(ar); sendback = false; if (bytesRead > 0) { var st = (CallbackState)ar.AsyncState; st.size = bytesRead; lock (_decryptionLock) { var remoteRecvObfsBuffer = _obfs.ClientDecode(st.buffer, bytesRead, out var obfsRecvSize, out sendback); if (obfsRecvSize > 0) { Util.Utils.SetArrayMinSize(ref ReceiveDecryptBuffer, obfsRecvSize); _encryptor.Decrypt(remoteRecvObfsBuffer, obfsRecvSize, ReceiveDecryptBuffer, out var bytesToSend); st.protocol_size = bytesToSend; var buffer = _protocol.ClientPostDecrypt(ReceiveDecryptBuffer, bytesToSend, out var outlength); TcpMSS = _protocol.GetTcpMSS(); if (st.buffer.Length < outlength) { Array.Resize(ref st.buffer, outlength); } Array.Copy(buffer, 0, st.buffer, 0, outlength); return outlength; } } return 0; } _close = true; return bytesRead; } public int SendAll(byte[] buffer, int size, SocketFlags flags) { var sendSize = _socket.Send(buffer, size, flags); while (sendSize < size) { var new_size = _socket.Send(buffer, sendSize, size - sendSize, flags); sendSize += new_size; } return size; } public int Send(byte[] buffer, int size, SocketFlags flags) { int obfsSendSize; byte[] obfsBuffer; lock (_encryptionLock) { var bytesToEncrypt = _protocol.ClientPreEncrypt(buffer, size, out var outlength); if (bytesToEncrypt == null) { return 0; } Util.Utils.SetArrayMinSize(ref SendEncryptBuffer, outlength + 32); _encryptor.Encrypt(bytesToEncrypt, outlength, SendEncryptBuffer, out var bytesToSend); obfsBuffer = _obfs.ClientEncode(SendEncryptBuffer, bytesToSend, out obfsSendSize); } return SendAll(obfsBuffer, obfsSendSize, flags); } public IAsyncResult BeginReceiveFrom(byte[] buffer, int size, SocketFlags flags, ref EndPoint ep, AsyncCallback callback, object state) { var st = new CallbackState(); st.buffer = buffer; st.size = size; st.state = state; return _socket.BeginReceiveFrom(buffer, 0, size, flags, ref ep, callback, st); } private bool RemoveRemoteUDPRecvBufferHeader(byte[] remoteRecvBuffer, ref int bytesRead) { if (_proxy) { if (bytesRead < 7) { return false; } if (remoteRecvBuffer[3] == 1) { var head = 3 + 1 + 4 + 2; bytesRead = bytesRead - head; Array.Copy(remoteRecvBuffer, head, remoteRecvBuffer, 0, bytesRead); } else if (remoteRecvBuffer[3] == 4) { var head = 3 + 1 + 16 + 2; bytesRead = bytesRead - head; Array.Copy(remoteRecvBuffer, head, remoteRecvBuffer, 0, bytesRead); } else if (remoteRecvBuffer[3] == 3) { var head = 3 + 1 + 1 + remoteRecvBuffer[4] + 2; bytesRead = bytesRead - head; Array.Copy(remoteRecvBuffer, head, remoteRecvBuffer, 0, bytesRead); } else { return false; } //if (port != server.server_port && port != server.server_udp_port) //{ // return false; //} } return true; } protected static byte[] ParseUDPHeader(byte[] buffer, ref int len) { if (buffer.Length == 0) { return buffer; } if (buffer[0] == 0x81) { len = len - 1; var ret = new byte[len]; Array.Copy(buffer, 1, ret, 0, len); return ret; } if (buffer[0] == 0x80 && len >= 2) { int ofbs_len = buffer[1]; if (ofbs_len + 2 < len) { len = len - ofbs_len - 2; var ret = new byte[len]; Array.Copy(buffer, ofbs_len + 2, ret, 0, len); return ret; } } if (buffer[0] == 0x82 && len >= 3) { var ofbs_len = (buffer[1] << 8) + buffer[2]; if (ofbs_len + 3 < len) { len = len - ofbs_len - 3; var ret = new byte[len]; Array.Copy(buffer, ofbs_len + 3, ret, 0, len); return ret; } } if (len < buffer.Length) { var ret = new byte[len]; Array.Copy(buffer, ret, len); return ret; } return buffer; } protected void AddRemoteUDPRecvBufferHeader(byte[] decryptBuffer, byte[] remoteSendBuffer, ref int bytesToSend) { Array.Copy(decryptBuffer, 0, remoteSendBuffer, 3, bytesToSend); remoteSendBuffer[0] = 0; remoteSendBuffer[1] = 0; remoteSendBuffer[2] = 0; bytesToSend += 3; } public int EndReceiveFrom(IAsyncResult ar, ref EndPoint ep) { var bytesRead = _socket.EndReceiveFrom(ar, ref ep); if (bytesRead > 0) { var st = (CallbackState)ar.AsyncState; st.size = bytesRead; int bytesToSend; if (!RemoveRemoteUDPRecvBufferHeader(st.buffer, ref bytesRead)) { return 0; // drop } var remoteSendBuffer = new byte[RecvSize]; byte[] obfsBuffer; lock (_decryptionLock) { var decryptBuffer = new byte[RecvSize]; _encryptor.ResetDecrypt(); _encryptor.Decrypt(st.buffer, bytesRead, decryptBuffer, out bytesToSend); obfsBuffer = _protocol.ClientUdpPostDecrypt(decryptBuffer, bytesToSend, out bytesToSend); decryptBuffer = ParseUDPHeader(obfsBuffer, ref bytesToSend); AddRemoteUDPRecvBufferHeader(decryptBuffer, remoteSendBuffer, ref bytesToSend); } Array.Copy(remoteSendBuffer, 0, st.buffer, 0, bytesToSend); return bytesToSend; } _close = true; return bytesRead; } public int BeginSendTo(byte[] buffer, int size, SocketFlags flags, AsyncCallback callback, object state) { var st = new CallbackState(); st.buffer = buffer; st.size = size; st.state = state; int bytesToSend; var connetionSendBuffer = new byte[RecvSize]; var bytes_beg = 3; var length = size - bytes_beg; var bytesToEncrypt = new byte[length]; Array.Copy(buffer, bytes_beg, bytesToEncrypt, 0, length); lock (_encryptionLock) { _encryptor.ResetEncrypt(); _protocol.SetServerInfoIV(_encryptor.getIV()); var obfsBuffer = _protocol.ClientUdpPreEncrypt(bytesToEncrypt, length, out var obfsSendSize); _encryptor.Encrypt(obfsBuffer, obfsSendSize, connetionSendBuffer, out bytesToSend); } if (_proxy) { var serverURI = _proxy_server; var serverPort = _proxy_udp_port; var parsed = IPAddress.TryParse(serverURI, out var ipAddress); if (!parsed) { bytesToEncrypt = new byte[bytes_beg + 1 + 1 + serverURI.Length + 2 + bytesToSend]; Array.Copy(connetionSendBuffer, 0, bytesToEncrypt, bytes_beg + 1 + 1 + serverURI.Length + 2, bytesToSend); bytesToEncrypt[0] = 0; bytesToEncrypt[1] = 0; bytesToEncrypt[2] = 0; bytesToEncrypt[3] = 3; bytesToEncrypt[4] = (byte)serverURI.Length; for (var i = 0; i < serverURI.Length; ++i) { bytesToEncrypt[5 + i] = (byte)serverURI[i]; } bytesToEncrypt[5 + serverURI.Length] = (byte)(serverPort / 0x100); bytesToEncrypt[5 + serverURI.Length + 1] = (byte)(serverPort % 0x100); } else { var addBytes = ipAddress.GetAddressBytes(); bytesToEncrypt = new byte[bytes_beg + 1 + addBytes.Length + 2 + bytesToSend]; Array.Copy(connetionSendBuffer, 0, bytesToEncrypt, bytes_beg + 1 + addBytes.Length + 2, bytesToSend); bytesToEncrypt[0] = 0; bytesToEncrypt[1] = 0; bytesToEncrypt[2] = 0; bytesToEncrypt[3] = ipAddress.AddressFamily == AddressFamily.InterNetworkV6 ? (byte)4 : (byte)1; for (var i = 0; i < addBytes.Length; ++i) { bytesToEncrypt[4 + i] = addBytes[i]; } bytesToEncrypt[4 + addBytes.Length] = (byte)(serverPort / 0x100); bytesToEncrypt[4 + addBytes.Length + 1] = (byte)(serverPort % 0x100); } bytesToSend = bytesToEncrypt.Length; Array.Copy(bytesToEncrypt, connetionSendBuffer, bytesToSend); } _socket.BeginSendTo(connetionSendBuffer, 0, bytesToSend, flags, _remoteUDPEndPoint, callback, st); return bytesToSend; } public int EndSendTo(IAsyncResult ar) { return _socket.EndSendTo(ar); } public int GetAsyncResultSize(IAsyncResult ar) { var st = (CallbackState)ar.AsyncState; return st.size; } public int GetAsyncProtocolSize(IAsyncResult ar) { var st = (CallbackState)ar.AsyncState; return st.protocol_size; } public byte[] GetAsyncResultBuffer(IAsyncResult ar) { var st = (CallbackState)ar.AsyncState; return st.buffer; } public IPEndPoint GetProxyUdpEndPoint() { return _remoteUDPEndPoint; } public bool ConnectSocks5ProxyServer(string strRemoteHost, int iRemotePort, bool udp, string socks5RemoteUsername, string socks5RemotePassword) { var socketErrorCode = (int)SocketError.ConnectionReset; _proxy = true; //构造Socks5代理服务器第一连接头(无用户名密码) var bySock5Send = new byte[10]; bySock5Send[0] = 5; bySock5Send[1] = socks5RemoteUsername.Length == 0 ? (byte)1 : (byte)2; bySock5Send[2] = 0; bySock5Send[3] = 2; //发送Socks5代理第一次连接信息 SendAll(bySock5Send, 2 + bySock5Send[1], SocketFlags.None); var bySock5Receive = new byte[32]; var iRecCount = _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None); if (iRecCount < 2) { throw new SocketException(socketErrorCode); //throw new Exception("不能获得代理服务器正确响应。"); } if (bySock5Receive[0] != 5 || bySock5Receive[1] != 0 && bySock5Receive[1] != 2) { throw new SocketException(socketErrorCode); //throw new Exception("代理服务其返回的响应错误。"); } if (bySock5Receive[1] != 0) // auth { if (bySock5Receive[1] == 2) { if (socks5RemoteUsername.Length == 0) { throw new SocketException(socketErrorCode); //throw new Exception("代理服务器需要进行身份确认。"); } bySock5Send = new byte[socks5RemoteUsername.Length + socks5RemotePassword.Length + 3]; bySock5Send[0] = 1; bySock5Send[1] = (byte)socks5RemoteUsername.Length; for (var i = 0; i < socks5RemoteUsername.Length; ++i) { bySock5Send[2 + i] = (byte)socks5RemoteUsername[i]; } bySock5Send[socks5RemoteUsername.Length + 2] = (byte)socks5RemotePassword.Length; for (var i = 0; i < socks5RemotePassword.Length; ++i) { bySock5Send[socks5RemoteUsername.Length + 3 + i] = (byte)socks5RemotePassword[i]; } SendAll(bySock5Send, bySock5Send.Length, SocketFlags.None); _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None); if (bySock5Receive[0] != 1 || bySock5Receive[1] != 0) { throw new SocketException((int)SocketError.ConnectionRefused); } } else { return false; } } // connect if (!udp) // TCP { var dataSock5Send = new List { 5, 1, 0 }; if (!IPAddress.TryParse(strRemoteHost, out var ipAdd)) { dataSock5Send.Add(3); // remote DNS resolve dataSock5Send.Add((byte)strRemoteHost.Length); dataSock5Send.AddRange(strRemoteHost.Select(t => (byte)t)); } else { var addBytes = ipAdd.GetAddressBytes(); if (addBytes.GetLength(0) > 4) { dataSock5Send.Add(4); // IPv6 for (var i = 0; i < 16; ++i) { dataSock5Send.Add(addBytes[i]); } } else { dataSock5Send.Add(1); // IPv4 for (var i = 0; i < 4; ++i) { dataSock5Send.Add(addBytes[i]); } } } dataSock5Send.Add((byte)(iRemotePort / 256)); dataSock5Send.Add((byte)(iRemotePort % 256)); SendAll(dataSock5Send.ToArray(), dataSock5Send.Count, SocketFlags.None); iRecCount = _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None); if (iRecCount < 2 || bySock5Receive[0] != 5 || bySock5Receive[1] != 0) { throw new SocketException(socketErrorCode); //throw new Exception("第二次连接Socks5代理返回数据出错。"); } return true; } else // UDP { var dataSock5Send = new List(); dataSock5Send.Add(5); dataSock5Send.Add(3); dataSock5Send.Add(0); var ipAdd = ((IPEndPoint)_socketEndPoint).Address; { var addBytes = ipAdd.GetAddressBytes(); if (addBytes.GetLength(0) > 4) { dataSock5Send.Add(4); // IPv6 for (var i = 0; i < 16; ++i) { dataSock5Send.Add(addBytes[i]); } } else { dataSock5Send.Add(1); // IPv4 for (var i = 0; i < 4; ++i) { dataSock5Send.Add(addBytes[i]); } } } dataSock5Send.Add(0); dataSock5Send.Add(0); SendAll(dataSock5Send.ToArray(), dataSock5Send.Count, SocketFlags.None); _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None); if (bySock5Receive[0] != 5 || bySock5Receive[1] != 0) { throw new SocketException(socketErrorCode); //throw new Exception("第二次连接Socks5代理返回数据出错。"); } var ipv6 = bySock5Receive[0] == 4; byte[] addr; int port; if (!ipv6) { addr = new byte[4]; Array.Copy(bySock5Receive, 4, addr, 0, 4); port = bySock5Receive[8] * 0x100 + bySock5Receive[9]; } else { addr = new byte[16]; Array.Copy(bySock5Receive, 4, addr, 0, 16); port = bySock5Receive[20] * 0x100 + bySock5Receive[21]; } ipAdd = new IPAddress(addr); _remoteUDPEndPoint = new IPEndPoint(ipAdd, port); return true; } } public void SetTcpServer(string server, int port) { _proxy_server = server; _proxy_udp_port = port; } public void SetUdpServer(string server, int port) { _proxy_server = server; _proxy_udp_port = port; } public void SetUdpEndPoint(IPEndPoint ep) { _remoteUDPEndPoint = ep; } public bool ConnectHttpProxyServer(string strRemoteHost, int iRemotePort, string socks5RemoteUsername, string socks5RemotePassword, string proxyUserAgent) { _proxy = true; if (IPAddress.TryParse(strRemoteHost, out var ipAdd)) { strRemoteHost = ipAdd.ToString(); } var host = (strRemoteHost.IndexOf(':') >= 0 ? "[" + strRemoteHost + "]" : strRemoteHost) + ":" + iRemotePort; var authstr = Convert.ToBase64String(Encoding.UTF8.GetBytes(socks5RemoteUsername + ":" + socks5RemotePassword)); var cmd = "CONNECT " + host + " HTTP/1.0\r\n" + "Host: " + host + "\r\n"; if (!string.IsNullOrEmpty(proxyUserAgent)) { cmd += "User-Agent: " + proxyUserAgent + "\r\n"; } cmd += "Proxy-Connection: Keep-Alive\r\n"; if (socks5RemoteUsername.Length > 0) { cmd += "Proxy-Authorization: Basic " + authstr + "\r\n"; } cmd += "\r\n"; var httpData = Encoding.UTF8.GetBytes(cmd); SendAll(httpData, httpData.Length, SocketFlags.None); var byReceive = new byte[1024]; var iRecCount = _socket.Receive(byReceive, byReceive.Length, SocketFlags.None); if (iRecCount > 13) { var data = Encoding.UTF8.GetString(byReceive, 0, iRecCount); var data_part = data.Split(' '); if (data_part.Length > 1 && data_part[1] == "200") { return true; } } return false; } } } ================================================ FILE: shadowsocks-csharp/Proxy/ProxySocketTun.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; namespace Shadowsocks.Proxy { public class ProxySocketTun { protected Socket _socket; protected EndPoint _socketEndPoint; protected IPEndPoint _remoteUDPEndPoint; protected bool _proxy; protected string _proxy_server; protected int _proxy_udp_port; protected const int RecvSize = 1460 * 2; protected bool _close; public ProxySocketTun(Socket socket) { _socket = socket; } public ProxySocketTun(AddressFamily af, SocketType type, ProtocolType protocol) { _socket = new Socket(af, type, protocol); } public Socket GetSocket() { return _socket; } public bool IsClose => _close; public bool GoS5Proxy { get => _proxy; set => _proxy = value; } public AddressFamily AddressFamily => _socket.AddressFamily; public int Available => _socket.Available; public void Shutdown(SocketShutdown how) { _socket.Shutdown(how); } public void Close() { _socket.Close(); _socket = null; } public IAsyncResult BeginConnect(EndPoint ep, AsyncCallback callback, object state) { _close = false; _socketEndPoint = ep; return _socket.BeginConnect(ep, callback, state); } public void EndConnect(IAsyncResult ar) { _socket.EndConnect(ar); } public int Receive(byte[] buffer, int size, SocketFlags flags) { return _socket.Receive(buffer, size, flags); } public IAsyncResult BeginReceive(byte[] buffer, int size, SocketFlags flags, AsyncCallback callback, object state) { var st = new CallbackState(); st.buffer = buffer; st.size = size; st.state = state; return _socket.BeginReceive(buffer, 0, size, flags, callback, st); } public int EndReceive(IAsyncResult ar) { var bytesRead = _socket.EndReceive(ar); if (bytesRead > 0) { var st = (CallbackState)ar.AsyncState; st.size = bytesRead; return bytesRead; } _close = true; return bytesRead; } public int SendAll(byte[] buffer, int size, SocketFlags flags) { var sendSize = _socket.Send(buffer, size, flags); while (sendSize < size) { var new_size = _socket.Send(buffer, sendSize, size - sendSize, flags); sendSize += new_size; } return size; } public virtual int Send(byte[] buffer, int size, SocketFlags flags) { return SendAll(buffer, size, flags); } public int BeginSend(byte[] buffer, int size, SocketFlags flags, AsyncCallback callback, object state) { var st = new CallbackState(); st.size = size; st.state = state; _socket.BeginSend(buffer, 0, size, flags, callback, st); return size; } public int EndSend(IAsyncResult ar) { return _socket.EndSend(ar); } public IAsyncResult BeginReceiveFrom(byte[] buffer, int size, SocketFlags flags, ref EndPoint ep, AsyncCallback callback, object state) { var st = new CallbackState(); st.buffer = buffer; st.size = size; st.state = state; return _socket.BeginReceiveFrom(buffer, 0, size, flags, ref ep, callback, st); } public int GetAsyncResultSize(IAsyncResult ar) { var st = (CallbackState)ar.AsyncState; return st.size; } public byte[] GetAsyncResultBuffer(IAsyncResult ar) { var st = (CallbackState)ar.AsyncState; return st.buffer; } public bool ConnectSocks5ProxyServer(string strRemoteHost, int iRemotePort, bool udp, string socks5RemoteUsername, string socks5RemotePassword) { var socketErrorCode = (int)SocketError.ConnectionReset; _proxy = true; //构造Socks5代理服务器第一连接头(无用户名密码) var bySock5Send = new byte[10]; bySock5Send[0] = 5; bySock5Send[1] = socks5RemoteUsername.Length == 0 ? (byte)1 : (byte)2; bySock5Send[2] = 0; bySock5Send[3] = 2; //发送Socks5代理第一次连接信息 _socket.Send(bySock5Send, bySock5Send[1] + 2, SocketFlags.None); var bySock5Receive = new byte[32]; var iRecCount = _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None); if (iRecCount < 2) { throw new SocketException(socketErrorCode); } if (bySock5Receive[0] != 5 || bySock5Receive[1] != 0 && bySock5Receive[1] != 2) { throw new SocketException(socketErrorCode); } if (bySock5Receive[1] != 0) // auth { if (bySock5Receive[1] == 2) { if (socks5RemoteUsername.Length == 0) { throw new SocketException(socketErrorCode); } bySock5Send = new byte[socks5RemoteUsername.Length + socks5RemotePassword.Length + 3]; bySock5Send[0] = 1; bySock5Send[1] = (byte)socks5RemoteUsername.Length; for (var i = 0; i < socks5RemoteUsername.Length; ++i) { bySock5Send[2 + i] = (byte)socks5RemoteUsername[i]; } bySock5Send[socks5RemoteUsername.Length + 2] = (byte)socks5RemotePassword.Length; for (var i = 0; i < socks5RemotePassword.Length; ++i) { bySock5Send[socks5RemoteUsername.Length + 3 + i] = (byte)socks5RemotePassword[i]; } _socket.Send(bySock5Send, bySock5Send.Length, SocketFlags.None); _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None); if (bySock5Receive[0] != 1 || bySock5Receive[1] != 0) { throw new SocketException((int)SocketError.ConnectionRefused); } } else { return false; } } // connect if (!udp) // TCP { var dataSock5Send = new List { 5, 1, 0 }; if (!IPAddress.TryParse(strRemoteHost, out var ipAdd)) { dataSock5Send.Add(3); // remote DNS resolve dataSock5Send.Add((byte)strRemoteHost.Length); dataSock5Send.AddRange(strRemoteHost.Select(t => (byte)t)); } else { var addBytes = ipAdd.GetAddressBytes(); if (addBytes.GetLength(0) > 4) { dataSock5Send.Add(4); // IPv6 for (var i = 0; i < 16; ++i) { dataSock5Send.Add(addBytes[i]); } } else { dataSock5Send.Add(1); // IPv4 for (var i = 0; i < 4; ++i) { dataSock5Send.Add(addBytes[i]); } } } dataSock5Send.Add((byte)(iRemotePort / 256)); dataSock5Send.Add((byte)(iRemotePort % 256)); _socket.Send(dataSock5Send.ToArray(), dataSock5Send.Count, SocketFlags.None); iRecCount = _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None); if (iRecCount < 2 || bySock5Receive[0] != 5 || bySock5Receive[1] != 0) { throw new SocketException(socketErrorCode); //throw new Exception("第二次连接Socks5代理返回数据出错。"); } return true; } else // UDP { var dataSock5Send = new List(); dataSock5Send.Add(5); dataSock5Send.Add(3); dataSock5Send.Add(0); var ipAdd = ((IPEndPoint)_socketEndPoint).Address; { var addBytes = ipAdd.GetAddressBytes(); if (addBytes.GetLength(0) > 4) { dataSock5Send.Add(4); // IPv6 for (var i = 0; i < 16; ++i) { dataSock5Send.Add(addBytes[i]); } } else { dataSock5Send.Add(1); // IPv4 for (var i = 0; i < 4; ++i) { dataSock5Send.Add(addBytes[i]); } } } dataSock5Send.Add(0); dataSock5Send.Add(0); _socket.Send(dataSock5Send.ToArray(), dataSock5Send.Count, SocketFlags.None); _socket.Receive(bySock5Receive, bySock5Receive.Length, SocketFlags.None); if (bySock5Receive[0] != 5 || bySock5Receive[1] != 0) { throw new SocketException(socketErrorCode); //throw new Exception("第二次连接Socks5代理返回数据出错。"); } var ipv6 = bySock5Receive[0] == 4; byte[] addr; int port; if (!ipv6) { addr = new byte[4]; Array.Copy(bySock5Receive, 4, addr, 0, 4); port = bySock5Receive[8] * 0x100 + bySock5Receive[9]; } else { addr = new byte[16]; Array.Copy(bySock5Receive, 4, addr, 0, 16); port = bySock5Receive[20] * 0x100 + bySock5Receive[21]; } ipAdd = new IPAddress(addr); _remoteUDPEndPoint = new IPEndPoint(ipAdd, port); return true; } } public void SetTcpServer(string server, int port) { _proxy_server = server; _proxy_udp_port = port; } public void SetUdpServer(string server, int port) { _proxy_server = server; _proxy_udp_port = port; } public void SetUdpEndPoint(IPEndPoint ep) { _remoteUDPEndPoint = ep; } public bool ConnectHttpProxyServer(string strRemoteHost, int iRemotePort, string socks5RemoteUsername, string socks5RemotePassword, string proxyUserAgent) { _proxy = true; if (IPAddress.TryParse(strRemoteHost, out var ipAdd)) { strRemoteHost = ipAdd.ToString(); } var host = (strRemoteHost.IndexOf(':') >= 0 ? "[" + strRemoteHost + "]" : strRemoteHost) + ":" + iRemotePort; var authstr = Convert.ToBase64String(Encoding.UTF8.GetBytes(socks5RemoteUsername + ":" + socks5RemotePassword)); var cmd = "CONNECT " + host + " HTTP/1.0\r\n" + "Host: " + host + "\r\n"; if (!string.IsNullOrEmpty(proxyUserAgent)) { cmd += "User-Agent: " + proxyUserAgent + "\r\n"; } cmd += "Proxy-Connection: Keep-Alive\r\n"; if (socks5RemoteUsername.Length > 0) { cmd += "Proxy-Authorization: Basic " + authstr + "\r\n"; } cmd += "\r\n"; var httpData = Encoding.UTF8.GetBytes(cmd); _socket.Send(httpData, httpData.Length, SocketFlags.None); var byReceive = new byte[1024]; var iRecCount = _socket.Receive(byReceive, byReceive.Length, SocketFlags.None); if (iRecCount > 13) { var data = Encoding.UTF8.GetString(byReceive, 0, iRecCount); var data_part = data.Split(' '); if (data_part.Length > 1 && data_part[1] == "200") { return true; } } return false; } } } ================================================ FILE: shadowsocks-csharp/Proxy/ProxySocketTunLocal.cs ================================================ using System.Net.Sockets; namespace Shadowsocks.Proxy { public class ProxySocketTunLocal : ProxySocketTun { public string local_sendback_protocol; public ProxySocketTunLocal(Socket socket) : base(socket) { } public override int Send(byte[] buffer, int size, SocketFlags flags) { if (local_sendback_protocol != null) { if (local_sendback_protocol == "http") { var data = System.Text.Encoding.UTF8.GetBytes("HTTP/1.1 200 Connection Established\r\n\r\n"); _socket.Send(data, data.Length, 0); } else if (local_sendback_protocol == "socks5") { if (_socket.AddressFamily == AddressFamily.InterNetwork) { byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 }; _socket.Send(response); } else { byte[] response = { 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; _socket.Send(response); } } local_sendback_protocol = null; } return SendAll(buffer, size, flags); } } } ================================================ FILE: shadowsocks-csharp/SyncfusionLicenseRegister.bat ================================================ @echo on&setlocal setlocal enableextensions disabledelayedexpansion ::Arguments of either PreBuild or PostBuild set buildType=%1 ::License key replacement file set sourceFile=%2 ::Replacement string set DummyKey=##SyncfusionLicense## set LicenseKey=%SyncfusionLicenseKey% ::Replacement statement if NOT "%LicenseKey%" == "" ( if "%buildType%" == "PostBuild" ( powershell -Command "(gc %sourceFile%) -Replace '%LicenseKey%','%DummyKey%'|SC %sourceFile%" ) if "%buildType%" == "PreBuild" ( powershell -Command "(gc %sourceFile%) -Replace '%DummyKey%','%LicenseKey%'|SC %sourceFile%" ) ) ================================================ FILE: shadowsocks-csharp/Util/Base64.cs ================================================ using System; using System.Text; namespace Shadowsocks.Util { public static class Base64 { public static string DecodeBase64(string val) { return Encoding.UTF8.GetString(DecodeBase64ToBytes(val)); } private static byte[] DecodeBase64ToBytes(string val) { var data = val.PadRight(val.Length + (4 - val.Length % 4) % 4, '='); return Convert.FromBase64String(data); } private static string EncodeUrlSafeBase64(byte[] val, bool trim) { return trim ? Convert.ToBase64String(val).Replace('+', '-').Replace('/', '_').TrimEnd('=') : Convert.ToBase64String(val).Replace('+', '-').Replace('/', '_'); } private static byte[] DecodeUrlSafeBase64ToBytes(string val) { var data = val.Replace('-', '+').Replace('_', '/').PadRight(val.Length + (4 - val.Length % 4) % 4, '='); return Convert.FromBase64String(data); } public static string EncodeUrlSafeBase64(string val, bool trim = true) { return EncodeUrlSafeBase64(Encoding.UTF8.GetBytes(val), trim); } public static string DecodeUrlSafeBase64(string val) { return Encoding.UTF8.GetString(DecodeUrlSafeBase64ToBytes(val)); } } } ================================================ FILE: shadowsocks-csharp/Util/CRC.cs ================================================ using CryptoBase.Digests; using System; using System.Buffers.Binary; namespace Shadowsocks.Util { public static class CRC32 { public static ulong CalcCRC32(byte[] input, int len) { using var hash = DigestUtils.Create(DigestType.Crc32); var t = new byte[hash.Length]; hash.UpdateFinal(input.AsSpan(0, len), t); return BinaryPrimitives.ReadUInt32BigEndian(t); } public static void SetCRC32(byte[] buffer) { using var hash = DigestUtils.Create(DigestType.Crc32); var t = new byte[hash.Length]; hash.UpdateFinal(buffer.AsSpan(0, buffer.Length - 4), t); var x = ~BinaryPrimitives.ReadUInt32BigEndian(t); BinaryPrimitives.WriteUInt32LittleEndian(buffer.AsSpan(buffer.Length - 4), x); } } public static class Adler32 { public static ulong CalcAdler32(byte[] input, int len) { ulong a = 1; ulong b = 0; for (var i = 0; i < len; ++i) { a += input[i]; b += a; } a %= 65521; b %= 65521; return (b << 16) + a; } public static bool CheckAdler32(byte[] input, int len) { var adler32 = CalcAdler32(input, len - 4); var checksum = BinaryPrimitives.ReadUInt32LittleEndian(input.AsSpan(len - 4)); return (uint)adler32 == checksum; } } } ================================================ FILE: shadowsocks-csharp/Util/ColorConvert.cs ================================================ using System; using System.Linq; using System.Windows.Media; using Color = System.Windows.Media.Color; namespace Shadowsocks.Util { public static class ColorConvert { public static Color EnableColor = Color.FromRgb(0, 255, 170); public static readonly Brush EnableBrush = new SolidColorBrush(EnableColor); public static Color DisableColor = Colors.Red; public static readonly Brush DisableBrush = new SolidColorBrush(DisableColor); public static Color TotalDownloadColor1 = Color.FromRgb(229, 255, 246); public static readonly Brush TotalDownloadBrush1 = new SolidColorBrush(TotalDownloadColor1); public static Color TotalDownloadColor2 = Color.FromRgb(218, 242, 234); public static readonly Brush TotalDownloadBrush2 = new SolidColorBrush(TotalDownloadColor2); public static Color TotalUploadColor1 = Color.FromRgb(255, 229, 229); public static readonly Brush TotalUploadBrush1 = new SolidColorBrush(TotalUploadColor1); public static Color TotalUploadColor2 = Color.FromRgb(242, 218, 218); public static readonly Brush TotalUploadBrush2 = new SolidColorBrush(TotalUploadColor2); public static Color TotalDownloadRawColor1 = Color.FromRgb(255, 255, 229); public static readonly Brush TotalDownloadRawBrush1 = new SolidColorBrush(TotalDownloadRawColor1); public static Color TotalDownloadRawColor2 = Color.FromRgb(242, 242, 218); public static readonly Brush TotalDownloadRawBrush2 = new SolidColorBrush(TotalDownloadRawColor2); private static readonly Color[] SpeedColorList = { Colors.White, Colors.LightGreen, Colors.Yellow, Colors.Pink, Colors.Red }; private static readonly long[] SpeedBytesList = { 0, 1024 * 64, 1024 * 512, 1024 * 1024 * 4, 1024 * 1024 * 16 }; private static readonly Color[] ConnectionColorList = { Colors.White, Colors.LightGreen, Colors.Yellow, Colors.Red }; private static readonly long[] ConnectionBytesList = { 0, 16, 32, 64 }; private static readonly Color[] LatencyColorList = { Colors.White, Colors.LightGreen, Colors.Yellow, Colors.Red }; private static readonly long[] LatencyList = { 0, 128, 256, 512 }; private static byte ColorMix(byte a, byte b, double alpha) { return (byte)(b * alpha + a * (1 - alpha)); } private static Color ColorMix(Color a, Color b, double alpha) { return Color.FromRgb(ColorMix(a.R, b.R, alpha), ColorMix(a.G, b.G, alpha), ColorMix(a.B, b.B, alpha)); } public static Color GetSpeedColor(long bytes) { for (var i = 1; i < SpeedColorList.Length; ++i) { if (bytes < SpeedBytesList[i]) { return ColorMix(SpeedColorList[i - 1], SpeedColorList[i], (double)(bytes - SpeedBytesList[i - 1]) / (SpeedBytesList[i] - SpeedBytesList[i - 1])); } } return SpeedColorList.Last(); } public static Color GetConnectionColor(long connections) { for (var i = 1; i < ConnectionColorList.Length; ++i) { if (connections < ConnectionBytesList[i]) { return ColorMix(ConnectionColorList[i - 1], ConnectionColorList[i], (double)(connections - ConnectionBytesList[i - 1]) / (ConnectionBytesList[i] - ConnectionBytesList[i - 1])); } } return ConnectionColorList.Last(); } public static Color GetLatencyColor(long latency) { for (var i = 1; i < ConnectionColorList.Length; ++i) { if (latency < LatencyList[i]) { return ColorMix(LatencyColorList[i - 1], LatencyColorList[i], (double)(latency - LatencyList[i - 1]) / (LatencyList[i] - LatencyList[i - 1])); } } return ConnectionColorList.Last(); } public static Color GetConnectErrorColor(long val) { return Color.FromRgb(255, (byte)Math.Max(0, 255 - val * 2.5), (byte)Math.Max(0, 255 - val * 2.5)); } public static Color GetConnectEmptyColor(long val) { return Color.FromRgb(255, (byte)Math.Max(0, 255 - val * 8), (byte)Math.Max(0, 255 - val * 8)); } public static Color GetErrorPercentColor(double? percent) { if (percent != null) { return Color.FromRgb(255, (byte)(255 - percent * 2), (byte)(255 - percent * 2)); } return Colors.Transparent; } } } ================================================ FILE: shadowsocks-csharp/Util/Constants.cs ================================================ namespace Shadowsocks.Util { internal static class Constants { public const string ParameterMultiplyInstance = @"-show"; } } ================================================ FILE: shadowsocks-csharp/Util/I18NUtil.cs ================================================ using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; namespace Shadowsocks.Util { public static class I18NUtil { private const string DefaultLanguage = @"en-US"; public static string CurrentLanguage; public static readonly Dictionary SupportLanguage = new() { { @"zh-CN", @"zh-CN" }, { @"zh", @"zh-CN" }, { @"zh-Hans", @"zh-CN" }, { @"zh-SG", @"zh-CN" }, { @"zh-Hant", @"zh-TW" }, { @"zh-HK", @"zh-TW" }, { @"zh-TW", @"zh-TW" }, { @"zh-MO", @"zh-TW" }, { @"en-US", @"en-US" } }; public static string GetLanguage(string langName = @"") { if (string.IsNullOrEmpty(langName)) { langName = System.Globalization.CultureInfo.CurrentCulture.Name; } if (SupportLanguage.TryGetValue(langName, out var res)) { return res; } return DefaultLanguage; } public static void SetLanguage(string langName) { SetLanguage(Application.Current.Resources, @"App", langName); CurrentLanguage = langName; } public static string GetAppStringValue(string key) { if (Application.Current.Resources.MergedDictionaries[0][key] is string str) { return str; } return key; } public static string GetWindowStringValue(this Window window, string key) { if (window.Resources.MergedDictionaries[0][key] is string str) { return str; } return key; } public static void SetLanguage(ResourceDictionary resources, string filename, string langName = @"") { langName = GetLanguage(string.IsNullOrEmpty(langName) ? CurrentLanguage : langName); var url = new Uri($@"../I18N/{filename}.{langName}.xaml", UriKind.Relative); if (resources.MergedDictionaries.Count > 0) { resources.MergedDictionaries[0].Source = url; } else if (Application.LoadComponent(url) is ResourceDictionary langRd) { resources.MergedDictionaries.Add(langRd); } } public static void SetLanguage(object obj) { if (obj is ContextMenu contextMenu) { foreach (var o in contextMenu.Items) { if (o is MenuItem) { SetLanguage(o); } } } else if (obj is MenuItem menuItem) { menuItem.Header = GetAppStringValue(menuItem.Name); foreach (var o in menuItem.Items) { if (o is MenuItem) { SetLanguage(o); } } } } } } ================================================ FILE: shadowsocks-csharp/Util/JsonUtils.cs ================================================ using System.Text.Encodings.Web; using System.Text.Json; namespace Shadowsocks.Util { public static class JsonUtils { private static readonly JsonSerializerOptions Options = new() { WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; private static readonly JsonSerializerOptions StrictOptions = new() { WriteIndented = true, Encoder = JavaScriptEncoder.Default }; public static string Serialize(object obj, bool strict) { return JsonSerializer.Serialize(obj, strict ? StrictOptions : Options); } } } ================================================ FILE: shadowsocks-csharp/Util/NetUtils/DnsUtil.cs ================================================ using Shadowsocks.Controller; using Shadowsocks.Model; using System.Collections.Generic; using System.Linq; using System.Net; using System.Reactive.Linq; using System.Threading.Tasks; #nullable enable namespace Shadowsocks.Util.NetUtils { public static class DnsUtil { public static LRUCache DnsBuffer { get; } = new(); public static IPAddress? QueryDns(string host) { var res = host.Contains('.') && Global.GuiConfig.DnsClients.Any(s => s.Enable) ? QueryAsync(host, Global.GuiConfig.DnsClients).Result : QueryDefaultAsync(host).Result; Logging.Info(res is null ? $@"DNS query {host} failed." : $@"DNS query {host} answer {res}"); return res; } public static async Task QueryDefaultAsync(string host, bool ipv6First = default) { return await DnsClient.QueryIpAddressDefaultAsync(host, ipv6First, default); } public static async Task QueryAsync(string host, IEnumerable clients) { return await clients .Where(client => client.Enable) .Select(s => Observable .FromAsync(ct => s.QueryIpAddressAsync(host, ct)) .Where(ip => ip is not null) ) .Merge() .FirstOrDefaultAsync(); } } } ================================================ FILE: shadowsocks-csharp/Util/NetUtils/IPSubnet.cs ================================================ using System; using System.Collections; using System.Linq; using System.Net; using System.Net.Sockets; namespace Shadowsocks.Util.NetUtils { public static class IPSubnet { public static bool IsInSubnet(this IPAddress address, string subnetMask) { var slashIdx = subnetMask.IndexOf("/", StringComparison.Ordinal); if (!subnetMask.Contains("/")) { // We only handle netmasks in format "IP/PrefixLength". throw new NotSupportedException("Only SubNetMasks with a given prefix length are supported."); } // First parse the address of the netmask before the prefix length. var maskAddress = IPAddress.Parse(subnetMask.Substring(0, slashIdx)); if (maskAddress.AddressFamily != address.AddressFamily) { // We got something like an IPV4-Address for an IPv6-Mask. This is not valid. return false; } // Now find out how long the prefix is. var maskLength = int.Parse(subnetMask.Substring(slashIdx + 1)); if (maskAddress.AddressFamily == AddressFamily.InterNetwork) { // Convert the mask address to an unsigned integer. var maskAddressBits = BitConverter.ToUInt32(maskAddress.GetAddressBytes().Reverse().ToArray()); // And convert the IpAddress to an unsigned integer. var ipAddressBits = BitConverter.ToUInt32(address.GetAddressBytes().Reverse().ToArray()); // Get the mask/network address as unsigned integer. var mask = uint.MaxValue << (32 - maskLength); // https://stackoverflow.com/a/1499284/3085985 // Bitwise AND mask and MaskAddress, this should be the same as mask and IpAddress // as the end of the mask is 0000 which leads to both addresses to end with 0000 // and to start with the prefix. return (maskAddressBits & mask) == (ipAddressBits & mask); } if (maskAddress.AddressFamily == AddressFamily.InterNetworkV6) { // Convert the mask address to a BitArray. var maskAddressBits = new BitArray(maskAddress.GetAddressBytes()); // And convert the IpAddress to a BitArray. var ipAddressBits = new BitArray(address.GetAddressBytes()); if (maskAddressBits.Length != ipAddressBits.Length) { throw new ArgumentException("Length of IP Address and Subnet Mask do not match."); } // Compare the prefix bits. for (var i = 0; i < maskLength; i++) { if (ipAddressBits[i] != maskAddressBits[i]) { return false; } } return true; } throw new NotSupportedException("Only InterNetworkV6 or InterNetwork address families are supported."); } public static bool IsLoopBack(IPAddress ip) { return Equals(ip, IPAddress.IPv6Loopback) || ip.IsInSubnet(@"127.0.0.0/8"); } public static bool IsLocal(IPAddress ip) { return ip.IsInSubnet(@"127.0.0.0/8") || ip.IsInSubnet(@"169.254.0.0/16") || ip.IsInSubnet(@"::1/128"); } public static bool IsLocal(Socket socket) { return IsLocal(((IPEndPoint)socket.RemoteEndPoint).Address); } public static bool IsLan(IPAddress ip) { var netmasks = new[] { @"0.0.0.0/8", @"10.0.0.0/8", //"100.64.0.0/10", //部分地区运营商貌似在使用这个,这个可能不安全 @"127.0.0.0/8", @"169.254.0.0/16", @"172.16.0.0/12", //"192.0.0.0/24", //"192.0.2.0/24", //"192.88.99.0/24", @"192.168.0.0/16", //"198.18.0.0/15", //"198.51.100.0/24", //"203.0.113.0/24", @"::1/128", @"fc00::/7", @"fe80::/10" }; return netmasks.Any(ip.IsInSubnet); } public static bool IsLan(Socket socket) { return IsLan(((IPEndPoint)socket.RemoteEndPoint).Address); } } } ================================================ FILE: shadowsocks-csharp/Util/NetUtils/SocketUtil.cs ================================================ using System; using System.Net.Sockets; namespace Shadowsocks.Util.NetUtils { public static class SocketUtil { public static void FullClose(this Socket s) { try { s.Shutdown(SocketShutdown.Both); } catch (Exception) { // ignored } try { s.Disconnect(false); } catch (Exception) { // ignored } try { s.Close(); } catch (Exception) { // ignored } } } } ================================================ FILE: shadowsocks-csharp/Util/NetUtils/WrappedSocket.cs ================================================ using System; using System.Net; using System.Net.Sockets; using System.Threading; namespace Shadowsocks.Util.NetUtils { /* * A wrapped socket class which support both ipv4 and ipv6 based on the * connected remote endpoint. * * If the server address is host name, then it may have both ipv4 and ipv6 address * after resolving. The main idea is we don't want to resolve and choose the address * by ourselves. Instead, Socket.ConnectAsync() do handle this thing internally by trying * each address and returning an established socket connection. */ public class WrappedSocket { public EndPoint LocalEndPoint => _activeSocket?.LocalEndPoint; // Only used during connection and close, so it won't cost too much. private SpinLock _socketSyncLock = new(); private bool _disposed; private bool Connected => _activeSocket != null; private Socket _activeSocket; public void BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (Connected) { throw new SocketException((int)SocketError.IsConnected); } var arg = new SocketAsyncEventArgs { RemoteEndPoint = remoteEP }; arg.Completed += OnTcpConnectCompleted; arg.UserToken = new TcpUserToken(callback, state); if (!Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, arg)) { OnTcpConnectCompleted(this, arg); } } private class FakeAsyncResult : IAsyncResult { public bool IsCompleted { get; } = true; // ReSharper disable once AssignNullToNotNullAttribute public WaitHandle AsyncWaitHandle { get; } = null; public object AsyncState { get; set; } public bool CompletedSynchronously { get; } = true; public Exception InternalException { get; set; } } private class TcpUserToken { public AsyncCallback Callback { get; } public object AsyncState { get; } public TcpUserToken(AsyncCallback callback, object state) { Callback = callback; AsyncState = state; } } private void OnTcpConnectCompleted(object sender, SocketAsyncEventArgs args) { using (args) { args.Completed -= OnTcpConnectCompleted; var token = (TcpUserToken)args.UserToken; if (args.SocketError != SocketError.Success) { var ex = args.ConnectByNameError ?? new SocketException((int)args.SocketError); var r = new FakeAsyncResult { AsyncState = token.AsyncState, InternalException = ex }; token.Callback(r); } else { var lockTaken = false; if (!_socketSyncLock.IsHeldByCurrentThread) { _socketSyncLock.TryEnter(ref lockTaken); } try { if (Connected) { args.ConnectSocket.FullClose(); } else { _activeSocket = args.ConnectSocket; if (_disposed) { _activeSocket.FullClose(); } var r = new FakeAsyncResult { AsyncState = token.AsyncState }; token.Callback(r); } } finally { if (lockTaken) { _socketSyncLock.Exit(); } } } } } public void EndConnect(IAsyncResult asyncResult) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } var r = asyncResult as FakeAsyncResult; if (r == null) { throw new ArgumentException(@"Invalid asyncResult.", nameof(asyncResult)); } if (r.InternalException != null) { throw r.InternalException; } } public void Dispose() { if (_disposed) { return; } var lockTaken = false; if (!_socketSyncLock.IsHeldByCurrentThread) { _socketSyncLock.TryEnter(ref lockTaken); } try { _disposed = true; _activeSocket?.FullClose(); } finally { if (lockTaken) { _socketSyncLock.Exit(); } } } public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (!Connected) { throw new SocketException((int)SocketError.NotConnected); } return _activeSocket.BeginSend(buffer, offset, size, socketFlags, callback, state); } public int EndSend(IAsyncResult asyncResult) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (!Connected) { throw new SocketException((int)SocketError.NotConnected); } return _activeSocket.EndSend(asyncResult); } public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (!Connected) { throw new SocketException((int)SocketError.NotConnected); } return _activeSocket.BeginReceive(buffer, offset, size, socketFlags, callback, state); } public int EndReceive(IAsyncResult asyncResult) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (!Connected) { throw new SocketException((int)SocketError.NotConnected); } return _activeSocket.EndReceive(asyncResult); } public void Shutdown(SocketShutdown how) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (!Connected) { return; } _activeSocket.Shutdown(how); } public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue) { SetSocketOption(optionLevel, optionName, optionValue ? 1 : 0); } public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue) { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } if (!Connected) { throw new SocketException((int)SocketError.NotConnected); } _activeSocket.SetSocketOption(optionLevel, optionName, optionValue); } } } ================================================ FILE: shadowsocks-csharp/Util/QrCodeUtils.cs ================================================ using System; using System.Drawing; using System.IO; using System.Windows.Media; using System.Windows.Media.Imaging; using ZXing; using ZXing.Common; using ZXing.QrCode; using ZXing.QrCode.Internal; using ZXing.Windows.Compatibility; using Brush = System.Drawing.Brush; using Color = System.Drawing.Color; namespace Shadowsocks.Util; public static class QrCodeUtils { private static BitmapImage ToBitmapImage(Image src) { var ms = new MemoryStream(); src.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); var image = new BitmapImage(); image.BeginInit(); ms.Seek(0, SeekOrigin.Begin); image.StreamSource = ms; image.EndInit(); return image; } public static ImageSource GenQrCode(string content, int width, int height) { var options = new QrCodeEncodingOptions { DisableECI = true, CharacterSet = @"UTF-8", Width = width, Height = height, Margin = 0, ErrorCorrection = ErrorCorrectionLevel.H }; var write = new BarcodeWriter { Format = BarcodeFormat.QR_CODE, Options = options }; var bitmap = write.Write(content); return ToBitmapImage(bitmap); } public static ImageSource GenQrCode2(string str, int height) { var options = new QrCodeEncodingOptions { DisableECI = true, CharacterSet = @"UTF-8", Margin = 0 }; var code = Encoder.encode(str, ErrorCorrectionLevel.H, options.Hints); var m = code.Matrix; var blockSize = Math.Max(height / (m.Height + 1), 1); var drawArea = new Bitmap(m.Width * blockSize, m.Height * blockSize); using (var g = Graphics.FromImage(drawArea)) { g.Clear(Color.White); using Brush b = new SolidBrush(Color.Black); for (var row = 0; row < m.Width; ++row) { for (var col = 0; col < m.Height; ++col) { if (m[row, col] != 0) { g.FillRectangle(b, blockSize * row, blockSize * col, blockSize, blockSize); } } } } return ToBitmapImage(drawArea); } public static Result ScanBitmap(Bitmap target) { var source = new BitmapLuminanceSource(target); var bitmap = new BinaryBitmap(new HybridBinarizer(source)); var reader = new QRCodeReader(); return reader.decode(bitmap); } } ================================================ FILE: shadowsocks-csharp/Util/RNG.cs ================================================ using System; using System.Security.Cryptography; namespace Shadowsocks.Util; public static class Rng { public static void RandBytes(byte[] buf, int length = -1) { RandomNumberGenerator.Fill(length < 0 ? buf : buf.AsSpan(0, length)); } } ================================================ FILE: shadowsocks-csharp/Util/Reg.cs ================================================ using System.Diagnostics; using URIScheme; namespace Shadowsocks.Util { public static class Reg { [Conditional("RELEASE")] public static void SetUrlProtocol(string link) { try { var service = new URISchemeService(link, @"URL:ShadowsocksR Link", Utils.GetExecutablePath()); service.Set(); } catch { // ignored } } [Conditional("RELEASE")] public static void RemoveUrlProtocol(string link) { try { var service = new URISchemeService(link, string.Empty, string.Empty); service.Delete(); } catch { // ignored } } } } ================================================ FILE: shadowsocks-csharp/Util/Utils.cs ================================================ using Shadowsocks.Controller; using Shadowsocks.Encryption; using Shadowsocks.Model; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Text; #nullable enable namespace Shadowsocks.Util { public static class Utils { public static void SetArrayMinSize(ref T[] array, int size) { if (size > array.Length) { Array.Resize(ref array, size); } } public static void SetArrayMinSize2(ref T[] array, int size) { if (size > array.Length) { Array.Resize(ref array, size * 2); } } public static string GetExecutablePath() { var p = Process.GetCurrentProcess(); var res = p.MainModule?.FileName; if (res is not null) { return res; } var dllPath = GetDllPath(); return Path.ChangeExtension(dllPath, @"exe"); } public static string GetDllPath() { return Assembly.GetExecutingAssembly().Location; } /// /// return path to store temporary files /// public static string TempPath => TempPathLazy.Value; private static readonly Lazy TempPathLazy = new(() => { try { return Directory.CreateDirectory(Path.Combine(Directory.GetCurrentDirectory(), @"temp")).FullName; } catch (Exception e) { Logging.Error(e); throw; } }); public static string GetTempPath(string filename) { return Path.Combine(TempPath, filename); } public static bool IsGFWListPAC(string filename) { if (File.Exists(filename)) { var original = FileManager.NonExclusiveReadAllText(filename, Encoding.UTF8); if (original.Contains(@"adblockplus") && !original.Contains(@"cnIpRange")) { return true; } } return false; } public static void OpenURL(string path) { new Process { StartInfo = new ProcessStartInfo(path) { UseShellExecute = true } }.Start(); } public static string EncryptLargeBytesToBase64String(IEncryptor encryptor, byte[] cfgData) { var cfgEncrypt = new byte[cfgData.Length + 128]; var dataLen = 0; const int bufferSize = 32768; var input = new byte[bufferSize]; var output = new byte[bufferSize + 128]; for (var startPos = 0; startPos < cfgData.Length; startPos += bufferSize) { var len = Math.Min(cfgData.Length - startPos, bufferSize); Buffer.BlockCopy(cfgData, startPos, input, 0, len); encryptor.Encrypt(input, len, output, out var outLen); Buffer.BlockCopy(output, 0, cfgEncrypt, dataLen, outLen); dataLen += outLen; } return Convert.ToBase64String(cfgEncrypt, 0, dataLen); } public static byte[] DecryptLargeBase64StringToBytes(IEncryptor encryptor, string encodeStr) { var cfgEncrypt = Convert.FromBase64String(encodeStr); var cfgData = new byte[cfgEncrypt.Length]; var dataLen = 0; const int bufferSize = 32768; var input = new byte[bufferSize]; var output = new byte[bufferSize + 128]; for (var startPos = 0; startPos < cfgEncrypt.Length; startPos += bufferSize) { var len = Math.Min(cfgEncrypt.Length - startPos, bufferSize); Buffer.BlockCopy(cfgEncrypt, startPos, input, 0, len); encryptor.Decrypt(input, len, output, out var outLen); Buffer.BlockCopy(output, 0, cfgData, dataLen, outLen); dataLen += outLen; } Array.Resize(ref cfgData, dataLen); return cfgData; } public static string FormatBytes(long bytes) { const long K = 1024L; const long M = K * 1024L; const long G = M * 1024L; const long T = G * 1024L; const long P = T * 1024L; const long E = P * 1024L; return bytes switch { >= M * 990 and >= G * 990 => bytes switch { >= P * 990 => $@"{bytes / (double)E:F3}EB", >= T * 990 => $@"{bytes / (double)P:F3}PB", _ => $@"{bytes / (double)T:F3}TB" }, >= M * 990 and >= G * 99 => $@"{bytes / (double)G:F2}GB", >= M * 990 and >= G * 9 => $@"{bytes / (double)G:F3}GB", >= M * 990 => $@"{bytes / (double)G:F4}GB", >= K * 990 and >= M * 100 => $@"{bytes / (double)M:F1}MB", >= K * 990 when bytes > M * 9.9 => $@"{bytes / (double)M:F2}MB", >= K * 990 => $@"{bytes / (double)M:F3}MB", > K * 99 => $@"{bytes / (double)K:F0}KB", > 900 => $@"{bytes / (double)K:F1}KB", _ => bytes == 0 ? $@"{bytes}Byte" : $@"{bytes}Bytes" }; } public static IEnumerable Except(this IEnumerable x, IList y) { return from xi in x let found = y.Any(xi.IsMatchServer) where !found select xi; } public static IEnumerable GetLines(this string str, bool removeEmptyLines = true) { using var sr = new StringReader(str); string? line; while ((line = sr.ReadLine()) is not null) { if (removeEmptyLines && string.IsNullOrEmpty(line)) { continue; } yield return line; } } public static void SetTls() { if (!OperatingSystem.IsWindows()) { return; } ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 20170)) { ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls13; } } } } ================================================ FILE: shadowsocks-csharp/Util/ViewUtils.cs ================================================ using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using Color = System.Drawing.Color; using Size = System.Drawing.Size; namespace Shadowsocks.Util { public static class ViewUtils { private static readonly Color ColorMaskDirect = Color.FromArgb(255, 102, 102, 255); private static readonly Color ColorMaskPac = Color.FromArgb(102, 204, 102); private static readonly Color ColorMaskGlobal = Color.FromArgb(255, 102, 255, 255); [DllImport(@"user32.dll", CharSet = CharSet.Auto)] public static extern bool DestroyIcon(IntPtr handle); public static void BringToFront(this FrameworkElement element) { if (element?.Parent is Panel parent) { var maxZ = parent.Children.OfType() .Where(x => x != element) .Select(Panel.GetZIndex) .Max(); Panel.SetZIndex(element, maxZ + 1); } } public static IEnumerable FindVisualChildren(DependencyObject depObj) where T : DependencyObject { if (depObj != null) { for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { var child = VisualTreeHelper.GetChild(depObj, i); if (child is T dependencyObject) { yield return dependencyObject; } foreach (var childOfChild in FindVisualChildren(child)) { yield return childOfChild; } } } } public static Color SelectColorMask(bool isProxyEnabled, bool isGlobalProxy) { if (isProxyEnabled) { return isGlobalProxy ? ColorMaskGlobal : ColorMaskPac; } return ColorMaskDirect; } public static Bitmap ChangeBitmapColor(Bitmap original, Color colorMask, bool isRandom = false) { var newBitmap = new Bitmap(original); for (var x = 0; x < newBitmap.Width; ++x) { for (var y = 0; y < newBitmap.Height; ++y) { var color = original.GetPixel(x, y); if (color.A != 0) { var red = Convert.ToByte(color.R * colorMask.R * (isRandom ? 2.5 : 1) / 255); var green = Convert.ToByte(color.G * colorMask.G / 255); var blue = Convert.ToByte(color.B * colorMask.B / 255); var alpha = Convert.ToByte(color.A * colorMask.A / 255); newBitmap.SetPixel(x, y, Color.FromArgb(alpha, red, green, blue)); } else { newBitmap.SetPixel(x, y, color); } } } return newBitmap; } public static Bitmap ResizeBitmap(Bitmap original, int width, int height) { var newBitmap = new Bitmap(width, height); using (var g = Graphics.FromImage(newBitmap)) { g.SmoothingMode = SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.CompositingQuality = CompositingQuality.HighQuality; g.DrawImage(original, new Rectangle(0, 0, width, height)); } return newBitmap; } public static int GetDpi() { var dpiXProperty = typeof(SystemParameters).GetProperty(@"DpiX", BindingFlags.NonPublic | BindingFlags.Static); return dpiXProperty?.GetValue(null, null) is int dpiX ? dpiX : 96; } /// /// Determine the icon size based on the screen DPI. /// /// /// https://stackoverflow.com/a/40851713/2075611 public static Size GetIconSize() { var dpi = GetDpi(); var size = dpi switch { < 97 => new Size(16, 16), < 121 => new Size(20, 20), < 145 => new Size(24, 24), < 169 => new Size(28, 28), _ => new Size(32, 32) }; return size; } public static void SetResource(ResourceDictionary resources, string filename, int index) { var url = new Uri(filename, UriKind.Relative); if (resources.MergedDictionaries.Count > index) { resources.MergedDictionaries[index].Source = url; } else if (Application.LoadComponent(url) is ResourceDictionary langRd) { resources.MergedDictionaries.Add(langRd); } } public static bool IsOnScreen(Window window) { return IsOnScreen(window.Left, window.Top) || IsOnScreen(window.Left + window.Width, window.Top + window.Height); } public static bool IsOnScreen(double x, double y) { return SystemParameters.VirtualScreenLeft <= x && SystemParameters.VirtualScreenLeft + SystemParameters.VirtualScreenWidth >= x && SystemParameters.VirtualScreenTop <= y && SystemParameters.VirtualScreenTop + SystemParameters.VirtualScreenHeight >= y; } public static bool IsScrolledToEnd(this TextBox textBox) { return Math.Abs(textBox.VerticalOffset + textBox.ViewportHeight - textBox.ExtentHeight) < 0.001; } } } ================================================ FILE: shadowsocks-csharp/View/Controls/BindablePasswordBox.cs ================================================ using System.Windows; using System.Windows.Controls; namespace Shadowsocks.View.Controls { public sealed class BindablePasswordBox : Decorator { /// /// The password dependency property. /// public static readonly DependencyProperty PasswordProperty; private bool _isPreventCallback; private readonly RoutedEventHandler _savedCallback; /// /// Static constructor to initialize the dependency properties. /// static BindablePasswordBox() { PasswordProperty = DependencyProperty.Register( "Password", typeof(string), typeof(BindablePasswordBox), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnPasswordPropertyChanged) ); } /// /// Saves the password changed callback and sets the child element to the password box. /// public BindablePasswordBox() { _savedCallback = HandlePasswordChanged; var passwordBox = new PasswordBox(); passwordBox.PasswordChanged += _savedCallback; Child = passwordBox; } /// /// The password dependency property. /// public string Password { get => GetValue(PasswordProperty) as string; set => SetValue(PasswordProperty, value); } /// /// Handles changes to the password dependency property. /// /// the dependency object /// the event args private static void OnPasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs eventArgs) { var bindablePasswordBox = (BindablePasswordBox)d; var passwordBox = (PasswordBox)bindablePasswordBox.Child; if (bindablePasswordBox._isPreventCallback) { return; } passwordBox.PasswordChanged -= bindablePasswordBox._savedCallback; passwordBox.Password = eventArgs.NewValue != null ? eventArgs.NewValue.ToString() : string.Empty; passwordBox.PasswordChanged += bindablePasswordBox._savedCallback; } /// /// Handles the password changed event. /// /// the sender /// the event args private void HandlePasswordChanged(object sender, RoutedEventArgs eventArgs) { var passwordBox = (PasswordBox)sender; _isPreventCallback = true; Password = passwordBox.Password; _isPreventCallback = false; } } } ================================================ FILE: shadowsocks-csharp/View/Controls/GridColumnSizerExt.cs ================================================ using Syncfusion.UI.Xaml.Grid; using System.Linq; using System.Windows; namespace Shadowsocks.View.Controls { public class GridColumnSizerExt : GridColumnSizer { public GridColumnSizerExt(SfDataGrid dataGrid) : base(dataGrid) { } protected override double CalculateCellWidth(GridColumn column, bool setWidth = true) { var length = base.CalculateCellWidth(column, setWidth); if (column is GridTextColumn) { var clientSize = new Size(double.MaxValue, DataGrid.RowHeight); length = DataGrid.View.Records.Where(recordEntry => recordEntry?.Data != null) .Select(recordEntry => GetDisplayText(column, recordEntry.Data)).Select(text => MeasureText(clientSize, text, column, null, GridQueryBounds.Width).Width).Prepend(length).Max(); } return length; } } } ================================================ FILE: shadowsocks-csharp/View/Controls/MaskedTextBox.xaml ================================================  ================================================ FILE: shadowsocks-csharp/View/Controls/MaskedTextBox.xaml.cs ================================================ using System; using System.Windows; namespace Shadowsocks.View.Controls { public partial class MaskedTextBox { public MaskedTextBox() { InitializeComponent(); PlainModeChanged += MaskedTextBoxPlainModeChanged; MyPasswordBox.PasswordChanged += (o, e) => { if (MyPasswordBox.IsFocused) { Text = MyPasswordBox.Password; } }; MyTextBox.TextChanged += (o, e) => { if (!MyPasswordBox.IsFocused) { MyPasswordBox.Password = MyTextBox.Text; } }; } private bool _plainMode; public bool PlainMode { get => _plainMode; set { if (_plainMode != value) { _plainMode = value; PlainModeChanged?.Invoke(this, EventArgs.Empty); } } } public string Text { get => GetValue(TextProperty) as string; set => SetValue(TextProperty, value); } public static readonly DependencyProperty TextProperty = DependencyProperty.Register(@"Text", typeof(string), typeof(MaskedTextBox)); public event EventHandler PlainModeChanged; private void MaskedTextBoxPlainModeChanged(object sender, EventArgs e) { if (_plainMode) { MyPasswordBox.Visibility = Visibility.Collapsed; MyTextBox.Visibility = Visibility.Visible; } else { MyPasswordBox.Visibility = Visibility.Visible; MyTextBox.Visibility = Visibility.Collapsed; } } } } ================================================ FILE: shadowsocks-csharp/View/Controls/NumberUpDown.xaml ================================================  ================================================ FILE: shadowsocks-csharp/View/Controls/NumberUpDown.xaml.cs ================================================ using System; using System.Windows; using System.Windows.Controls; namespace Shadowsocks.View.Controls { public partial class NumberUpDown { private int _numValue; private int _maxNum = 65535; private int _minNum; public int NumValue { get { if (_numValue > _maxNum) { return _maxNum; } if (_numValue < _minNum) { return _minNum; } return _numValue; } set { if (_numValue != value) { _numValue = value; TxtNum.Text = value.ToString(); ValueChanged?.Invoke(this, EventArgs.Empty); } } } public string Value { get => GetValue(ValueProperty) as string; set => SetValue(ValueProperty, value); } public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(@"Value", typeof(string), typeof(NumberUpDown)); public int MinNum { get => _minNum; set => _minNum = value > _maxNum ? _maxNum : value; } public int MaxNum { get => _maxNum; set => _maxNum = value < _minNum ? _minNum : value; } public event EventHandler ValueChanged; public NumberUpDown() { InitializeComponent(); } private void Up_Click(object sender, RoutedEventArgs e) { if (NumValue < _maxNum) { ++NumValue; } else { NumValue = _maxNum; } } private void Down_Click(object sender, RoutedEventArgs e) { if (NumValue > _minNum) { --NumValue; } else { NumValue = _minNum; } } private void TxtNum_TextChanged(object sender, TextChangedEventArgs e) { if (TxtNum == null) { return; } if (int.TryParse(TxtNum.Text, out var num)) { NumValue = num; } } private void UserControl_Loaded(object sender, RoutedEventArgs e) { TxtNum.Text = NumValue.ToString(); } private void Grid_LostFocus(object sender, RoutedEventArgs e) { TxtNum.Text = NumValue.ToString(); } } } ================================================ FILE: shadowsocks-csharp/View/DnsSettingWindow.xaml ================================================  ================================================ FILE: shadowsocks-csharp/View/ServerConfigWindow.xaml.cs ================================================ using Shadowsocks.Controller; using Shadowsocks.Encryption; using Shadowsocks.Enums; using Shadowsocks.Model; using Shadowsocks.Util; using Shadowsocks.ViewModel; using Syncfusion.Data.Extensions; using Syncfusion.UI.Xaml.TreeView; using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace Shadowsocks.View { public partial class ServerConfigWindow { public ServerConfigWindow(MainController controller, int focusIndex) { InitializeComponent(); I18NUtil.SetLanguage(Resources, @"ConfigWindow"); SizeChanged += (o, args) => { GenQr(LinkTextBox.Text); }; Splitter2.DragDelta += (o, args) => { GenQr(LinkTextBox.Text); }; Closed += (o, e) => { _controller.ConfigChanged -= controller_ConfigChanged; ServerConfigViewModel.ServersChanged -= ServerViewModel_ServersChanged; }; _controller = controller; foreach (var name in from name in EncryptorFactory.RegisteredEncryptors.Keys let info = EncryptorFactory.GetEncryptorInfo(name) where info.Display select name) { EncryptionComboBox.Items.Add(name); } foreach (var protocol in Protocols) { ProtocolComboBox.Items.Add(protocol); } foreach (var obfs in ObfsStrings) { ObfsComboBox.Items.Add(obfs); } _controller.ConfigChanged += controller_ConfigChanged; ServerConfigViewModel.ServersChanged += ServerViewModel_ServersChanged; _focusIndex = focusIndex; ServersTreeView_OnSelectionChanged(this, new ItemSelectionChangedEventArgs()); } private void ServerViewModel_ServersChanged(object sender, EventArgs e) { ApplyButton.IsEnabled = true; } private static readonly string[] Protocols = { "origin", "verify_deflate", "auth_sha1_v4", "auth_aes128_md5", "auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c", "auth_chain_d", "auth_chain_e", "auth_chain_f", "auth_akarin_rand", "auth_akarin_spec_a" }; private static readonly string[] ObfsStrings = { "plain", "http_simple", "http_post", "random_head", "tls1.2_ticket_auth", "tls1.2_ticket_fastauth" }; private readonly MainController _controller; private Configuration _modifiedConfiguration; private int _focusIndex; public ServerConfigViewModel ServerConfigViewModel { get; set; } = new(); private void Window_Loaded(object sender, RoutedEventArgs e) { UpdateTitle(); LoadCurrentConfiguration(false); switch (_focusIndex) { case -1: { var index = _modifiedConfiguration.Index + 1; if (index < 0 || index > _modifiedConfiguration.Configs.Count) { index = _modifiedConfiguration.Configs.Count; } _focusIndex = index; break; } case -2: { var index = _modifiedConfiguration.Index; if (index < 0 || index > _modifiedConfiguration.Configs.Count) { index = _modifiedConfiguration.Configs.Count; } _focusIndex = index; break; } } if (_focusIndex >= 0 && _focusIndex < _modifiedConfiguration.Configs.Count) { MoveToSelectedItem(_focusIndex); } } private void UpdateTitle() { Title = $@"{this.GetWindowStringValue(@"Title")}({(Global.GuiConfig.ShareOverLan ? this.GetWindowStringValue(@"Any") : this.GetWindowStringValue(@"Local"))}:{Global.GuiConfig.LocalPort} {this.GetWindowStringValue(@"Version")}:{Controller.HttpRequest.UpdateChecker.FullVersion})"; } private void controller_ConfigChanged(object sender, EventArgs e) { LoadCurrentConfiguration(true); UpdateTitle(); } private void LoadCurrentConfiguration(bool scrollToSelectedItem) { _modifiedConfiguration = Global.Load(); ServerConfigViewModel.ReadServers(_modifiedConfiguration.Configs); ServersTreeView.ExpandAll(); ServersTreeView.CollapseAll(); if (scrollToSelectedItem) { MoveToSelectedItem(_modifiedConfiguration.Index); } ApplyButton.IsEnabled = false; } #region TreeView public void MoveToSelectedItem(int index) { if (index >= 0 && index < _modifiedConfiguration.Configs.Count) { var server = _modifiedConfiguration.Configs[index]; MoveToSelectedItem(server.Id); } } private void MoveToSelectedItem(string id) { var serverTreeViewModel = ServerTreeViewModel.FindNode(ServerConfigViewModel.ServersTreeViewCollection, id); if (serverTreeViewModel != null) { MoveToSelectedItem(serverTreeViewModel); } } private void MoveToSelectedItem(ServerTreeViewModel serverTreeViewModel) { ServersTreeView.BringIntoView(serverTreeViewModel, false, true, ScrollToPosition.Center); ServersTreeView.SelectedItems?.Clear(); ServersTreeView.SelectedItem = serverTreeViewModel; ServersTreeView_OnSelectionChanged(this, new ItemSelectionChangedEventArgs()); } private void AddButton_Click(object sender, RoutedEventArgs e) { if (ServersTreeView.SelectedItem is ServerTreeViewModel st) { switch (st.Type) { case ServerTreeViewType.Subtag: MessageBox.Show(this.GetWindowStringValue(@"AddServerError"), Controller.HttpRequest.UpdateChecker.Name, MessageBoxButton.OK, MessageBoxImage.Error); return; case ServerTreeViewType.Group: { var item = new ServerTreeViewModel { Type = ServerTreeViewType.Server, Server = new Server { Group = st.Name } }; st.Nodes.Add(item); MoveToSelectedItem(item); return; } case ServerTreeViewType.Server: { var parent = ServerTreeViewModel.FindParentNode(ServerConfigViewModel.ServersTreeViewCollection, st); if (parent != null) { var item = new ServerTreeViewModel { Type = ServerTreeViewType.Server, Server = Server.Clone(st.Server) }; var index = parent.Nodes.IndexOf(st) + 1; parent.Nodes.Insert(index, item); MoveToSelectedItem(item); } return; } default: throw new ArgumentOutOfRangeException(); } } var newServer = new Server(); ServerConfigViewModel.ReadServers(new List { newServer }); MoveToSelectedItem(newServer.Id); } private void DeleteButton_Click(object sender, RoutedEventArgs e) { var deleteItems = ServersTreeView.SelectedItems.ToArray(); foreach (var selectedItem in deleteItems) { if (selectedItem is ServerTreeViewModel st) { ServerTreeViewModel.Remove(ServerConfigViewModel.ServersTreeViewCollection, st); ServersTreeView.SelectedItems.Clear(); ServersTreeView_OnSelectionChanged(this, new ItemSelectionChangedEventArgs()); } } } private void ServersTreeView_OnSelectionChanged(object sender, ItemSelectionChangedEventArgs e) { if (ServersTreeView.SelectedItems is not null && ServersTreeView.SelectedItems.Count == 1 && ServersTreeView.SelectedItem is ServerTreeViewModel { Type: ServerTreeViewType.Server }) { ServerGroupBox.Visibility = Visibility.Visible; } else { ServerGroupBox.Visibility = Visibility.Hidden; } } private void ServersTreeView_OnItemDropping(object sender, TreeViewItemDroppingEventArgs e) { if (e.TargetNode.Content is ServerTreeViewModel target) { var source = e.DraggingNodes.Where(n => n.Content is ServerTreeViewModel).Select(n => (ServerTreeViewModel)n.Content).ToArray(); if (!source.Any()) { goto Skip; } if (source.Any(st => st.Type == ServerTreeViewType.Subtag)) { if (ServerTreeViewModel.FindParentNode(ServerConfigViewModel.ServersTreeViewCollection, target) != null) { goto Skip; } var res = e.DraggingNodes.Where(n => n.Content is ServerTreeViewModel st && st.Type == ServerTreeViewType.Subtag).ToArray(); e.DraggingNodes.Clear(); res.ForEach(x => e.DraggingNodes.Add(x)); if (e.DropPosition == DropPosition.DropAsChild) { e.DropPosition = DropPosition.DropBelow; } return; } if (source.Any(st => st.Type == ServerTreeViewType.Group)) { var res = e.DraggingNodes.Where(n => n.Content is ServerTreeViewModel st && st.Type == ServerTreeViewType.Group).ToArray(); e.DraggingNodes.Clear(); res.ForEach(x => e.DraggingNodes.Add(x)); if (target.Type == ServerTreeViewType.Subtag) { goto Skip; } if (target.Type == ServerTreeViewType.Group) { var parent = ServerTreeViewModel.FindParentNode(ServerConfigViewModel.ServersTreeViewCollection, target); if (parent == null) { goto Skip; } var isSameParent = e.DraggingNodes.All(n => n.Content is ServerTreeViewModel st && ServerTreeViewModel.FindParentNode(ServerConfigViewModel.ServersTreeViewCollection, st) == parent); if (!isSameParent) { goto Skip; } if (e.DropPosition == DropPosition.DropAsChild) { e.DropPosition = DropPosition.DropBelow; } return; } goto Skip; } // all is servers if (target.Type == ServerTreeViewType.Subtag) { goto Skip; } if (target.Type == ServerTreeViewType.Group) { var sub = ServerTreeViewModel.FindParentNode(ServerConfigViewModel.ServersTreeViewCollection, target); if (sub == null) { return; } var subName = sub.Name == I18NUtil.GetAppStringValue(@"EmptySubtag") ? string.Empty : sub.Name; var groupName = target.Name == I18NUtil.GetAppStringValue(@"EmptyGroup") ? string.Empty : target.Name; e.DraggingNodes.ForEach(n => { var server = ((ServerTreeViewModel)n.Content).Server; server.Group = groupName; server.SubTag = subName; }); e.DropPosition = DropPosition.DropAsChild; return; } e.DraggingNodes.ForEach(n => { var server = ((ServerTreeViewModel)n.Content).Server; server.Group = target.Server.Group; server.SubTag = target.Server.SubTag; }); if (e.DropPosition == DropPosition.DropAsChild) { e.DropPosition = DropPosition.DropBelow; } return; } Skip: e.Handled = true; } #endregion #region LinkTextBox private void LinkTextBox_TextChanged(object sender, TextChangedEventArgs e) { GenQr(LinkTextBox.Text); } private void LinkTextBox_PreviewMouseUp(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left) { var textBox = (TextBox)sender; textBox.Dispatcher?.InvokeAsync(() => { textBox.SelectAll(); }); } } private void LinkTextBox_GotFocus(object sender, RoutedEventArgs e) { ((TextBox)sender).SelectAll(); } #endregion private void ObfsComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { try { if (ObfsComboBox.SelectedItem == null) { return; } var obfs = (Obfs.ObfsBase)Obfs.ObfsFactory.GetObfs(ObfsComboBox.SelectedItem.ToString()); var properties = obfs.GetObfs()[$@"{ObfsComboBox.SelectedItem}"]; ObfsParamTextBox.IsEnabled = properties[2] > 0; } catch { ObfsParamTextBox.IsEnabled = true; } } private bool SaveConfig() { string oldServerId = null; if (_modifiedConfiguration.Index >= 0 && _modifiedConfiguration.Index < _modifiedConfiguration.Configs.Count) { oldServerId = _modifiedConfiguration.Configs[_modifiedConfiguration.Index].Id; } _modifiedConfiguration.Configs.Clear(); _modifiedConfiguration.Configs.AddRange(ServerConfigViewModel.ServerTreeViewModelToList(ServerConfigViewModel.ServersTreeViewCollection)); if (oldServerId != null) { var currentIndex = _modifiedConfiguration.Configs.FindIndex(server => server.Id == oldServerId); if (currentIndex != -1) { _modifiedConfiguration.Index = currentIndex; } } if (_modifiedConfiguration.Configs.Count == 0) { MessageBox.Show(this.GetWindowStringValue(@"NoServer")); return false; } _controller.SaveServersConfig(_modifiedConfiguration, true); return true; } private void OkButton_Click(object sender, RoutedEventArgs e) { if (ApplyButton.IsEnabled) { if (SaveConfig()) { Close(); } } else { Close(); } } private void CancelButton_Click(object sender, RoutedEventArgs e) { Close(); } private void ApplyButton_Click(object sender, RoutedEventArgs e) { if (SaveConfig()) { ApplyButton.IsEnabled = false; } } #region QrCode private void GenQr(string text) { if (PictureQrCode.Visibility != Visibility.Visible) { return; } try { var h = Convert.ToInt32(MainGrid.ActualHeight); var w = Convert.ToInt32(MainGrid.ColumnDefinitions[2].ActualWidth - PictureQrCode.Margin.Left - PictureQrCode.Margin.Right); if (h <= 0 || w <= 0) { PictureQrCode.Source = null; } else { PictureQrCode.Source = text != string.Empty ? QrCodeUtils.GenQrCode(text, w, h) : QrCodeUtils.GenQrCode2(text, Math.Min(w, h)); } } catch { PictureQrCode.Source = null; } } private double _oldWidth = 400.0; private void ShowQrCodeButton_OnClick(object sender, RoutedEventArgs e) { if (PictureQrCode.Visibility != Visibility.Visible) { PictureQrCode.Visibility = Splitter2.Visibility = Visibility.Visible; MainGrid.ColumnDefinitions[2].Width = new GridLength(_oldWidth, GridUnitType.Pixel); Width += _oldWidth; ShowQrCodeButton.Content = @"<<"; } else { PictureQrCode.Visibility = Splitter2.Visibility = Visibility.Collapsed; _oldWidth = MainGrid.ColumnDefinitions[2].ActualWidth; Width -= _oldWidth; MainGrid.ColumnDefinitions[2].Width = new GridLength(0); ShowQrCodeButton.Content = @">>"; } } #endregion private void ConfigWindow_OnActivated(object sender, EventArgs e) { Topmost = false; } } } ================================================ FILE: shadowsocks-csharp/View/ServerLogWindow.xaml ================================================ Index GroupName FriendlyName SpeedLog.Connecting SpeedLog.AvgConnectTimeText SpeedLog.AvgDownloadBytesText SpeedLog.MaxDownSpeedText SpeedLog.AvgUploadBytesText SpeedLog.MaxUpSpeedText SpeedLog.TotalDownloadBytesText SpeedLog.TotalUploadBytesText SpeedLog.TotalDownloadRawBytesText SpeedLog.ConnectError SpeedLog.ErrorTimeoutTimes SpeedLog.ErrorEmptyTimes SpeedLog.ErrorContinuousTimes SpeedLog.ErrorPercent #E5E5E5 ================================================ FILE: shadowsocks-csharp/View/ServerLogWindow.xaml.cs ================================================ using Shadowsocks.Controller; using Shadowsocks.Controller.HttpRequest; using Shadowsocks.Model; using Shadowsocks.Util; using Shadowsocks.View.Controls; using Shadowsocks.ViewModel; using Syncfusion.Data; using Syncfusion.UI.Xaml.Grid; using Syncfusion.UI.Xaml.Grid.Helpers; using Syncfusion.UI.Xaml.ScrollAxis; using System; using System.ComponentModel; using System.Linq; using System.Windows; using System.Windows.Input; using System.Windows.Threading; namespace Shadowsocks.View { public partial class ServerLogWindow { public ServerLogWindow(MainController controller, WindowStatus status) { InitializeComponent(); I18NUtil.SetLanguage(Resources, @"ServerLogWindow"); LoadLanguage(); ServerDataGrid.GridColumnSizer = new GridColumnSizerExt(ServerDataGrid); _controller = controller; Closed += (o, e) => { _controller.ConfigChanged -= controller_ConfigChanged; }; _controller.ConfigChanged += controller_ConfigChanged; LoadConfig(true); ServerDataGrid.GridColumnSizer.SortIconWidth = 0; if (status == null) { SizeToContent = SizeToContent.Width; Height = 600; WindowStartupLocation = WindowStartupLocation.CenterScreen; ServerDataGrid.ShowBusyIndicator = false; } else { ServerDataGrid.ShowBusyIndicator = true; SizeToContent = SizeToContent.Manual; status.SetStatus(this); } } private void LoadLanguage() { ServerDataGrid.Columns[Resources[@"IndexMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"Index"); ServerDataGrid.Columns[Resources[@"GroupMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"Group"); ServerDataGrid.Columns[Resources[@"ServerMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"Server"); ServerDataGrid.Columns[Resources[@"ConnectingMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"Connecting"); ServerDataGrid.Columns[Resources[@"AvgConnectTimeMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"Latency"); ServerDataGrid.Columns[Resources[@"AvgDownloadBytesMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"AvgDSpeed"); ServerDataGrid.Columns[Resources[@"MaxDownSpeedMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"MaxDSpeed"); ServerDataGrid.Columns[Resources[@"AvgUploadBytesMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"AvgUpSpeed"); ServerDataGrid.Columns[Resources[@"MaxUpSpeedMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"MaxUpSpeed"); ServerDataGrid.Columns[Resources[@"TotalDownloadBytesMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"Dload"); ServerDataGrid.Columns[Resources[@"TotalUploadBytesMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"Upload"); ServerDataGrid.Columns[Resources[@"TotalDownloadRawBytesMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"DloadRaw"); ServerDataGrid.Columns[Resources[@"ConnectErrorMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"Error"); ServerDataGrid.Columns[Resources[@"ErrorTimeoutTimesMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"Timeout"); ServerDataGrid.Columns[Resources[@"ErrorEmptyTimesMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"EmptyResponse"); ServerDataGrid.Columns[Resources[@"ErrorContinuousTimesMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"Continuous"); ServerDataGrid.Columns[Resources[@"ErrorPercentMappingName"].ToString()].HeaderText = this.GetWindowStringValue(@"ErrorPercent"); } private void LoadConfig(bool isFirstLoad) { UpdateTitle(); ServerDataGrid.View?.BeginInit(); ServerLogViewModel.ReadConfig(); ServerDataGrid.View?.EndInit(); Dispatcher.CurrentDispatcher.InvokeAsync(() => { if (isFirstLoad && ServerLogViewModel.SelectedServer != null) { ServerDataGrid.ScrollInView(new RowColumnIndex(ServerLogViewModel.SelectedServer.Index, 2)); } }, DispatcherPriority.Input); } private void controller_ConfigChanged(object sender, EventArgs e) { LoadConfig(false); } private readonly MainController _controller; public ServerLogViewModel ServerLogViewModel { get; set; } = new(); private void UpdateTitle() { Title = $@"{this.GetWindowStringValue(@"Title")}({(Global.GuiConfig.ShareOverLan ? this.GetWindowStringValue(@"Any") : this.GetWindowStringValue(@"Local"))}:{Global.GuiConfig.LocalPort} {this.GetWindowStringValue(@"Version")}{Controller.HttpRequest.UpdateChecker.FullVersion})"; } private void AlwaysTopMenuItem_OnClick(object sender, RoutedEventArgs e) { Topmost = !Topmost; } private void AutoSizeMenuItem_OnClick(object sender, RoutedEventArgs e) { //Refreshing auto size calculation ServerDataGrid.GridColumnSizer.ResetAutoCalculationforAllColumns(); ServerDataGrid.GridColumnSizer.Refresh(); foreach (var column in ServerDataGrid.Columns.Where(column => !double.IsNaN(column.Width))) { column.Width = double.NaN; } ServerDataGrid.GridColumnSizer.Refresh(); SizeToContent = SizeToContent.Width; } private void DisconnectDirectMenuItem_OnClick(object sender, RoutedEventArgs e) { Server.ForwardServer.Connections.CloseAll(); } private void DisconnectAllMenuItem_OnClick(object sender, RoutedEventArgs e) { _controller.DisconnectAllConnections(); Server.ForwardServer.Connections.CloseAll(); } private void ClearMaxMenuItem_OnClick(object sender, RoutedEventArgs e) { var config = Global.GuiConfig; foreach (var server in config.Configs) { server.SpeedLog.ClearMaxSpeed(); } } private void ClearAllMenuItem_OnClick(object sender, RoutedEventArgs e) { var config = Global.GuiConfig; foreach (var server in config.Configs) { server.SpeedLog.Clear(); } } private void ClearSelectedTotalMenuItem_OnClick(object sender, RoutedEventArgs e) { var config = Global.GuiConfig; if (config.Index >= 0 && config.Index < config.Configs.Count) { try { _controller.ClearTransferTotal(config.Configs[config.Index].Id); } catch { // ignored } } } private void ClearTotalMenuItem_OnClick(object sender, RoutedEventArgs e) { var config = Global.GuiConfig; foreach (var server in config.Configs) { _controller.ClearTransferTotal(server.Id); } } private void CopyCurrentLinkMenuItem_OnClick(object sender, RoutedEventArgs e) { var config = Global.GuiConfig; if (config.Index >= 0 && config.Index < config.Configs.Count) { var link = config.Configs[config.Index].SsrLink; Clipboard.SetDataObject(link); } } private void CopyCurrentGroupLinksMenuItem_OnClick(object sender, RoutedEventArgs e) { var config = Global.GuiConfig; if (config.Index >= 0 && config.Index < config.Configs.Count) { var group = config.Configs[config.Index].Group; var link = config.Configs.Where(t => t.Group == group).Aggregate(string.Empty, (current, t) => current + $@"{t.SsrLink}{Environment.NewLine}"); Clipboard.SetDataObject(link); } } private void CopyAllEnableLinksMenuItem_OnClick(object sender, RoutedEventArgs e) { var config = Global.GuiConfig; var link = config.Configs.Where(t => t.Enable).Aggregate(string.Empty, (current, t) => current + $@"{t.SsrLink}{Environment.NewLine}"); Clipboard.SetDataObject(link); } private void CopyAllLinksMenuItem_OnClick(object sender, RoutedEventArgs e) { var config = Global.GuiConfig; var link = config.Configs.Aggregate(string.Empty, (current, t) => current + $@"{t.SsrLink}{Environment.NewLine}"); Clipboard.SetDataObject(link); } private void ServerDataGrid_OnCellTapped(object sender, GridCellTappedEventArgs e) { if (e.ChangedButton != MouseButton.Left) { return; } if (ServerDataGrid.CurrentColumn != null && ServerDataGrid.SelectedItem is Server server) { var index = server.Index - 1; var mappingName = ServerDataGrid.CurrentColumn.MappingName; if (mappingName == Resources[@"ServerMappingName"].ToString()) { _controller.DisconnectAllConnections(true); _controller.SelectServerIndex(index); } else if (mappingName == Resources[@"GroupMappingName"].ToString()) { var group = server.Group; if (!string.IsNullOrEmpty(group)) { var enable = !server.Enable; foreach (var sameGroupServer in ServerLogViewModel.ServersCollection) { if (sameGroupServer.Group == group) { sameGroupServer.Enable = enable; } } Global.SaveConfig(); } } else { return; } ServerDataGrid.ClearSelections(false); ServerDataGrid.SelectCell(server, ServerDataGrid.Columns[0]); } } private void ServerDataGrid_OnCellDoubleTapped(object sender, GridCellDoubleTappedEventArgs e) { if (e.ChangedButton != MouseButton.Left) { return; } if (ServerDataGrid.CurrentColumn != null && ServerDataGrid.SelectedItem is Server server) { var index = server.Index - 1; var mappingName = ServerDataGrid.CurrentColumn.MappingName; if (mappingName == Resources[@"IndexMappingName"].ToString()) { _controller.ShowConfigForm(index); } else if (mappingName == Resources[@"ConnectingMappingName"].ToString()) { server.Connections.CloseAll(); } else if (mappingName == Resources[@"MaxDownSpeedMappingName"].ToString() || mappingName == Resources[@"MaxUpSpeedMappingName"].ToString()) { server.SpeedLog.ClearMaxSpeed(); } else if (mappingName == Resources[@"TotalDownloadBytesMappingName"].ToString() || mappingName == Resources[@"TotalUploadBytesMappingName"].ToString()) { server.SpeedLog.ClearTrans(); } else if (mappingName == Resources[@"TotalDownloadRawBytesMappingName"].ToString()) { server.SpeedLog.Clear(); server.Enable = true; } else if (mappingName == Resources[@"ConnectErrorMappingName"].ToString() || mappingName == Resources[@"ErrorTimeoutTimesMappingName"].ToString() || mappingName == Resources[@"ErrorEmptyTimesMappingName"].ToString() || mappingName == Resources[@"ErrorContinuousTimesMappingName"].ToString() || mappingName == Resources[@"ErrorPercentMappingName"].ToString()) { server.SpeedLog.ClearError(); server.Enable = true; } else { ServerDataGrid.ClearSelections(false); ServerDataGrid.SelectCell(server, ServerDataGrid.Columns[0]); } } } private void ServerDataGrid_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { var visualContainer = ServerDataGrid.GetVisualContainer(); var rowColumnIndex = visualContainer.PointToCellRowColumnIndex(e.GetPosition(visualContainer)); if (rowColumnIndex.IsEmpty) { return; } var columnIndex = ServerDataGrid.ResolveToGridVisibleColumnIndex(rowColumnIndex.ColumnIndex); if (columnIndex != -1) { return; } var recordIndex = ServerDataGrid.ResolveToRecordIndex(rowColumnIndex.RowIndex); if (recordIndex == -1) { const string columnName = @"Enable"; var sortColumnDescription = ServerDataGrid.SortColumnDescriptions.FirstOrDefault(col => col.ColumnName == columnName); if (sortColumnDescription != null) { sortColumnDescription.SortDirection = sortColumnDescription.SortDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending; ServerDataGrid.SortColumnDescriptions.Remove(sortColumnDescription); } else { sortColumnDescription = new SortColumnDescription { ColumnName = columnName, SortDirection = ListSortDirection.Ascending }; } if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) { } else { ServerDataGrid.SortColumnDescriptions.Clear(); } ServerDataGrid.SortColumnDescriptions.Add(sortColumnDescription); } else { var entry = ServerDataGrid.View.GroupDescriptions.Count == 0 ? ServerDataGrid.View.Records[recordIndex] : ServerDataGrid.View.TopLevelGroup.DisplayElements[recordIndex]; if (entry.IsRecords && entry is RecordEntry recordEntry && recordEntry.Data is Server server) { server.Enable = !server.Enable; Global.SaveConfig(); } } } } } ================================================ FILE: shadowsocks-csharp/View/SettingsWindow.xaml ================================================